dart-sdk/tools/make_bundle.py
dgrove@google.com 6b6b28e065 Initial checkin.
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@18 260f80e4-7a28-3924-810f-c04153c831b5
2011-10-05 05:34:19 +00:00

229 lines
7.7 KiB
Python
Executable file

#!/usr/bin/env python
#
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
#
"""Tool for automating creation of a Dart bundle."""
import optparse
import os
from os import path
import shutil
import subprocess
import sys
import utils
class BundleMaker(object):
"""Main class for building a Dart bundle."""
def __init__(self, top_dir=None, dest=None, verbose=False, skip_build=False):
self._top_dir = top_dir
self._dest = dest
self._verbose = verbose
self._skip_build = skip_build
self._os = utils.GuessOS()
self._release_build_root = utils.GetBuildRoot(self._os, mode='release',
arch='ia32')
self._debug_build_root = utils.GetBuildRoot(self._os, mode='debug',
arch='ia32')
self._dartc_build_root = utils.GetBuildRoot(self._os, mode='release',
arch='dartc')
@staticmethod
def BuildOptions():
"""Make an option parser with the options supported by this tool.
Returns:
A newly created OptionParser.
"""
op = optparse.OptionParser('usage: %prog [options]')
op.add_option('-d', '--dest')
op.add_option('-v', '--verbose', default=False, action='store_true')
op.add_option('--skip-build', default=False, action='store_true')
return op
@staticmethod
def CheckOptions(op, top_dir, cmd_line_args):
"""Check the command line arguments.
Args:
op: An OptionParser (see BuildOptions).
top_dir: The top-level source directory.
cmd_line_args: The command line arguments.
Returns:
A dict with the analyzed options and other values. The dict
includes these keys:
dest: The destition directory for storing the bundle.
verbose: Whether the tool should be verbose.
top_dir: Same as top_dir argument.
skip_build: Whether the tool should skip the build steps.
"""
(options, args) = op.parse_args(args=cmd_line_args)
if args:
# Terminate program.
op.error('extra arguments on command line')
dest = options.dest
if not dest:
dest = path.normpath(path.join(top_dir, 'new_bundle'))
print 'Bundle is saved to %r' % dest
if not path.exists(dest):
os.makedirs(dest)
elif not path.isdir(dest):
# Terminate program.
op.error('%s: is not a directory' % dest)
return {
'dest': dest,
'verbose': options.verbose,
'top_dir': top_dir,
'skip_build': options.skip_build,
}
def _PrintConfiguration(self):
for member in [m for m in dir(self) if not m.startswith('_')]:
value = getattr(self, member)
if not callable(value):
print '%s = %r' % (member, value)
def _GetTool(self, name):
return self._GetLocation('tools', name)
def _GetLocation(self, *arguments):
location = path.join(self._top_dir, *arguments)
if not path.exists(location):
raise utils.Error('%s: does not exist' % location)
return location
def _InvokeTool(self, project, name, *arguments):
location = self._GetLocation(project)
tool = path.relpath(self._GetTool(name), location)
command_array = [tool]
for argument in arguments:
command_array.append(str(argument))
stdout = subprocess.PIPE
if self._verbose:
print 'Invoking', ' '.join(command_array)
print 'in', location
stdout = None # In verbose mode we want to see the output from the tool.
proc = subprocess.Popen(command_array,
cwd=location,
stdout=stdout,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
exit_code = proc.wait()
if exit_code != 0:
sys.stderr.write(stdout)
raise utils.Error('%s returned %s' % (name, exit_code))
elif self._verbose:
print name, 'returned', exit_code
def _GetReleaseOutput(self, project, name):
return self._GetLocation(project, self._release_build_root, name)
def _GetDebugOutput(self, project, name):
return self._GetLocation(project, self._debug_build_root, name)
def _GetDartcOutput(self, project, name):
return self._GetLocation(project, self._dartc_build_root, name)
def _GetNativeDest(self, mode, name):
return path.join('native', self._os, utils.GetBuildConf(mode, 'ia32'), name)
def _EnsureExists(self, artifact):
if not path.exists(artifact):
raise utils.Error('%s: does not exist' % artifact)
def _BuildArtifacts(self):
if not self._skip_build:
self._InvokeTool('runtime', 'build.py', '--arch=ia32',
'--mode=release,debug')
self._InvokeTool('compiler', 'build.py', '--arch=dartc', '--mode=release')
self._InvokeTool('language', 'build.py', '--arch=ia32', '--mode=release')
release_vm = self._GetReleaseOutput('runtime', 'dart_bin')
self._EnsureExists(release_vm)
release_vm_dest = self._GetNativeDest('release', 'dart_bin')
debug_vm = self._GetDebugOutput('runtime', 'dart_bin')
self._EnsureExists(debug_vm)
debug_vm_dest = self._GetNativeDest('debug', 'dart_bin')
dartc_bundle = self._GetDartcOutput('compiler', 'compiler')
self._EnsureExists(dartc_bundle)
return (
(self._GetLocation('bundle', 'bin', 'dart'), 'dart', False),
(release_vm, release_vm_dest, True),
(debug_vm, debug_vm_dest, True),
(dartc_bundle, 'compiler', False),
(self._GetLocation('bundle', 'samples'), 'samples', False),
(self._GetLocation('bundle', 'README'), 'README.txt', False),
(self._GetReleaseOutput('language', 'guide'), 'guide', False),
)
def _CopyCorelib(self):
def ReadSources(sources, *paths):
p = path.join(*paths)
return [self._GetLocation(p, s) for s in sources if s.endswith('.dart')]
gypi = self._GetLocation('corelib', 'src', 'corelib_sources.gypi')
sources = []
with open(gypi, 'r') as f:
text = f.read()
sources.extend(ReadSources(eval(text)['sources'], 'corelib', 'src'))
gypi = self._GetLocation('runtime', 'lib', 'lib_sources.gypi')
with open(gypi, 'r') as f:
text = f.read()
sources.extend(ReadSources(eval(text)['sources'], 'runtime', 'lib'))
dest = path.join(self._dest, 'lib', 'core')
if not path.exists(dest):
os.makedirs(dest)
for source in sources:
if self._verbose:
print 'Copying', source, 'to', dest
shutil.copy2(source, dest)
def MakeBundle(self):
"""Build and install all the components of a bundle.
Returns:
0 if the bundle was created successfully.
"""
if self._verbose:
self._PrintConfiguration()
for artifact, reldest, strip in self._BuildArtifacts():
dest = path.join(self._dest, reldest)
if not path.exists(path.dirname(dest)):
os.makedirs(path.dirname(dest))
if self._verbose:
print 'Copying', artifact, 'to', dest
if path.isdir(artifact):
assert not strip
if path.exists(dest):
shutil.rmtree(dest)
shutil.copytree(artifact, dest)
else:
if strip:
os.system('strip -o %s %s' % (dest, artifact))
else:
shutil.copy2(artifact, dest)
self._CopyCorelib()
os.system('chmod -R a+rX %s' % self._dest)
return 0
def main():
top_dir = path.normpath(path.join(path.dirname(sys.argv[0]), os.pardir))
cmd_line_args = sys.argv[1:]
try:
op = BundleMaker.BuildOptions()
options = BundleMaker.CheckOptions(op, top_dir, cmd_line_args)
except utils.Error:
return 1
sys.exit(BundleMaker(**options).MakeBundle())
if __name__ == '__main__':
main()