]> arthur.barton.de Git - bup.git/blobdiff - cmd-save.py
Fix some problems running on older Debian.
[bup.git] / cmd-save.py
index 458dc1a179bdbc6ebcd4bf04e20a7d10b9d427b4..e68539c730a3e57ac6f1213fcd8c78c528bf4404 100755 (executable)
@@ -1,30 +1,36 @@
-#!/usr/bin/env python
-import sys, re, errno
+#!/usr/bin/env python2.5
+import sys, re, errno, stat
 import hashsplit, git, options
 from helpers import *
 
-saved_errors = []
 
+saved_errors = []
 def add_error(e):
     saved_errors.append(e)
-    log('%s\n' % e)
+    log('\n%s\n' % e)
+
+
+def _direxpand(name):
+    st = os.lstat(name)
+    try:
+        if stat.S_ISDIR(st.st_mode):
+            for sub in os.listdir(name):
+                subfull = os.path.join(name, sub)
+                for fn_st in _direxpand(subfull):
+                    yield fn_st
+        else:
+            yield (name,st)
+    except OSError, e:
+        if e.errno in [errno.ENOENT, errno.EPERM, errno.EACCES]:
+            add_error(e)
+        else:
+            raise
 
 
 def direxpand(names):
     for n in names:
-        log('%s\n' % n)
-        try:
-            for sub in os.listdir(n):
-                subfull = os.path.join(n, sub)
-                for sub2 in direxpand([subfull]):
-                    yield sub2
-        except OSError, e:
-            if e.errno == errno.ENOTDIR:
-                yield n
-            elif e.errno in [errno.ENOENT, errno.EPERM, errno.EACCES]:
-                add_error(e)
-            else:
-                raise
+        for fn_st in _direxpand(n):
+            yield fn_st
             
 
 def _normpath(dir):
@@ -56,13 +62,14 @@ class Tree:
         return p
         
     def getdir(self, dir):
-        # FIXME: deal with '..' somehow
+        # FIXME: deal with '..' somehow (look at how tar does it)
+        dir = _normpath(dir)
         if dir.startswith('/'):
             dir = dir[1:]
         top = self.gettop()
         if not dir:
             return top
-        for part in _normpath(dir).split('/'):
+        for part in dir.split('/'):
             sub = top.children.get(part)
             if not sub:
                 sub = top.children[part] = Tree(top, part)
@@ -73,17 +80,17 @@ class Tree:
         (dir, name) = os.path.split(fullname)
         self.getdir(dir).children[name] = (mode, name, id)
         
-    def shalist(self):
+    def shalist(self, w):
         for c in self.children.values():
             if isinstance(c, tuple):  # sha1 entry for a file
                 yield c
             else:  # tree
-                t = ('40000', c.name, c.gen_tree())
+                t = ('40000', c.name, c.gen_tree(w))
                 yield t
         
-    def gen_tree(self):
+    def gen_tree(self, w):
         if not self.sha:
-            self.sha = git.gen_tree(self.shalist())
+            self.sha = w.new_tree(self.shalist(w))
         return self.sha
 
 
@@ -93,36 +100,54 @@ bup save [-tc] [-n name] <filenames...>
 t,tree     output a tree id
 c,commit   output a commit id
 n,name=    name of backup set to update (if any)
+v,verbose  increase log output (can be used more than once)
 """
 o = options.Options('bup save', optspec)
 (opt, flags, extra) = o.parse(sys.argv[1:])
 
+git.check_repo_or_die()
 if not (opt.tree or opt.commit or opt.name):
     log("bup save: use one or more of -t, -c, -n\n")
     o.usage()
 
+if opt.verbose >= 2:
+    git.verbose = opt.verbose - 1
+    hashsplit.split_verbosely = opt.verbose - 1
+
+w = git.PackWriter()
 root = Tree(None, '')
-for fn in direxpand(extra):
+for (fn,st) in direxpand(extra):
+    if opt.verbose:
+        log('\n%s ' % fn)
     try:
-        # FIXME: symlinks etc.
-        f = open(fn)
+        if stat.S_ISREG(st.st_mode):  # regular file
+            f = open(fn)
+            (mode, id) = hashsplit.split_to_blob_or_tree(w, [f])
+        elif stat.S_ISLNK(st.st_mode):  # symlink
+            (mode, id) = ('120000', w.new_blob(os.readlink(fn)))
+        else:
+            add_error(Exception('skipping special file "%s"' % fn))
     except IOError, e:
         add_error(e)
-        continue
     except OSError, e:
         add_error(e)
-        continue
-    (mode, id) = hashsplit.split_to_blob_or_tree([f])
-    root.addfile(mode, fn, id)
-tree = root.gen_tree()
+    else:
+        root.addfile(mode, fn, id)
+tree = root.gen_tree(w)
+if opt.verbose:
+    log('\n')
 if opt.tree:
-    print tree
+    print tree.encode('hex')
 if opt.commit or opt.name:
     msg = 'bup save\n\nGenerated by command:\n%r' % sys.argv
     ref = opt.name and ('refs/heads/%s' % opt.name) or None
-    commit = git.gen_commit_easy(ref, tree, msg)
+    commit = w.new_commit(ref, tree, msg)
     if opt.commit:
-        print commit
+        if opt.verbose:
+            log('\n')
+        print commit.encode('hex')
+
+w.close()
 
 if saved_errors:
     log('WARNING: %d errors encountered while saving.\n' % len(saved_errors))