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