UpdateBuildVersions.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. ## @file
  2. # Update build revisions of the tools when performing a developer build
  3. #
  4. # This script will modife the C/Include/Common/BuildVersion.h file and the two
  5. # Python scripts, Python/Common/BuildVersion.py and Python/UPT/BuildVersion.py.
  6. # If SVN is available, the tool will obtain the current checked out version of
  7. # the source tree for including the --version commands.
  8. # Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
  9. #
  10. # SPDX-License-Identifier: BSD-2-Clause-Patent
  11. ##
  12. """ This program will update the BuildVersion.py and BuildVersion.h files used to set a tool's version value """
  13. from __future__ import absolute_import
  14. import os
  15. import shlex
  16. import subprocess
  17. import sys
  18. from argparse import ArgumentParser, SUPPRESS
  19. from tempfile import NamedTemporaryFile
  20. from types import IntType, ListType
  21. SYS_ENV_ERR = "ERROR : %s system environment variable must be set prior to running this tool.\n"
  22. __execname__ = "UpdateBuildVersions.py"
  23. SVN_REVISION = "$LastChangedRevision: 3 $"
  24. SVN_REVISION = SVN_REVISION.replace("$LastChangedRevision:", "").replace("$", "").strip()
  25. __copyright__ = "Copyright (c) 2014, Intel Corporation. All rights reserved."
  26. VERSION_NUMBER = "0.7.0"
  27. __version__ = "Version %s.%s" % (VERSION_NUMBER, SVN_REVISION)
  28. def ParseOptions():
  29. """
  30. Parse the command-line options.
  31. The options for this tool will be passed along to the MkBinPkg tool.
  32. """
  33. parser = ArgumentParser(
  34. usage=("%s [options]" % __execname__),
  35. description=__copyright__,
  36. conflict_handler='resolve')
  37. # Standard Tool Options
  38. parser.add_argument("--version", action="version",
  39. version=__execname__ + " " + __version__)
  40. parser.add_argument("-s", "--silent", action="store_true",
  41. dest="silent",
  42. help="All output will be disabled, pass/fail determined by the exit code")
  43. parser.add_argument("-v", "--verbose", action="store_true",
  44. dest="verbose",
  45. help="Enable verbose output")
  46. # Tool specific options
  47. parser.add_argument("--revert", action="store_true",
  48. dest="REVERT", default=False,
  49. help="Revert the BuildVersion files only")
  50. parser.add_argument("--svn-test", action="store_true",
  51. dest="TEST_SVN", default=False,
  52. help="Test if the svn command is available")
  53. parser.add_argument("--svnFlag", action="store_true",
  54. dest="HAVE_SVN", default=False,
  55. help=SUPPRESS)
  56. return(parser.parse_args())
  57. def ShellCommandResults(CmdLine, Opt):
  58. """ Execute the command, returning the output content """
  59. file_list = NamedTemporaryFile(delete=False)
  60. filename = file_list.name
  61. Results = []
  62. returnValue = 0
  63. try:
  64. subprocess.check_call(args=shlex.split(CmdLine), stderr=subprocess.STDOUT, stdout=file_list)
  65. except subprocess.CalledProcessError as err_val:
  66. file_list.close()
  67. if not Opt.silent:
  68. sys.stderr.write("ERROR : %d : %s\n" % (err_val.returncode, err_val.__str__()))
  69. if os.path.exists(filename):
  70. sys.stderr.write(" : Partial results may be in this file: %s\n" % filename)
  71. sys.stderr.flush()
  72. returnValue = err_val.returncode
  73. except IOError as err_val:
  74. (errno, strerror) = err_val.args
  75. file_list.close()
  76. if not Opt.silent:
  77. sys.stderr.write("I/O ERROR : %s : %s\n" % (str(errno), strerror))
  78. sys.stderr.write("ERROR : this command failed : %s\n" % CmdLine)
  79. if os.path.exists(filename):
  80. sys.stderr.write(" : Partial results may be in this file: %s\n" % filename)
  81. sys.stderr.flush()
  82. returnValue = errno
  83. except OSError as err_val:
  84. (errno, strerror) = err_val.args
  85. file_list.close()
  86. if not Opt.silent:
  87. sys.stderr.write("OS ERROR : %s : %s\n" % (str(errno), strerror))
  88. sys.stderr.write("ERROR : this command failed : %s\n" % CmdLine)
  89. if os.path.exists(filename):
  90. sys.stderr.write(" : Partial results may be in this file: %s\n" % filename)
  91. sys.stderr.flush()
  92. returnValue = errno
  93. except KeyboardInterrupt:
  94. file_list.close()
  95. if not Opt.silent:
  96. sys.stderr.write("ERROR : Command terminated by user : %s\n" % CmdLine)
  97. if os.path.exists(filename):
  98. sys.stderr.write(" : Partial results may be in this file: %s\n" % filename)
  99. sys.stderr.flush()
  100. returnValue = 1
  101. finally:
  102. if not file_list.closed:
  103. file_list.flush()
  104. os.fsync(file_list.fileno())
  105. file_list.close()
  106. if os.path.exists(filename):
  107. fd_ = open(filename, 'r')
  108. Results = fd_.readlines()
  109. fd_.close()
  110. os.unlink(filename)
  111. if returnValue > 0:
  112. return returnValue
  113. return Results
  114. def UpdateBuildVersionPython(Rev, UserModified, opts):
  115. """ This routine will update the BuildVersion.h files in the C source tree """
  116. for SubDir in ["Common", "UPT"]:
  117. PyPath = os.path.join(os.environ['BASE_TOOLS_PATH'], "Source", "Python", SubDir)
  118. BuildVersionPy = os.path.join(PyPath, "BuildVersion.py")
  119. fd_ = open(os.path.normpath(BuildVersionPy), 'r')
  120. contents = fd_.readlines()
  121. fd_.close()
  122. if opts.HAVE_SVN is False:
  123. BuildVersionOrig = os.path.join(PyPath, "orig_BuildVersion.py")
  124. fd_ = open (BuildVersionOrig, 'w')
  125. for line in contents:
  126. fd_.write(line)
  127. fd_.flush()
  128. fd_.close()
  129. new_content = []
  130. for line in contents:
  131. if line.strip().startswith("gBUILD_VERSION"):
  132. new_line = "gBUILD_VERSION = \"Developer Build based on Revision: %s\"" % Rev
  133. if UserModified:
  134. new_line = "gBUILD_VERSION = \"Developer Build based on Revision: %s with Modified Sources\"" % Rev
  135. new_content.append(new_line)
  136. continue
  137. new_content.append(line)
  138. fd_ = open(os.path.normpath(BuildVersionPy), 'w')
  139. for line in new_content:
  140. fd_.write(line)
  141. fd_.close()
  142. def UpdateBuildVersionH(Rev, UserModified, opts):
  143. """ This routine will update the BuildVersion.h files in the C source tree """
  144. CPath = os.path.join(os.environ['BASE_TOOLS_PATH'], "Source", "C", "Include", "Common")
  145. BuildVersionH = os.path.join(CPath, "BuildVersion.h")
  146. fd_ = open(os.path.normpath(BuildVersionH), 'r')
  147. contents = fd_.readlines()
  148. fd_.close()
  149. if opts.HAVE_SVN is False:
  150. BuildVersionOrig = os.path.join(CPath, "orig_BuildVersion.h")
  151. fd_ = open(BuildVersionOrig, 'w')
  152. for line in contents:
  153. fd_.write(line)
  154. fd_.flush()
  155. fd_.close()
  156. new_content = []
  157. for line in contents:
  158. if line.strip().startswith("#define"):
  159. new_line = "#define __BUILD_VERSION \"Developer Build based on Revision: %s\"" % Rev
  160. if UserModified:
  161. new_line = "#define __BUILD_VERSION \"Developer Build based on Revision: %s with Modified Sources\"" % \
  162. Rev
  163. new_content.append(new_line)
  164. continue
  165. new_content.append(line)
  166. fd_ = open(os.path.normpath(BuildVersionH), 'w')
  167. for line in new_content:
  168. fd_.write(line)
  169. fd_.close()
  170. def RevertCmd(Filename, Opt):
  171. """ This is the shell command that does the SVN revert """
  172. CmdLine = "svn revert %s" % Filename.replace("\\", "/").strip()
  173. try:
  174. subprocess.check_output(args=shlex.split(CmdLine))
  175. except subprocess.CalledProcessError as err_val:
  176. if not Opt.silent:
  177. sys.stderr.write("Subprocess ERROR : %s\n" % err_val)
  178. sys.stderr.flush()
  179. except IOError as err_val:
  180. (errno, strerror) = err_val.args
  181. if not Opt.silent:
  182. sys.stderr.write("I/O ERROR : %d : %s\n" % (str(errno), strerror))
  183. sys.stderr.write("ERROR : this command failed : %s\n" % CmdLine)
  184. sys.stderr.flush()
  185. except OSError as err_val:
  186. (errno, strerror) = err_val.args
  187. if not Opt.silent:
  188. sys.stderr.write("OS ERROR : %d : %s\n" % (str(errno), strerror))
  189. sys.stderr.write("ERROR : this command failed : %s\n" % CmdLine)
  190. sys.stderr.flush()
  191. except KeyboardInterrupt:
  192. if not Opt.silent:
  193. sys.stderr.write("ERROR : Command terminated by user : %s\n" % CmdLine)
  194. sys.stderr.flush()
  195. if Opt.verbose:
  196. sys.stdout.write("Reverted this file: %s\n" % Filename)
  197. sys.stdout.flush()
  198. def GetSvnRevision(opts):
  199. """ Get the current revision of the BaseTools/Source tree, and check if any of the files have been modified """
  200. Revision = "Unknown"
  201. Modified = False
  202. if opts.HAVE_SVN is False:
  203. sys.stderr.write("WARNING: the svn command-line tool is not available.\n")
  204. return (Revision, Modified)
  205. SrcPath = os.path.join(os.environ['BASE_TOOLS_PATH'], "Source")
  206. # Check if there are modified files.
  207. Cwd = os.getcwd()
  208. os.chdir(SrcPath)
  209. StatusCmd = "svn st -v --depth infinity --non-interactive"
  210. contents = ShellCommandResults(StatusCmd, opts)
  211. os.chdir(Cwd)
  212. if isinstance(contents, ListType):
  213. for line in contents:
  214. if line.startswith("M "):
  215. Modified = True
  216. break
  217. # Get the repository revision of BaseTools/Source
  218. InfoCmd = "svn info %s" % SrcPath.replace("\\", "/").strip()
  219. Revision = 0
  220. contents = ShellCommandResults(InfoCmd, opts)
  221. if isinstance(contents, IntType):
  222. return 0, Modified
  223. for line in contents:
  224. line = line.strip()
  225. if line.startswith("Revision:"):
  226. Revision = line.replace("Revision:", "").strip()
  227. break
  228. return (Revision, Modified)
  229. def CheckSvn(opts):
  230. """
  231. This routine will return True if an svn --version command succeeds, or False if it fails.
  232. If it failed, SVN is not available.
  233. """
  234. OriginalSilent = opts.silent
  235. opts.silent = True
  236. VerCmd = "svn --version"
  237. contents = ShellCommandResults(VerCmd, opts)
  238. opts.silent = OriginalSilent
  239. if isinstance(contents, IntType):
  240. if opts.verbose:
  241. sys.stdout.write("SVN does not appear to be available.\n")
  242. sys.stdout.flush()
  243. return False
  244. if opts.verbose:
  245. sys.stdout.write("Found %s" % contents[0])
  246. sys.stdout.flush()
  247. return True
  248. def CopyOrig(Src, Dest, Opt):
  249. """ Overwrite the Dest File with the Src File content """
  250. try:
  251. fd_ = open(Src, 'r')
  252. contents = fd_.readlines()
  253. fd_.close()
  254. fd_ = open(Dest, 'w')
  255. for line in contents:
  256. fd_.write(line)
  257. fd_.flush()
  258. fd_.close()
  259. except IOError:
  260. if not Opt.silent:
  261. sys.stderr.write("Unable to restore this file: %s\n" % Dest)
  262. sys.stderr.flush()
  263. return 1
  264. os.remove(Src)
  265. if Opt.verbose:
  266. sys.stdout.write("Restored this file: %s\n" % Src)
  267. sys.stdout.flush()
  268. return 0
  269. def CheckOriginals(Opts):
  270. """
  271. If SVN was not available, then the tools may have made copies of the original BuildVersion.* files using
  272. orig_BuildVersion.* for the name. If they exist, replace the existing BuildVersion.* file with the corresponding
  273. orig_BuildVersion.* file.
  274. Returns 0 if this succeeds, or 1 if the copy function fails. It will also return 0 if the orig_BuildVersion.* file
  275. does not exist.
  276. """
  277. CPath = os.path.join(os.environ['BASE_TOOLS_PATH'], "Source", "C", "Include", "Common")
  278. BuildVersionH = os.path.join(CPath, "BuildVersion.h")
  279. OrigBuildVersionH = os.path.join(CPath, "orig_BuildVersion.h")
  280. if not os.path.exists(OrigBuildVersionH):
  281. return 0
  282. if CopyOrig(OrigBuildVersionH, BuildVersionH, Opts):
  283. return 1
  284. for SubDir in ["Common", "UPT"]:
  285. PyPath = os.path.join(os.environ['BASE_TOOLS_PATH'], "Source", "Python", SubDir)
  286. BuildVersionPy = os.path.join(PyPath, "BuildVersion.h")
  287. OrigBuildVersionPy = os.path.join(PyPath, "orig_BuildVersion.h")
  288. if not os.path.exists(OrigBuildVersionPy):
  289. return 0
  290. if CopyOrig(OrigBuildVersionPy, BuildVersionPy, Opts):
  291. return 1
  292. return 0
  293. def RevertBuildVersionFiles(opts):
  294. """
  295. This routine will attempt to perform an SVN --revert on each of the BuildVersion.* files
  296. """
  297. if not opts.HAVE_SVN:
  298. if CheckOriginals(opts):
  299. return 1
  300. return 0
  301. # SVN is available
  302. BuildVersionH = os.path.join(os.environ['BASE_TOOLS_PATH'], "Source", "C", "Include", "Common", "BuildVersion.h")
  303. RevertCmd(BuildVersionH, opts)
  304. for SubDir in ["Common", "UPT"]:
  305. BuildVersionPy = os.path.join(os.environ['BASE_TOOLS_PATH'], "Source", "Python", SubDir, "BuildVersion.py")
  306. RevertCmd(BuildVersionPy, opts)
  307. def UpdateRevisionFiles():
  308. """ Main routine that will update the BuildVersion.py and BuildVersion.h files."""
  309. options = ParseOptions()
  310. # Check the working environment
  311. if "WORKSPACE" not in os.environ.keys():
  312. sys.stderr.write(SYS_ENV_ERR % 'WORKSPACE')
  313. return 1
  314. if 'BASE_TOOLS_PATH' not in os.environ.keys():
  315. sys.stderr.write(SYS_ENV_ERR % 'BASE_TOOLS_PATH')
  316. return 1
  317. if not os.path.exists(os.environ['BASE_TOOLS_PATH']):
  318. sys.stderr.write("Unable to locate the %s directory." % os.environ['BASE_TOOLS_PATH'])
  319. return 1
  320. options.HAVE_SVN = CheckSvn(options)
  321. if options.TEST_SVN:
  322. return (not options.HAVE_SVN)
  323. # done processing the option, now use the option.HAVE_SVN as a flag. True = Have it, False = Don't have it.
  324. if options.REVERT:
  325. # Just revert the tools an exit
  326. RevertBuildVersionFiles(options)
  327. else:
  328. # Revert any changes in the BuildVersion.* files before setting them again.
  329. RevertBuildVersionFiles(options)
  330. Revision, Modified = GetSvnRevision(options)
  331. if options.verbose:
  332. sys.stdout.write("Revision: %s is Modified: %s\n" % (Revision, Modified))
  333. sys.stdout.flush()
  334. UpdateBuildVersionH(Revision, Modified, options)
  335. UpdateBuildVersionPython(Revision, Modified, options)
  336. return 0
  337. if __name__ == "__main__":
  338. sys.exit(UpdateRevisionFiles())