Home | History | Annotate | Download | only in Scripts
      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