]> arthur.barton.de Git - bup.git/blob - cmd-save.py
Name temp files from 'make test' as *.tmp to make them easier to clean.
[bup.git] / cmd-save.py
1 #!/usr/bin/env python
2 import sys, re, errno
3 import hashsplit, git, options
4 from helpers import *
5
6 saved_errors = []
7
8 def add_error(e):
9     saved_errors.append(e)
10     log('\n%s\n' % e)
11
12
13 def direxpand(names):
14     for n in names:
15         try:
16             for sub in os.listdir(n):
17                 subfull = os.path.join(n, sub)
18                 for sub2 in direxpand([subfull]):
19                     yield sub2
20         except OSError, e:
21             if e.errno == errno.ENOTDIR:
22                 yield n
23             elif e.errno in [errno.ENOENT, errno.EPERM, errno.EACCES]:
24                 add_error(e)
25             else:
26                 raise
27             
28
29 def _normpath(dir):
30     p = os.path.normpath(dir)
31     return (p != '.') and p or ''
32
33
34 class Tree:
35     def __init__(self, parent, name):
36         assert(name != '.')
37         assert(not (parent and not name))
38         self.parent = parent
39         self.name = name
40         self.sha = None
41         self.children = {}
42         if self.parent:
43             self.parent.children[self.name] = self
44     
45     def fullpath(self):
46         if self.parent:
47             return os.path.join(self.parent.fullpath(), self.name)
48         else:
49             return self.name
50         
51     def gettop(self):
52         p = self
53         while p.parent:
54             p = p.parent
55         return p
56         
57     def getdir(self, dir):
58         # FIXME: deal with '..' somehow
59         if dir.startswith('/'):
60             dir = dir[1:]
61         top = self.gettop()
62         if not dir:
63             return top
64         for part in _normpath(dir).split('/'):
65             sub = top.children.get(part)
66             if not sub:
67                 sub = top.children[part] = Tree(top, part)
68             top = sub
69         return top
70     
71     def addfile(self, mode, fullname, id):
72         (dir, name) = os.path.split(fullname)
73         self.getdir(dir).children[name] = (mode, name, id)
74         
75     def shalist(self):
76         for c in self.children.values():
77             if isinstance(c, tuple):  # sha1 entry for a file
78                 yield c
79             else:  # tree
80                 t = ('40000', c.name, c.gen_tree())
81                 yield t
82         
83     def gen_tree(self):
84         if not self.sha:
85             self.sha = git.gen_tree(self.shalist())
86         return self.sha
87
88
89 optspec = """
90 bup save [-tc] [-n name] <filenames...>
91 --
92 t,tree     output a tree id
93 c,commit   output a commit id
94 n,name=    name of backup set to update (if any)
95 v,verbose  increase log output (can be used more than once)
96 """
97 o = options.Options('bup save', optspec)
98 (opt, flags, extra) = o.parse(sys.argv[1:])
99
100 if not (opt.tree or opt.commit or opt.name):
101     log("bup save: use one or more of -t, -c, -n\n")
102     o.usage()
103
104 if opt.verbose >= 2:
105     git.verbose = opt.verbose - 1
106     hashsplit.split_verbosely = opt.verbose - 1
107
108 root = Tree(None, '')
109 for fn in direxpand(extra):
110     if opt.verbose:
111         log('\n%s ' % fn)
112     try:
113         # FIXME: symlinks etc.
114         f = open(fn)
115     except IOError, e:
116         add_error(e)
117         continue
118     except OSError, e:
119         add_error(e)
120         continue
121     (mode, id) = hashsplit.split_to_blob_or_tree([f])
122     root.addfile(mode, fn, id)
123 tree = root.gen_tree()
124 if opt.verbose:
125     log('\n')
126 if opt.tree:
127     print tree.encode('hex')
128 if opt.commit or opt.name:
129     msg = 'bup save\n\nGenerated by command:\n%r' % sys.argv
130     ref = opt.name and ('refs/heads/%s' % opt.name) or None
131     commit = git.gen_commit_easy(ref, tree, msg)
132     if opt.commit:
133         print commit.encode('hex')
134
135 git.flush_pack()
136
137 if saved_errors:
138     log('WARNING: %d errors encountered while saving.\n' % len(saved_errors))