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