3 # Copyright (C) 2010 Rob Browning
5 # This code is covered under the terms of the GNU Library General
6 # Public License as described in the bup LICENSE file.
8 # TODO: Add tar-like -C option.
11 from bup import metadata
12 from bup import options
13 from bup.helpers import handle_ctrl_c, log, saved_errors
17 if not name or name == '-':
19 return open(name, 'r')
22 def open_output(name):
23 if not name or name == '-':
25 return open(name, 'w')
29 bup meta --create [OPTION ...] <PATH ...>
30 bup meta --extract [OPTION ...]
31 bup meta --start-extract [OPTION ...]
32 bup meta --finish-extract [OPTION ...]
33 bup meta --edit [OPTION ...] <PATH ...>
35 c,create write metadata for PATHs to stdout (or --file)
36 t,list display metadata
37 x,extract perform --start-extract followed by --finish-extract
38 start-extract build tree matching metadata provided on standard input (or --file)
39 finish-extract finish applying standard input (or --file) metadata to filesystem
40 edit alter metadata; write to stdout (or --file)
41 f,file= specify source or destination file
42 R,recurse recurse into subdirectories
43 xdev,one-file-system don't cross filesystem boundaries
44 numeric-ids apply numeric IDs (user, group, etc.) rather than names
45 symlinks handle symbolic links (default is true)
46 paths include paths in metadata (default is true)
47 set-uid= set metadata uid (via --edit)
48 set-gid= set metadata gid (via --edit)
49 set-user= set metadata user (via --edit)
50 unset-user remove metadata user (via --edit)
51 set-group= set metadata group (via --edit)
52 unset-group remove metadata group (via --edit)
53 v,verbose increase log output (can be used more than once)
54 q,quiet don't show progress meter
59 o = options.Options(optspec)
60 (opt, flags, remainder) = o.parse(['--paths', '--symlinks'] + sys.argv[1:])
62 opt.verbose = opt.verbose or 0
63 opt.quiet = opt.quiet or 0
64 metadata.verbose = opt.verbose - opt.quiet
66 action_count = sum([bool(x) for x in [opt.create, opt.list, opt.extract,
67 opt.start_extract, opt.finish_extract,
70 o.fatal("bup: only one action permitted: --create --list --extract --edit")
72 o.fatal("bup: no action specified")
75 if len(remainder) < 1:
76 o.fatal("no paths specified for create")
77 output_file = open_output(opt.file)
78 metadata.save_tree(output_file,
81 write_paths=opt.paths,
82 save_symlinks=opt.symlinks,
85 if len(remainder) > 0:
86 o.fatal("cannot specify paths for --list")
87 src = open_input(opt.file)
88 metadata.display_archive(src)
89 elif opt.start_extract:
90 if len(remainder) > 0:
91 o.fatal("cannot specify paths for --start-extract")
92 src = open_input(opt.file)
93 metadata.start_extract(src, create_symlinks=opt.symlinks)
94 elif opt.finish_extract:
95 if len(remainder) > 0:
96 o.fatal("cannot specify paths for --finish-extract")
97 src = open_input(opt.file)
98 metadata.finish_extract(src, restore_numeric_ids=opt.numeric_ids)
100 if len(remainder) > 0:
101 o.fatal("cannot specify paths for --extract")
102 src = open_input(opt.file)
103 metadata.extract(src,
104 restore_numeric_ids=opt.numeric_ids,
105 create_symlinks=opt.symlinks)
107 if len(remainder) < 1:
108 o.fatal("no paths specified for edit")
109 output_file = open_output(opt.file)
111 unset_user = False # True if --unset-user was the last relevant option.
112 unset_group = False # True if --unset-group was the last relevant option.
114 if flag[0] == '--set-user':
116 elif flag[0] == '--unset-user':
118 elif flag[0] == '--set-group':
120 elif flag[0] == '--unset-group':
123 for path in remainder:
126 for m in metadata._ArchiveIterator(f):
127 if opt.set_uid is not None:
129 m.uid = int(opt.set_uid)
131 o.fatal("uid must be an integer")
133 if opt.set_gid is not None:
135 m.gid = int(opt.set_gid)
137 o.fatal("gid must be an integer")
141 elif opt.set_user is not None:
142 m.user = opt.set_user
146 elif opt.set_group is not None:
147 m.group = opt.set_group
155 log('WARNING: %d errors encountered.\n' % len(saved_errors))