git.py 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. # -*- coding: utf-8 -*-
  2. import collections
  3. import tempfile
  4. import subprocess
  5. import re
  6. import tarfile
  7. GitRef = collections.namedtuple('VersionRef', [
  8. 'name',
  9. 'commit',
  10. 'source',
  11. 'is_remote',
  12. 'refname',
  13. ])
  14. def get_all_refs(gitroot):
  15. cmd = ("git", "for-each-ref", "--format", "%(objectname) %(refname)", "refs")
  16. output = subprocess.check_output(cmd, cwd=gitroot).decode()
  17. for line in output.splitlines():
  18. is_remote = False
  19. line = line.strip()
  20. # Parse refname
  21. matchobj = re.match(r"^(\w+) refs/(heads|tags|remotes/[^/]+)/(\S+)$", line)
  22. if not matchobj:
  23. continue
  24. commit = matchobj.group(1)
  25. source = matchobj.group(2)
  26. name = matchobj.group(3)
  27. refname = line.partition(' ')[2]
  28. if source.startswith('remotes/'):
  29. is_remote = True
  30. yield GitRef(name, commit, source, is_remote, refname)
  31. def get_refs(gitroot, tag_whitelist, branch_whitelist, remote_whitelist):
  32. for ref in get_all_refs(gitroot):
  33. if ref.source == 'tags':
  34. if tag_whitelist is None or not re.match(tag_whitelist, ref.name):
  35. continue
  36. elif ref.source == 'heads':
  37. if branch_whitelist is None or not re.match(branch_whitelist, ref.name):
  38. continue
  39. elif ref.is_remote and remote_whitelist is not None:
  40. remote_name = ref.source.partition('/')[2]
  41. if not re.match(remote_whitelist, remote_name):
  42. continue
  43. if branch_whitelist is None or not re.match(branch_whitelist, ref.name):
  44. continue
  45. else:
  46. continue
  47. yield ref
  48. def copy_tree(src, dst, reference, sourcepath='.'):
  49. with tempfile.SpooledTemporaryFile() as fp:
  50. cmd = ("git", "archive", "--format", "tar", reference.commit, "--", sourcepath)
  51. subprocess.check_call(cmd, stdout=fp)
  52. fp.seek(0)
  53. with tarfile.TarFile(fileobj=fp) as tarfp:
  54. tarfp.extractall(dst)