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