3 bup_python="$(dirname "$0")/bup-python" || exit $?
4 exec "$bup_python" "$0" ${1+"$@"}
8 # Copyright (C) 2010 Rob Browning
10 # This code is covered under the terms of the GNU Library General
11 # Public License as described in the bup LICENSE file.
13 # TODO: Add tar-like -C option.
15 from __future__ import absolute_import
17 from bup import metadata
18 from bup import options
19 from bup.compat import argv_bytes
20 from bup.io import byte_stream
21 from bup.helpers import handle_ctrl_c, log, saved_errors
25 if not name or name == b'-':
26 return byte_stream(sys.stdin)
27 return open(name, 'rb')
30 def open_output(name):
31 if not name or name == b'-':
33 return byte_stream(sys.stdout)
34 return open(name, 'wb')
38 bup meta --create [OPTION ...] <PATH ...>
39 bup meta --list [OPTION ...]
40 bup meta --extract [OPTION ...]
41 bup meta --start-extract [OPTION ...]
42 bup meta --finish-extract [OPTION ...]
43 bup meta --edit [OPTION ...] <PATH ...>
45 c,create write metadata for PATHs to stdout (or --file)
46 t,list display metadata
47 x,extract perform --start-extract followed by --finish-extract
48 start-extract build tree matching metadata provided on standard input (or --file)
49 finish-extract finish applying standard input (or --file) metadata to filesystem
50 edit alter metadata; write to stdout (or --file)
51 f,file= specify source or destination file
52 R,recurse recurse into subdirectories
53 xdev,one-file-system don't cross filesystem boundaries
54 numeric-ids apply numeric IDs (user, group, etc.) rather than names
55 symlinks handle symbolic links (default is true)
56 paths include paths in metadata (default is true)
57 set-uid= set metadata uid (via --edit)
58 set-gid= set metadata gid (via --edit)
59 set-user= set metadata user (via --edit)
60 unset-user remove metadata user (via --edit)
61 set-group= set metadata group (via --edit)
62 unset-group remove metadata group (via --edit)
63 v,verbose increase log output (can be used more than once)
64 q,quiet don't show progress meter
69 o = options.Options(optspec)
70 (opt, flags, remainder) = o.parse(['--paths', '--symlinks', '--recurse']
73 opt.verbose = opt.verbose or 0
74 opt.quiet = opt.quiet or 0
75 metadata.verbose = opt.verbose - opt.quiet
76 opt.file = argv_bytes(opt.file) if opt.file else None
78 action_count = sum([bool(x) for x in [opt.create, opt.list, opt.extract,
79 opt.start_extract, opt.finish_extract,
82 o.fatal("bup: only one action permitted: --create --list --extract --edit")
84 o.fatal("bup: no action specified")
87 if len(remainder) < 1:
88 o.fatal("no paths specified for create")
89 output_file = open_output(opt.file)
90 metadata.save_tree(output_file,
91 [argv_bytes(r) for r in remainder],
93 write_paths=opt.paths,
94 save_symlinks=opt.symlinks,
97 if len(remainder) > 0:
98 o.fatal("cannot specify paths for --list")
99 src = open_input(opt.file)
100 metadata.display_archive(src, open_output(b'-'))
101 elif opt.start_extract:
102 if len(remainder) > 0:
103 o.fatal("cannot specify paths for --start-extract")
104 src = open_input(opt.file)
105 metadata.start_extract(src, create_symlinks=opt.symlinks)
106 elif opt.finish_extract:
107 if len(remainder) > 0:
108 o.fatal("cannot specify paths for --finish-extract")
109 src = open_input(opt.file)
110 metadata.finish_extract(src, restore_numeric_ids=opt.numeric_ids)
112 if len(remainder) > 0:
113 o.fatal("cannot specify paths for --extract")
114 src = open_input(opt.file)
115 metadata.extract(src,
116 restore_numeric_ids=opt.numeric_ids,
117 create_symlinks=opt.symlinks)
119 if len(remainder) < 1:
120 o.fatal("no paths specified for edit")
121 output_file = open_output(opt.file)
123 unset_user = False # True if --unset-user was the last relevant option.
124 unset_group = False # True if --unset-group was the last relevant option.
126 if flag[0] == '--set-user':
128 elif flag[0] == '--unset-user':
130 elif flag[0] == '--set-group':
132 elif flag[0] == '--unset-group':
135 for path in remainder:
136 f = open(argv_bytes(path), 'rb')
138 for m in metadata._ArchiveIterator(f):
139 if opt.set_uid is not None:
141 m.uid = int(opt.set_uid)
143 o.fatal("uid must be an integer")
145 if opt.set_gid is not None:
147 m.gid = int(opt.set_gid)
149 o.fatal("gid must be an integer")
153 elif opt.set_user is not None:
154 m.user = argv_bytes(opt.set_user)
158 elif opt.set_group is not None:
159 m.group = argv_bytes(opt.set_group)
167 log('WARNING: %d errors encountered.\n' % len(saved_errors))