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