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 """ 20 from __future__ import absolute_import 21 22 import os 23 import shlex 24 import subprocess 25 import sys 26 27 from argparse import ArgumentParser, SUPPRESS 28 from tempfile import NamedTemporaryFile 29 from types import IntType, ListType 30 31 32 SYS_ENV_ERR = "ERROR : %s system environment variable must be set prior to running this tool.\n" 33 34 __execname__ = "UpdateBuildVersions.py" 35 SVN_REVISION = "$LastChangedRevision: 3 $" 36 SVN_REVISION = SVN_REVISION.replace("$LastChangedRevision:", "").replace("$", "").strip() 37 __copyright__ = "Copyright (c) 2014, Intel Corporation. All rights reserved." 38 VERSION_NUMBER = "0.7.0" 39 __version__ = "Version %s.%s" % (VERSION_NUMBER, SVN_REVISION) 40 41 42 def 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 75 def 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 140 def 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 171 def 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 203 def 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 235 def 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 273 def 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 295 def 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 320 def 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 347 def 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 362 def 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 397 if __name__ == "__main__": 398 sys.exit(UpdateRevisionFiles()) 399 400 401