| #!/usr/bin/env python | 
 | # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
 | # Use of this source code is governed by a BSD-style license that can be | 
 | # found in the LICENSE file. | 
 |  | 
 | import argparse | 
 | import json | 
 | import os | 
 | import re | 
 | import sys | 
 |  | 
 | if sys.version_info < (2, 7, 0): | 
 |   sys.stderr.write("python 2.7 or later is required run this script\n") | 
 |   sys.exit(1) | 
 |  | 
 | import buildbot_common | 
 | import build_projects | 
 | import build_version | 
 | import easy_template | 
 | import parse_dsc | 
 |  | 
 | from build_paths import SDK_SRC_DIR, OUT_DIR, SDK_RESOURCE_DIR | 
 |  | 
 | sys.path.append(os.path.join(SDK_SRC_DIR, 'tools')) | 
 | import getos | 
 | import oshelpers | 
 |  | 
 |  | 
 | def RemoveBuildCruft(outdir): | 
 |   for root, _, files in os.walk(outdir): | 
 |     for f in files: | 
 |       path = os.path.join(root, f) | 
 |       ext = os.path.splitext(path)[1] | 
 |       # Remove unwanted files from the package. Also remove manifest.json files | 
 |       # (which we usually want). These ones are the manifests of the invidual | 
 |       # examples, though, which CWS complains about. The master manifest.json | 
 |       # is generated after we call RemoveBuildCruft. | 
 |       if (ext in ('.d', '.o') or | 
 |           f == 'dir.stamp' or | 
 |           f == 'manifest.json' or | 
 |           re.search(r'_unstripped_.*?\.nexe', f)): | 
 |         buildbot_common.RemoveFile(path) | 
 |  | 
 |  | 
 | def StripNexes(outdir, platform, pepperdir): | 
 |   for root, _, files in os.walk(outdir): | 
 |     for f in files: | 
 |       path = os.path.join(root, f) | 
 |       m = re.search(r'lib(32|64).*\.so', path) | 
 |       arch = None | 
 |       if m: | 
 |         # System .so file. Must be x86, because ARM doesn't support glibc yet. | 
 |         arch = 'x86_' + m.group(1) | 
 |       else: | 
 |         basename, ext = os.path.splitext(f) | 
 |         if ext in ('.nexe', '.so'): | 
 |           # We can get the arch from the filename... | 
 |           valid_arches = ('x86_64', 'x86_32', 'arm') | 
 |           for a in valid_arches: | 
 |             if basename.endswith(a): | 
 |               arch = a | 
 |               break | 
 |       if not arch: | 
 |         continue | 
 |  | 
 |       strip = GetStrip(pepperdir, platform, arch, 'newlib') | 
 |       buildbot_common.Run([strip, path]) | 
 |  | 
 |  | 
 | def GetStrip(pepperdir, platform, arch, toolchain): | 
 |   base_arch = {'x86_32': 'x86', 'x86_64': 'x86', 'arm': 'arm'}[arch] | 
 |   bin_dir = os.path.join(pepperdir, 'toolchain', | 
 |                          '%s_%s_%s' % (platform, base_arch, toolchain), 'bin') | 
 |   strip_prefix = {'x86_32': 'i686', 'x86_64': 'x86_64', 'arm': 'arm'}[arch] | 
 |   strip_name = '%s-nacl-strip' % strip_prefix | 
 |   return os.path.join(bin_dir, strip_name) | 
 |  | 
 |  | 
 | def main(args): | 
 |   parser = argparse.ArgumentParser() | 
 |   parser.add_argument('-c', '--channel', | 
 |       help='Channel to display in the name of the package.') | 
 |  | 
 |   # To setup bash completion for this command first install optcomplete | 
 |   # and then add this line to your .bashrc: | 
 |   #  complete -F _optcomplete build_app.py | 
 |   try: | 
 |     import optcomplete | 
 |     optcomplete.autocomplete(parser) | 
 |   except ImportError: | 
 |     pass | 
 |  | 
 |   options = parser.parse_args(args) | 
 |  | 
 |   if options.channel: | 
 |     if options.channel not in ('Dev', 'Beta'): | 
 |       parser.error('Unknown channel: %s' % options.channel) | 
 |  | 
 |   toolchains = ['newlib', 'glibc'] | 
 |  | 
 |   pepper_ver = str(int(build_version.ChromeMajorVersion())) | 
 |   pepperdir = os.path.join(OUT_DIR, 'pepper_' + pepper_ver) | 
 |   app_dir = os.path.join(OUT_DIR, 'naclsdk_app') | 
 |   app_examples_dir = os.path.join(app_dir, 'examples') | 
 |   sdk_resources_dir = SDK_RESOURCE_DIR | 
 |   platform = getos.GetPlatform() | 
 |  | 
 |   buildbot_common.RemoveDir(app_dir) | 
 |   buildbot_common.MakeDir(app_dir) | 
 |  | 
 |   # Add some dummy directories so build_projects doesn't complain... | 
 |   buildbot_common.MakeDir(os.path.join(app_dir, 'tools')) | 
 |   buildbot_common.MakeDir(os.path.join(app_dir, 'toolchain')) | 
 |  | 
 |   config = 'Release' | 
 |  | 
 |   filters = {} | 
 |   filters['DISABLE_PACKAGE'] = False | 
 |   filters['EXPERIMENTAL'] = False | 
 |   filters['TOOLS'] = toolchains | 
 |   filters['DEST'] = ['examples/api', 'examples/benchmarks', | 
 |                      'examples/getting_started', 'examples/demo', | 
 |                      'examples/tutorial'] | 
 |   tree = parse_dsc.LoadProjectTree(SDK_SRC_DIR, include=filters) | 
 |   build_projects.UpdateHelpers(app_dir, clobber=True) | 
 |   build_projects.UpdateProjects(app_dir, tree, clobber=False, | 
 |                                 toolchains=toolchains, configs=[config], | 
 |                                 first_toolchain=True) | 
 |  | 
 |   # Collect permissions from each example, and aggregate them. | 
 |   def MergeLists(list1, list2): | 
 |     return list1 + [x for x in list2 if x not in list1] | 
 |   all_permissions = [] | 
 |   all_socket_permissions = [] | 
 |   all_filesystem_permissions = [] | 
 |   for _, project in parse_dsc.GenerateProjects(tree): | 
 |     permissions = project.get('PERMISSIONS', []) | 
 |     all_permissions = MergeLists(all_permissions, permissions) | 
 |     socket_permissions = project.get('SOCKET_PERMISSIONS', []) | 
 |     all_socket_permissions = MergeLists(all_socket_permissions, | 
 |                                         socket_permissions) | 
 |     filesystem_permissions = project.get('FILESYSTEM_PERMISSIONS', []) | 
 |     all_filesystem_permissions = MergeLists(all_filesystem_permissions, | 
 |                                             filesystem_permissions) | 
 |   if all_socket_permissions: | 
 |     all_permissions.append({'socket': all_socket_permissions}) | 
 |   if all_filesystem_permissions: | 
 |     all_permissions.append({'fileSystem': all_filesystem_permissions}) | 
 |   pretty_permissions = json.dumps(all_permissions, sort_keys=True, indent=4) | 
 |  | 
 |   for filename in ['background.js', 'icon128.png']: | 
 |     buildbot_common.CopyFile(os.path.join(sdk_resources_dir, filename), | 
 |                              os.path.join(app_examples_dir, filename)) | 
 |  | 
 |   os.environ['NACL_SDK_ROOT'] = pepperdir | 
 |  | 
 |   build_projects.BuildProjects(app_dir, tree, deps=False, clean=False, | 
 |                                config=config) | 
 |  | 
 |   RemoveBuildCruft(app_dir) | 
 |   StripNexes(app_dir, platform, pepperdir) | 
 |  | 
 |   # Add manifest.json after RemoveBuildCruft... that function removes the | 
 |   # manifest.json files for the individual examples. | 
 |   name = 'Native Client SDK' | 
 |   if options.channel: | 
 |     name += ' (%s)' % options.channel | 
 |   template_dict = { | 
 |     'name': name, | 
 |     'channel': options.channel, | 
 |     'description': | 
 |         'Native Client SDK examples, showing API use and key concepts.', | 
 |     'key': False,  # manifests with "key" are rejected when uploading to CWS. | 
 |     'permissions': pretty_permissions, | 
 |     'version': build_version.ChromeVersionNoTrunk() | 
 |   } | 
 |   easy_template.RunTemplateFile( | 
 |       os.path.join(sdk_resources_dir, 'manifest.json.template'), | 
 |       os.path.join(app_examples_dir, 'manifest.json'), | 
 |       template_dict) | 
 |  | 
 |   app_zip = os.path.join(app_dir, 'examples.zip') | 
 |   os.chdir(app_examples_dir) | 
 |   oshelpers.Zip([app_zip, '-r', '*']) | 
 |  | 
 |   return 0 | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |   sys.exit(main(sys.argv[1:])) |