1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Handles generating profiles and transferring them to/from mobile devices."""
14 from telemetry.core import browser_options
15 from telemetry.core import discover
16 from telemetry.core import util
17 from telemetry.page import page_runner
18 from telemetry.page import profile_creator
19 from telemetry.page import test_expectations
22 def _DiscoverProfileCreatorClasses():
23 profile_creators_dir = os.path.abspath(os.path.join(util.GetBaseDir(),
24 os.pardir, 'perf', 'profile_creators'))
25 base_dir = os.path.abspath(os.path.join(profile_creators_dir, os.pardir))
27 profile_creators_unfiltered = discover.DiscoverClasses(
28 profile_creators_dir, base_dir, profile_creator.ProfileCreator)
30 # Remove '_creator' suffix from keys.
32 for test_name, test_class in profile_creators_unfiltered.iteritems():
33 assert test_name.endswith('_creator')
34 test_name = test_name[:-len('_creator')]
35 profile_creators[test_name] = test_class
36 return profile_creators
38 def GenerateProfiles(profile_creator_class, profile_creator_name, options):
39 """Generate a profile"""
40 expectations = test_expectations.TestExpectations()
41 test = profile_creator_class()
43 temp_output_directory = tempfile.mkdtemp()
44 options.output_profile_path = temp_output_directory
46 results = page_runner.Run(test, test.page_set, expectations, options)
48 if results.errors or results.failures:
49 logging.warning('Some pages failed.')
50 if results.errors or results.failures:
51 logging.warning('Failed pages:\n%s',
52 '\n'.join(zip(*results.errors + results.failures)[0]))
55 # Everything is a-ok, move results to final destination.
56 generated_profiles_dir = os.path.abspath(options.output_dir)
57 if not os.path.exists(generated_profiles_dir):
58 os.makedirs(generated_profiles_dir)
59 out_path = os.path.join(generated_profiles_dir, profile_creator_name)
60 if os.path.exists(out_path):
61 shutil.rmtree(out_path)
63 # A profile may contain pseudo files like sockets which can't be copied
65 def IsPseudoFile(directory, paths):
68 full_path = os.path.join(directory, path)
69 if (not os.path.isfile(full_path) and
70 not os.path.isdir(full_path) and
71 not os.path.islink(full_path)):
72 logging.warning('Ignoring pseudo file: %s' % full_path)
73 ignore_list.append(path)
75 shutil.copytree(temp_output_directory, out_path, ignore=IsPseudoFile)
76 shutil.rmtree(temp_output_directory)
77 sys.stderr.write("SUCCESS: Generated profile copied to: '%s'.\n" % out_path)
82 profile_creators = _DiscoverProfileCreatorClasses()
83 legal_profile_creators = '|'.join(profile_creators.keys())
85 options = browser_options.BrowserFinderOptions()
86 parser = options.CreateParser(
87 "%%prog <--profile-type-to-generate=...> <--browser=...>"
88 " <--output-directory>")
89 page_runner.AddCommandLineOptions(parser)
91 group = optparse.OptionGroup(parser, 'Profile generation options')
92 group.add_option('--profile-type-to-generate',
93 dest='profile_type_to_generate',
95 help='Type of profile to generate. '
96 'Supported values: %s' % legal_profile_creators)
97 group.add_option('--output-dir',
99 help='Generated profile is placed in this directory.')
100 parser.add_option_group(group)
102 _, _ = parser.parse_args()
104 # Sanity check arguments.
105 if not options.profile_type_to_generate:
106 raise Exception("Must specify --profile-type-to-generate option.")
108 if options.profile_type_to_generate not in profile_creators.keys():
109 raise Exception("Invalid profile type, legal values are: %s." %
110 legal_profile_creators)
112 if not options.browser_type:
113 raise Exception("Must specify --browser option.")
115 if not options.output_dir:
116 raise Exception("Must specify --output-dir option.")
118 if options.browser_options.dont_override_profile:
119 raise Exception("Can't use existing profile when generating profile.")
122 profile_creator_class = profile_creators[options.profile_type_to_generate]
123 return GenerateProfiles(profile_creator_class,
124 options.profile_type_to_generate, options)