3 bup_python="$(dirname "$0")/bup-python" || exit $?
4 exec "$bup_python" "$0" ${1+"$@"}
8 # For now, this completely relies on the assumption that the current
9 # encoding (LC_CTYPE, etc.) is ASCII compatible, and that it returns
10 # the exact same bytes from a decode/encode round-trip (or the reverse
13 from __future__ import absolute_import, print_function
14 import sys, os, stat, fnmatch
16 from bup import options, git, shquote, ls, vfs
17 from bup.compat import argv_bytes, input
18 from bup.helpers import chunkyreader, handle_ctrl_c, log
19 from bup.io import byte_stream, path_msg
20 from bup.repo import LocalRepo
25 class OptionError(Exception):
30 return s.encode('iso-8859-1')
33 def do_ls(repo, args, out):
35 opt = ls.opts_from_cmdline(args, onabort=OptionError)
36 except OptionError as e:
39 return ls.within_repo(repo, opt, out)
42 def write_to_file(inf, outf):
43 for blob in chunkyreader(inf):
48 if os.isatty(sys.stdin.fileno()):
53 print() # Clear the line for the terminal's next prompt
56 for line in sys.stdin:
60 def _completer_get_subs(repo, line):
61 (qtype, lastword) = shquote.unfinished_word(line)
62 dir, name = os.path.split(lastword.encode('iso-8859-1'))
63 dir_path = vfs.resolve(repo, dir or b'/')
64 _, dir_item = dir_path[-1]
68 subs = tuple(dir_path + (entry,)
69 for entry in vfs.contents(repo, dir_item)
70 if (entry[0] != b'.' and entry[0].startswith(name)))
71 return qtype, lastword, subs
76 def completer(text, iteration):
81 line = readline.get_line_buffer()[:readline.get_endidx()]
82 if _last_line != line:
83 _last_res = _completer_get_subs(repo, line)
85 qtype, lastword, subs = _last_res
86 if iteration < len(subs):
87 path = subs[iteration]
88 leaf_name, leaf_item = path[-1]
89 res = vfs.try_resolve(repo, leaf_name, parent=path[:-1])
90 leaf_name, leaf_item = res[-1]
91 fullname = os.path.join(*(name for name, item in res))
92 if stat.S_ISDIR(vfs.item_mode(leaf_item)):
93 ret = shquote.what_to_add(qtype, lastword,
94 fullname.decode('iso-8859-1') + '/',
97 ret = shquote.what_to_add(qtype, lastword,
98 fullname.decode('iso-8859-1'),
99 terminate=True) + b' '
101 except Exception as e:
105 traceback.print_tb(sys.exc_traceback)
106 except Exception as e2:
107 log('Error printing traceback: %s\n' % e2)
108 log('\nError in completion: %s\n' % e)
112 bup ftp [commands...]
114 o = options.Options(optspec)
115 (opt, flags, extra) = o.parse(sys.argv[1:])
117 git.check_repo_or_die()
120 out = byte_stream(sys.stdout)
122 pwd = vfs.resolve(repo, b'/')
131 log('* readline module not available: line editing disabled.\n')
135 readline.set_completer_delims(' \t\n\r/')
136 readline.set_completer(completer)
137 if sys.platform.startswith('darwin'):
138 # MacOS uses a slightly incompatible clone of libreadline
139 readline.parse_and_bind('bind ^I rl_complete')
140 readline.parse_and_bind('tab: complete')
146 words = [word for (wordstart,word) in shquote.quotesplit(line)]
147 cmd = words[0].lower()
148 #log('execute: %r %r\n' % (cmd, parm))
151 # FIXME: respect pwd (perhaps via ls accepting resolve path/parent)
152 do_ls(repo, words[1:], out)
155 for parm in words[1:]:
156 res = vfs.resolve(repo, input_bytes(parm), parent=np)
157 _, leaf_item = res[-1]
159 raise Exception('%s does not exist'
160 % path_msg(b'/'.join(name for name, item
162 if not stat.S_ISDIR(vfs.item_mode(leaf_item)):
163 raise Exception('%s is not a directory' % path_msg(parm))
169 out.write(b'/'.join(name for name, item in pwd) + b'\n')
171 for parm in words[1:]:
172 res = vfs.resolve(repo, input_bytes(parm), parent=pwd)
173 _, leaf_item = res[-1]
175 raise Exception('%s does not exist' %
176 path_msg(b'/'.join(name for name, item
178 with vfs.fopen(repo, leaf_item) as srcfile:
179 write_to_file(srcfile, out)
181 if len(words) not in [2,3]:
183 raise Exception('Usage: get <filename> [localname]')
184 rname = input_bytes(words[1])
185 (dir,base) = os.path.split(rname)
186 lname = input_bytes(len(words) > 2 and words[2] or base)
187 res = vfs.resolve(repo, rname, parent=pwd)
188 _, leaf_item = res[-1]
190 raise Exception('%s does not exist' %
191 path_msg(b'/'.join(name for name, item in res)))
192 with vfs.fopen(repo, leaf_item) as srcfile:
193 with open(lname, 'wb') as destfile:
194 log('Saving %s\n' % path_msg(lname))
195 write_to_file(srcfile, destfile)
197 for parm in words[1:]:
198 dir, base = os.path.split(input_bytes(parm))
200 res = vfs.resolve(repo, dir, parent=pwd)
201 _, dir_item = res[-1]
203 raise Exception('%s does not exist' % path_msg(dir))
204 for name, item in vfs.contents(repo, dir_item):
207 if fnmatch.fnmatch(name, base):
208 if stat.S_ISLNK(vfs.item_mode(item)):
209 deref = vfs.resolve(repo, name, parent=res)
210 deref_name, deref_item = deref[-1]
212 raise Exception('%s does not exist' %
213 path_msg('/'.join(name for name, item
216 with vfs.fopen(repo, item) as srcfile:
217 with open(name, 'wb') as destfile:
218 log('Saving %s\n' % path_msg(name))
219 write_to_file(srcfile, destfile)
220 elif cmd == 'help' or cmd == '?':
221 # FIXME: move to stdout
222 log('Commands: ls cd pwd cat get mget help quit\n')
223 elif cmd in ('quit', 'exit', 'bye'):
227 raise Exception('no such command %r' % cmd)
228 except Exception as e:
230 log('error: %s\n' % e)