gitdist.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. #!/usr/bin/env python3
  2. # Creates a source distribution package.
  3. from os import makedirs, remove
  4. from os.path import isdir
  5. from subprocess import CalledProcessError, PIPE, Popen, check_output
  6. from tarfile import TarError, TarFile
  7. import stat, sys
  8. verbose = False
  9. def archiveFromGit(versionedPackageName, committish):
  10. prefix = '%s/' % versionedPackageName
  11. distBase = 'derived/dist/'
  12. umask = (
  13. stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR |
  14. stat.S_IRGRP | stat.S_IXGRP |
  15. stat.S_IROTH | stat.S_IXOTH
  16. )
  17. def exclude(info):
  18. '''Returns True iff the given tar entry should be excluded.
  19. '''
  20. return any((
  21. info.name.endswith('/.gitignore'),
  22. info.name.startswith(prefix + 'doc/internal'),
  23. info.name.startswith(prefix + '.'),
  24. info.name[info.name.rfind('/') + 1:].startswith('meson'),
  25. ))
  26. proc = Popen(
  27. ('git', 'archive', '--prefix=' + prefix, '--format=tar', committish),
  28. bufsize = -1,
  29. stdin = None, stdout = PIPE, stderr = sys.stderr,
  30. )
  31. try:
  32. outTarPath = distBase + versionedPackageName + '.tar.gz'
  33. print('archive:', outTarPath)
  34. if not isdir(distBase):
  35. makedirs(distBase)
  36. try:
  37. with TarFile.open(outTarPath, 'w:gz') as outTar:
  38. # Copy entries from "git archive" into output tarball,
  39. # except for excluded entries.
  40. numIncluded = numExcluded = 0
  41. with TarFile.open(mode='r|', fileobj=proc.stdout) as inTar:
  42. for info in inTar:
  43. if exclude(info):
  44. if verbose:
  45. print('EX', info.name)
  46. numExcluded += 1
  47. else:
  48. if verbose:
  49. print('IN', info.name)
  50. numIncluded += 1
  51. info.uid = info.gid = 1000
  52. info.uname = info.gname = 'openmsx'
  53. info.mode = info.mode & umask
  54. outTar.addfile(info, inTar.extractfile(info))
  55. print('entries: %d included, %d excluded' % (
  56. numIncluded, numExcluded))
  57. except:
  58. # Clean up partial output file.
  59. remove(outTarPath)
  60. raise
  61. except:
  62. proc.terminate()
  63. raise
  64. else:
  65. data, _ = proc.communicate()
  66. if len(data) != 0:
  67. print(
  68. 'WARNING: %d more bytes of data from "git archive" after '
  69. 'tar stream ended' % len(data),
  70. file=sys.stderr
  71. )
  72. def niceVersionFromGitDescription(description):
  73. '''Our release tag names are still based on naming limitations from CVS;
  74. convert them to something more pleasing to the eyes.
  75. '''
  76. parts = description.split('-')
  77. tag = parts[0]
  78. if tag.startswith('RELEASE_'):
  79. tagParts = tag.split('_')[1 : ]
  80. i = 0
  81. while i < len(tagParts) and tagParts[i].isdigit():
  82. i += 1
  83. version = '-'.join(
  84. ['.'.join(tagParts[ : i])] +
  85. [s.lower() for s in tagParts[i : ]]
  86. )
  87. else:
  88. version = tag
  89. if len(parts) >= 2:
  90. parts[1] = 'dev' + parts[1]
  91. return '-'.join([version] + parts[1 : ])
  92. def getDescription(committish):
  93. args = ['git', 'describe', '--abbrev=9']
  94. if committish is not None:
  95. args.append(committish)
  96. try:
  97. data = check_output(args)
  98. except CalledProcessError as ex:
  99. print(
  100. '"%s" returned %d' % (' '.join(args), ex.returncode),
  101. file=sys.stderr
  102. )
  103. raise
  104. else:
  105. return data.decode('utf-8', 'replace').rstrip('\n')
  106. def main(committish = None):
  107. try:
  108. description = getDescription(committish)
  109. except CalledProcessError:
  110. sys.exit(1)
  111. version = niceVersionFromGitDescription(description)
  112. try:
  113. archiveFromGit('openmsx-%s' % version, description)
  114. except (OSError, TarError) as ex:
  115. print('ERROR: %s' % ex, file=sys.stderr)
  116. sys.exit(1)
  117. if __name__ == '__main__':
  118. if len(sys.argv) == 1:
  119. main()
  120. elif len(sys.argv) == 2:
  121. main(sys.argv[1])
  122. else:
  123. print('Usage: gitdist.py [branch | tag]', file=sys.stderr)
  124. sys.exit(2)