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