X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=cmd%2Fftp-cmd.py;h=8bd57b6d81accff181dde968af13f865f3979348;hb=c40b3dd5fd74e72024fbaad3daf5a958aefa1c54;hp=1edb5f521442d731f50a105100639b22249e37c2;hpb=2ff672c48f3dbde761b30775adcdc76a621df527;p=bup.git diff --git a/cmd/ftp-cmd.py b/cmd/ftp-cmd.py index 1edb5f5..8bd57b6 100755 --- a/cmd/ftp-cmd.py +++ b/cmd/ftp-cmd.py @@ -1,50 +1,31 @@ -#!/usr/bin/env python -import sys, os, stat, fnmatch -from bup import options, git, shquote, vfs -from bup.helpers import * +#!/bin/sh +"""": # -*-python-*- +bup_python="$(dirname "$0")/bup-python" || exit $? +exec "$bup_python" "$0" ${1+"$@"} +""" +# end of bup preamble -handle_ctrl_c() +from __future__ import absolute_import +import sys, os, stat, fnmatch +from bup import options, git, shquote, ls, vfs +from bup.helpers import chunkyreader, handle_ctrl_c, log +from bup.repo import LocalRepo -def node_name(text, n): - if stat.S_ISDIR(n.mode): - return '%s/' % text - elif stat.S_ISLNK(n.mode): - return '%s@' % text - else: - return '%s' % text +handle_ctrl_c() class OptionError(Exception): pass -ls_optspec = """ -ls [-a] [path...] --- -a,all include hidden files in the listing -""" -ls_opt = options.Options('ls', ls_optspec, onabort=OptionError) - -def do_ls(cmd_args): +def do_ls(repo, args): try: - (opt, flags, extra) = ls_opt.parse(cmd_args) - except OptionError, e: + opt = ls.opts_from_cmdline(args, onabort=OptionError) + except OptionError as e: + log('error: %s' % e) return - - L = [] - - for path in (extra or ['.']): - n = pwd.try_resolve(path) - - if stat.S_ISDIR(n.mode): - for sub in n: - name = sub.name - if opt.all or not len(name)>1 or not name.startswith('.'): - L.append(node_name(name, sub)) - else: - L.append(node_name(path, n)) - print columnate(L, '') + return ls.within_repo(repo, opt) def write_to_file(inf, outf): @@ -58,23 +39,25 @@ def inputiter(): try: yield raw_input('bup> ') except EOFError: + print '' # Clear the line for the terminal's next prompt break else: for line in sys.stdin: yield line -def _completer_get_subs(line): +def _completer_get_subs(repo, line): (qtype, lastword) = shquote.unfinished_word(line) (dir,name) = os.path.split(lastword) - #log('\ncompleter: %r %r %r\n' % (qtype, lastword, text)) - try: - n = pwd.resolve(dir) - subs = list(filter(lambda x: x.name.startswith(name), - n.subs())) - except vfs.NoSuchFile, e: - subs = [] - return (dir, name, qtype, lastword, subs) + dir_path = vfs.resolve(repo, dir or '/') + _, dir_item = dir_path[-1] + if not dir_item: + subs = tuple() + else: + subs = tuple(dir_path + (entry,) + for entry in vfs.contents(repo, dir_item) + if (entry[0] != '.' and entry[0].startswith(name))) + return dir, name, qtype, lastword, subs def find_readline_lib(): @@ -115,7 +98,8 @@ def init_readline_vars(): rl_completion_suppress_append = None _last_line = None _last_res = None -def completer(text, state): +def completer(text, iteration): + global repo global _last_line global _last_res global rl_completion_suppress_append @@ -124,26 +108,28 @@ def completer(text, state): try: line = readline.get_line_buffer()[:readline.get_endidx()] if _last_line != line: - _last_res = _completer_get_subs(line) + _last_res = _completer_get_subs(repo, line) _last_line = line (dir, name, qtype, lastword, subs) = _last_res - if state < len(subs): - sn = subs[state] - sn1 = sn.try_resolve() # find the type of any symlink target - fullname = os.path.join(dir, sn.name) - if stat.S_ISDIR(sn1.mode): + if iteration < len(subs): + path = subs[iteration] + leaf_name, leaf_item = path[-1] + res = vfs.try_resolve(repo, leaf_name, parent=path[:-1]) + leaf_name, leaf_item = res[-1] + fullname = os.path.join(*(name for name, item in res)) + if stat.S_ISDIR(vfs.item_mode(leaf_item)): ret = shquote.what_to_add(qtype, lastword, fullname+'/', terminate=False) else: ret = shquote.what_to_add(qtype, lastword, fullname, terminate=True) + ' ' return text + ret - except Exception, e: + except Exception as e: log('\n') try: import traceback traceback.print_tb(sys.exc_traceback) - except Exception, e2: + except Exception as e2: log('Error printing traceback: %s\n' % e2) log('\nError in completion: %s\n' % e) @@ -151,13 +137,13 @@ def completer(text, state): optspec = """ bup ftp [commands...] """ -o = options.Options('bup ftp', optspec) +o = options.Options(optspec) (opt, flags, extra) = o.parse(sys.argv[1:]) git.check_repo_or_die() -top = vfs.RefList(None) -pwd = top +repo = LocalRepo() +pwd = vfs.resolve(repo, '/') rv = 0 if extra: @@ -172,7 +158,10 @@ else: if readline: readline.set_completer_delims(' \t\n\r/') readline.set_completer(completer) - readline.parse_and_bind("tab: complete") + if sys.platform.startswith('darwin'): + # MacOS uses a slightly incompatible clone of libreadline + readline.parse_and_bind('bind ^I rl_complete') + readline.parse_and_bind('tab: complete') init_readline_vars() lines = inputiter() @@ -184,19 +173,33 @@ for line in lines: #log('execute: %r %r\n' % (cmd, parm)) try: if cmd == 'ls': - do_ls(words[1:]) + # FIXME: respect pwd (perhaps via ls accepting resolve path/parent) + do_ls(repo, words[1:]) elif cmd == 'cd': np = pwd for parm in words[1:]: - np = np.resolve(parm) - if not stat.S_ISDIR(np.mode): - raise vfs.NotDir('%s is not a directory' % parm) + res = vfs.resolve(repo, parm, parent=np) + _, leaf_item = res[-1] + if not leaf_item: + raise Exception('%r does not exist' + % '/'.join(name for name, item in res)) + if not stat.S_ISDIR(vfs.item_mode(leaf_item)): + raise Exception('%r is not a directory' % parm) + np = res pwd = np elif cmd == 'pwd': - print pwd.fullname() + if len(pwd) == 1: + sys.stdout.write('/') + print '/'.join(name for name, item in pwd) elif cmd == 'cat': for parm in words[1:]: - write_to_file(pwd.resolve(parm).open(), sys.stdout) + res = vfs.resolve(repo, parm, parent=pwd) + _, leaf_item = res[-1] + if not leaf_item: + raise Exception('%r does not exist' % + '/'.join(name for name, item in res)) + with vfs.fopen(repo, leaf_item) as srcfile: + write_to_file(srcfile, sys.stdout) elif cmd == 'get': if len(words) not in [2,3]: rv = 1 @@ -204,33 +207,50 @@ for line in lines: rname = words[1] (dir,base) = os.path.split(rname) lname = len(words)>2 and words[2] or base - inf = pwd.resolve(rname).open() - log('Saving %r\n' % lname) - write_to_file(inf, open(lname, 'wb')) + res = vfs.resolve(repo, rname, parent=pwd) + _, leaf_item = res[-1] + if not leaf_item: + raise Exception('%r does not exist' % + '/'.join(name for name, item in res)) + with vfs.fopen(repo, leaf_item) as srcfile: + with open(lname, 'wb') as destfile: + log('Saving %r\n' % lname) + write_to_file(srcfile, destfile) elif cmd == 'mget': for parm in words[1:]: (dir,base) = os.path.split(parm) - for n in pwd.resolve(dir).subs(): - if fnmatch.fnmatch(n.name, base): - try: - log('Saving %r\n' % n.name) - inf = n.open() - outf = open(n.name, 'wb') - write_to_file(inf, outf) - outf.close() - except Exception, e: - rv = 1 - log(' error: %s\n' % e) + + res = vfs.resolve(repo, dir, parent=pwd) + _, dir_item = res[-1] + if not dir_item: + raise Exception('%r does not exist' % dir) + for name, item in vfs.contents(repo, dir_item): + if name == '.': + continue + if fnmatch.fnmatch(name, base): + if stat.S_ISLNK(vfs.item_mode(item)): + deref = vfs.resolve(repo, name, parent=res) + deref_name, deref_item = deref[-1] + if not deref_item: + raise Exception('%r does not exist' % + '/'.join(name for name, item + in deref)) + item = deref_item + with vfs.fopen(repo, item) as srcfile: + with open(name, 'wb') as destfile: + log('Saving %r\n' % name) + write_to_file(srcfile, destfile) elif cmd == 'help' or cmd == '?': + # FIXME: move to stdout log('Commands: ls cd pwd cat get mget help quit\n') - elif cmd == 'quit' or cmd == 'exit' or cmd == 'bye': + elif cmd in ('quit', 'exit', 'bye'): break else: rv = 1 raise Exception('no such command %r' % cmd) - except Exception, e: + except Exception as e: rv = 1 log('error: %s\n' % e) - #raise + raise sys.exit(rv)