]> arthur.barton.de Git - bup.git/blob - cmd/meta-cmd.py
Use absolute_import from the __future__ everywhere
[bup.git] / cmd / meta-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 # Copyright (C) 2010 Rob Browning
9 #
10 # This code is covered under the terms of the GNU Library General
11 # Public License as described in the bup LICENSE file.
12
13 # TODO: Add tar-like -C option.
14
15 from __future__ import absolute_import
16 import sys
17 from bup import metadata
18 from bup import options
19 from bup.helpers import handle_ctrl_c, log, saved_errors
20
21
22 def open_input(name):
23     if not name or name == '-':
24         return sys.stdin
25     return open(name, 'r')
26
27
28 def open_output(name):
29     if not name or name == '-':
30         return sys.stdout
31     return open(name, 'w')
32
33
34 optspec = """
35 bup meta --create [OPTION ...] <PATH ...>
36 bup meta --list [OPTION ...]
37 bup meta --extract [OPTION ...]
38 bup meta --start-extract [OPTION ...]
39 bup meta --finish-extract [OPTION ...]
40 bup meta --edit [OPTION ...] <PATH ...>
41 --
42 c,create       write metadata for PATHs to stdout (or --file)
43 t,list         display metadata
44 x,extract      perform --start-extract followed by --finish-extract
45 start-extract  build tree matching metadata provided on standard input (or --file)
46 finish-extract finish applying standard input (or --file) metadata to filesystem
47 edit           alter metadata; write to stdout (or --file)
48 f,file=        specify source or destination file
49 R,recurse      recurse into subdirectories
50 xdev,one-file-system  don't cross filesystem boundaries
51 numeric-ids    apply numeric IDs (user, group, etc.) rather than names
52 symlinks       handle symbolic links (default is true)
53 paths          include paths in metadata (default is true)
54 set-uid=       set metadata uid (via --edit)
55 set-gid=       set metadata gid (via --edit)
56 set-user=      set metadata user (via --edit)
57 unset-user     remove metadata user (via --edit)
58 set-group=     set metadata group (via --edit)
59 unset-group    remove metadata group (via --edit)
60 v,verbose      increase log output (can be used more than once)
61 q,quiet        don't show progress meter
62 """
63
64 handle_ctrl_c()
65
66 o = options.Options(optspec)
67 (opt, flags, remainder) = o.parse(['--paths', '--symlinks', '--recurse']
68                                   + sys.argv[1:])
69
70 opt.verbose = opt.verbose or 0
71 opt.quiet = opt.quiet or 0
72 metadata.verbose = opt.verbose - opt.quiet
73
74 action_count = sum([bool(x) for x in [opt.create, opt.list, opt.extract,
75                                       opt.start_extract, opt.finish_extract,
76                                       opt.edit]])
77 if action_count > 1:
78     o.fatal("bup: only one action permitted: --create --list --extract --edit")
79 if action_count == 0:
80     o.fatal("bup: no action specified")
81
82 if opt.create:
83     if len(remainder) < 1:
84         o.fatal("no paths specified for create")
85     output_file = open_output(opt.file)
86     metadata.save_tree(output_file,
87                        remainder,
88                        recurse=opt.recurse,
89                        write_paths=opt.paths,
90                        save_symlinks=opt.symlinks,
91                        xdev=opt.xdev)
92 elif opt.list:
93     if len(remainder) > 0:
94         o.fatal("cannot specify paths for --list")
95     src = open_input(opt.file)
96     metadata.display_archive(src)
97 elif opt.start_extract:
98     if len(remainder) > 0:
99         o.fatal("cannot specify paths for --start-extract")
100     src = open_input(opt.file)
101     metadata.start_extract(src, create_symlinks=opt.symlinks)
102 elif opt.finish_extract:
103     if len(remainder) > 0:
104         o.fatal("cannot specify paths for --finish-extract")
105     src = open_input(opt.file)
106     metadata.finish_extract(src, restore_numeric_ids=opt.numeric_ids)
107 elif opt.extract:
108     if len(remainder) > 0:
109         o.fatal("cannot specify paths for --extract")
110     src = open_input(opt.file)
111     metadata.extract(src,
112                      restore_numeric_ids=opt.numeric_ids,
113                      create_symlinks=opt.symlinks)
114 elif opt.edit:
115     if len(remainder) < 1:
116         o.fatal("no paths specified for edit")
117     output_file = open_output(opt.file)
118
119     unset_user = False # True if --unset-user was the last relevant option.
120     unset_group = False # True if --unset-group was the last relevant option.
121     for flag in flags:
122         if flag[0] == '--set-user':
123             unset_user = False
124         elif flag[0] == '--unset-user':
125             unset_user = True
126         elif flag[0] == '--set-group':
127             unset_group = False
128         elif flag[0] == '--unset-group':
129             unset_group = True
130
131     for path in remainder:
132         f = open(path, 'r')
133         try:
134             for m in metadata._ArchiveIterator(f):
135                 if opt.set_uid is not None:
136                     try:
137                         m.uid = int(opt.set_uid)
138                     except ValueError:
139                         o.fatal("uid must be an integer")
140
141                 if opt.set_gid is not None:
142                     try:
143                         m.gid = int(opt.set_gid)
144                     except ValueError:
145                         o.fatal("gid must be an integer")
146
147                 if unset_user:
148                     m.user = ''
149                 elif opt.set_user is not None:
150                     m.user = opt.set_user
151
152                 if unset_group:
153                     m.group = ''
154                 elif opt.set_group is not None:
155                     m.group = opt.set_group
156
157                 m.write(output_file)
158         finally:
159             f.close()
160
161
162 if saved_errors:
163     log('WARNING: %d errors encountered.\n' % len(saved_errors))
164     sys.exit(1)
165 else:
166     sys.exit(0)