| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/env python | |
| 2 # | |
| 3 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | |
| 4 # for details. All rights reserved. Use of this source code is governed by a | |
| 5 # BSD-style license that can be found in the LICENSE file. | |
| 6 # | |
| 7 | |
| 8 """Tool for automating creation of a Dart bundle.""" | |
| 9 | |
| 10 import optparse | |
| 11 import os | |
| 12 from os import path | |
| 13 import shutil | |
| 14 import subprocess | |
| 15 import sys | |
| 16 | |
| 17 import utils | |
| 18 | |
| 19 | |
| 20 class BundleMaker(object): | |
| 21 """Main class for building a Dart bundle.""" | |
| 22 | |
| 23 def __init__(self, top_dir=None, dest=None, verbose=False, skip_build=False): | |
| 24 self._top_dir = top_dir | |
| 25 self._dest = dest | |
| 26 self._verbose = verbose | |
| 27 self._skip_build = skip_build | |
| 28 self._os = utils.GuessOS() | |
| 29 self._release_build_root = utils.GetBuildRoot(self._os, mode='release', | |
| 30 arch='ia32') | |
| 31 self._debug_build_root = utils.GetBuildRoot(self._os, mode='debug', | |
| 32 arch='ia32') | |
| 33 self._dartc_build_root = utils.GetBuildRoot(self._os, mode='release', | |
| 34 arch='ia32') | |
| 35 | |
| 36 @staticmethod | |
| 37 def BuildOptions(): | |
| 38 """Make an option parser with the options supported by this tool. | |
| 39 | |
| 40 Returns: | |
| 41 A newly created OptionParser. | |
| 42 """ | |
| 43 op = optparse.OptionParser('usage: %prog [options]') | |
| 44 op.add_option('-d', '--dest') | |
| 45 op.add_option('-v', '--verbose', default=False, action='store_true') | |
| 46 op.add_option('--skip-build', default=False, action='store_true') | |
| 47 return op | |
| 48 | |
| 49 @staticmethod | |
| 50 def CheckOptions(op, top_dir, cmd_line_args): | |
| 51 """Check the command line arguments. | |
| 52 | |
| 53 Args: | |
| 54 op: An OptionParser (see BuildOptions). | |
| 55 top_dir: The top-level source directory. | |
| 56 cmd_line_args: The command line arguments. | |
| 57 | |
| 58 Returns: | |
| 59 A dict with the analyzed options and other values. The dict | |
| 60 includes these keys: | |
| 61 dest: The destition directory for storing the bundle. | |
| 62 verbose: Whether the tool should be verbose. | |
| 63 top_dir: Same as top_dir argument. | |
| 64 skip_build: Whether the tool should skip the build steps. | |
| 65 """ | |
| 66 (options, args) = op.parse_args(args=cmd_line_args) | |
| 67 if args: | |
| 68 # Terminate program. | |
| 69 op.error('extra arguments on command line') | |
| 70 dest = options.dest | |
| 71 if not dest: | |
| 72 dest = path.normpath(path.join(top_dir, 'new_bundle')) | |
| 73 print 'Bundle is saved to %r' % dest | |
| 74 if not path.exists(dest): | |
| 75 os.makedirs(dest) | |
| 76 elif not path.isdir(dest): | |
| 77 # Terminate program. | |
| 78 op.error('%s: is not a directory' % dest) | |
| 79 return { | |
| 80 'dest': dest, | |
| 81 'verbose': options.verbose, | |
| 82 'top_dir': top_dir, | |
| 83 'skip_build': options.skip_build, | |
| 84 } | |
| 85 | |
| 86 def _PrintConfiguration(self): | |
| 87 for member in [m for m in dir(self) if not m.startswith('_')]: | |
| 88 value = getattr(self, member) | |
| 89 if not callable(value): | |
| 90 print '%s = %r' % (member, value) | |
| 91 | |
| 92 def _GetTool(self, name): | |
| 93 return self._GetLocation('tools', name) | |
| 94 | |
| 95 def _GetLocation(self, *arguments): | |
| 96 location = path.join(self._top_dir, *arguments) | |
| 97 if not path.exists(location): | |
| 98 raise utils.Error('%s: does not exist' % location) | |
| 99 return location | |
| 100 | |
| 101 def _InvokeTool(self, project, name, *arguments): | |
| 102 location = self._GetLocation(project) | |
| 103 tool = path.relpath(self._GetTool(name), location) | |
| 104 command_array = [tool] | |
| 105 for argument in arguments: | |
| 106 command_array.append(str(argument)) | |
| 107 stdout = subprocess.PIPE | |
| 108 if self._verbose: | |
| 109 print 'Invoking', ' '.join(command_array) | |
| 110 print 'in', location | |
| 111 stdout = None # In verbose mode we want to see the output from the tool. | |
| 112 proc = subprocess.Popen(command_array, | |
| 113 cwd=location, | |
| 114 stdout=stdout, | |
| 115 stderr=subprocess.STDOUT) | |
| 116 stdout = proc.communicate()[0] | |
| 117 exit_code = proc.wait() | |
| 118 if exit_code != 0: | |
| 119 sys.stderr.write(stdout) | |
| 120 raise utils.Error('%s returned %s' % (name, exit_code)) | |
| 121 elif self._verbose: | |
| 122 print name, 'returned', exit_code | |
| 123 | |
| 124 def _GetReleaseOutput(self, project, name): | |
| 125 return self._GetLocation(project, self._release_build_root, name) | |
| 126 | |
| 127 def _GetDebugOutput(self, project, name): | |
| 128 return self._GetLocation(project, self._debug_build_root, name) | |
| 129 | |
| 130 def _GetDartcOutput(self, project, name): | |
| 131 return self._GetLocation(project, self._dartc_build_root, name) | |
| 132 | |
| 133 def _GetNativeDest(self, mode, name): | |
| 134 return path.join('native', self._os, utils.GetBuildConf(mode, 'ia32'), name) | |
| 135 | |
| 136 def _EnsureExists(self, artifact): | |
| 137 if not path.exists(artifact): | |
| 138 raise utils.Error('%s: does not exist' % artifact) | |
| 139 | |
| 140 def _BuildArtifacts(self): | |
| 141 if not self._skip_build: | |
| 142 self._InvokeTool('runtime', 'build.py', '--arch=ia32', | |
| 143 '--mode=release,debug') | |
| 144 self._InvokeTool('compiler', 'build.py', '--arch=ia32', '--mode=release') | |
| 145 self._InvokeTool('language', 'build.py', '--arch=ia32', '--mode=release') | |
| 146 | |
| 147 release_vm = self._GetReleaseOutput('runtime', 'dart_bin') | |
| 148 self._EnsureExists(release_vm) | |
| 149 release_vm_dest = self._GetNativeDest('release', 'dart_bin') | |
| 150 | |
| 151 debug_vm = self._GetDebugOutput('runtime', 'dart_bin') | |
| 152 self._EnsureExists(debug_vm) | |
| 153 debug_vm_dest = self._GetNativeDest('debug', 'dart_bin') | |
| 154 | |
| 155 dartc_bundle = self._GetDartcOutput('compiler', 'compiler') | |
| 156 self._EnsureExists(dartc_bundle) | |
| 157 return ( | |
| 158 (self._GetLocation('bundle', 'bin', 'dart'), 'dart', False), | |
| 159 (release_vm, release_vm_dest, True), | |
| 160 (debug_vm, debug_vm_dest, True), | |
| 161 (dartc_bundle, 'compiler', False), | |
| 162 (self._GetLocation('bundle', 'samples'), 'samples', False), | |
| 163 (self._GetLocation('bundle', 'README'), 'README.txt', False), | |
| 164 (self._GetReleaseOutput('language', 'guide'), 'guide', False), | |
| 165 ) | |
| 166 | |
| 167 def _CopyCorelib(self): | |
| 168 def ReadSources(sources, *paths): | |
| 169 p = path.join(*paths) | |
| 170 return [self._GetLocation(p, s) for s in sources if s.endswith('.dart')] | |
| 171 gypi = self._GetLocation('corelib', 'src', 'corelib_sources.gypi') | |
| 172 sources = [] | |
| 173 with open(gypi, 'r') as f: | |
| 174 text = f.read() | |
| 175 sources.extend(ReadSources(eval(text)['sources'], 'corelib', 'src')) | |
| 176 gypi = self._GetLocation('runtime', 'lib', 'lib_sources.gypi') | |
| 177 with open(gypi, 'r') as f: | |
| 178 text = f.read() | |
| 179 sources.extend(ReadSources(eval(text)['sources'], 'runtime', 'lib')) | |
| 180 dest = path.join(self._dest, 'lib', 'core') | |
| 181 if not path.exists(dest): | |
| 182 os.makedirs(dest) | |
| 183 for source in sources: | |
| 184 if self._verbose: | |
| 185 print 'Copying', source, 'to', dest | |
| 186 shutil.copy2(source, dest) | |
| 187 | |
| 188 def MakeBundle(self): | |
| 189 """Build and install all the components of a bundle. | |
| 190 | |
| 191 Returns: | |
| 192 0 if the bundle was created successfully. | |
| 193 """ | |
| 194 if self._verbose: | |
| 195 self._PrintConfiguration() | |
| 196 for artifact, reldest, strip in self._BuildArtifacts(): | |
| 197 dest = path.join(self._dest, reldest) | |
| 198 if not path.exists(path.dirname(dest)): | |
| 199 os.makedirs(path.dirname(dest)) | |
| 200 if self._verbose: | |
| 201 print 'Copying', artifact, 'to', dest | |
| 202 if path.isdir(artifact): | |
| 203 assert not strip | |
| 204 if path.exists(dest): | |
| 205 shutil.rmtree(dest) | |
| 206 shutil.copytree(artifact, dest) | |
| 207 else: | |
| 208 if strip: | |
| 209 os.system('strip -o %s %s' % (dest, artifact)) | |
| 210 else: | |
| 211 shutil.copy2(artifact, dest) | |
| 212 self._CopyCorelib() | |
| 213 os.system('chmod -R a+rX %s' % self._dest) | |
| 214 return 0 | |
| 215 | |
| 216 | |
| 217 def main(): | |
| 218 top_dir = path.normpath(path.join(path.dirname(sys.argv[0]), os.pardir)) | |
| 219 cmd_line_args = sys.argv[1:] | |
| 220 try: | |
| 221 op = BundleMaker.BuildOptions() | |
| 222 options = BundleMaker.CheckOptions(op, top_dir, cmd_line_args) | |
| 223 except utils.Error: | |
| 224 return 1 | |
| 225 sys.exit(BundleMaker(**options).MakeBundle()) | |
| 226 | |
| 227 | |
| 228 if __name__ == '__main__': | |
| 229 main() | |
| OLD | NEW |