Initial import chromium-67.0.3396.87
[chromium-dfly.git] / tools / variations / fieldtrial_util.py
1 # Copyright 2015 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.
4
5 import json
6 import sys
7
8 import fieldtrial_to_struct
9
10 def _hex(ch):
11   hv = hex(ord(ch)).replace('0x', '')
12   hv.zfill(2)
13   return hv.upper()
14
15 # URL escapes the delimiter characters from the output. urllib.quote is not
16 # used because it cannot escape '.'.
17 def _escape(str):
18   result = str
19   # Must perform replace on '%' first before the others.
20   for c in '%:/.,':
21     result = result.replace(c, '%' + _hex(c))
22   return result
23
24 def _FindDuplicates(entries):
25   seen = set()
26   duplicates = set()
27   for entry in entries:
28     if entry in seen:
29       duplicates.add(entry)
30     else:
31       seen.add(entry)
32   return duplicates
33
34 def _CheckForDuplicateFeatures(enable_features, disable_features):
35   enable_features = [f.split('<')[0] for f in enable_features]
36   enable_features_set = set(enable_features)
37   if len(enable_features_set) != len(enable_features):
38     raise Exception('Duplicate feature(s) in enable_features: ' +
39                     ', '.join(_FindDuplicates(enable_features)))
40
41   disable_features = [f.split('<')[0] for f in disable_features]
42   disable_features_set = set(disable_features)
43   if len(disable_features_set) != len(disable_features):
44     raise Exception('Duplicate feature(s) in disable_features: ' +
45                     ', '.join(_FindDuplicates(disable_features)))
46
47   features_in_both = enable_features_set.intersection(disable_features_set)
48   if len(features_in_both) > 0:
49     raise Exception('Conflicting features set as both enabled and disabled: ' +
50                     ', '.join(features_in_both))
51
52 # Generate a list of command-line switches to enable field trials for the
53 # provided config_path and platform.
54 def GenerateArgs(config_path, platform):
55   try:
56     with open(config_path, 'r') as config_file:
57       config = json.load(config_file)
58   except (IOError, ValueError):
59     return []
60
61   platform_studies = fieldtrial_to_struct.ConfigToStudies(config, platform)
62
63   studies = []
64   params = []
65   enable_features = []
66   disable_features = []
67
68   for study in platform_studies:
69     study_name = study['name']
70     experiments = study['experiments']
71     # For now, only take the first experiment.
72     experiment = experiments[0]
73     selected_study = [study_name, experiment['name']]
74     studies.extend(selected_study)
75     param_list = []
76     if 'params' in experiment:
77       for param in experiment['params']:
78         param_list.append(param['key'])
79         param_list.append(param['value'])
80     if len(param_list):
81        # Escape the variables for the command-line.
82        selected_study = [_escape(x) for x in selected_study]
83        param_list = [_escape(x) for x in param_list]
84        param = '%s:%s' % ('.'.join(selected_study), '/'.join(param_list))
85        params.append(param)
86     for feature in experiment.get('enable_features', []):
87       enable_features.append(feature + '<' + study_name)
88     for feature in experiment.get('disable_features', []):
89       disable_features.append(feature + '<' + study_name)
90
91   if not len(studies):
92     return []
93   _CheckForDuplicateFeatures(enable_features, disable_features)
94   args = ['--force-fieldtrials=%s' % '/'.join(studies)]
95   if len(params):
96     args.append('--force-fieldtrial-params=%s' % ','.join(params))
97   if len(enable_features):
98     args.append('--enable-features=%s' % ','.join(enable_features))
99   if len(disable_features):
100     args.append('--disable-features=%s' % ','.join(disable_features))
101   return args
102
103 def main():
104   if len(sys.argv) < 3:
105     print 'Usage: fieldtrial_util.py [config_path] [platform]'
106     print 'Optionally pass \'shell_cmd\' as an extra argument to print'
107     print 'quoted command line arguments.'
108     exit(-1)
109   print_shell_cmd = len(sys.argv) >= 4 and sys.argv[3] == 'shell_cmd'
110
111   supported_platforms = ['android', 'chromeos', 'ios', 'linux', 'mac', 'win']
112   if sys.argv[2] not in supported_platforms:
113     print ('\'%s\' is an unknown platform. Supported platforms: %s' %
114         (sys.argv[2], supported_platforms))
115     exit(-1)
116
117   generated_args = GenerateArgs(sys.argv[1], sys.argv[2])
118   if print_shell_cmd:
119     print " ".join(map((lambda arg: '"{0}"'.format(arg)), generated_args))
120   else:
121     print generated_args
122
123 if __name__ == '__main__':
124   main()