15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import fnmatch
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import imp
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import logging
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import modulefinder
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import optparse
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import os
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import sys
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import zipfile
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from telemetry import test
1523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)from telemetry.core import command_line
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from telemetry.core import discover
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from telemetry.core import util
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from telemetry.page import cloud_storage
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)from telemetry.util import bootstrap
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)from telemetry.util import path_set
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DEPS_FILE = 'bootstrap_deps'
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def _InDirectory(subdirectory, directory):
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  subdirectory = os.path.realpath(subdirectory)
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  directory = os.path.realpath(directory)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  common_prefix = os.path.commonprefix([subdirectory, directory])
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return common_prefix == directory
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def FindBootstrapDependencies(base_dir):
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  deps_file = os.path.join(base_dir, DEPS_FILE)
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if not os.path.exists(deps_file):
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return []
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  deps_paths = bootstrap.ListAllDepsPaths(deps_file)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return set(
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      os.path.realpath(os.path.join(util.GetChromiumSrcDir(), os.pardir, path))
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      for path in deps_paths)
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def FindPythonDependencies(module_path):
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  logging.info('Finding Python dependencies of %s' % module_path)
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Load the module to inherit its sys.path modifications.
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  imp.load_source(
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      os.path.splitext(os.path.basename(module_path))[0], module_path)
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Analyze the module for its imports.
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  finder = modulefinder.ModuleFinder()
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  finder.run_script(module_path)
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Filter for only imports in Chromium.
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for module in finder.modules.itervalues():
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # If it's an __init__.py, module.__path__ gives the package's folder.
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    module_path = module.__path__[0] if module.__path__ else module.__file__
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not module_path:
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    module_path = os.path.realpath(module_path)
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not _InDirectory(module_path, util.GetChromiumSrcDir()):
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    yield module_path
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def FindPageSetDependencies(base_dir):
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  logging.info('Finding page sets in %s' % base_dir)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Add base_dir to path so our imports relative to base_dir will work.
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sys.path.append(base_dir)
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  tests = discover.DiscoverClasses(base_dir, base_dir, test.Test,
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   index_by_class_name=True)
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for test_class in tests.itervalues():
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    test_obj = test_class()
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Ensure the test's default options are set if needed.
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parser = optparse.OptionParser()
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    test_obj.AddCommandLineArgs(parser)
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    options = optparse.Values()
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for k, v in parser.get_default_values().__dict__.iteritems():
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      options.ensure_value(k, v)
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Page set paths are relative to their runner script, not relative to us.
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    util.GetBaseDir = lambda: base_dir
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # TODO: Loading the page set will automatically download its Cloud Storage
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # deps. This is really expensive, and we don't want to do this by default.
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    page_set = test_obj.CreatePageSet(options)
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Add all of its serving_dirs as dependencies.
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for serving_dir in page_set.serving_dirs:
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      yield serving_dir
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for page in page_set:
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if page.is_file:
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        yield page.serving_dir
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def FindExcludedFiles(files, options):
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def MatchesConditions(path, conditions):
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for condition in conditions:
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if condition(path):
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return True
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return False
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Define some filters for files.
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def IsHidden(path):
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for pathname_component in path.split(os.sep):
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if pathname_component.startswith('.'):
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return True
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return False
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def IsPyc(path):
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return os.path.splitext(path)[1] == '.pyc'
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def IsInCloudStorage(path):
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return os.path.exists(path + '.sha1')
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def MatchesExcludeOptions(path):
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for pattern in options.exclude:
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (fnmatch.fnmatch(path, pattern) or
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          fnmatch.fnmatch(os.path.basename(path), pattern)):
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return True
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return False
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Collect filters we're going to use to exclude files.
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  exclude_conditions = [
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      IsHidden,
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      IsPyc,
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      IsInCloudStorage,
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      MatchesExcludeOptions,
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ]
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Check all the files against the filters.
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for path in files:
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if MatchesConditions(path, exclude_conditions):
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      yield path
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def FindDependencies(paths, options):
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Verify arguments.
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for path in paths:
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not os.path.exists(path):
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      raise ValueError('Path does not exist: %s' % path)
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  dependencies = path_set.PathSet()
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  # Including __init__.py will include Telemetry and its dependencies.
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # If the user doesn't pass any arguments, we just have Telemetry.
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  dependencies |= FindPythonDependencies(os.path.realpath(
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    os.path.join(util.GetTelemetryDir(), 'telemetry', '__init__.py')))
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  dependencies |= FindBootstrapDependencies(util.GetTelemetryDir())
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Add dependencies.
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for path in paths:
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base_dir = os.path.dirname(os.path.realpath(path))
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    dependencies.add(base_dir)
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    dependencies |= FindBootstrapDependencies(base_dir)
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    dependencies |= FindPythonDependencies(path)
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if options.include_page_set_data:
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      dependencies |= FindPageSetDependencies(base_dir)
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  # Remove excluded files.
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  dependencies -= FindExcludedFiles(set(dependencies), options)
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return dependencies
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def ZipDependencies(paths, dependencies, options):
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base_dir = os.path.dirname(os.path.realpath(util.GetChromiumSrcDir()))
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  with zipfile.ZipFile(options.zip, 'w', zipfile.ZIP_DEFLATED) as zip_file:
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Add dependencies to archive.
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for path in dependencies:
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      path_in_archive = os.path.join(
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'telemetry', os.path.relpath(path, base_dir))
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      zip_file.write(path, path_in_archive)
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Add symlinks to executable paths, for ease of use.
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for path in paths:
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      link_info = zipfile.ZipInfo(
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          os.path.join('telemetry', os.path.basename(path)))
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      link_info.create_system = 3  # Unix attributes.
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      # 010 is regular file, 0111 is the permission bits rwxrwxrwx.
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      link_info.external_attr = 0100777 << 16  # Octal.
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      relative_path = os.path.relpath(path, base_dir)
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      link_script = (
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          '#!/usr/bin/env python\n\n'
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'import os\n'
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'import sys\n\n\n'
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'script = os.path.join(os.path.dirname(__file__), \'%s\')\n'
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'os.execv(sys.executable, [sys.executable, script] + sys.argv[1:])'
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        % relative_path)
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      zip_file.writestr(link_info, link_script)
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Add gsutil to the archive, if it's available. The gsutil in
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # depot_tools is modified to allow authentication using prodaccess.
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # TODO: If there's a gsutil in telemetry/third_party/, bootstrap_deps
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # will include it. Then there will be two copies of gsutil at the same
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # location in the archive. This can be confusing for users.
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    gsutil_path = os.path.realpath(cloud_storage.FindGsutil())
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if cloud_storage.SupportsProdaccess(gsutil_path):
20423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      gsutil_base_dir = os.path.join(os.path.dirname(gsutil_path), os.pardir)
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      gsutil_dependencies = path_set.PathSet()
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      gsutil_dependencies.add(os.path.dirname(gsutil_path))
20723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      # Also add modules from depot_tools that are needed by gsutil.
20823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      gsutil_dependencies.add(os.path.join(gsutil_base_dir, 'boto'))
20923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      gsutil_dependencies.add(os.path.join(gsutil_base_dir, 'retry_decorator'))
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      gsutil_dependencies -= FindExcludedFiles(
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          set(gsutil_dependencies), options)
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      # Also add upload.py to the archive from depot_tools, if it is available.
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      # This allows us to post patches without requiring a full depot_tools
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      # install. There's no real point in including upload.py if we do not
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      # also have gsutil, which is why this is inside the gsutil block.
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      gsutil_dependencies.add(os.path.join(gsutil_base_dir, 'upload.py'))
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      for path in gsutil_dependencies:
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        path_in_archive = os.path.join(
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            'telemetry', os.path.relpath(util.GetTelemetryDir(), base_dir),
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            'third_party', os.path.relpath(path, gsutil_base_dir))
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        zip_file.write(path, path_in_archive)
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
22623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)class FindDependenciesCommand(command_line.OptparseCommand):
22723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  """Prints all dependencies"""
22823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
22923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  @classmethod
23023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  def AddCommandLineArgs(cls, parser):
23123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    parser.add_option(
23223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        '-v', '--verbose', action='count', dest='verbosity',
23323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        help='Increase verbosity level (repeat as needed).')
23423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
23523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    parser.add_option(
23623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        '-p', '--include-page-set-data', action='store_true', default=False,
23723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        help='Scan tests for page set data and include them.')
23823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
23923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    parser.add_option(
24023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        '-e', '--exclude', action='append', default=[],
24123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        help='Exclude paths matching EXCLUDE. Can be used multiple times.')
24223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
24323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    parser.add_option(
24423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        '-z', '--zip',
24523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        help='Store files in a zip archive at ZIP.')
24623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
24723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  @classmethod
24823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  def ProcessCommandLineArgs(cls, parser, args):
24923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if args.verbosity >= 2:
25023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      logging.getLogger().setLevel(logging.DEBUG)
25123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    elif args.verbosity:
25223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      logging.getLogger().setLevel(logging.INFO)
25323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    else:
25423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      logging.getLogger().setLevel(logging.WARNING)
25523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
25623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  def Run(self, args):
25723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    paths = args.positional_args
25823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    dependencies = FindDependencies(paths, args)
25923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if args.zip:
26023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      ZipDependencies(paths, dependencies, args)
26123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      print 'Zip archive written to %s.' % args.zip
26223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    else:
26323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      print '\n'.join(sorted(dependencies))
26423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return 0
265