text: #!/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/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:]))
  