## @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.<BR> | |
# | |
# 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()) | |