buildrelease.py 7.4 KB

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