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