git.py 2.2 KB

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