]> arthur.barton.de Git - bup.git/blob - cmd/ftp-cmd.py
Don't import * from helpers
[bup.git] / cmd / ftp-cmd.py
1 #!/bin/sh
2 """": # -*-python-*-
3 bup_python="$(dirname "$0")/bup-python" || exit $?
4 exec "$bup_python" "$0" ${1+"$@"}
5 """
6 # end of bup preamble
7
8 import sys, os, stat, fnmatch
9
10 from bup import options, git, shquote, vfs, ls
11 from bup.helpers import chunkyreader, handle_ctrl_c, log
12
13
14 handle_ctrl_c()
15
16
17 class OptionError(Exception):
18     pass
19
20
21 # Check out lib/bup/ls.py for the opt spec
22 def do_ls(cmd_args):
23     try:
24         ls.do_ls(cmd_args, pwd, onabort=OptionError)
25     except OptionError as e:
26         return
27
28
29 def write_to_file(inf, outf):
30     for blob in chunkyreader(inf):
31         outf.write(blob)
32
33
34 def inputiter():
35     if os.isatty(sys.stdin.fileno()):
36         while 1:
37             try:
38                 yield raw_input('bup> ')
39             except EOFError:
40                 print ''  # Clear the line for the terminal's next prompt
41                 break
42     else:
43         for line in sys.stdin:
44             yield line
45
46
47 def _completer_get_subs(line):
48     (qtype, lastword) = shquote.unfinished_word(line)
49     (dir,name) = os.path.split(lastword)
50     #log('\ncompleter: %r %r %r\n' % (qtype, lastword, text))
51     try:
52         n = pwd.resolve(dir)
53         subs = list(filter(lambda x: x.name.startswith(name),
54                            n.subs()))
55     except vfs.NoSuchFile as e:
56         subs = []
57     return (dir, name, qtype, lastword, subs)
58
59
60 def find_readline_lib():
61     """Return the name (and possibly the full path) of the readline library
62     linked to the given readline module.
63     """
64     import readline
65     f = open(readline.__file__, "rb")
66     try:
67         data = f.read()
68     finally:
69         f.close()
70     import re
71     m = re.search('\0([^\0]*libreadline[^\0]*)\0', data)
72     if m:
73         return m.group(1)
74     return None
75
76
77 def init_readline_vars():
78     """Work around trailing space automatically inserted by readline.
79     See http://bugs.python.org/issue5833"""
80     try:
81         import ctypes
82     except ImportError:
83         # python before 2.5 didn't have the ctypes module; but those
84         # old systems probably also didn't have this readline bug, so
85         # just ignore it.
86         return
87     lib_name = find_readline_lib()
88     if lib_name is not None:
89         lib = ctypes.cdll.LoadLibrary(lib_name)
90         global rl_completion_suppress_append
91         rl_completion_suppress_append = ctypes.c_int.in_dll(lib,
92                                     "rl_completion_suppress_append")
93
94
95 rl_completion_suppress_append = None
96 _last_line = None
97 _last_res = None
98 def completer(text, state):
99     global _last_line
100     global _last_res
101     global rl_completion_suppress_append
102     if rl_completion_suppress_append is not None:
103         rl_completion_suppress_append.value = 1
104     try:
105         line = readline.get_line_buffer()[:readline.get_endidx()]
106         if _last_line != line:
107             _last_res = _completer_get_subs(line)
108             _last_line = line
109         (dir, name, qtype, lastword, subs) = _last_res
110         if state < len(subs):
111             sn = subs[state]
112             sn1 = sn.try_resolve()  # find the type of any symlink target
113             fullname = os.path.join(dir, sn.name)
114             if stat.S_ISDIR(sn1.mode):
115                 ret = shquote.what_to_add(qtype, lastword, fullname+'/',
116                                           terminate=False)
117             else:
118                 ret = shquote.what_to_add(qtype, lastword, fullname,
119                                           terminate=True) + ' '
120             return text + ret
121     except Exception as e:
122         log('\n')
123         try:
124             import traceback
125             traceback.print_tb(sys.exc_traceback)
126         except Exception as e2:
127             log('Error printing traceback: %s\n' % e2)
128         log('\nError in completion: %s\n' % e)
129
130
131 optspec = """
132 bup ftp [commands...]
133 """
134 o = options.Options(optspec)
135 (opt, flags, extra) = o.parse(sys.argv[1:])
136
137 git.check_repo_or_die()
138
139 top = vfs.RefList(None)
140 pwd = top
141 rv = 0
142
143 if extra:
144     lines = extra
145 else:
146     try:
147         import readline
148     except ImportError:
149         log('* readline module not available: line editing disabled.\n')
150         readline = None
151
152     if readline:
153         readline.set_completer_delims(' \t\n\r/')
154         readline.set_completer(completer)
155         if sys.platform.startswith('darwin'):
156             # MacOS uses a slighly incompatible clone of libreadline
157             readline.parse_and_bind('bind ^I rl_complete')
158         readline.parse_and_bind('tab: complete')
159         init_readline_vars()
160     lines = inputiter()
161
162 for line in lines:
163     if not line.strip():
164         continue
165     words = [word for (wordstart,word) in shquote.quotesplit(line)]
166     cmd = words[0].lower()
167     #log('execute: %r %r\n' % (cmd, parm))
168     try:
169         if cmd == 'ls':
170             do_ls(words[1:])
171         elif cmd == 'cd':
172             np = pwd
173             for parm in words[1:]:
174                 np = np.resolve(parm)
175                 if not stat.S_ISDIR(np.mode):
176                     raise vfs.NotDir('%s is not a directory' % parm)
177             pwd = np
178         elif cmd == 'pwd':
179             print pwd.fullname()
180         elif cmd == 'cat':
181             for parm in words[1:]:
182                 write_to_file(pwd.resolve(parm).open(), sys.stdout)
183         elif cmd == 'get':
184             if len(words) not in [2,3]:
185                 rv = 1
186                 raise Exception('Usage: get <filename> [localname]')
187             rname = words[1]
188             (dir,base) = os.path.split(rname)
189             lname = len(words)>2 and words[2] or base
190             inf = pwd.resolve(rname).open()
191             log('Saving %r\n' % lname)
192             write_to_file(inf, open(lname, 'wb'))
193         elif cmd == 'mget':
194             for parm in words[1:]:
195                 (dir,base) = os.path.split(parm)
196                 for n in pwd.resolve(dir).subs():
197                     if fnmatch.fnmatch(n.name, base):
198                         try:
199                             log('Saving %r\n' % n.name)
200                             inf = n.open()
201                             outf = open(n.name, 'wb')
202                             write_to_file(inf, outf)
203                             outf.close()
204                         except Exception as e:
205                             rv = 1
206                             log('  error: %s\n' % e)
207         elif cmd == 'help' or cmd == '?':
208             log('Commands: ls cd pwd cat get mget help quit\n')
209         elif cmd == 'quit' or cmd == 'exit' or cmd == 'bye':
210             break
211         else:
212             rv = 1
213             raise Exception('no such command %r' % cmd)
214     except Exception as e:
215         rv = 1
216         log('error: %s\n' % e)
217         #raise
218
219 sys.exit(rv)