| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2012 The Native Client Authors. All rights reserved. | 2 # Copyright (c) 2012 The Native Client Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Build NativeClient toolchain packages.""" | 6 """Build NativeClient toolchain packages.""" |
| 7 | 7 |
| 8 import logging | 8 import logging |
| 9 import optparse | 9 import optparse |
| 10 import os | 10 import os |
| 11 import subprocess |
| 11 import sys | 12 import sys |
| 12 import textwrap | 13 import textwrap |
| 13 | 14 |
| 14 sys.path.append(os.path.join(os.path.dirname(__file__), '..')) | 15 sys.path.append(os.path.join(os.path.dirname(__file__), '..')) |
| 15 import pynacl.file_tools | 16 import pynacl.file_tools |
| 16 import pynacl.gsd_storage | 17 import pynacl.gsd_storage |
| 17 import pynacl.log_tools | 18 import pynacl.log_tools |
| 18 import pynacl.local_storage_cache | 19 import pynacl.local_storage_cache |
| 19 | 20 |
| 20 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) | 21 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
| (...skipping 22 matching lines...) Expand all Loading... |
| 43 """ | 44 """ |
| 44 if cloud_item.dir_item: | 45 if cloud_item.dir_item: |
| 45 url = cloud_item.dir_item.url | 46 url = cloud_item.dir_item.url |
| 46 pynacl.log_tools.WriteAnnotatorLine('@@@STEP_LINK@download@%s@@@' % url) | 47 pynacl.log_tools.WriteAnnotatorLine('@@@STEP_LINK@download@%s@@@' % url) |
| 47 | 48 |
| 48 if cloud_item.log_url: | 49 if cloud_item.log_url: |
| 49 log_url = cloud_item.log_url | 50 log_url = cloud_item.log_url |
| 50 pynacl.log_tools.WriteAnnotatorLine('@@@STEP_LINK@log@%s@@@' % log_url) | 51 pynacl.log_tools.WriteAnnotatorLine('@@@STEP_LINK@log@%s@@@' % log_url) |
| 51 | 52 |
| 52 | 53 |
| 54 class BuildError(Exception): |
| 55 pass |
| 56 |
| 53 class PackageBuilder(object): | 57 class PackageBuilder(object): |
| 54 """Module to build a setup of packages.""" | 58 """Module to build a setup of packages.""" |
| 55 | 59 |
| 56 def __init__(self, packages, package_targets, args): | 60 def __init__(self, packages, package_targets, args): |
| 57 """Constructor. | 61 """Constructor. |
| 58 | 62 |
| 59 Args: | 63 Args: |
| 60 packages: A dictionary with the following format. There are two types of | 64 packages: A dictionary with the following format. There are two types of |
| 61 packages: source and build (described below). | 65 packages: source and build (described below). |
| 62 { | 66 { |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 def Main(self): | 156 def Main(self): |
| 153 """Main entry point.""" | 157 """Main entry point.""" |
| 154 pynacl.file_tools.MakeDirectoryIfAbsent(self._options.source) | 158 pynacl.file_tools.MakeDirectoryIfAbsent(self._options.source) |
| 155 pynacl.file_tools.MakeDirectoryIfAbsent(self._options.output) | 159 pynacl.file_tools.MakeDirectoryIfAbsent(self._options.output) |
| 156 | 160 |
| 157 pynacl.log_tools.SetupLogging( | 161 pynacl.log_tools.SetupLogging( |
| 158 verbose=self._options.verbose, | 162 verbose=self._options.verbose, |
| 159 log_file=self._options.log_file, | 163 log_file=self._options.log_file, |
| 160 quiet=self._options.quiet, | 164 quiet=self._options.quiet, |
| 161 no_annotator=self._options.no_annotator) | 165 no_annotator=self._options.no_annotator) |
| 162 self.BuildAll() | 166 try: |
| 163 self.OutputPackagesInformation() | 167 self.BuildAll() |
| 168 self.OutputPackagesInformation() |
| 169 except BuildError as e: |
| 170 print e |
| 171 return 1 |
| 172 return 0 |
| 164 | 173 |
| 165 def GetOutputDir(self, package, use_subdir): | 174 def GetOutputDir(self, package, use_subdir): |
| 166 # The output dir of source packages is in the source directory, and can be | 175 # The output dir of source packages is in the source directory, and can be |
| 167 # overridden. | 176 # overridden. |
| 168 if self._packages[package]['type'] == 'source': | 177 if self._packages[package]['type'] == 'source': |
| 169 dirname = self._packages[package].get('output_dirname', package) | 178 dirname = self._packages[package].get('output_dirname', package) |
| 170 return os.path.join(self._options.source, dirname) | 179 return os.path.join(self._options.source, dirname) |
| 171 else: | 180 else: |
| 172 root = os.path.join(self._options.output, package + '_install') | 181 root = os.path.join(self._options.output, package + '_install') |
| 173 if use_subdir and 'output_subdir' in self._packages[package]: | 182 if use_subdir and 'output_subdir' in self._packages[package]: |
| 174 return os.path.join(root, self._packages[package]['output_subdir']) | 183 return os.path.join(root, self._packages[package]['output_subdir']) |
| 175 return root | 184 return root |
| 176 | 185 |
| 177 def BuildPackage(self, package): | 186 def BuildPackage(self, package): |
| 178 """Build a single package. | 187 """Build a single package. |
| 179 | 188 |
| 180 Assumes dependencies of the package have been built. | 189 Assumes dependencies of the package have been built. |
| 181 Args: | 190 Args: |
| 182 package: Package to build. | 191 package: Package to build. |
| 183 """ | 192 """ |
| 184 | 193 |
| 185 package_info = self._packages[package] | 194 package_info = self._packages[package] |
| 186 | 195 |
| 187 # Validate the package description. | 196 # Validate the package description. |
| 188 if 'type' not in package_info: | 197 if 'type' not in package_info: |
| 189 raise Exception('package %s does not have a type' % package) | 198 raise BuildError('package %s does not have a type' % package) |
| 190 type_text = package_info['type'] | 199 type_text = package_info['type'] |
| 191 if type_text not in ('source', 'build', 'build_noncanonical', 'work'): | 200 if type_text not in ('source', 'build', 'build_noncanonical', 'work'): |
| 192 raise Exception('package %s has unrecognized type: %s' % | 201 raise BuildError('package %s has unrecognized type: %s' % |
| 193 (package, type_text)) | 202 (package, type_text)) |
| 194 is_source_target = type_text == 'source' | 203 is_source_target = type_text == 'source' |
| 195 is_build_target = type_text in ('build', 'build_noncanonical') | 204 is_build_target = type_text in ('build', 'build_noncanonical') |
| 196 build_signature_key_extra = '' | 205 build_signature_key_extra = '' |
| 197 if type_text == 'build_noncanonical': | 206 if type_text == 'build_noncanonical': |
| 198 build_signature_key_extra = '_' + pynacl.gsd_storage.LegalizeName( | 207 build_signature_key_extra = '_' + pynacl.gsd_storage.LegalizeName( |
| 199 pynacl.platform.PlatformTriple()) | 208 pynacl.platform.PlatformTriple()) |
| 200 | 209 |
| 201 if 'commands' not in package_info: | 210 if 'commands' not in package_info: |
| 202 raise Exception('package %s does not have any commands' % package) | 211 raise BuildError('package %s does not have any commands' % package) |
| 203 | 212 |
| 204 # Source targets are the only ones to run when doing sync-only. | 213 # Source targets are the only ones to run when doing sync-only. |
| 205 if not is_source_target and self._options.sync_sources_only: | 214 if not is_source_target and self._options.sync_sources_only: |
| 206 logging.debug('Build skipped: not running commands for %s' % package) | 215 logging.debug('Build skipped: not running commands for %s' % package) |
| 207 return | 216 return |
| 208 | 217 |
| 209 # Source targets do not run when skipping sync. | 218 # Source targets do not run when skipping sync. |
| 210 if is_source_target and not ( | 219 if is_source_target and not ( |
| 211 self._options.sync_sources or self._options.sync_sources_only): | 220 self._options.sync_sources or self._options.sync_sources_only): |
| 212 logging.debug('Sync skipped: not running commands for %s' % package) | 221 logging.debug('Sync skipped: not running commands for %s' % package) |
| 213 return | 222 return |
| 214 | 223 |
| 215 if type_text == 'build_noncanonical' and self._options.canonical_only: | 224 if type_text == 'build_noncanonical' and self._options.canonical_only: |
| 216 logging.debug('Non-canonical build of %s skipped' % package) | 225 logging.debug('Non-canonical build of %s skipped' % package) |
| 217 return | 226 return |
| 218 | 227 |
| 219 pynacl.log_tools.WriteAnnotatorLine( | 228 pynacl.log_tools.WriteAnnotatorLine( |
| 220 '@@@BUILD_STEP %s (%s)@@@' % (package, type_text)) | 229 '@@@BUILD_STEP %s (%s)@@@' % (package, type_text)) |
| 221 logging.debug('Building %s package %s' % (type_text, package)) | 230 logging.debug('Building %s package %s' % (type_text, package)) |
| 222 | 231 |
| 223 dependencies = package_info.get('dependencies', []) | 232 dependencies = package_info.get('dependencies', []) |
| 224 | 233 |
| 225 # Collect a dict of all the inputs. | 234 # Collect a dict of all the inputs. |
| 226 inputs = {} | 235 inputs = {} |
| 227 # Add in explicit inputs. | 236 # Add in explicit inputs. |
| 228 if 'inputs' in package_info: | 237 if 'inputs' in package_info: |
| 229 for key, value in package_info['inputs'].iteritems(): | 238 for key, value in package_info['inputs'].iteritems(): |
| 230 if key in dependencies: | 239 if key in dependencies: |
| 231 raise Exception('key "%s" found in both dependencies and inputs of ' | 240 raise BuildError('key "%s" found in both dependencies and inputs of ' |
| 232 'package "%s"' % (key, package)) | 241 'package "%s"' % (key, package)) |
| 233 inputs[key] = value | 242 inputs[key] = value |
| 234 elif type_text != 'source': | 243 elif type_text != 'source': |
| 235 # Non-source packages default to a particular input directory. | 244 # Non-source packages default to a particular input directory. |
| 236 inputs['src'] = os.path.join(self._options.source, package) | 245 inputs['src'] = os.path.join(self._options.source, package) |
| 237 # Add in each dependency by package name. | 246 # Add in each dependency by package name. |
| 238 for dependency in dependencies: | 247 for dependency in dependencies: |
| 239 inputs[dependency] = self.GetOutputDir(dependency, True) | 248 inputs[dependency] = self.GetOutputDir(dependency, True) |
| 240 | 249 |
| 241 # Each package generates intermediate into output/<PACKAGE>_work. | 250 # Each package generates intermediate into output/<PACKAGE>_work. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 258 | 267 |
| 259 # Create a command option object specifying current build. | 268 # Create a command option object specifying current build. |
| 260 cmd_options = command_options.CommandOptions( | 269 cmd_options = command_options.CommandOptions( |
| 261 work_dir=work_dir, | 270 work_dir=work_dir, |
| 262 clobber_working=self._options.clobber, | 271 clobber_working=self._options.clobber, |
| 263 clobber_source=self._options.clobber_source, | 272 clobber_source=self._options.clobber_source, |
| 264 trybot=self._options.trybot, | 273 trybot=self._options.trybot, |
| 265 buildbot=self._options.buildbot) | 274 buildbot=self._options.buildbot) |
| 266 | 275 |
| 267 # Do it. | 276 # Do it. |
| 268 self._build_once.Run( | 277 try: |
| 278 self._build_once.Run( |
| 269 package, inputs, output, | 279 package, inputs, output, |
| 270 commands=commands, | 280 commands=commands, |
| 271 cmd_options=cmd_options, | 281 cmd_options=cmd_options, |
| 272 working_dir=work_dir, | 282 working_dir=work_dir, |
| 273 memoize=is_build_target, | 283 memoize=is_build_target, |
| 274 signature_file=self._signature_file, | 284 signature_file=self._signature_file, |
| 275 subdir=output_subdir, | 285 subdir=output_subdir, |
| 276 bskey_extra = build_signature_key_extra) | 286 bskey_extra = build_signature_key_extra) |
| 287 except subprocess.CalledProcessError as e: |
| 288 raise BuildError( |
| 289 'Error building %s: %s' % (package, str(e))) |
| 277 | 290 |
| 278 if not is_source_target and self._options.install: | 291 if not is_source_target and self._options.install: |
| 279 install = pynacl.platform.CygPath(self._options.install) | 292 install = pynacl.platform.CygPath(self._options.install) |
| 280 logging.debug('Installing output to %s' % install) | 293 logging.debug('Installing output to %s' % install) |
| 281 pynacl.file_tools.CopyTree(output, install) | 294 pynacl.file_tools.CopyTree(output, install) |
| 282 | 295 |
| 283 def BuildOrder(self, targets): | 296 def BuildOrder(self, targets): |
| 284 """Find what needs to be built in what order to build all targets. | 297 """Find what needs to be built in what order to build all targets. |
| 285 | 298 |
| 286 Args: | 299 Args: |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 """Returns a dictionary of extra substitution paths allowed for commands.""" | 530 """Returns a dictionary of extra substitution paths allowed for commands.""" |
| 518 if self._options.disable_git_cache: | 531 if self._options.disable_git_cache: |
| 519 git_cache_dir = '' | 532 git_cache_dir = '' |
| 520 else: | 533 else: |
| 521 git_cache_dir = self._options.git_cache | 534 git_cache_dir = self._options.git_cache |
| 522 | 535 |
| 523 return { | 536 return { |
| 524 'top_srcdir': NACL_DIR, | 537 'top_srcdir': NACL_DIR, |
| 525 'git_cache_dir': git_cache_dir, | 538 'git_cache_dir': git_cache_dir, |
| 526 } | 539 } |
| OLD | NEW |