buildrelease.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. #!/usr/bin/python -u
  2. '''
  3. ADOdb release build script
  4. - Create release tag if it does not exist
  5. - Copy release files to target directory
  6. - Generate zip/tar balls
  7. -
  8. '''
  9. import errno
  10. import getopt
  11. import re
  12. import os
  13. from os import path
  14. import shutil
  15. import subprocess
  16. import sys
  17. import tempfile
  18. import updateversion
  19. # ADOdb Repository reference
  20. origin_repo = "https://github.com/ADOdb/ADOdb.git"
  21. release_branch = "master"
  22. release_prefix = "adodb"
  23. # Directories and files to exclude from release tarballs
  24. exclude_list = (".git*",
  25. "replicate",
  26. "scripts",
  27. "tests",
  28. # There are no png files in there...
  29. # "cute_icons_for_site/*.png",
  30. "hs~*.*",
  31. "adodb-text.inc.php",
  32. # This file does not exist in current repo
  33. # 'adodb-lite.inc.php'
  34. )
  35. # Command-line options
  36. options = "hb:dfk"
  37. long_options = ["help", "branch", "debug", "fresh", "keep"]
  38. # Global flags
  39. debug_mode = False
  40. fresh_clone = False
  41. cleanup = True
  42. def usage():
  43. print '''Usage: %s [options] version release_path
  44. Parameters:
  45. version ADOdb version to bundle (e.g. v5.19)
  46. release_path Where to save the release tarballs
  47. Options:
  48. -h | --help Show this usage message
  49. -b | --branch <branch> Use specified branch (defaults to '%s' for '.0'
  50. releases, or 'hotfix/<version>' for patches)
  51. -d | --debug Debug mode (ignores upstream: no fetch, allows
  52. build even if local branch is not in sync)
  53. -f | --fresh Create a fresh clone of the repository
  54. -k | --keep Keep build directories after completion
  55. (useful for debugging)
  56. ''' % (
  57. path.basename(__file__),
  58. release_branch
  59. )
  60. #end usage()
  61. def set_version_and_tag(version):
  62. '''
  63. '''
  64. global release_branch, debug_mode, fresh_clone, cleanup
  65. # Delete existing tag to force creation in debug mode
  66. if debug_mode:
  67. try:
  68. updateversion.tag_delete(version)
  69. except:
  70. pass
  71. # Checkout release branch
  72. subprocess.call("git checkout %s" % release_branch, shell=True)
  73. if not debug_mode:
  74. # Make sure we're up-to-date, ignore untracked files
  75. ret = subprocess.check_output(
  76. "git status --branch --porcelain --untracked-files=no",
  77. shell=True
  78. )
  79. if not re.search(release_branch + "$", ret):
  80. print "\nERROR: branch must be aligned with upstream"
  81. sys.exit(4)
  82. # Update the code, create commit and tag
  83. updateversion.version_set(version)
  84. # Make sure we don't delete the modified repo
  85. if fresh_clone:
  86. cleanup = False
  87. def main():
  88. global release_branch, debug_mode, fresh_clone, cleanup
  89. # Get command-line options
  90. try:
  91. opts, args = getopt.gnu_getopt(sys.argv[1:], options, long_options)
  92. except getopt.GetoptError, err:
  93. print str(err)
  94. usage()
  95. sys.exit(2)
  96. if len(args) < 2:
  97. usage()
  98. print "ERROR: please specify the version and release_path"
  99. sys.exit(1)
  100. for opt, val in opts:
  101. if opt in ("-h", "--help"):
  102. usage()
  103. sys.exit(0)
  104. elif opt in ("-b", "--branch"):
  105. release_branch = val
  106. elif opt in ("-d", "--debug"):
  107. debug_mode = True
  108. elif opt in ("-f", "--fresh"):
  109. fresh_clone = True
  110. elif opt in ("-k", "--keep"):
  111. cleanup = False
  112. # Mandatory parameters
  113. version = updateversion.version_check(args[0])
  114. release_path = args[1]
  115. # Default release branch
  116. if updateversion.version_is_patch(version):
  117. release_branch = 'hotfix/' + version
  118. # -------------------------------------------------------------------------
  119. # Start the build
  120. #
  121. global release_prefix
  122. print "Building ADOdb release %s into '%s'\n" % (
  123. version,
  124. release_path
  125. )
  126. if debug_mode:
  127. print "DEBUG MODE: ignoring upstream repository status"
  128. if fresh_clone:
  129. # Create a new repo clone
  130. print "Cloning a new repository"
  131. repo_path = tempfile.mkdtemp(prefix=release_prefix + "-",
  132. suffix=".git")
  133. subprocess.call(
  134. "git clone %s %s" % (origin_repo, repo_path),
  135. shell=True
  136. )
  137. os.chdir(repo_path)
  138. else:
  139. repo_path = subprocess.check_output('git root', shell=True).rstrip()
  140. os.chdir(repo_path)
  141. # Check for any uncommitted changes
  142. try:
  143. subprocess.check_output(
  144. "git diff --exit-code && "
  145. "git diff --cached --exit-code",
  146. shell=True
  147. )
  148. except:
  149. print "ERROR: there are uncommitted changes in the repository"
  150. sys.exit(3)
  151. # Update the repository
  152. if not debug_mode:
  153. print "Updating repository in '%s'" % os.getcwd()
  154. try:
  155. subprocess.check_output("git fetch", shell=True)
  156. except:
  157. print "ERROR: unable to fetch\n"
  158. sys.exit(3)
  159. # Check existence of Tag for version in repo, create if not found
  160. try:
  161. updateversion.tag_check(version)
  162. if debug_mode:
  163. set_version_and_tag(version)
  164. except:
  165. set_version_and_tag(version)
  166. # Copy files to release dir
  167. release_files = release_prefix + version.split(".")[0]
  168. release_tmp_dir = path.join(release_path, release_files)
  169. print "Copying release files to '%s'" % release_tmp_dir
  170. retry = True
  171. while True:
  172. try:
  173. shutil.copytree(
  174. repo_path,
  175. release_tmp_dir,
  176. ignore=shutil.ignore_patterns(*exclude_list)
  177. )
  178. break
  179. except OSError, err:
  180. # First try and file exists, try to delete dir
  181. if retry and err.errno == errno.EEXIST:
  182. print "WARNING: Directory '%s' exists, delete it and retry" % (
  183. release_tmp_dir
  184. )
  185. shutil.rmtree(release_tmp_dir)
  186. retry = False
  187. continue
  188. else:
  189. # We already tried to delete or some other error occured
  190. raise
  191. # Create tarballs
  192. print "Creating release tarballs..."
  193. release_name = release_prefix + '-' + version
  194. print release_prefix, version, release_name
  195. os.chdir(release_path)
  196. print "- tar"
  197. subprocess.call(
  198. "tar -czf %s.tar.gz %s" % (release_name, release_files),
  199. shell=True
  200. )
  201. print "- zip"
  202. subprocess.call(
  203. "zip -rq %s.zip %s" % (release_name, release_files),
  204. shell=True
  205. )
  206. if cleanup:
  207. print "Deleting working directories"
  208. shutil.rmtree(release_tmp_dir)
  209. if fresh_clone:
  210. shutil.rmtree(repo_path)
  211. else:
  212. print "\nThe following working directories were kept:"
  213. if fresh_clone:
  214. print "- '%s' (repo clone)" % repo_path
  215. print "- '%s' (release temp dir)" % release_tmp_dir
  216. print "Delete them manually when they are no longer needed."
  217. # Done
  218. print "\nADOdb release %s build complete, files saved in '%s'." % (
  219. version,
  220. release_path
  221. )
  222. print "Don't forget to generate a README file with the changelog"
  223. #end main()
  224. if __name__ == "__main__":
  225. main()