]> arthur.barton.de Git - bup.git/blob - git.py
'bup split' can now update a git ref if you give it the -n option.
[bup.git] / git.py
1 import os, errno, zlib, time, sha, subprocess
2 from helpers import *
3
4
5 def hash_raw(type, s):
6     header = '%s %d\0' % (type, len(s))
7     sum = sha.sha(header)
8     sum.update(s)
9     hex = sum.hexdigest()
10     dir = '.git/objects/%s' % hex[0:2]
11     fn = '%s/%s' % (dir, hex[2:])
12     if not os.path.exists(fn):
13         #log('creating %s' % fn)
14         try:
15             os.mkdir(dir)
16         except OSError, e:
17             if e.errno != errno.EEXIST:
18                 raise
19         tfn = '%s.%d' % (fn, os.getpid())
20         f = open(tfn, 'w')
21         z = zlib.compressobj(1)
22         f.write(z.compress(header))
23         f.write(z.compress(s))
24         f.write(z.flush())
25         f.close()
26         os.rename(tfn, fn)
27     else:
28         #log('exists %s' % fn)
29         pass
30     return hex
31
32
33 def hash_blob(blob):
34     return hash_raw('blob', blob)
35
36
37 def gen_tree(shalist):
38     l = ['%s %s\0%s' % (mode,name,hex.decode('hex')) 
39          for (mode,name,hex) in shalist]
40     return hash_raw('tree', ''.join(l))
41
42
43 def _git_date(date):
44     return time.strftime('%s %z', time.localtime(date))
45
46
47 def _gitenv(repo):
48     os.environ['GIT_DIR'] = os.path.abspath(repo)
49
50
51 def _read_ref(repo, refname):
52     p = subprocess.Popen(['git', 'show-ref', '--', refname],
53                          preexec_fn = lambda: _gitenv(repo),
54                          stdout = subprocess.PIPE)
55     out = p.stdout.read().strip()
56     p.wait()
57     if out:
58         return out.split()[0]
59     else:
60         return None
61
62
63 def _update_ref(repo, refname, newval, oldval):
64     if not oldval:
65         oldval = ''
66     p = subprocess.Popen(['git', 'update-ref', '--', refname, newval, oldval],
67                          preexec_fn = lambda: _gitenv(repo))
68     p.wait()
69     return newval
70
71
72 def gen_commit(tree, parent, author, adate, committer, cdate, msg):
73     l = []
74     if tree: l.append('tree %s' % tree)
75     if parent: l.append('parent %s' % parent)
76     if author: l.append('author %s %s' % (author, _git_date(adate)))
77     if committer: l.append('committer %s %s' % (committer, _git_date(cdate)))
78     l.append('')
79     l.append(msg)
80     return hash_raw('commit', '\n'.join(l))
81
82
83 def gen_commit_easy(ref, tree, msg):
84     now = time.time()
85     userline = '%s <%s@%s>' % (userfullname(), username(), hostname())
86     oldref = ref and _read_ref('.git', ref) or None
87     commit = gen_commit(tree, oldref, userline, now, userline, now, msg)
88     if ref:
89         _update_ref('.git', ref, commit, oldref)
90     return commit