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