]> arthur.barton.de Git - bup.git/blob - lib/bup/t/tgit.py
Simplify bup startup process
[bup.git] / lib / bup / t / tgit.py
1
2 from __future__ import absolute_import, print_function
3 from subprocess import check_call
4 import struct, os, time
5
6 from wvtest import *
7
8 from bup import git, path
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 bup_exe = path.exe()
15
16
17 def exc(*cmd):
18     cmd_str = ' '.join(cmd)
19     print(cmd_str, file=sys.stderr)
20     check_call(cmd)
21
22
23 def exo(*cmd):
24     cmd_str = ' '.join(cmd)
25     print(cmd_str, file=sys.stderr)
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 range(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_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_DIR'] = bupdir = tmpdir + "/bup"
134             git.init_repo(bupdir)
135             git.verbose = 1
136             packdir = git.repo('objects/pack')
137
138             idxnames = []
139             hashes = []
140
141             for start in range(0,28,2):
142                 w = git.PackWriter()
143                 for i in range(start, start+2):
144                     hashes.append(w.new_blob(str(i)))
145                 log('\n')
146                 idxnames.append(os.path.basename(w.close() + '.idx'))
147
148             r = git.PackIdxList(packdir)
149             WVPASSEQ(len(r.packs), 2)
150             for e,idxname in enumerate(idxnames):
151                 for i in range(e*2, (e+1)*2):
152                     WVPASSEQ(r.exists(hashes[i], want_source=True), idxname)
153
154
155 @wvtest
156 def test_long_index():
157     with no_lingering_errors():
158         with test_tempdir('bup-tgit-') as tmpdir:
159             os.environ['BUP_DIR'] = bupdir = tmpdir + "/bup"
160             git.init_repo(bupdir)
161             w = git.PackWriter()
162             obj_bin = struct.pack('!IIIII',
163                     0x00112233, 0x44556677, 0x88990011, 0x22334455, 0x66778899)
164             obj2_bin = struct.pack('!IIIII',
165                     0x11223344, 0x55667788, 0x99001122, 0x33445566, 0x77889900)
166             obj3_bin = struct.pack('!IIIII',
167                     0x22334455, 0x66778899, 0x00112233, 0x44556677, 0x88990011)
168             pack_bin = struct.pack('!IIIII',
169                     0x99887766, 0x55443322, 0x11009988, 0x77665544, 0x33221100)
170             idx = list(list() for i in range(256))
171             idx[0].append((obj_bin, 1, 0xfffffffff))
172             idx[0x11].append((obj2_bin, 2, 0xffffffffff))
173             idx[0x22].append((obj3_bin, 3, 0xff))
174             w.count = 3
175             name = tmpdir + '/tmp.idx'
176             r = w._write_pack_idx_v2(name, idx, pack_bin)
177             i = git.PackIdxV2(name, open(name, 'rb'))
178             WVPASSEQ(i.find_offset(obj_bin), 0xfffffffff)
179             WVPASSEQ(i.find_offset(obj2_bin), 0xffffffffff)
180             WVPASSEQ(i.find_offset(obj3_bin), 0xff)
181
182
183 @wvtest
184 def test_check_repo_or_die():
185     with no_lingering_errors():
186         with test_tempdir('bup-tgit-') as tmpdir:
187             os.environ['BUP_DIR'] = bupdir = tmpdir + "/bup"
188             orig_cwd = os.getcwd()
189             try:
190                 os.chdir(tmpdir)
191                 git.init_repo(bupdir)
192                 git.check_repo_or_die()
193                 # if we reach this point the call above passed
194                 WVPASS('check_repo_or_die')
195
196                 os.rename(bupdir + '/objects/pack',
197                           bupdir + '/objects/pack.tmp')
198                 open(bupdir + '/objects/pack', 'w').close()
199                 try:
200                     git.check_repo_or_die()
201                 except SystemExit as e:
202                     WVPASSEQ(e.code, 14)
203                 else:
204                     WVFAIL()
205                 os.unlink(bupdir + '/objects/pack')
206                 os.rename(bupdir + '/objects/pack.tmp',
207                           bupdir + '/objects/pack')
208
209                 try:
210                     git.check_repo_or_die('nonexistantbup.tmp')
211                 except SystemExit as e:
212                     WVPASSEQ(e.code, 15)
213                 else:
214                     WVFAIL()
215             finally:
216                 os.chdir(orig_cwd)
217
218
219 @wvtest
220 def test_commit_parsing():
221
222     def restore_env_var(name, val):
223         if val is None:
224             del os.environ[name]
225         else:
226             os.environ[name] = val
227
228     def showval(commit, val):
229         return readpipe(['git', 'show', '-s',
230                          '--pretty=format:%s' % val, commit]).strip()
231
232     with no_lingering_errors():
233         with test_tempdir('bup-tgit-') as tmpdir:
234             orig_cwd = os.getcwd()
235             workdir = tmpdir + "/work"
236             repodir = workdir + '/.git'
237             orig_author_name = os.environ.get('GIT_AUTHOR_NAME')
238             orig_author_email = os.environ.get('GIT_AUTHOR_EMAIL')
239             orig_committer_name = os.environ.get('GIT_COMMITTER_NAME')
240             orig_committer_email = os.environ.get('GIT_COMMITTER_EMAIL')
241             os.environ['GIT_AUTHOR_NAME'] = 'bup test'
242             os.environ['GIT_COMMITTER_NAME'] = os.environ['GIT_AUTHOR_NAME']
243             os.environ['GIT_AUTHOR_EMAIL'] = 'bup@a425bc70a02811e49bdf73ee56450e6f'
244             os.environ['GIT_COMMITTER_EMAIL'] = os.environ['GIT_AUTHOR_EMAIL']
245             try:
246                 readpipe(['git', 'init', workdir])
247                 os.environ['GIT_DIR'] = os.environ['BUP_DIR'] = repodir
248                 git.check_repo_or_die(repodir)
249                 os.chdir(workdir)
250                 with open('foo', 'w') as f:
251                     print('bar', file=f)
252                 readpipe(['git', 'add', '.'])
253                 readpipe(['git', 'commit', '-am', 'Do something',
254                           '--author', 'Someone <someone@somewhere>',
255                           '--date', 'Sat Oct 3 19:48:49 2009 -0400'])
256                 commit = readpipe(['git', 'show-ref', '-s', 'master']).strip()
257                 parents = showval(commit, '%P')
258                 tree = showval(commit, '%T')
259                 cname = showval(commit, '%cn')
260                 cmail = showval(commit, '%ce')
261                 cdate = showval(commit, '%ct')
262                 coffs = showval(commit, '%ci')
263                 coffs = coffs[-5:]
264                 coff = (int(coffs[-4:-2]) * 60 * 60) + (int(coffs[-2:]) * 60)
265                 if coffs[-5] == '-':
266                     coff = - coff
267                 commit_items = git.get_commit_items(commit, git.cp())
268                 WVPASSEQ(commit_items.parents, [])
269                 WVPASSEQ(commit_items.tree, tree)
270                 WVPASSEQ(commit_items.author_name, 'Someone')
271                 WVPASSEQ(commit_items.author_mail, 'someone@somewhere')
272                 WVPASSEQ(commit_items.author_sec, 1254613729)
273                 WVPASSEQ(commit_items.author_offset, -(4 * 60 * 60))
274                 WVPASSEQ(commit_items.committer_name, cname)
275                 WVPASSEQ(commit_items.committer_mail, cmail)
276                 WVPASSEQ(commit_items.committer_sec, int(cdate))
277                 WVPASSEQ(commit_items.committer_offset, coff)
278                 WVPASSEQ(commit_items.message, 'Do something\n')
279                 with open('bar', 'w') as f:
280                     print('baz', file=f)
281                 readpipe(['git', 'add', '.'])
282                 readpipe(['git', 'commit', '-am', 'Do something else'])
283                 child = readpipe(['git', 'show-ref', '-s', 'master']).strip()
284                 parents = showval(child, '%P')
285                 commit_items = git.get_commit_items(child, git.cp())
286                 WVPASSEQ(commit_items.parents, [commit])
287             finally:
288                 os.chdir(orig_cwd)
289                 restore_env_var('GIT_AUTHOR_NAME', orig_author_name)
290                 restore_env_var('GIT_AUTHOR_EMAIL', orig_author_email)
291                 restore_env_var('GIT_COMMITTER_NAME', orig_committer_name)
292                 restore_env_var('GIT_COMMITTER_EMAIL', orig_committer_email)
293
294
295 @wvtest
296 def test_new_commit():
297     with no_lingering_errors():
298         with test_tempdir('bup-tgit-') as tmpdir:
299             os.environ['BUP_DIR'] = bupdir = tmpdir + "/bup"
300             git.init_repo(bupdir)
301             git.verbose = 1
302
303             w = git.PackWriter()
304             tree = os.urandom(20)
305             parent = os.urandom(20)
306             author_name = 'Author'
307             author_mail = 'author@somewhere'
308             adate_sec = 1439657836
309             cdate_sec = adate_sec + 1
310             committer_name = 'Committer'
311             committer_mail = 'committer@somewhere'
312             adate_tz_sec = cdate_tz_sec = None
313             commit = w.new_commit(tree, parent,
314                                   '%s <%s>' % (author_name, author_mail),
315                                   adate_sec, adate_tz_sec,
316                                   '%s <%s>' % (committer_name, committer_mail),
317                                   cdate_sec, cdate_tz_sec,
318                                   'There is a small mailbox here')
319             adate_tz_sec = -60 * 60
320             cdate_tz_sec = 120 * 60
321             commit_off = w.new_commit(tree, parent,
322                                       '%s <%s>' % (author_name, author_mail),
323                                       adate_sec, adate_tz_sec,
324                                       '%s <%s>' % (committer_name, committer_mail),
325                                       cdate_sec, cdate_tz_sec,
326                                       'There is a small mailbox here')
327             w.close()
328
329             commit_items = git.get_commit_items(commit.encode('hex'), git.cp())
330             local_author_offset = localtime(adate_sec).tm_gmtoff
331             local_committer_offset = localtime(cdate_sec).tm_gmtoff
332             WVPASSEQ(tree, commit_items.tree.decode('hex'))
333             WVPASSEQ(1, len(commit_items.parents))
334             WVPASSEQ(parent, commit_items.parents[0].decode('hex'))
335             WVPASSEQ(author_name, commit_items.author_name)
336             WVPASSEQ(author_mail, commit_items.author_mail)
337             WVPASSEQ(adate_sec, commit_items.author_sec)
338             WVPASSEQ(local_author_offset, commit_items.author_offset)
339             WVPASSEQ(committer_name, commit_items.committer_name)
340             WVPASSEQ(committer_mail, commit_items.committer_mail)
341             WVPASSEQ(cdate_sec, commit_items.committer_sec)
342             WVPASSEQ(local_committer_offset, commit_items.committer_offset)
343
344             commit_items = git.get_commit_items(commit_off.encode('hex'), git.cp())
345             WVPASSEQ(tree, commit_items.tree.decode('hex'))
346             WVPASSEQ(1, len(commit_items.parents))
347             WVPASSEQ(parent, commit_items.parents[0].decode('hex'))
348             WVPASSEQ(author_name, commit_items.author_name)
349             WVPASSEQ(author_mail, commit_items.author_mail)
350             WVPASSEQ(adate_sec, commit_items.author_sec)
351             WVPASSEQ(adate_tz_sec, commit_items.author_offset)
352             WVPASSEQ(committer_name, commit_items.committer_name)
353             WVPASSEQ(committer_mail, commit_items.committer_mail)
354             WVPASSEQ(cdate_sec, commit_items.committer_sec)
355             WVPASSEQ(cdate_tz_sec, commit_items.committer_offset)
356
357
358 @wvtest
359 def test_list_refs():
360     with no_lingering_errors():
361         with test_tempdir('bup-tgit-') as tmpdir:
362             os.environ['BUP_DIR'] = bupdir = tmpdir + "/bup"
363             src = tmpdir + '/src'
364             mkdirp(src)
365             with open(src + '/1', 'w+') as f:
366                 print('something', file=f)
367             with open(src + '/2', 'w+') as f:
368                 print('something else', file=f)
369             git.init_repo(bupdir)
370             emptyset = frozenset()
371             WVPASSEQ(frozenset(git.list_refs()), emptyset)
372             WVPASSEQ(frozenset(git.list_refs(limit_to_tags=True)), emptyset)
373             WVPASSEQ(frozenset(git.list_refs(limit_to_heads=True)), emptyset)
374             exc(bup_exe, 'index', src)
375             exc(bup_exe, 'save', '-n', 'src', '--strip', src)
376             src_hash = exo('git', '--git-dir', bupdir,
377                            'rev-parse', 'src').strip().split('\n')
378             assert(len(src_hash) == 1)
379             src_hash = src_hash[0].decode('hex')
380             tree_hash = exo('git', '--git-dir', bupdir,
381                            'rev-parse', 'src:').strip().split('\n')[0].decode('hex')
382             blob_hash = exo('git', '--git-dir', bupdir,
383                            'rev-parse', 'src:1').strip().split('\n')[0].decode('hex')
384             WVPASSEQ(frozenset(git.list_refs()),
385                      frozenset([('refs/heads/src', src_hash)]))
386             WVPASSEQ(frozenset(git.list_refs(limit_to_tags=True)), emptyset)
387             WVPASSEQ(frozenset(git.list_refs(limit_to_heads=True)),
388                      frozenset([('refs/heads/src', src_hash)]))
389             exc('git', '--git-dir', bupdir, 'tag', 'commit-tag', 'src')
390             WVPASSEQ(frozenset(git.list_refs()),
391                      frozenset([('refs/heads/src', src_hash),
392                                 ('refs/tags/commit-tag', src_hash)]))
393             WVPASSEQ(frozenset(git.list_refs(limit_to_tags=True)),
394                      frozenset([('refs/tags/commit-tag', src_hash)]))
395             WVPASSEQ(frozenset(git.list_refs(limit_to_heads=True)),
396                      frozenset([('refs/heads/src', src_hash)]))
397             exc('git', '--git-dir', bupdir, 'tag', 'tree-tag', 'src:')
398             exc('git', '--git-dir', bupdir, 'tag', 'blob-tag', 'src:1')
399             os.unlink(bupdir + '/refs/heads/src')
400             expected_tags = frozenset([('refs/tags/commit-tag', src_hash),
401                                        ('refs/tags/tree-tag', tree_hash),
402                                        ('refs/tags/blob-tag', blob_hash)])
403             WVPASSEQ(frozenset(git.list_refs()), expected_tags)
404             WVPASSEQ(frozenset(git.list_refs(limit_to_heads=True)), frozenset([]))
405             WVPASSEQ(frozenset(git.list_refs(limit_to_tags=True)), expected_tags)
406
407
408 @wvtest
409 def test__git_date_str():
410     with no_lingering_errors():
411         WVPASSEQ('0 +0000', git._git_date_str(0, 0))
412         WVPASSEQ('0 -0130', git._git_date_str(0, -90 * 60))
413         WVPASSEQ('0 +0130', git._git_date_str(0, 90 * 60))
414
415
416 @wvtest
417 def test_cat_pipe():
418     with no_lingering_errors():
419         with test_tempdir('bup-tgit-') as tmpdir:
420             os.environ['BUP_DIR'] = bupdir = tmpdir + "/bup"
421             src = tmpdir + '/src'
422             mkdirp(src)
423             with open(src + '/1', 'w+') as f:
424                 print('something', file=f)
425             with open(src + '/2', 'w+') as f:
426                 print('something else', file=f)
427             git.init_repo(bupdir)
428             exc(bup_exe, 'index', src)
429             oidx = exo(bup_exe, 'save', '-cn', 'src', '--strip', src).strip()
430             typ = exo('git', '--git-dir', bupdir,
431                       'cat-file', '-t', 'src').strip()
432             size = int(exo('git', '--git-dir', bupdir,
433                                'cat-file', '-s', 'src'))
434             it = git.cp().get('src')
435             get_info = it.next()
436             for buf in it.next():
437                 pass
438             WVPASSEQ((oidx, typ, size), get_info)