Commit 0cae6ca1 by willmcgugan@gmail.com

Fixes for fs commands in PY3

parent 747c7b9b
...@@ -8,17 +8,17 @@ from collections import defaultdict ...@@ -8,17 +8,17 @@ from collections import defaultdict
import sys import sys
class FSls(Command): class FSls(Command):
usage = """fsls [OPTIONS]... [PATH] usage = """fsls [OPTIONS]... [PATH]
List contents of [PATH]""" List contents of [PATH]"""
def get_optparse(self): def get_optparse(self):
optparse = super(FSls, self).get_optparse() optparse = super(FSls, self).get_optparse()
optparse.add_option('-u', '--full', dest='fullpath', action="store_true", default=False, optparse.add_option('-u', '--full', dest='fullpath', action="store_true", default=False,
help="output full path", metavar="FULL") help="output full path", metavar="FULL")
optparse.add_option('-s', '--syspath', dest='syspath', action="store_true", default=False, optparse.add_option('-s', '--syspath', dest='syspath', action="store_true", default=False,
help="output system path (if one exists)", metavar="SYSPATH") help="output system path (if one exists)", metavar="SYSPATH")
optparse.add_option('-r', '--url', dest='url', action="store_true", default=False, optparse.add_option('-r', '--url', dest='url', action="store_true", default=False,
help="output URL in place of path (if one exists)", metavar="URL") help="output URL in place of path (if one exists)", metavar="URL")
optparse.add_option('-d', '--dirsonly', dest='dirsonly', action="store_true", default=False, optparse.add_option('-d', '--dirsonly', dest='dirsonly', action="store_true", default=False,
...@@ -29,73 +29,73 @@ List contents of [PATH]""" ...@@ -29,73 +29,73 @@ List contents of [PATH]"""
help="use a long listing format", metavar="LONG") help="use a long listing format", metavar="LONG")
optparse.add_option('-a', '--all', dest='all', action='store_true', default=False, optparse.add_option('-a', '--all', dest='all', action='store_true', default=False,
help="do not hide dot files") help="do not hide dot files")
return optparse return optparse
def do_run(self, options, args): def do_run(self, options, args):
output = self.output output = self.output
if not args: if not args:
args = [u'.'] args = [u'.']
dir_paths = [] dir_paths = []
file_paths = [] file_paths = []
fs_used = set() fs_used = set()
for fs_url in args: for fs_url in args:
fs, path = self.open_fs(fs_url) fs, path = self.open_fs(fs_url)
fs_used.add(fs) fs_used.add(fs)
path = path or '.' path = path or '.'
wildcard = None wildcard = None
if iswildcard(path): if iswildcard(path):
path, wildcard = pathsplit(path) path, wildcard = pathsplit(path)
if path != '.' and fs.isfile(path): if path != '.' and fs.isfile(path):
if not options.dirsonly: if not options.dirsonly:
file_paths.append(path) file_paths.append(path)
else: else:
if not options.filesonly: if not options.filesonly:
dir_paths += fs.listdir(path, dir_paths += fs.listdir(path,
wildcard=wildcard, wildcard=wildcard,
full=options.fullpath or options.url, full=options.fullpath or options.url,
dirs_only=True) dirs_only=True)
if not options.dirsonly: if not options.dirsonly:
file_paths += fs.listdir(path, file_paths += fs.listdir(path,
wildcard=wildcard, wildcard=wildcard,
full=options.fullpath or options.url, full=options.fullpath or options.url,
files_only=True) files_only=True)
for fs in fs_used: for fs in fs_used:
try: try:
fs.close() fs.close()
except FSError: except FSError:
pass pass
if options.syspath: if options.syspath:
# Path without a syspath, just won't be displayed # Path without a syspath, just won't be displayed
dir_paths = filter(None, [fs.getsyspath(path, allow_none=True) for path in dir_paths]) dir_paths = filter(None, [fs.getsyspath(path, allow_none=True) for path in dir_paths])
file_paths = filter(None, [fs.getsyspath(path, allow_none=True) for path in file_paths]) file_paths = filter(None, [fs.getsyspath(path, allow_none=True) for path in file_paths])
if options.url: if options.url:
# Path without a syspath, just won't be displayed # Path without a syspath, just won't be displayed
dir_paths = filter(None, [fs.getpathurl(path, allow_none=True) for path in dir_paths]) dir_paths = filter(None, [fs.getpathurl(path, allow_none=True) for path in dir_paths])
file_paths = filter(None, [fs.getpathurl(path, allow_none=True) for path in file_paths]) file_paths = filter(None, [fs.getpathurl(path, allow_none=True) for path in file_paths])
dirs = frozenset(dir_paths) dirs = frozenset(dir_paths)
paths = sorted(dir_paths + file_paths, key=lambda p:p.lower()) paths = sorted(dir_paths + file_paths, key=lambda p: p.lower())
if not options.all: if not options.all:
paths = [path for path in paths if not isdotfile(path)] paths = [path for path in paths if not isdotfile(path)]
if not paths: if not paths:
return return
def columnize(paths, num_columns): def columnize(paths, num_columns):
col_height = (len(paths) + num_columns - 1) / num_columns col_height = (len(paths) + num_columns - 1) / num_columns
columns = [[] for _ in xrange(num_columns)] columns = [[] for _ in xrange(num_columns)]
col_no = 0 col_no = 0
col_pos = 0 col_pos = 0
for path in paths: for path in paths:
...@@ -104,73 +104,72 @@ List contents of [PATH]""" ...@@ -104,73 +104,72 @@ List contents of [PATH]"""
if col_pos >= col_height: if col_pos >= col_height:
col_no += 1 col_no += 1
col_pos = 0 col_pos = 0
padded_columns = [] padded_columns = []
wrap_filename = self.wrap_filename wrap_filename = self.wrap_filename
wrap_dirname = self.wrap_dirname wrap_dirname = self.wrap_dirname
def wrap(path):
def wrap(path):
if path in dirs: if path in dirs:
return wrap_dirname(path.ljust(max_width)) return wrap_dirname(path.ljust(max_width))
else: else:
return wrap_filename(path.ljust(max_width)) return wrap_filename(path.ljust(max_width))
for column in columns: for column in columns:
if column: if column:
max_width = max([len(path) for path in column]) max_width = max([len(path) for path in column])
else: else:
max_width = 1 max_width = 1
max_width = min(max_width, terminal_width) max_width = min(max_width, terminal_width)
padded_columns.append([wrap(path) for path in column]) padded_columns.append([wrap(path) for path in column])
return padded_columns return padded_columns
def condense_columns(columns): def condense_columns(columns):
max_column_height = max([len(col) for col in columns]) max_column_height = max([len(col) for col in columns])
lines = [[] for _ in xrange(max_column_height)] lines = [[] for _ in xrange(max_column_height)]
for column in columns: for column in columns:
for line, path in zip(lines, column): for line, path in zip(lines, column):
line.append(path) line.append(path)
return '\n'.join(u' '.join(line) for line in lines) return '\n'.join(u' '.join(line) for line in lines)
if options.long: if options.long:
for path in paths: for path in paths:
if path in dirs: if path in dirs:
output((self.wrap_dirname(path), '\n')) output((self.wrap_dirname(path), '\n'))
else: else:
output((self.wrap_filename(path), '\n')) output((self.wrap_filename(path), '\n'))
else: else:
terminal_width = self.terminal_width terminal_width = self.terminal_width
path_widths = [len(path) for path in paths] path_widths = [len(path) for path in paths]
smallest_paths = min(path_widths) smallest_paths = min(path_widths)
num_paths = len(paths) num_paths = len(paths)
num_cols = min(terminal_width / (smallest_paths + 2), num_paths) num_cols = min(terminal_width // (smallest_paths + 2), num_paths)
while num_cols: while num_cols:
col_height = (num_paths + num_cols - 1) / num_cols col_height = (num_paths + num_cols - 1) // num_cols
line_width = 0 line_width = 0
for col_no in xrange(num_cols): for col_no in xrange(num_cols):
try: try:
col_width = max(path_widths[col_no*col_height:(col_no + 1) * col_height]) col_width = max(path_widths[col_no * col_height: (col_no + 1) * col_height])
except ValueError: except ValueError:
continue continue
line_width += col_width line_width += col_width
if line_width > terminal_width: if line_width > terminal_width:
break; break
line_width += 2 line_width += 2
else: else:
if line_width - 1 <= terminal_width: if line_width - 1 <= terminal_width:
break break
num_cols -= 1 num_cols -= 1
num_cols = max(1, num_cols) num_cols = max(1, num_cols)
columns = columnize(paths, num_cols) columns = columnize(paths, num_cols)
output((condense_columns(columns), '\n')) output((condense_columns(columns), '\n'))
def run(): def run():
return FSls().run() return FSls().run()
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(run()) sys.exit(run())
\ No newline at end of file
...@@ -8,7 +8,7 @@ from fs.errors import FSError ...@@ -8,7 +8,7 @@ from fs.errors import FSError
from fs.path import splitext, pathsplit, isdotfile, iswildcard from fs.path import splitext, pathsplit, isdotfile, iswildcard
import platform import platform
from collections import defaultdict from collections import defaultdict
import re import six
if platform.system() == 'Windows': if platform.system() == 'Windows':
...@@ -76,8 +76,12 @@ class Command(object): ...@@ -76,8 +76,12 @@ class Command(object):
version = '' version = ''
def __init__(self, usage='', version=''): def __init__(self, usage='', version=''):
self.output_file = sys.stdout if six.PY3:
self.error_file = sys.stderr self.output_file = sys.stdout.buffer
self.error_file = sys.stderr.buffer
else:
self.output_file = sys.stdout
self.error_file = sys.stderr
self.encoding = getattr(self.output_file, 'encoding', 'utf-8') or 'utf-8' self.encoding = getattr(self.output_file, 'encoding', 'utf-8') or 'utf-8'
self.verbosity_level = 0 self.verbosity_level = 0
self.terminal_colors = not sys.platform.startswith('win') and self.is_terminal() self.terminal_colors = not sys.platform.startswith('win') and self.is_terminal()
...@@ -210,11 +214,9 @@ class Command(object): ...@@ -210,11 +214,9 @@ class Command(object):
return raw_input('%s: %s ' % (self.name, msg)) return raw_input('%s: %s ' % (self.name, msg))
def text_encode(self, text): def text_encode(self, text):
if not isinstance(text, unicode): if not isinstance(text, unicode):
text = text.decode('ascii', 'replace') text = text.decode('ascii', 'replace')
text = text.encode(self.encoding, 'replace') text = text.encode(self.encoding, 'replace')
return text return text
def output(self, msgs, verbose=False): def output(self, msgs, verbose=False):
...@@ -226,10 +228,8 @@ class Command(object): ...@@ -226,10 +228,8 @@ class Command(object):
self.output_file.write(self.text_encode(msg)) self.output_file.write(self.text_encode(msg))
def output_table(self, table, col_process=None, verbose=False): def output_table(self, table, col_process=None, verbose=False):
if verbose and not self.verbose: if verbose and not self.verbose:
return return
if col_process is None: if col_process is None:
col_process = {} col_process = {}
...@@ -248,7 +248,9 @@ class Command(object): ...@@ -248,7 +248,9 @@ class Command(object):
td = col_process[col_no](td) td = col_process[col_no](td)
out_col.append(td) out_col.append(td)
lines.append(self.text_encode('%s\n' % ' '.join(out_col).rstrip())) lines.append(self.text_encode('%s\n' % ' '.join(out_col).rstrip()))
self.output(''.join(lines)) for l in lines:
self.output_file.write(l)
#self.output(''.join(lines))
def error(self, *msgs): def error(self, *msgs):
for msg in msgs: for msg in msgs:
...@@ -275,7 +277,7 @@ class Command(object): ...@@ -275,7 +277,7 @@ class Command(object):
desc = getattr(fs_opener, 'desc', '') desc = getattr(fs_opener, 'desc', '')
opener_table.append((names, desc)) opener_table.append((names, desc))
opener_table.sort(key = lambda r:r[0]) opener_table.sort(key=lambda r: r[0])
def wrap_line(text): def wrap_line(text):
...@@ -298,14 +300,13 @@ class Command(object): ...@@ -298,14 +300,13 @@ class Command(object):
for names, desc in opener_table: for names, desc in opener_table:
self.output(('-' * self.terminal_width, '\n')) self.output(('-' * self.terminal_width, '\n'))
proto = ', '.join([n+'://' for n in names]) proto = ', '.join([n + '://' for n in names])
self.output((self.wrap_dirname('[%s]' % proto), '\n\n')) self.output((self.wrap_dirname('[%s]' % proto), '\n\n'))
if not desc.strip(): if not desc.strip():
desc = "No information available" desc = "No information available"
wrap_line(desc) wrap_line(desc)
self.output('\n') self.output('\n')
def run(self): def run(self):
parser = self.get_optparse() parser = self.get_optparse()
options, args = parser.parse_args() options, args = parser.parse_args()
...@@ -340,7 +341,8 @@ class Command(object): ...@@ -340,7 +341,8 @@ class Command(object):
opener.add(new_opener) opener.add(new_opener)
args = [unicode(arg, sys.getfilesystemencoding()) for arg in args] if not six.PY3:
args = [unicode(arg, sys.getfilesystemencoding()) for arg in args]
self.verbose = options.verbose self.verbose = options.verbose
try: try:
return self.do_run(options, args) or 0 return self.do_run(options, args) or 0
......
...@@ -18,15 +18,16 @@ __all__ = ['copyfile', ...@@ -18,15 +18,16 @@ __all__ = ['copyfile',
'find_duplicates', 'find_duplicates',
'print_fs'] 'print_fs']
import os
import sys import sys
import stat import stat
import six
from fs.mountfs import MountFS from fs.mountfs import MountFS
from fs.path import pathjoin from fs.path import pathjoin
from fs.errors import DestinationExistsError, RemoveRootError from fs.errors import DestinationExistsError, RemoveRootError
from fs.base import FS from fs.base import FS
def copyfile(src_fs, src_path, dst_fs, dst_path, overwrite=True, chunk_size=64*1024): def copyfile(src_fs, src_path, dst_fs, dst_path, overwrite=True, chunk_size=64*1024):
"""Copy a file from one filesystem to another. Will use system copyfile, if both files have a syspath. """Copy a file from one filesystem to another. Will use system copyfile, if both files have a syspath.
Otherwise file will be copied a chunk at a time. Otherwise file will be copied a chunk at a time.
...@@ -491,7 +492,7 @@ def print_fs(fs, ...@@ -491,7 +492,7 @@ def print_fs(fs,
terminal_colors = hasattr(file_out, 'isatty') and file_out.isatty() terminal_colors = hasattr(file_out, 'isatty') and file_out.isatty()
def write(line): def write(line):
file_out.write(line.encode(file_encoding, 'replace')+'\n') file_out.write(line.encode(file_encoding, 'replace') + b'\n')
def wrap_prefix(prefix): def wrap_prefix(prefix):
if not terminal_colors: if not terminal_colors:
...@@ -511,11 +512,7 @@ def print_fs(fs, ...@@ -511,11 +512,7 @@ def print_fs(fs,
def wrap_filename(fname): def wrap_filename(fname):
if not terminal_colors: if not terminal_colors:
return fname return fname
# if '.' in fname:
# name, ext = os.path.splitext(fname)
# fname = '%s\x1b[36m%s\x1b[0m' % (name, ext)
if fname.startswith('.'): if fname.startswith('.'):
#fname = '\x1b[2m%s\x1b[0m' % fname
fname = '\x1b[33m%s\x1b[0m' % fname fname = '\x1b[33m%s\x1b[0m' % fname
return fname return fname
dircount = [0] dircount = [0]
......
...@@ -15,6 +15,16 @@ changedir=.tox ...@@ -15,6 +15,16 @@ changedir=.tox
commands = nosetests fs.tests -v \ commands = nosetests fs.tests -v \
[] []
[testenv:py31]
commands = nosetests fs.tests -v \
[]
deps = distribute
six
dexml
nose
winpdb
[testenv:py32] [testenv:py32]
commands = nosetests fs.tests -v \ commands = nosetests fs.tests -v \
[] []
...@@ -24,3 +34,12 @@ deps = distribute ...@@ -24,3 +34,12 @@ deps = distribute
nose nose
winpdb winpdb
[testenv:py33]
commands = nosetests fs.tests -v \
[]
deps = distribute
six
dexml
nose
winpdb
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment