## @file # Update build revisions of the tools when performing a developer build # # This script will modife the C/Include/Common/BuildVersion.h file and the two # Python scripts, Python/Common/BuildVersion.py and Python/UPT/BuildVersion.py. # If SVN is available, the tool will obtain the current checked out version of # the source tree for including the --version commands. # Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent ## """ This program will update the BuildVersion.py and BuildVersion.h files used to set a tool's version value """ from __future__ import absolute_import import os import shlex import subprocess import sys from argparse import ArgumentParser, SUPPRESS from tempfile import NamedTemporaryFile from types import IntType, ListType SYS_ENV_ERR = "ERROR : %s system environment variable must be set prior to running this tool.\n" __execname__ = "UpdateBuildVersions.py" SVN_REVISION = "$LastChangedRevision: 3 $" SVN_REVISION = SVN_REVISION.replace("$LastChangedRevision:", "").replace("$", "").strip() __copyright__ = "Copyright (c) 2014, Intel Corporation. All rights reserved." VERSION_NUMBER = "0.7.0" __version__ = "Version %s.%s" % (VERSION_NUMBER, SVN_REVISION) def ParseOptions(): """ Parse the command-line options. The options for this tool will be passed along to the MkBinPkg tool. """ parser = ArgumentParser( usage=("%s [options]" % __execname__), description=__copyright__, conflict_handler='resolve') # Standard Tool Options parser.add_argument("--version", action="version", version=__execname__ + " " + __version__) parser.add_argument("-s", "--silent", action="store_true", dest="silent", help="All output will be disabled, pass/fail determined by the exit code") parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", help="Enable verbose output") # Tool specific options parser.add_argument("--revert", action="store_true", dest="REVERT", default=False, help="Revert the BuildVersion files only") parser.add_argument("--svn-test", action="store_true", dest="TEST_SVN", default=False, help="Test if the svn command is available") parser.add_argument("--svnFlag", action="store_true", dest="HAVE_SVN", default=False, help=SUPPRESS) return(parser.parse_args()) def ShellCommandResults(CmdLine, Opt): """ Execute the command, returning the output content """ file_list = NamedTemporaryFile(delete=False) filename = file_list.name Results = [] returnValue = 0 try: subprocess.check_call(args=shlex.split(CmdLine), stderr=subprocess.STDOUT, stdout=file_list) except subprocess.CalledProcessError as err_val: file_list.close() if not Opt.silent: sys.stderr.write("ERROR : %d : %s\n" % (err_val.returncode, err_val.__str__())) if os.path.exists(filename): sys.stderr.write(" : Partial results may be in this file: %s\n" % filename) sys.stderr.flush() returnValue = err_val.returncode except IOError as err_val: (errno, strerror) = err_val.args file_list.close() if not Opt.silent: sys.stderr.write("I/O ERROR : %s : %s\n" % (str(errno), strerror)) sys.stderr.write("ERROR : this command failed : %s\n" % CmdLine) if os.path.exists(filename): sys.stderr.write(" : Partial results may be in this file: %s\n" % filename) sys.stderr.flush() returnValue = errno except OSError as err_val: (errno, strerror) = err_val.args file_list.close() if not Opt.silent: sys.stderr.write("OS ERROR : %s : %s\n" % (str(errno), strerror)) sys.stderr.write("ERROR : this command failed : %s\n" % CmdLine) if os.path.exists(filename): sys.stderr.write(" : Partial results may be in this file: %s\n" % filename) sys.stderr.flush() returnValue = errno except KeyboardInterrupt: file_list.close() if not Opt.silent: sys.stderr.write("ERROR : Command terminated by user : %s\n" % CmdLine) if os.path.exists(filename): sys.stderr.write(" : Partial results may be in this file: %s\n" % filename) sys.stderr.flush() returnValue = 1 finally: if not file_list.closed: file_list.flush() os.fsync(file_list.fileno()) file_list.close() if os.path.exists(filename): fd_ = open(filename, 'r') Results = fd_.readlines() fd_.close() os.unlink(filename) if returnValue > 0: return returnValue return Results def UpdateBuildVersionPython(Rev, UserModified, opts): """ This routine will update the BuildVersion.h files in the C source tree """ for SubDir in ["Common", "UPT"]: PyPath = os.path.join(os.environ['BASE_TOOLS_PATH'], "Source", "Python", SubDir) BuildVersionPy = os.path.join(PyPath, "BuildVersion.py") fd_ = open(os.path.normpath(BuildVersionPy), 'r') contents = fd_.readlines() fd_.close() if opts.HAVE_SVN is False: BuildVersionOrig = os.path.join(PyPath, "orig_BuildVersion.py") fd_ = open (BuildVersionOrig, 'w') for line in contents: fd_.write(line) fd_.flush() fd_.close() new_content = [] for line in contents: if line.strip().startswith("gBUILD_VERSION"): new_line = "gBUILD_VERSION = \"Developer Build based on Revision: %s\"" % Rev if UserModified: new_line = "gBUILD_VERSION = \"Developer Build based on Revision: %s with Modified Sources\"" % Rev new_content.append(new_line) continue new_content.append(line) fd_ = open(os.path.normpath(BuildVersionPy), 'w') for line in new_content: fd_.write(line) fd_.close() def UpdateBuildVersionH(Rev, UserModified, opts): """ This routine will update the BuildVersion.h files in the C source tree """ CPath = os.path.join(os.environ['BASE_TOOLS_PATH'], "Source", "C", "Include", "Common") BuildVersionH = os.path.join(CPath, "BuildVersion.h") fd_ = open(os.path.normpath(BuildVersionH), 'r') contents = fd_.readlines() fd_.close() if opts.HAVE_SVN is False: BuildVersionOrig = os.path.join(CPath, "orig_BuildVersion.h") fd_ = open(BuildVersionOrig, 'w') for line in contents: fd_.write(line) fd_.flush() fd_.close() new_content = [] for line in contents: if line.strip().startswith("#define"): new_line = "#define __BUILD_VERSION \"Developer Build based on Revision: %s\"" % Rev if UserModified: new_line = "#define __BUILD_VERSION \"Developer Build based on Revision: %s with Modified Sources\"" % \ Rev new_content.append(new_line) continue new_content.append(line) fd_ = open(os.path.normpath(BuildVersionH), 'w') for line in new_content: fd_.write(line) fd_.close() def RevertCmd(Filename, Opt): """ This is the shell command that does the SVN revert """ CmdLine = "svn revert %s" % Filename.replace("\\", "/").strip() try: subprocess.check_output(args=shlex.split(CmdLine)) except subprocess.CalledProcessError as err_val: if not Opt.silent: sys.stderr.write("Subprocess ERROR : %s\n" % err_val) sys.stderr.flush() except IOError as err_val: (errno, strerror) = err_val.args if not Opt.silent: sys.stderr.write("I/O ERROR : %d : %s\n" % (str(errno), strerror)) sys.stderr.write("ERROR : this command failed : %s\n" % CmdLine) sys.stderr.flush() except OSError as err_val: (errno, strerror) = err_val.args if not Opt.silent: sys.stderr.write("OS ERROR : %d : %s\n" % (str(errno), strerror)) sys.stderr.write("ERROR : this command failed : %s\n" % CmdLine) sys.stderr.flush() except KeyboardInterrupt: if not Opt.silent: sys.stderr.write("ERROR : Command terminated by user : %s\n" % CmdLine) sys.stderr.flush() if Opt.verbose: sys.stdout.write("Reverted this file: %s\n" % Filename) sys.stdout.flush() def GetSvnRevision(opts): """ Get the current revision of the BaseTools/Source tree, and check if any of the files have been modified """ Revision = "Unknown" Modified = False if opts.HAVE_SVN is False: sys.stderr.write("WARNING: the svn command-line tool is not available.\n") return (Revision, Modified) SrcPath = os.path.join(os.environ['BASE_TOOLS_PATH'], "Source") # Check if there are modified files. Cwd = os.getcwd() os.chdir(SrcPath) StatusCmd = "svn st -v --depth infinity --non-interactive" contents = ShellCommandResults(StatusCmd, opts) os.chdir(Cwd) if isinstance(contents, ListType): for line in contents: if line.startswith("M "): Modified = True break # Get the repository revision of BaseTools/Source InfoCmd = "svn info %s" % SrcPath.replace("\\", "/").strip() Revision = 0 contents = ShellCommandResults(InfoCmd, opts) if isinstance(contents, IntType): return 0, Modified for line in contents: line = line.strip() if line.startswith("Revision:"): Revision = line.replace("Revision:", "").strip() break return (Revision, Modified) def CheckSvn(opts): """ This routine will return True if an svn --version command succeeds, or False if it fails. If it failed, SVN is not available. """ OriginalSilent = opts.silent opts.silent = True VerCmd = "svn --version" contents = ShellCommandResults(VerCmd, opts) opts.silent = OriginalSilent if isinstance(contents, IntType): if opts.verbose: sys.stdout.write("SVN does not appear to be available.\n") sys.stdout.flush() return False if opts.verbose: sys.stdout.write("Found %s" % contents[0]) sys.stdout.flush() return True def CopyOrig(Src, Dest, Opt): """ Overwrite the Dest File with the Src File content """ try: fd_ = open(Src, 'r') contents = fd_.readlines() fd_.close() fd_ = open(Dest, 'w') for line in contents: fd_.write(line) fd_.flush() fd_.close() except IOError: if not Opt.silent: sys.stderr.write("Unable to restore this file: %s\n" % Dest) sys.stderr.flush() return 1 os.remove(Src) if Opt.verbose: sys.stdout.write("Restored this file: %s\n" % Src) sys.stdout.flush() return 0 def CheckOriginals(Opts): """ If SVN was not available, then the tools may have made copies of the original BuildVersion.* files using orig_BuildVersion.* for the name. If they exist, replace the existing BuildVersion.* file with the corresponding orig_BuildVersion.* file. Returns 0 if this succeeds, or 1 if the copy function fails. It will also return 0 if the orig_BuildVersion.* file does not exist. """ CPath = os.path.join(os.environ['BASE_TOOLS_PATH'], "Source", "C", "Include", "Common") BuildVersionH = os.path.join(CPath, "BuildVersion.h") OrigBuildVersionH = os.path.join(CPath, "orig_BuildVersion.h") if not os.path.exists(OrigBuildVersionH): return 0 if CopyOrig(OrigBuildVersionH, BuildVersionH, Opts): return 1 for SubDir in ["Common", "UPT"]: PyPath = os.path.join(os.environ['BASE_TOOLS_PATH'], "Source", "Python", SubDir) BuildVersionPy = os.path.join(PyPath, "BuildVersion.h") OrigBuildVersionPy = os.path.join(PyPath, "orig_BuildVersion.h") if not os.path.exists(OrigBuildVersionPy): return 0 if CopyOrig(OrigBuildVersionPy, BuildVersionPy, Opts): return 1 return 0 def RevertBuildVersionFiles(opts): """ This routine will attempt to perform an SVN --revert on each of the BuildVersion.* files """ if not opts.HAVE_SVN: if CheckOriginals(opts): return 1 return 0 # SVN is available BuildVersionH = os.path.join(os.environ['BASE_TOOLS_PATH'], "Source", "C", "Include", "Common", "BuildVersion.h") RevertCmd(BuildVersionH, opts) for SubDir in ["Common", "UPT"]: BuildVersionPy = os.path.join(os.environ['BASE_TOOLS_PATH'], "Source", "Python", SubDir, "BuildVersion.py") RevertCmd(BuildVersionPy, opts) def UpdateRevisionFiles(): """ Main routine that will update the BuildVersion.py and BuildVersion.h files.""" options = ParseOptions() # Check the working environment if "WORKSPACE" not in os.environ.keys(): sys.stderr.write(SYS_ENV_ERR % 'WORKSPACE') return 1 if 'BASE_TOOLS_PATH' not in os.environ.keys(): sys.stderr.write(SYS_ENV_ERR % 'BASE_TOOLS_PATH') return 1 if not os.path.exists(os.environ['BASE_TOOLS_PATH']): sys.stderr.write("Unable to locate the %s directory." % os.environ['BASE_TOOLS_PATH']) return 1 options.HAVE_SVN = CheckSvn(options) if options.TEST_SVN: return (not options.HAVE_SVN) # done processing the option, now use the option.HAVE_SVN as a flag. True = Have it, False = Don't have it. if options.REVERT: # Just revert the tools an exit RevertBuildVersionFiles(options) else: # Revert any changes in the BuildVersion.* files before setting them again. RevertBuildVersionFiles(options) Revision, Modified = GetSvnRevision(options) if options.verbose: sys.stdout.write("Revision: %s is Modified: %s\n" % (Revision, Modified)) sys.stdout.flush() UpdateBuildVersionH(Revision, Modified, options) UpdateBuildVersionPython(Revision, Modified, options) return 0 if __name__ == "__main__": sys.exit(UpdateRevisionFiles())