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