2 from __future__ import absolute_import, print_function
3 from binascii import hexlify, unhexlify
4 from subprocess import check_call
5 import struct, os, time
9 from bup import git, path
10 from bup.compat import bytes_from_byte, environ, range
11 from bup.helpers import localtime, log, mkdirp, readpipe
12 from buptest import no_lingering_errors, test_tempdir
19 print(repr(cmd), file=sys.stderr)
24 print(repr(cmd), file=sys.stderr)
30 with no_lingering_errors():
36 WVPASSEQ(git.mangle_name(b'a', adir2, adir), b'a')
37 WVPASSEQ(git.mangle_name(b'.bup', adir2, adir), b'.bup.bupl')
38 WVPASSEQ(git.mangle_name(b'a.bupa', adir2, adir), b'a.bupa.bupl')
39 WVPASSEQ(git.mangle_name(b'b.bup', alink, alink), b'b.bup.bupl')
40 WVPASSEQ(git.mangle_name(b'b.bu', alink, alink), b'b.bu')
41 WVPASSEQ(git.mangle_name(b'f', afile, afile2), b'f')
42 WVPASSEQ(git.mangle_name(b'f.bup', afile, afile2), b'f.bup.bupl')
43 WVPASSEQ(git.mangle_name(b'f.bup', afile, adir), b'f.bup.bup')
44 WVPASSEQ(git.mangle_name(b'f', afile, adir), b'f.bup')
46 WVPASSEQ(git.demangle_name(b'f.bup', afile), (b'f', git.BUP_CHUNKED))
47 WVPASSEQ(git.demangle_name(b'f.bupl', afile), (b'f', git.BUP_NORMAL))
48 WVPASSEQ(git.demangle_name(b'f.bup.bupl', afile), (b'f.bup', git.BUP_NORMAL))
50 WVPASSEQ(git.demangle_name(b'.bupm', afile), (b'', git.BUP_NORMAL))
51 WVPASSEQ(git.demangle_name(b'.bupm', adir), (b'', git.BUP_CHUNKED))
53 # for safety, we ignore .bup? suffixes we don't recognize. Future
54 # versions might implement a .bup[a-z] extension as something other
56 WVPASSEQ(git.demangle_name(b'f.bupa', afile), (b'f.bupa', git.BUP_NORMAL))
61 with no_lingering_errors():
63 looseb = b''.join(git._encode_looseobj(b'blob', s))
64 looset = b''.join(git._encode_looseobj(b'tree', s))
65 loosec = b''.join(git._encode_looseobj(b'commit', s))
66 packb = b''.join(git._encode_packobj(b'blob', s))
67 packt = b''.join(git._encode_packobj(b'tree', s))
68 packc = b''.join(git._encode_packobj(b'commit', s))
69 packlb = b''.join(git._encode_packobj(b'blob', s * 200))
70 WVPASSEQ(git._decode_looseobj(looseb), (b'blob', s))
71 WVPASSEQ(git._decode_looseobj(looset), (b'tree', s))
72 WVPASSEQ(git._decode_looseobj(loosec), (b'commit', s))
73 WVPASSEQ(git._decode_packobj(packb), (b'blob', s))
74 WVPASSEQ(git._decode_packobj(packt), (b'tree', s))
75 WVPASSEQ(git._decode_packobj(packc), (b'commit', s))
76 WVPASSEQ(git._decode_packobj(packlb), (b'blob', s * 200))
78 WVPASS(git._encode_looseobj(b'blob', s, compression_level=i))
80 return b''.join(git._encode_packobj(b'blob', s, compression_level=n))
81 WVEXCEPT(ValueError, encode_pobj, -1)
82 WVEXCEPT(ValueError, encode_pobj, 10)
83 WVEXCEPT(ValueError, encode_pobj, b'x')
88 with no_lingering_errors():
89 with test_tempdir(b'bup-tgit-') as tmpdir:
90 environ[b'BUP_DIR'] = bupdir = tmpdir + b'/bup'
95 w.new_blob(os.urandom(100))
96 w.new_blob(os.urandom(100))
102 for i in range(nobj):
103 hashes.append(w.new_blob(b'%d' % i))
105 nameprefix = w.close()
106 print(repr(nameprefix))
107 WVPASS(os.path.exists(nameprefix + b'.pack'))
108 WVPASS(os.path.exists(nameprefix + b'.idx'))
110 r = git.open_idx(nameprefix + b'.idx')
111 print(repr(r.fanout))
113 for i in range(nobj):
114 WVPASS(r.find_offset(hashes[i]) > 0)
115 WVPASS(r.exists(hashes[99]))
116 WVFAIL(r.exists(b'\0'*20))
119 for h in sorted(hashes):
120 WVPASSEQ(hexlify(next(pi)), hexlify(h))
122 WVFAIL(r.find_offset(b'\0'*20))
124 r = git.PackIdxList(bupdir + b'/objects/pack')
125 WVPASS(r.exists(hashes[5]))
126 WVPASS(r.exists(hashes[6]))
127 WVFAIL(r.exists(b'\0'*20))
131 def test_pack_name_lookup():
132 with no_lingering_errors():
133 with test_tempdir(b'bup-tgit-') as tmpdir:
134 environ[b'BUP_DIR'] = bupdir = tmpdir + b'/bup'
135 git.init_repo(bupdir)
137 packdir = git.repo(b'objects/pack')
142 for start in range(0,28,2):
144 for i in range(start, start+2):
145 hashes.append(w.new_blob(b'%d' % i))
147 idxnames.append(os.path.basename(w.close() + b'.idx'))
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(idxname, r.exists(hashes[i], want_source=True))
157 def test_long_index():
158 with no_lingering_errors():
159 with test_tempdir(b'bup-tgit-') as tmpdir:
160 environ[b'BUP_DIR'] = bupdir = tmpdir + b'/bup'
161 git.init_repo(bupdir)
163 obj_bin = struct.pack('!IIIII',
164 0x00112233, 0x44556677, 0x88990011, 0x22334455, 0x66778899)
165 obj2_bin = struct.pack('!IIIII',
166 0x11223344, 0x55667788, 0x99001122, 0x33445566, 0x77889900)
167 obj3_bin = struct.pack('!IIIII',
168 0x22334455, 0x66778899, 0x00112233, 0x44556677, 0x88990011)
169 pack_bin = struct.pack('!IIIII',
170 0x99887766, 0x55443322, 0x11009988, 0x77665544, 0x33221100)
171 idx = list(list() for i in range(256))
172 idx[0].append((obj_bin, 1, 0xfffffffff))
173 idx[0x11].append((obj2_bin, 2, 0xffffffffff))
174 idx[0x22].append((obj3_bin, 3, 0xff))
176 name = tmpdir + b'/tmp.idx'
177 r = w._write_pack_idx_v2(name, idx, pack_bin)
178 i = git.PackIdxV2(name, open(name, 'rb'))
179 WVPASSEQ(i.find_offset(obj_bin), 0xfffffffff)
180 WVPASSEQ(i.find_offset(obj2_bin), 0xffffffffff)
181 WVPASSEQ(i.find_offset(obj3_bin), 0xff)
185 def test_check_repo_or_die():
186 with no_lingering_errors():
187 with test_tempdir(b'bup-tgit-') as tmpdir:
188 environ[b'BUP_DIR'] = bupdir = tmpdir + b'/bup'
189 orig_cwd = os.getcwd()
192 git.init_repo(bupdir)
193 git.check_repo_or_die()
194 # if we reach this point the call above passed
195 WVPASS('check_repo_or_die')
197 os.rename(bupdir + b'/objects/pack',
198 bupdir + b'/objects/pack.tmp')
199 open(bupdir + b'/objects/pack', 'w').close()
201 git.check_repo_or_die()
202 except SystemExit as e:
206 os.unlink(bupdir + b'/objects/pack')
207 os.rename(bupdir + b'/objects/pack.tmp',
208 bupdir + b'/objects/pack')
211 git.check_repo_or_die(b'nonexistantbup.tmp')
212 except SystemExit as e:
221 def test_commit_parsing():
223 def restore_env_var(name, val):
229 def showval(commit, val):
230 return readpipe([b'git', b'show', b'-s',
231 b'--pretty=format:%s' % val, commit]).strip()
233 with no_lingering_errors():
234 with test_tempdir(b'bup-tgit-') as tmpdir:
235 orig_cwd = os.getcwd()
236 workdir = tmpdir + b'/work'
237 repodir = workdir + b'/.git'
238 orig_author_name = environ.get(b'GIT_AUTHOR_NAME')
239 orig_author_email = environ.get(b'GIT_AUTHOR_EMAIL')
240 orig_committer_name = environ.get(b'GIT_COMMITTER_NAME')
241 orig_committer_email = environ.get(b'GIT_COMMITTER_EMAIL')
242 environ[b'GIT_AUTHOR_NAME'] = b'bup test'
243 environ[b'GIT_COMMITTER_NAME'] = environ[b'GIT_AUTHOR_NAME']
244 environ[b'GIT_AUTHOR_EMAIL'] = b'bup@a425bc70a02811e49bdf73ee56450e6f'
245 environ[b'GIT_COMMITTER_EMAIL'] = environ[b'GIT_AUTHOR_EMAIL']
247 readpipe([b'git', b'init', workdir])
248 environ[b'GIT_DIR'] = environ[b'BUP_DIR'] = repodir
249 git.check_repo_or_die(repodir)
251 with open('foo', 'w') as f:
253 readpipe([b'git', b'add', b'.'])
254 readpipe([b'git', b'commit', b'-am', b'Do something',
255 b'--author', b'Someone <someone@somewhere>',
256 b'--date', b'Sat Oct 3 19:48:49 2009 -0400'])
257 commit = readpipe([b'git', b'show-ref', b'-s', b'master']).strip()
258 parents = showval(commit, b'%P')
259 tree = showval(commit, b'%T')
260 cname = showval(commit, b'%cn')
261 cmail = showval(commit, b'%ce')
262 cdate = showval(commit, b'%ct')
263 coffs = showval(commit, b'%ci')
265 coff = (int(coffs[-4:-2]) * 60 * 60) + (int(coffs[-2:]) * 60)
266 if bytes_from_byte(coffs[-5]) == b'-':
268 commit_items = git.get_commit_items(commit, git.cp())
269 WVPASSEQ(commit_items.parents, [])
270 WVPASSEQ(commit_items.tree, tree)
271 WVPASSEQ(commit_items.author_name, b'Someone')
272 WVPASSEQ(commit_items.author_mail, b'someone@somewhere')
273 WVPASSEQ(commit_items.author_sec, 1254613729)
274 WVPASSEQ(commit_items.author_offset, -(4 * 60 * 60))
275 WVPASSEQ(commit_items.committer_name, cname)
276 WVPASSEQ(commit_items.committer_mail, cmail)
277 WVPASSEQ(commit_items.committer_sec, int(cdate))
278 WVPASSEQ(commit_items.committer_offset, coff)
279 WVPASSEQ(commit_items.message, b'Do something\n')
280 with open(b'bar', 'wb') as f:
282 readpipe([b'git', b'add', '.'])
283 readpipe([b'git', b'commit', b'-am', b'Do something else'])
284 child = readpipe([b'git', b'show-ref', b'-s', b'master']).strip()
285 parents = showval(child, b'%P')
286 commit_items = git.get_commit_items(child, git.cp())
287 WVPASSEQ(commit_items.parents, [commit])
290 restore_env_var(b'GIT_AUTHOR_NAME', orig_author_name)
291 restore_env_var(b'GIT_AUTHOR_EMAIL', orig_author_email)
292 restore_env_var(b'GIT_COMMITTER_NAME', orig_committer_name)
293 restore_env_var(b'GIT_COMMITTER_EMAIL', orig_committer_email)
297 def test_new_commit():
298 with no_lingering_errors():
299 with test_tempdir(b'bup-tgit-') as tmpdir:
300 environ[b'BUP_DIR'] = bupdir = tmpdir + b'/bup'
301 git.init_repo(bupdir)
305 tree = os.urandom(20)
306 parent = os.urandom(20)
307 author_name = b'Author'
308 author_mail = b'author@somewhere'
309 adate_sec = 1439657836
310 cdate_sec = adate_sec + 1
311 committer_name = b'Committer'
312 committer_mail = b'committer@somewhere'
313 adate_tz_sec = cdate_tz_sec = None
314 commit = w.new_commit(tree, parent,
315 b'%s <%s>' % (author_name, author_mail),
316 adate_sec, adate_tz_sec,
317 b'%s <%s>' % (committer_name, committer_mail),
318 cdate_sec, cdate_tz_sec,
319 b'There is a small mailbox here')
320 adate_tz_sec = -60 * 60
321 cdate_tz_sec = 120 * 60
322 commit_off = w.new_commit(tree, parent,
323 b'%s <%s>' % (author_name, author_mail),
324 adate_sec, adate_tz_sec,
325 b'%s <%s>' % (committer_name, committer_mail),
326 cdate_sec, cdate_tz_sec,
327 b'There is a small mailbox here')
330 commit_items = git.get_commit_items(hexlify(commit), git.cp())
331 local_author_offset = localtime(adate_sec).tm_gmtoff
332 local_committer_offset = localtime(cdate_sec).tm_gmtoff
333 WVPASSEQ(tree, unhexlify(commit_items.tree))
334 WVPASSEQ(1, len(commit_items.parents))
335 WVPASSEQ(parent, unhexlify(commit_items.parents[0]))
336 WVPASSEQ(author_name, commit_items.author_name)
337 WVPASSEQ(author_mail, commit_items.author_mail)
338 WVPASSEQ(adate_sec, commit_items.author_sec)
339 WVPASSEQ(local_author_offset, commit_items.author_offset)
340 WVPASSEQ(committer_name, commit_items.committer_name)
341 WVPASSEQ(committer_mail, commit_items.committer_mail)
342 WVPASSEQ(cdate_sec, commit_items.committer_sec)
343 WVPASSEQ(local_committer_offset, commit_items.committer_offset)
345 commit_items = git.get_commit_items(hexlify(commit_off), git.cp())
346 WVPASSEQ(tree, unhexlify(commit_items.tree))
347 WVPASSEQ(1, len(commit_items.parents))
348 WVPASSEQ(parent, unhexlify(commit_items.parents[0]))
349 WVPASSEQ(author_name, commit_items.author_name)
350 WVPASSEQ(author_mail, commit_items.author_mail)
351 WVPASSEQ(adate_sec, commit_items.author_sec)
352 WVPASSEQ(adate_tz_sec, commit_items.author_offset)
353 WVPASSEQ(committer_name, commit_items.committer_name)
354 WVPASSEQ(committer_mail, commit_items.committer_mail)
355 WVPASSEQ(cdate_sec, commit_items.committer_sec)
356 WVPASSEQ(cdate_tz_sec, commit_items.committer_offset)
360 def test_list_refs():
361 with no_lingering_errors():
362 with test_tempdir(b'bup-tgit-') as tmpdir:
363 environ[b'BUP_DIR'] = bupdir = tmpdir + b'/bup'
364 src = tmpdir + b'/src'
366 with open(src + b'/1', 'wb+') as f:
367 f.write(b'something\n')
368 with open(src + b'/2', 'wb+') as f:
369 f.write(b'something else\n')
370 git.init_repo(bupdir)
371 emptyset = frozenset()
372 WVPASSEQ(frozenset(git.list_refs()), emptyset)
373 WVPASSEQ(frozenset(git.list_refs(limit_to_tags=True)), emptyset)
374 WVPASSEQ(frozenset(git.list_refs(limit_to_heads=True)), emptyset)
375 exc(bup_exe, b'index', src)
376 exc(bup_exe, b'save', b'-n', b'src', b'--strip', src)
377 src_hash = exo(b'git', b'--git-dir', bupdir,
378 b'rev-parse', b'src').strip().split(b'\n')
379 assert(len(src_hash) == 1)
380 src_hash = unhexlify(src_hash[0])
381 tree_hash = unhexlify(exo(b'git', b'--git-dir', bupdir,
383 b'src:').strip().split(b'\n')[0])
384 blob_hash = unhexlify(exo(b'git', b'--git-dir', bupdir,
386 b'src:1').strip().split(b'\n')[0])
387 WVPASSEQ(frozenset(git.list_refs()),
388 frozenset([(b'refs/heads/src', src_hash)]))
389 WVPASSEQ(frozenset(git.list_refs(limit_to_tags=True)), emptyset)
390 WVPASSEQ(frozenset(git.list_refs(limit_to_heads=True)),
391 frozenset([(b'refs/heads/src', src_hash)]))
392 exc(b'git', b'--git-dir', bupdir, b'tag', b'commit-tag', b'src')
393 WVPASSEQ(frozenset(git.list_refs()),
394 frozenset([(b'refs/heads/src', src_hash),
395 (b'refs/tags/commit-tag', src_hash)]))
396 WVPASSEQ(frozenset(git.list_refs(limit_to_tags=True)),
397 frozenset([(b'refs/tags/commit-tag', src_hash)]))
398 WVPASSEQ(frozenset(git.list_refs(limit_to_heads=True)),
399 frozenset([(b'refs/heads/src', src_hash)]))
400 exc(b'git', b'--git-dir', bupdir, b'tag', b'tree-tag', b'src:')
401 exc(b'git', b'--git-dir', bupdir, b'tag', b'blob-tag', b'src:1')
402 os.unlink(bupdir + b'/refs/heads/src')
403 expected_tags = frozenset([(b'refs/tags/commit-tag', src_hash),
404 (b'refs/tags/tree-tag', tree_hash),
405 (b'refs/tags/blob-tag', blob_hash)])
406 WVPASSEQ(frozenset(git.list_refs()), expected_tags)
407 WVPASSEQ(frozenset(git.list_refs(limit_to_heads=True)), frozenset([]))
408 WVPASSEQ(frozenset(git.list_refs(limit_to_tags=True)), expected_tags)
412 def test__git_date_str():
413 with no_lingering_errors():
414 WVPASSEQ(b'0 +0000', git._git_date_str(0, 0))
415 WVPASSEQ(b'0 -0130', git._git_date_str(0, -90 * 60))
416 WVPASSEQ(b'0 +0130', git._git_date_str(0, 90 * 60))
421 with no_lingering_errors():
422 with test_tempdir(b'bup-tgit-') as tmpdir:
423 environ[b'BUP_DIR'] = bupdir = tmpdir + b'/bup'
424 src = tmpdir + b'/src'
426 with open(src + b'/1', 'wb+') as f:
427 f.write(b'something\n')
428 with open(src + b'/2', 'wb+') as f:
429 f.write(b'something else\n')
430 git.init_repo(bupdir)
431 exc(bup_exe, b'index', src)
432 oidx = exo(bup_exe, b'save', b'-cn', b'src', b'--strip',
434 typ = exo(b'git', b'--git-dir', bupdir,
435 b'cat-file', b'-t', b'src').strip()
436 size = int(exo(b'git', b'--git-dir', bupdir,
437 b'cat-file', b'-s', b'src'))
438 it = git.cp().get(b'src')
442 WVPASSEQ((oidx, typ, size), get_info)