3 bup_python="$(dirname "$0")/bup-python" || exit $?
4 exec "$bup_python" "$0" ${1+"$@"}
8 import sys, os, stat, fnmatch
10 from bup import options, git, shquote, ls, vfs
11 from bup.helpers import chunkyreader, handle_ctrl_c, log
12 from bup.repo import LocalRepo
17 class OptionError(Exception):
21 def do_ls(repo, args):
23 opt = ls.opts_from_cmdline(args, onabort=OptionError)
24 except OptionError as e:
27 return ls.within_repo(repo, opt)
30 def write_to_file(inf, outf):
31 for blob in chunkyreader(inf):
36 if os.isatty(sys.stdin.fileno()):
39 yield raw_input('bup> ')
41 print '' # Clear the line for the terminal's next prompt
44 for line in sys.stdin:
48 def _completer_get_subs(repo, line):
49 (qtype, lastword) = shquote.unfinished_word(line)
50 (dir,name) = os.path.split(lastword)
51 dir_path = vfs.resolve(repo, dir or '/')
52 _, dir_item = dir_path[-1]
56 subs = tuple(dir_path + (entry,)
57 for entry in vfs.contents(repo, dir_item)
58 if (entry[0] != '.' and entry[0].startswith(name)))
59 return dir, name, qtype, lastword, subs
62 def find_readline_lib():
63 """Return the name (and possibly the full path) of the readline library
64 linked to the given readline module.
67 f = open(readline.__file__, "rb")
73 m = re.search('\0([^\0]*libreadline[^\0]*)\0', data)
79 def init_readline_vars():
80 """Work around trailing space automatically inserted by readline.
81 See http://bugs.python.org/issue5833"""
85 # python before 2.5 didn't have the ctypes module; but those
86 # old systems probably also didn't have this readline bug, so
89 lib_name = find_readline_lib()
90 if lib_name is not None:
91 lib = ctypes.cdll.LoadLibrary(lib_name)
92 global rl_completion_suppress_append
93 rl_completion_suppress_append = ctypes.c_int.in_dll(lib,
94 "rl_completion_suppress_append")
97 rl_completion_suppress_append = None
100 def completer(text, iteration):
104 global rl_completion_suppress_append
105 if rl_completion_suppress_append is not None:
106 rl_completion_suppress_append.value = 1
108 line = readline.get_line_buffer()[:readline.get_endidx()]
109 if _last_line != line:
110 _last_res = _completer_get_subs(repo, line)
112 (dir, name, qtype, lastword, subs) = _last_res
113 if iteration < len(subs):
114 path = subs[iteration]
115 leaf_name, leaf_item = path[-1]
116 res = vfs.try_resolve(repo, leaf_name, parent=path[:-1])
117 leaf_name, leaf_item = res[-1]
118 fullname = os.path.join(*(name for name, item in res))
119 if stat.S_ISDIR(vfs.item_mode(leaf_item)):
120 ret = shquote.what_to_add(qtype, lastword, fullname+'/',
123 ret = shquote.what_to_add(qtype, lastword, fullname,
124 terminate=True) + ' '
126 except Exception as e:
130 traceback.print_tb(sys.exc_traceback)
131 except Exception as e2:
132 log('Error printing traceback: %s\n' % e2)
133 log('\nError in completion: %s\n' % e)
137 bup ftp [commands...]
139 o = options.Options(optspec)
140 (opt, flags, extra) = o.parse(sys.argv[1:])
142 git.check_repo_or_die()
145 pwd = vfs.resolve(repo, '/')
154 log('* readline module not available: line editing disabled.\n')
158 readline.set_completer_delims(' \t\n\r/')
159 readline.set_completer(completer)
160 if sys.platform.startswith('darwin'):
161 # MacOS uses a slightly incompatible clone of libreadline
162 readline.parse_and_bind('bind ^I rl_complete')
163 readline.parse_and_bind('tab: complete')
170 words = [word for (wordstart,word) in shquote.quotesplit(line)]
171 cmd = words[0].lower()
172 #log('execute: %r %r\n' % (cmd, parm))
175 # FIXME: respect pwd (perhaps via ls accepting resolve path/parent)
176 do_ls(repo, words[1:])
179 for parm in words[1:]:
180 res = vfs.resolve(repo, parm, parent=np)
181 _, leaf_item = res[-1]
183 raise Exception('%r does not exist'
184 % '/'.join(name for name, item in res))
185 if not stat.S_ISDIR(vfs.item_mode(leaf_item)):
186 raise Exception('%r is not a directory' % parm)
191 sys.stdout.write('/')
192 print '/'.join(name for name, item in pwd)
194 for parm in words[1:]:
195 res = vfs.resolve(repo, parm, parent=pwd)
196 _, leaf_item = res[-1]
198 raise Exception('%r does not exist' %
199 '/'.join(name for name, item in res))
200 with vfs.fopen(repo, leaf_item) as srcfile:
201 write_to_file(srcfile, sys.stdout)
203 if len(words) not in [2,3]:
205 raise Exception('Usage: get <filename> [localname]')
207 (dir,base) = os.path.split(rname)
208 lname = len(words)>2 and words[2] or base
209 res = vfs.resolve(repo, rname, parent=pwd)
210 _, leaf_item = res[-1]
212 raise Exception('%r does not exist' %
213 '/'.join(name for name, item in res))
214 with vfs.fopen(repo, leaf_item) as srcfile:
215 with open(lname, 'wb') as destfile:
216 log('Saving %r\n' % lname)
217 write_to_file(srcfile, destfile)
219 for parm in words[1:]:
220 (dir,base) = os.path.split(parm)
222 res = vfs.resolve(repo, dir, parent=pwd)
223 _, dir_item = res[-1]
225 raise Exception('%r does not exist' % dir)
226 for name, item in vfs.contents(repo, dir_item):
229 if fnmatch.fnmatch(name, base):
230 if stat.S_ISLNK(vfs.item_mode(item)):
231 deref = vfs.resolve(repo, name, parent=res)
232 deref_name, deref_item = deref[-1]
234 raise Exception('%r does not exist' %
235 '/'.join(name for name, item
238 with vfs.fopen(repo, item) as srcfile:
239 with open(name, 'wb') as destfile:
240 log('Saving %r\n' % name)
241 write_to_file(srcfile, destfile)
242 elif cmd == 'help' or cmd == '?':
243 # FIXME: move to stdout
244 log('Commands: ls cd pwd cat get mget help quit\n')
245 elif cmd in ('quit', 'exit', 'bye'):
249 raise Exception('no such command %r' % cmd)
250 except Exception as e:
252 log('error: %s\n' % e)