]> arthur.barton.de Git - bup.git/blobdiff - cmd/meta-cmd.py
Use absolute_import from the __future__ everywhere
[bup.git] / cmd / meta-cmd.py
index 4f6e013810024b2c5e60e59246dd381084039b5f..38ec94348e02fc3ddca871032a0335390ce753eb 100755 (executable)
@@ -1,4 +1,9 @@
-#!/usr/bin/env python
+#!/bin/sh
+"""": # -*-python-*-
+bup_python="$(dirname "$0")/bup-python" || exit $?
+exec "$bup_python" "$0" ${1+"$@"}
+"""
+# end of bup preamble
 
 # Copyright (C) 2010 Rob Browning
 #
 # Public License as described in the bup LICENSE file.
 
 # TODO: Add tar-like -C option.
-# TODO: Add tar-like -v support to --list.
 
+from __future__ import absolute_import
 import sys
 from bup import metadata
 from bup import options
 from bup.helpers import handle_ctrl_c, log, saved_errors
 
+
+def open_input(name):
+    if not name or name == '-':
+        return sys.stdin
+    return open(name, 'r')
+
+
+def open_output(name):
+    if not name or name == '-':
+        return sys.stdout
+    return open(name, 'w')
+
+
 optspec = """
 bup meta --create [OPTION ...] <PATH ...>
+bup meta --list [OPTION ...]
 bup meta --extract [OPTION ...]
 bup meta --start-extract [OPTION ...]
 bup meta --finish-extract [OPTION ...]
+bup meta --edit [OPTION ...] <PATH ...>
 --
 c,create       write metadata for PATHs to stdout (or --file)
 t,list         display metadata
 x,extract      perform --start-extract followed by --finish-extract
 start-extract  build tree matching metadata provided on standard input (or --file)
 finish-extract finish applying standard input (or --file) metadata to filesystem
+edit           alter metadata; write to stdout (or --file)
 f,file=        specify source or destination file
 R,recurse      recurse into subdirectories
 xdev,one-file-system  don't cross filesystem boundaries
-numeric-ids    apply numeric IDs (user, group, etc.), not names, during restore
+numeric-ids    apply numeric IDs (user, group, etc.) rather than names
 symlinks       handle symbolic links (default is true)
 paths          include paths in metadata (default is true)
+set-uid=       set metadata uid (via --edit)
+set-gid=       set metadata gid (via --edit)
+set-user=      set metadata user (via --edit)
+unset-user     remove metadata user (via --edit)
+set-group=     set metadata group (via --edit)
+unset-group    remove metadata group (via --edit)
 v,verbose      increase log output (can be used more than once)
 q,quiet        don't show progress meter
 """
 
-action = None
-target_filename = ''
-should_recurse = False
-restore_numeric_ids = False
-include_paths = True
-handle_symlinks = True
-xdev = False
-
 handle_ctrl_c()
 
 o = options.Options(optspec)
-(opt, flags, remainder) = o.parse(sys.argv[1:])
-
-for flag, value in flags:
-    if flag == '--create' or flag == '-c':
-        action = 'create'
-    elif flag == '--list' or flag == '-t':
-        action = 'list'
-    elif flag == '--extract' or flag == '-x':
-        action = 'extract'
-    elif flag == '--start-extract':
-        action = 'start-extract'
-    elif flag == '--finish-extract':
-        action = 'finish-extract'
-    elif flag == '--file' or flag == '-f':
-        target_filename = value
-    elif flag == '--recurse' or flag == '-R':
-        should_recurse = True
-    elif flag == '--no-recurse':
-        should_recurse = False
-    elif flag in frozenset(['--xdev', '--one-file-system']):
-        xdev = True
-    elif flag in frozenset(['--no-xdev', '--no-one-file-system']):
-        xdev = False
-    elif flag == '--numeric-ids':
-        restore_numeric_ids = True
-    elif flag == '--no-numeric-ids':
-        restore_numeric_ids = False
-    elif flag == '--paths':
-        include_paths = True
-    elif flag == '--no-paths':
-        include_paths = False
-    elif flag == '--symlinks':
-        handle_symlinks = True
-    elif flag == '--no-symlinks':
-        handle_symlinks = False
-    elif flag == '--verbose' or flag == '-v':
-        metadata.verbose += 1
-    elif flag == '--quiet' or flag == '-q':
-        metadata.verbose = 0
-
-if not action:
-    o.fatal("no action specified")
-
-if action == 'create':
+(opt, flags, remainder) = o.parse(['--paths', '--symlinks', '--recurse']
+                                  + sys.argv[1:])
+
+opt.verbose = opt.verbose or 0
+opt.quiet = opt.quiet or 0
+metadata.verbose = opt.verbose - opt.quiet
+
+action_count = sum([bool(x) for x in [opt.create, opt.list, opt.extract,
+                                      opt.start_extract, opt.finish_extract,
+                                      opt.edit]])
+if action_count > 1:
+    o.fatal("bup: only one action permitted: --create --list --extract --edit")
+if action_count == 0:
+    o.fatal("bup: no action specified")
+
+if opt.create:
     if len(remainder) < 1:
         o.fatal("no paths specified for create")
-    if target_filename != '-':
-        output_file = open(target_filename, 'w')
-    else:
-        output_file = sys.stdout
+    output_file = open_output(opt.file)
     metadata.save_tree(output_file,
                        remainder,
-                       recurse=should_recurse,
-                       write_paths=include_paths,
-                       save_symlinks=handle_symlinks,
-                       xdev=xdev)
-
-elif action == 'list':
+                       recurse=opt.recurse,
+                       write_paths=opt.paths,
+                       save_symlinks=opt.symlinks,
+                       xdev=opt.xdev)
+elif opt.list:
     if len(remainder) > 0:
         o.fatal("cannot specify paths for --list")
-    if target_filename != '-':
-        src = open(target_filename, 'r')
-    else:
-        src = sys.stdin
+    src = open_input(opt.file)
     metadata.display_archive(src)
-
-elif action == 'start-extract':
+elif opt.start_extract:
     if len(remainder) > 0:
         o.fatal("cannot specify paths for --start-extract")
-    if target_filename != '-':
-        src = open(target_filename, 'r')
-    else:
-        src = sys.stdin
-    metadata.start_extract(src, create_symlinks=handle_symlinks)
-
-elif action == 'finish-extract':
+    src = open_input(opt.file)
+    metadata.start_extract(src, create_symlinks=opt.symlinks)
+elif opt.finish_extract:
     if len(remainder) > 0:
         o.fatal("cannot specify paths for --finish-extract")
-    if target_filename != '-':
-        src = open(target_filename, 'r')
-    else:
-        src = sys.stdin
-    num_ids = restore_numeric_ids
-    metadata.finish_extract(src, restore_numeric_ids=num_ids)
-
-elif action == 'extract':
+    src = open_input(opt.file)
+    metadata.finish_extract(src, restore_numeric_ids=opt.numeric_ids)
+elif opt.extract:
     if len(remainder) > 0:
         o.fatal("cannot specify paths for --extract")
-    if target_filename != '-':
-        src = open(target_filename, 'r')
-    else:
-        src = sys.stdin
+    src = open_input(opt.file)
     metadata.extract(src,
-                     restore_numeric_ids=restore_numeric_ids,
-                     create_symlinks=handle_symlinks)
+                     restore_numeric_ids=opt.numeric_ids,
+                     create_symlinks=opt.symlinks)
+elif opt.edit:
+    if len(remainder) < 1:
+        o.fatal("no paths specified for edit")
+    output_file = open_output(opt.file)
+
+    unset_user = False # True if --unset-user was the last relevant option.
+    unset_group = False # True if --unset-group was the last relevant option.
+    for flag in flags:
+        if flag[0] == '--set-user':
+            unset_user = False
+        elif flag[0] == '--unset-user':
+            unset_user = True
+        elif flag[0] == '--set-group':
+            unset_group = False
+        elif flag[0] == '--unset-group':
+            unset_group = True
+
+    for path in remainder:
+        f = open(path, 'r')
+        try:
+            for m in metadata._ArchiveIterator(f):
+                if opt.set_uid is not None:
+                    try:
+                        m.uid = int(opt.set_uid)
+                    except ValueError:
+                        o.fatal("uid must be an integer")
+
+                if opt.set_gid is not None:
+                    try:
+                        m.gid = int(opt.set_gid)
+                    except ValueError:
+                        o.fatal("gid must be an integer")
+
+                if unset_user:
+                    m.user = ''
+                elif opt.set_user is not None:
+                    m.user = opt.set_user
+
+                if unset_group:
+                    m.group = ''
+                elif opt.set_group is not None:
+                    m.group = opt.set_group
+
+                m.write(output_file)
+        finally:
+            f.close()
+
 
 if saved_errors:
     log('WARNING: %d errors encountered.\n' % len(saved_errors))