]> arthur.barton.de Git - bup.git/blob - main.py
Add man pages for random, newliner, help, memtest, ftp.
[bup.git] / main.py
1 #!/usr/bin/env python
2 import sys, os, subprocess, signal
3
4 argv = sys.argv
5 exe = argv[0]
6 exepath = os.path.split(exe)[0] or '.'
7
8 # fix the PYTHONPATH to include our lib dir
9 libpath = os.path.join(exepath, 'lib')
10 cmdpath = os.path.join(exepath, 'cmd')
11 sys.path[:0] = [libpath]
12 os.environ['PYTHONPATH'] = libpath + ':' + os.environ.get('PYTHONPATH', '')
13
14 from bup.helpers import *
15
16
17 def columnate(l, prefix):
18     l = l[:]
19     clen = max(len(s) for s in l)
20     ncols = (78 - len(prefix)) / (clen + 2)
21     if ncols <= 1:
22         ncols = 1
23         clen = 0
24     cols = []
25     while len(l) % ncols:
26         l.append('')
27     rows = len(l)/ncols
28     for s in range(0, len(l), rows):
29         cols.append(l[s:s+rows])
30     for row in zip(*cols):
31         print prefix + ''.join(('%-*s' % (clen+2, s)) for s in row)
32
33
34 def usage():
35     log('Usage: bup <command> <options...>\n\n')
36     common = dict(
37         ftp = 'Browse backup sets using an ftp-like client',
38         fsck = 'Check backup sets for damage and add redundancy information',
39         fuse = 'Mount your backup sets as a filesystem',
40         help = 'Print detailed help for the given command',
41         index = 'Create or display the index of files to back up',
42         join = 'Retrieve a file backed up using "bup split"',
43         ls = 'Browse the files in your backup sets',
44         midx = 'Index objects to speed up future backups',
45         save = 'Save files into a backup set (note: run "bup index" first)',
46         split = 'Split a single file into its own backup set',
47     )
48
49     log('Common commands:\n')
50     for cmd,synopsis in sorted(common.items()):
51         print '    %-10s %s' % (cmd, synopsis)
52     log('\n')
53     
54     log('Other available commands:\n')
55     cmds = []
56     for c in sorted(os.listdir(cmdpath) + os.listdir(exepath)):
57         if c.startswith('bup-') and c.find('.') < 0:
58             cname = c[4:]
59             if cname not in common:
60                 cmds.append(c[4:])
61     columnate(cmds, '    ')
62     log('\n')
63     
64     log("See 'bup help <command>' for more information on " +
65         "a specific command.\n")
66     sys.exit(99)
67
68
69 if len(argv) < 2 or not argv[1] or argv[1][0] == '-':
70     usage()
71
72 subcmd = argv[1]
73
74 def subpath(s):
75     sp = os.path.join(exepath, 'bup-%s' % s)
76     if not os.path.exists(sp):
77         sp = os.path.join(cmdpath, 'bup-%s' % s)
78     return sp
79
80 if not os.path.exists(subpath(subcmd)):
81     log('error: unknown command "%s"\n' % subcmd)
82     usage()
83
84
85 already_fixed = atoi(os.environ.get('BUP_FORCE_TTY'))
86 if subcmd in ['ftp', 'help']:
87     already_fixed = True
88 fix_stdout = not already_fixed and os.isatty(1)
89 fix_stderr = not already_fixed and os.isatty(2)
90
91 def force_tty():
92     if fix_stdout or fix_stderr:
93         amt = (fix_stdout and 1 or 0) + (fix_stderr and 2 or 0)
94         os.environ['BUP_FORCE_TTY'] = str(amt)
95
96 if fix_stdout or fix_stderr:
97     realf = fix_stderr and 2 or 1
98     n = subprocess.Popen([subpath('newliner')],
99                          stdin=subprocess.PIPE, stdout=os.dup(realf),
100                          close_fds=True, preexec_fn=force_tty)
101     outf = fix_stdout and n.stdin.fileno() or 1
102     errf = fix_stderr and n.stdin.fileno() or 2
103 else:
104     n = None
105     outf = 1
106     errf = 2
107
108
109 class SigException(Exception):
110     pass
111 def handler(signum, frame):
112     raise SigException('signal %d received' % signum)
113
114 signal.signal(signal.SIGTERM, handler)
115 signal.signal(signal.SIGINT, handler)
116
117 ret = 95
118 try:
119     try:
120         p = subprocess.Popen([subpath(subcmd)] + argv[2:],
121                              stdout=outf, stderr=errf, preexec_fn=force_tty)
122         ret = p.wait()
123     except OSError, e:
124         log('%s: %s\n' % (subpath(subcmd), e))
125         ret = 98
126     except SigException, e:
127         ret = 94
128 finally:
129     if p and p.poll() == None:
130         os.kill(p.pid, signal.SIGTERM)
131         p.wait()
132     if n:
133         n.stdin.close()
134         try:
135             n.wait()
136         except:
137             pass
138 sys.exit(ret)