]> arthur.barton.de Git - bup.git/blob - lib/bup/t/tgit.py
3d2e903f9337159136e5d7c633a03ab3ac5afe3e
[bup.git] / lib / bup / t / tgit.py
1
2 from subprocess import check_call
3 import struct, os, time
4
5 from wvtest import *
6
7 from bup import git
8 from bup.helpers import localtime, log, mkdirp, readpipe
9 from buptest import no_lingering_errors, test_tempdir
10
11
12 top_dir = os.path.realpath('../../..')
13 bup_exe = top_dir + '/bup'
14
15
16 def exc(*cmd):
17     cmd_str = ' '.join(cmd)
18     print >> sys.stderr, cmd_str
19     check_call(cmd)
20
21
22 def exo(*cmd):
23     cmd_str = ' '.join(cmd)
24     print >> sys.stderr, cmd_str
25     return readpipe(cmd)
26
27
28 @wvtest
29 def testmangle():
30     with no_lingering_errors():
31         afile  = 0o100644
32         afile2 = 0o100770
33         alink  = 0o120000
34         adir   = 0o040000
35         adir2  = 0o040777
36         WVPASSEQ(git.mangle_name("a", adir2, adir), "a")
37         WVPASSEQ(git.mangle_name(".bup", adir2, adir), ".bup.bupl")
38         WVPASSEQ(git.mangle_name("a.bupa", adir2, adir), "a.bupa.bupl")
39         WVPASSEQ(git.mangle_name("b.bup", alink, alink), "b.bup.bupl")
40         WVPASSEQ(git.mangle_name("b.bu", alink, alink), "b.bu")
41         WVPASSEQ(git.mangle_name("f", afile, afile2), "f")
42         WVPASSEQ(git.mangle_name("f.bup", afile, afile2), "f.bup.bupl")
43         WVPASSEQ(git.mangle_name("f.bup", afile, adir), "f.bup.bup")
44         WVPASSEQ(git.mangle_name("f", afile, adir), "f.bup")
45
46         WVPASSEQ(git.demangle_name("f.bup", afile), ("f", git.BUP_CHUNKED))
47         WVPASSEQ(git.demangle_name("f.bupl", afile), ("f", git.BUP_NORMAL))
48         WVPASSEQ(git.demangle_name("f.bup.bupl", afile), ("f.bup", git.BUP_NORMAL))
49
50         WVPASSEQ(git.demangle_name(".bupm", afile), ('', git.BUP_NORMAL))
51         WVPASSEQ(git.demangle_name(".bupm", adir), ('', git.BUP_CHUNKED))
52
53         # for safety, we ignore .bup? suffixes we don't recognize.  Future
54         # versions might implement a .bup[a-z] extension as something other
55         # than BUP_NORMAL.
56         WVPASSEQ(git.demangle_name("f.bupa", afile), ("f.bupa", git.BUP_NORMAL))
57
58
59 @wvtest
60 def testencode():
61     with no_lingering_errors():
62         s = 'hello world'
63         looseb = ''.join(git._encode_looseobj('blob', s))
64         looset = ''.join(git._encode_looseobj('tree', s))
65         loosec = ''.join(git._encode_looseobj('commit', s))
66         packb = ''.join(git._encode_packobj('blob', s))
67         packt = ''.join(git._encode_packobj('tree', s))
68         packc = ''.join(git._encode_packobj('commit', s))
69         WVPASSEQ(git._decode_looseobj(looseb), ('blob', s))
70         WVPASSEQ(git._decode_looseobj(looset), ('tree', s))
71         WVPASSEQ(git._decode_looseobj(loosec), ('commit', s))
72         WVPASSEQ(git._decode_packobj(packb), ('blob', s))
73         WVPASSEQ(git._decode_packobj(packt), ('tree', s))
74         WVPASSEQ(git._decode_packobj(packc), ('commit', s))
75         for i in xrange(10):
76             WVPASS(git._encode_looseobj('blob', s, compression_level=i))
77         def encode_pobj(n):
78             return ''.join(git._encode_packobj('blob', s, compression_level=n))
79         WVEXCEPT(ValueError, encode_pobj, -1)
80         WVEXCEPT(ValueError, encode_pobj, 10)
81         WVEXCEPT(ValueError, encode_pobj, 'x')
82
83
84 @wvtest
85 def testpacks():
86     with no_lingering_errors():
87         with test_tempdir('bup-tgit-') as tmpdir:
88             os.environ['BUP_MAIN_EXE'] = bup_exe
89             os.environ['BUP_DIR'] = bupdir = tmpdir + "/bup"
90             git.init_repo(bupdir)
91             git.verbose = 1
92
93             w = git.PackWriter()
94             w.new_blob(os.urandom(100))
95             w.new_blob(os.urandom(100))
96             w.abort()
97
98             w = git.PackWriter()
99             hashes = []
100             nobj = 1000
101             for i in range(nobj):
102                 hashes.append(w.new_blob(str(i)))
103             log('\n')
104             nameprefix = w.close()
105             print repr(nameprefix)
106             WVPASS(os.path.exists(nameprefix + '.pack'))
107             WVPASS(os.path.exists(nameprefix + '.idx'))
108
109             r = git.open_idx(nameprefix + '.idx')
110             print repr(r.fanout)
111
112             for i in range(nobj):
113                 WVPASS(r.find_offset(hashes[i]) > 0)
114             WVPASS(r.exists(hashes[99]))
115             WVFAIL(r.exists('\0'*20))
116
117             pi = iter(r)
118             for h in sorted(hashes):
119                 WVPASSEQ(str(next(pi)).encode('hex'), h.encode('hex'))
120
121             WVFAIL(r.find_offset('\0'*20))
122
123             r = git.PackIdxList(bupdir + '/objects/pack')
124             WVPASS(r.exists(hashes[5]))
125             WVPASS(r.exists(hashes[6]))
126             WVFAIL(r.exists('\0'*20))
127
128
129 @wvtest
130 def test_pack_name_lookup():
131     with no_lingering_errors():
132         with test_tempdir('bup-tgit-') as tmpdir:
133             os.environ['BUP_MAIN_EXE'] = bup_exe
134             os.environ['BUP_DIR'] = bupdir = tmpdir + "/bup"
135             git.init_repo(bupdir)
136             git.verbose = 1
137             packdir = git.repo('objects/pack')
138
139             idxnames = []
140             hashes = []
141
142             for start in range(0,28,2):
143                 w = git.PackWriter()
144                 for i in range(start, start+2):
145                     hashes.append(w.new_blob(str(i)))
146                 log('\n')
147                 idxnames.append(os.path.basename(w.close() + '.idx'))
148
149             r = git.PackIdxList(packdir)
150             WVPASSEQ(len(r.packs), 2)
151             for e,idxname in enumerate(idxnames):
152                 for i in range(e*2, (e+1)*2):
153                     WVPASSEQ(r.exists(hashes[i], want_source=True), idxname)
154
155
156 @wvtest
157 def test_long_index():
158     with no_lingering_errors():
159         with test_tempdir('bup-tgit-') as tmpdir:
160             os.environ['BUP_MAIN_EXE'] = bup_exe
161             os.environ['BUP_DIR'] = bupdir = tmpdir + "/bup"
162             git.init_repo(bupdir)
163             w = git.PackWriter()
164             obj_bin = struct.pack('!IIIII',
165                     0x00112233, 0x44556677, 0x88990011, 0x22334455, 0x66778899)
166             obj2_bin = struct.pack('!IIIII',
167                     0x11223344, 0x55667788, 0x99001122, 0x33445566, 0x77889900)
168             obj3_bin = struct.pack('!IIIII',
169                     0x22334455, 0x66778899, 0x00112233, 0x44556677, 0x88990011)
170             pack_bin = struct.pack('!IIIII',
171                     0x99887766, 0x55443322, 0x11009988, 0x77665544, 0x33221100)
172             idx = list(list() for i in xrange(256))
173             idx[0].append((obj_bin, 1, 0xfffffffff))
174             idx[0x11].append((obj2_bin, 2, 0xffffffffff))
175             idx[0x22].append((obj3_bin, 3, 0xff))
176             w.count = 3
177             name = tmpdir + '/tmp.idx'
178             r = w._write_pack_idx_v2(name, idx, pack_bin)
179             i = git.PackIdxV2(name, open(name, 'rb'))
180             WVPASSEQ(i.find_offset(obj_bin), 0xfffffffff)
181             WVPASSEQ(i.find_offset(obj2_bin), 0xffffffffff)
182             WVPASSEQ(i.find_offset(obj3_bin), 0xff)
183
184
185 @wvtest
186 def test_check_repo_or_die():
187     with no_lingering_errors():
188         with test_tempdir('bup-tgit-') as tmpdir:
189             os.environ['BUP_DIR'] = bupdir = tmpdir + "/bup"
190             orig_cwd = os.getcwd()
191             try:
192                 os.chdir(tmpdir)
193                 git.init_repo(bupdir)
194                 git.check_repo_or_die()
195                 # if we reach this point the call above passed
196                 WVPASS('check_repo_or_die')
197
198                 os.rename(bupdir + '/objects/pack',
199                           bupdir + '/objects/pack.tmp')
200                 open(bupdir + '/objects/pack', 'w').close()
201                 try:
202                     git.check_repo_or_die()
203                 except SystemExit as e:
204                     WVPASSEQ(e.code, 14)
205                 else:
206                     WVFAIL()
207                 os.unlink(bupdir + '/objects/pack')
208                 os.rename(bupdir + '/objects/pack.tmp',
209                           bupdir + '/objects/pack')
210
211                 try:
212                     git.check_repo_or_die('nonexistantbup.tmp')
213                 except SystemExit as e:
214                     WVPASSEQ(e.code, 15)
215                 else:
216                     WVFAIL()
217             finally:
218                 os.chdir(orig_cwd)
219
220
221 @wvtest
222 def test_commit_parsing():
223
224     def restore_env_var(name, val):
225         if val is None:
226             del os.environ[name]
227         else:
228             os.environ[name] = val
229
230     def showval(commit, val):
231         return readpipe(['git', 'show', '-s',
232                          '--pretty=format:%s' % val, commit]).strip()
233
234     with no_lingering_errors():
235         with test_tempdir('bup-tgit-') as tmpdir:
236             orig_cwd = os.getcwd()
237             workdir = tmpdir + "/work"
238             repodir = workdir + '/.git'
239             orig_author_name = os.environ.get('GIT_AUTHOR_NAME')
240             orig_author_email = os.environ.get('GIT_AUTHOR_EMAIL')
241             orig_committer_name = os.environ.get('GIT_COMMITTER_NAME')
242             orig_committer_email = os.environ.get('GIT_COMMITTER_EMAIL')
243             os.environ['GIT_AUTHOR_NAME'] = 'bup test'
244             os.environ['GIT_COMMITTER_NAME'] = os.environ['GIT_AUTHOR_NAME']
245             os.environ['GIT_AUTHOR_EMAIL'] = 'bup@a425bc70a02811e49bdf73ee56450e6f'
246             os.environ['GIT_COMMITTER_EMAIL'] = os.environ['GIT_AUTHOR_EMAIL']
247             try:
248                 readpipe(['git', 'init', workdir])
249                 os.environ['GIT_DIR'] = os.environ['BUP_DIR'] = repodir
250                 git.check_repo_or_die(repodir)
251                 os.chdir(workdir)
252                 with open('foo', 'w') as f:
253                     print >> f, 'bar'
254                 readpipe(['git', 'add', '.'])
255                 readpipe(['git', 'commit', '-am', 'Do something',
256                           '--author', 'Someone <someone@somewhere>',
257                           '--date', 'Sat Oct 3 19:48:49 2009 -0400'])
258                 commit = readpipe(['git', 'show-ref', '-s', 'master']).strip()
259                 parents = showval(commit, '%P')
260                 tree = showval(commit, '%T')
261                 cname = showval(commit, '%cn')
262                 cmail = showval(commit, '%ce')
263                 cdate = showval(commit, '%ct')
264                 coffs = showval(commit, '%ci')
265                 coffs = coffs[-5:]
266                 coff = (int(coffs[-4:-2]) * 60 * 60) + (int(coffs[-2:]) * 60)
267                 if coffs[-5] == '-':
268                     coff = - coff
269                 commit_items = git.get_commit_items(commit, git.cp())
270                 WVPASSEQ(commit_items.parents, [])
271                 WVPASSEQ(commit_items.tree, tree)
272                 WVPASSEQ(commit_items.author_name, 'Someone')
273                 WVPASSEQ(commit_items.author_mail, 'someone@somewhere')
274                 WVPASSEQ(commit_items.author_sec, 1254613729)
275                 WVPASSEQ(commit_items.author_offset, -(4 * 60 * 60))
276                 WVPASSEQ(commit_items.committer_name, cname)
277                 WVPASSEQ(commit_items.committer_mail, cmail)
278                 WVPASSEQ(commit_items.committer_sec, int(cdate))
279                 WVPASSEQ(commit_items.committer_offset, coff)
280                 WVPASSEQ(commit_items.message, 'Do something\n')
281                 with open('bar', 'w') as f:
282                     print >> f, 'baz'
283                 readpipe(['git', 'add', '.'])
284                 readpipe(['git', 'commit', '-am', 'Do something else'])
285                 child = readpipe(['git', 'show-ref', '-s', 'master']).strip()
286                 parents = showval(child, '%P')
287                 commit_items = git.get_commit_items(child, git.cp())
288                 WVPASSEQ(commit_items.parents, [commit])
289             finally:
290                 os.chdir(orig_cwd)
291                 restore_env_var('GIT_AUTHOR_NAME', orig_author_name)
292                 restore_env_var('GIT_AUTHOR_EMAIL', orig_author_email)
293                 restore_env_var('GIT_COMMITTER_NAME', orig_committer_name)
294                 restore_env_var('GIT_COMMITTER_EMAIL', orig_committer_email)
295
296
297 @wvtest
298 def test_new_commit():
299     with no_lingering_errors():
300         with test_tempdir('bup-tgit-') as tmpdir:
301             os.environ['BUP_MAIN_EXE'] = bup_exe
302             os.environ['BUP_DIR'] = bupdir = tmpdir + "/bup"
303             git.init_repo(bupdir)
304             git.verbose = 1
305
306             w = git.PackWriter()
307             tree = os.urandom(20)
308             parent = os.urandom(20)
309             author_name = 'Author'
310             author_mail = 'author@somewhere'
311             adate_sec = 1439657836
312             cdate_sec = adate_sec + 1
313             committer_name = 'Committer'
314             committer_mail = 'committer@somewhere'
315             adate_tz_sec = cdate_tz_sec = None
316             commit = w.new_commit(tree, parent,
317                                   '%s <%s>' % (author_name, author_mail),
318                                   adate_sec, adate_tz_sec,
319                                   '%s <%s>' % (committer_name, committer_mail),
320                                   cdate_sec, cdate_tz_sec,
321                                   'There is a small mailbox here')
322             adate_tz_sec = -60 * 60
323             cdate_tz_sec = 120 * 60
324             commit_off = w.new_commit(tree, parent,
325                                       '%s <%s>' % (author_name, author_mail),
326                                       adate_sec, adate_tz_sec,
327                                       '%s <%s>' % (committer_name, committer_mail),
328                                       cdate_sec, cdate_tz_sec,
329                                       'There is a small mailbox here')
330             w.close()
331
332             commit_items = git.get_commit_items(commit.encode('hex'), git.cp())
333             local_author_offset = localtime(adate_sec).tm_gmtoff
334             local_committer_offset = localtime(cdate_sec).tm_gmtoff
335             WVPASSEQ(tree, commit_items.tree.decode('hex'))
336             WVPASSEQ(1, len(commit_items.parents))
337             WVPASSEQ(parent, commit_items.parents[0].decode('hex'))
338             WVPASSEQ(author_name, commit_items.author_name)
339             WVPASSEQ(author_mail, commit_items.author_mail)
340             WVPASSEQ(adate_sec, commit_items.author_sec)
341             WVPASSEQ(local_author_offset, commit_items.author_offset)
342             WVPASSEQ(committer_name, commit_items.committer_name)
343             WVPASSEQ(committer_mail, commit_items.committer_mail)
344             WVPASSEQ(cdate_sec, commit_items.committer_sec)
345             WVPASSEQ(local_committer_offset, commit_items.committer_offset)
346
347             commit_items = git.get_commit_items(commit_off.encode('hex'), git.cp())
348             WVPASSEQ(tree, commit_items.tree.decode('hex'))
349             WVPASSEQ(1, len(commit_items.parents))
350             WVPASSEQ(parent, commit_items.parents[0].decode('hex'))
351             WVPASSEQ(author_name, commit_items.author_name)
352             WVPASSEQ(author_mail, commit_items.author_mail)
353             WVPASSEQ(adate_sec, commit_items.author_sec)
354             WVPASSEQ(adate_tz_sec, commit_items.author_offset)
355             WVPASSEQ(committer_name, commit_items.committer_name)
356             WVPASSEQ(committer_mail, commit_items.committer_mail)
357             WVPASSEQ(cdate_sec, commit_items.committer_sec)
358             WVPASSEQ(cdate_tz_sec, commit_items.committer_offset)
359
360
361 @wvtest
362 def test_list_refs():
363     with no_lingering_errors():
364         with test_tempdir('bup-tgit-') as tmpdir:
365             os.environ['BUP_MAIN_EXE'] = bup_exe
366             os.environ['BUP_DIR'] = bupdir = tmpdir + "/bup"
367             src = tmpdir + '/src'
368             mkdirp(src)
369             with open(src + '/1', 'w+') as f:
370                 print f, 'something'
371             with open(src + '/2', 'w+') as f:
372                 print f, 'something else'
373             git.init_repo(bupdir)
374             emptyset = frozenset()
375             WVPASSEQ(frozenset(git.list_refs()), emptyset)
376             WVPASSEQ(frozenset(git.list_refs(limit_to_tags=True)), emptyset)
377             WVPASSEQ(frozenset(git.list_refs(limit_to_heads=True)), emptyset)
378             exc(bup_exe, 'index', src)
379             exc(bup_exe, 'save', '-n', 'src', '--strip', src)
380             src_hash = exo('git', '--git-dir', bupdir,
381                            'rev-parse', 'src').strip().split('\n')
382             assert(len(src_hash) == 1)
383             src_hash = src_hash[0].decode('hex')
384             tree_hash = exo('git', '--git-dir', bupdir,
385                            'rev-parse', 'src:').strip().split('\n')[0].decode('hex')
386             blob_hash = exo('git', '--git-dir', bupdir,
387                            'rev-parse', 'src:1').strip().split('\n')[0].decode('hex')
388             WVPASSEQ(frozenset(git.list_refs()),
389                      frozenset([('refs/heads/src', src_hash)]))
390             WVPASSEQ(frozenset(git.list_refs(limit_to_tags=True)), emptyset)
391             WVPASSEQ(frozenset(git.list_refs(limit_to_heads=True)),
392                      frozenset([('refs/heads/src', src_hash)]))
393             exc('git', '--git-dir', bupdir, 'tag', 'commit-tag', 'src')
394             WVPASSEQ(frozenset(git.list_refs()),
395                      frozenset([('refs/heads/src', src_hash),
396                                 ('refs/tags/commit-tag', src_hash)]))
397             WVPASSEQ(frozenset(git.list_refs(limit_to_tags=True)),
398                      frozenset([('refs/tags/commit-tag', src_hash)]))
399             WVPASSEQ(frozenset(git.list_refs(limit_to_heads=True)),
400                      frozenset([('refs/heads/src', src_hash)]))
401             exc('git', '--git-dir', bupdir, 'tag', 'tree-tag', 'src:')
402             exc('git', '--git-dir', bupdir, 'tag', 'blob-tag', 'src:1')
403             os.unlink(bupdir + '/refs/heads/src')
404             expected_tags = frozenset([('refs/tags/commit-tag', src_hash),
405                                        ('refs/tags/tree-tag', tree_hash),
406                                        ('refs/tags/blob-tag', blob_hash)])
407             WVPASSEQ(frozenset(git.list_refs()), expected_tags)
408             WVPASSEQ(frozenset(git.list_refs(limit_to_heads=True)), frozenset([]))
409             WVPASSEQ(frozenset(git.list_refs(limit_to_tags=True)), expected_tags)
410
411
412 @wvtest
413 def test__git_date_str():
414     with no_lingering_errors():
415         WVPASSEQ('0 +0000', git._git_date_str(0, 0))
416         WVPASSEQ('0 -0130', git._git_date_str(0, -90 * 60))
417         WVPASSEQ('0 +0130', git._git_date_str(0, 90 * 60))
418
419
420 @wvtest
421 def test_cat_pipe():
422     with no_lingering_errors():
423         with test_tempdir('bup-tgit-') as tmpdir:
424             os.environ['BUP_MAIN_EXE'] = bup_exe
425             os.environ['BUP_DIR'] = bupdir = tmpdir + "/bup"
426             src = tmpdir + '/src'
427             mkdirp(src)
428             with open(src + '/1', 'w+') as f:
429                 print f, 'something'
430             with open(src + '/2', 'w+') as f:
431                 print f, 'something else'
432             git.init_repo(bupdir)
433             exc(bup_exe, 'index', src)
434             oidx = exo(bup_exe, 'save', '-cn', 'src', '--strip', src).strip()
435             typ = exo('git', '--git-dir', bupdir,
436                       'cat-file', '-t', 'src').strip()
437             size = int(exo('git', '--git-dir', bupdir,
438                                'cat-file', '-s', 'src'))
439             it = git.cp().get('src')
440             get_info = it.next()
441             for buf in it.next():
442                 pass
443             WVPASSEQ((oidx, typ, size), get_info)