Home | History | Annotate | Download | only in build_tools
      1 #!/usr/bin/env python
      2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 """Build script to generate a new sdk_tools bundle.
      7 
      8 This script packages the files necessary to generate the SDK updater -- the
      9 tool users run to download new bundles, update existing bundles, etc.
     10 """
     11 
     12 import buildbot_common
     13 import build_version
     14 import glob
     15 import optparse
     16 import os
     17 import sys
     18 
     19 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
     20 SDK_SRC_DIR = os.path.dirname(SCRIPT_DIR)
     21 SDK_DIR = os.path.dirname(SDK_SRC_DIR)
     22 SRC_DIR = os.path.dirname(SDK_DIR)
     23 NACL_DIR = os.path.join(SRC_DIR, 'native_client')
     24 CYGTAR = os.path.join(NACL_DIR, 'build', 'cygtar.py')
     25 
     26 sys.path.append(os.path.join(SDK_SRC_DIR, 'tools'))
     27 
     28 import oshelpers
     29 
     30 
     31 UPDATER_FILES = [
     32   # launch scripts
     33   ('build_tools/naclsdk', 'nacl_sdk/naclsdk'),
     34   ('build_tools/naclsdk.bat', 'nacl_sdk/naclsdk.bat'),
     35 
     36   # base manifest
     37   ('build_tools/json/naclsdk_manifest0.json',
     38       'nacl_sdk/sdk_cache/naclsdk_manifest2.json'),
     39 
     40   # SDK tools
     41   ('build_tools/sdk_tools/cacerts.txt', 'nacl_sdk/sdk_tools/cacerts.txt'),
     42   ('build_tools/sdk_tools/*.py', 'nacl_sdk/sdk_tools/'),
     43   ('build_tools/sdk_tools/command/*.py', 'nacl_sdk/sdk_tools/command/'),
     44   ('build_tools/sdk_tools/third_party/*.py', 'nacl_sdk/sdk_tools/third_party/'),
     45   ('build_tools/sdk_tools/third_party/fancy_urllib/*.py',
     46       'nacl_sdk/sdk_tools/third_party/fancy_urllib/'),
     47   ('build_tools/sdk_tools/third_party/fancy_urllib/README',
     48       'nacl_sdk/sdk_tools/third_party/fancy_urllib/README'),
     49   ('build_tools/manifest_util.py', 'nacl_sdk/sdk_tools/manifest_util.py'),
     50   ('LICENSE', 'nacl_sdk/sdk_tools/LICENSE'),
     51   (CYGTAR, 'nacl_sdk/sdk_tools/cygtar.py'),
     52 ]
     53 
     54 
     55 def MakeUpdaterFilesAbsolute(out_dir):
     56   """Return the result of changing all relative paths in UPDATER_FILES to
     57   absolute paths.
     58 
     59   Args:
     60     out_dir: The output directory.
     61   Returns:
     62     A list of 2-tuples. The first element in each tuple is the source path and
     63     the second is the destination path.
     64   """
     65   assert os.path.isabs(out_dir)
     66 
     67   result = []
     68   for in_file, out_file in UPDATER_FILES:
     69     if not os.path.isabs(in_file):
     70       in_file = os.path.join(SDK_SRC_DIR, in_file)
     71     out_file = os.path.join(out_dir, out_file)
     72     result.append((in_file, out_file))
     73   return result
     74 
     75 
     76 def GlobFiles(files):
     77   """Expand wildcards for 2-tuples of sources/destinations.
     78 
     79   This function also will convert destinations from directories into filenames.
     80   For example:
     81     ('foo/*.py', 'bar/') => [('foo/a.py', 'bar/a.py'), ('foo/b.py', 'bar/b.py')]
     82 
     83   Args:
     84     files: A list of 2-tuples of (source, dest) paths.
     85   Returns:
     86     A new list of 2-tuples, after the sources have been wildcard-expanded, and
     87     the destinations have been changed from directories to filenames.
     88   """
     89   result = []
     90   for in_file_glob, out_file in files:
     91     if out_file.endswith('/'):
     92       for in_file in glob.glob(in_file_glob):
     93         result.append((in_file,
     94                       os.path.join(out_file, os.path.basename(in_file))))
     95     else:
     96       result.append((in_file_glob, out_file))
     97   return result
     98 
     99 
    100 def CopyFiles(files):
    101   """Given a list of 2-tuples (source, dest), copy each source file to a dest
    102   file.
    103 
    104   Args:
    105     files: A list of 2-tuples."""
    106   for in_file, out_file in files:
    107     buildbot_common.MakeDir(os.path.dirname(out_file))
    108     buildbot_common.CopyFile(in_file, out_file)
    109 
    110 
    111 def UpdateRevisionNumber(out_dir, revision_number):
    112   """Update the sdk_tools bundle to have the given revision number.
    113 
    114   This function finds all occurrences of the string "{REVISION}" in
    115   sdk_update_main.py and replaces them with |revision_number|. The only
    116   observable effect of this change should be that running:
    117 
    118     naclsdk -v
    119 
    120   will contain the new |revision_number|.
    121 
    122   Args:
    123     out_dir: The output directory containing the scripts to update.
    124     revision_number: The revision number as an integer, or None to use the
    125         current Chrome revision (as retrieved through svn/git).
    126   """
    127   if revision_number is None:
    128     revision_number = build_version.ChromeRevision()
    129 
    130   SDK_UPDATE_MAIN = os.path.join(out_dir,
    131       'nacl_sdk/sdk_tools/sdk_update_main.py')
    132 
    133   contents = open(SDK_UPDATE_MAIN, 'r').read().replace(
    134       '{REVISION}', str(revision_number))
    135   open(SDK_UPDATE_MAIN, 'w').write(contents)
    136 
    137 
    138 def BuildUpdater(out_dir, revision_number=None):
    139   """Build naclsdk.zip and sdk_tools.tgz in |out_dir|.
    140 
    141   Args:
    142     out_dir: The output directory.
    143     revision_number: The revision number of this updater, as an integer. Or
    144         None, to use the current Chrome revision."""
    145   buildbot_common.BuildStep('Create Updater')
    146 
    147   out_dir = os.path.abspath(out_dir)
    148 
    149   # Build SDK directory
    150   buildbot_common.RemoveDir(os.path.join(out_dir, 'nacl_sdk'))
    151 
    152   updater_files = MakeUpdaterFilesAbsolute(out_dir)
    153   updater_files = GlobFiles(updater_files)
    154 
    155   CopyFiles(updater_files)
    156   UpdateRevisionNumber(out_dir, revision_number)
    157 
    158   out_files = [os.path.relpath(out_file, out_dir)
    159                for _, out_file in updater_files]
    160 
    161   # Make zip
    162   buildbot_common.RemoveFile(os.path.join(out_dir, 'nacl_sdk.zip'))
    163   buildbot_common.Run([sys.executable, oshelpers.__file__, 'zip',
    164                       'nacl_sdk.zip'] + out_files,
    165                       cwd=out_dir)
    166 
    167   # Tar of all files under nacl_sdk/sdk_tools
    168   sdktoolsdir = os.path.join('nacl_sdk', 'sdk_tools')
    169   tarname = os.path.join(out_dir, 'sdk_tools.tgz')
    170   files_to_tar = [os.path.relpath(out_file, sdktoolsdir)
    171       for out_file in out_files if out_file.startswith(sdktoolsdir)]
    172   buildbot_common.RemoveFile(tarname)
    173   buildbot_common.Run([sys.executable, CYGTAR, '-C',
    174       os.path.join(out_dir, sdktoolsdir), '-czf', tarname] + files_to_tar)
    175   sys.stdout.write('\n')
    176 
    177 
    178 def main(args):
    179   parser = optparse.OptionParser()
    180   parser.add_option('-o', '--out', help='output directory',
    181       dest='out_dir', default=os.path.join(SRC_DIR, 'out'))
    182   parser.add_option('-r', '--revision', help='revision number of this updater',
    183       dest='revision', default=None)
    184   options, args = parser.parse_args(args[1:])
    185 
    186   if options.revision:
    187     options.revision = int(options.revision)
    188   BuildUpdater(options.out_dir, options.revision)
    189 
    190 
    191 if __name__ == '__main__':
    192   sys.exit(main(sys.argv))
    193