1 # Copyright 2014 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."""
15 from profile_creators
import profile_extender
16 from telemetry
.core
import browser_options
17 from telemetry
.core
import discover
18 from telemetry
.core
import util
19 from telemetry
.user_story
import user_story_runner
22 def _DiscoverProfileExtenderClasses():
23 profile_extenders_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_extenders_dir
, os
.pardir
))
27 profile_extenders_unfiltered
= discover
.DiscoverClasses(
28 profile_extenders_dir
, base_dir
, profile_extender
.ProfileExtender
)
30 # Remove 'extender' suffix from keys.
31 profile_extenders
= {}
32 for test_name
, test_class
in profile_extenders_unfiltered
.iteritems():
33 assert test_name
.endswith('_extender')
34 test_name
= test_name
[:-len('_extender')]
35 profile_extenders
[test_name
] = test_class
36 return profile_extenders
39 def _IsPseudoFile(directory
, paths
):
40 """Filter function for shutil.copytree() to reject socket files and symlinks
41 since those can't be copied around on bots."""
42 def IsSocket(full_path
):
43 """Check if a file at a given path is a socket."""
45 if stat
.S_ISSOCK(os
.stat(full_path
).st_mode
):
48 # Thrown if we encounter a broken symlink.
54 full_path
= os
.path
.join(directory
, path
)
56 if os
.path
.isdir(full_path
):
58 if not IsSocket(full_path
) and not os
.path
.islink(full_path
):
61 logging
.warning('Ignoring pseudo file: %s' % full_path
)
62 ignore_list
.append(path
)
67 def GenerateProfiles(profile_extender_class
, profile_creator_name
, options
):
68 """Generate a profile"""
70 temp_output_directory
= tempfile
.mkdtemp()
71 options
.output_profile_path
= temp_output_directory
73 profile_creator_instance
= profile_extender_class()
75 profile_creator_instance
.Run(options
)
76 except Exception as e
:
77 logging
.exception('Profile creation failed.')
78 shutil
.rmtree(temp_output_directory
)
81 # Everything is a-ok, move results to final destination.
82 generated_profiles_dir
= os
.path
.abspath(options
.output_dir
)
83 if not os
.path
.exists(generated_profiles_dir
):
84 os
.makedirs(generated_profiles_dir
)
85 out_path
= os
.path
.join(generated_profiles_dir
, profile_creator_name
)
86 if os
.path
.exists(out_path
):
87 shutil
.rmtree(out_path
)
89 shutil
.copytree(temp_output_directory
, out_path
, ignore
=_IsPseudoFile
)
90 shutil
.rmtree(temp_output_directory
)
91 sys
.stderr
.write("SUCCESS: Generated profile copied to: '%s'.\n" % out_path
)
96 def AddCommandLineArgs(parser
):
97 user_story_runner
.AddCommandLineArgs(parser
)
99 profile_extenders
= _DiscoverProfileExtenderClasses().keys()
100 legal_profile_creators
= '|'.join(profile_extenders
)
101 group
= optparse
.OptionGroup(parser
, 'Profile generation options')
102 group
.add_option('--profile-type-to-generate',
103 dest
='profile_type_to_generate',
105 help='Type of profile to generate. '
106 'Supported values: %s' % legal_profile_creators
)
107 parser
.add_option_group(group
)
110 def ProcessCommandLineArgs(parser
, args
):
111 user_story_runner
.ProcessCommandLineArgs(parser
, args
)
113 if not args
.profile_type_to_generate
:
114 parser
.error("Must specify --profile-type-to-generate option.")
116 profile_extenders
= _DiscoverProfileExtenderClasses().keys()
117 if args
.profile_type_to_generate
not in profile_extenders
:
118 legal_profile_creators
= '|'.join(profile_extenders
)
119 parser
.error("Invalid profile type, legal values are: %s." %
120 legal_profile_creators
)
122 if not args
.browser_type
:
123 parser
.error("Must specify --browser option.")
125 if not args
.output_dir
:
126 parser
.error("Must specify --output-dir option.")
128 if args
.browser_options
.dont_override_profile
:
129 parser
.error("Can't use existing profile when generating profile.")
133 options
= browser_options
.BrowserFinderOptions()
134 parser
= options
.CreateParser(
135 "%%prog <--profile-type-to-generate=...> <--browser=...> <--output-dir>")
136 AddCommandLineArgs(parser
)
137 _
, _
= parser
.parse_args()
138 ProcessCommandLineArgs(parser
, options
)
141 profile_extenders
= _DiscoverProfileExtenderClasses()
142 profile_extender_class
= profile_extenders
[options
.profile_type_to_generate
]
143 return GenerateProfiles(profile_extender_class
,
144 options
.profile_type_to_generate
, options
)