blob: 95d2d829795f231779909e4dd2f4b970cc3f0742 [file] [log] [blame]
Elly Fong-Jones4054f142020-04-17 17:12:331#!/usr/bin/env python
2# Copyright 2020 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5"""Generates extra flags needed to allow temporarily reverting flag expiry.
6
7This program generates three files:
8* A C++ source file, containing definitions of base::Features that unexpire
9 flags that expired in recent milestones, along with a definition of a
10 definition of a function `flags::ExpiryEnabledForMilestone`
11* A C++ header file, containing declarations of those base::Features
12* A C++ source fragment, containing definitions of flags_ui::FeatureEntry
13 structures for flags corresponding to those base::Features
14
15Which milestones are recent is sourced from //chrome/VERSION in the source tree.
16"""
17
18import os
19import sys
20
21ROOT_PATH = os.path.join(os.path.dirname(__file__), '..', '..')
22
23
24def get_chromium_version():
25 """Parses the chromium version out of //chrome/VERSION."""
26 with open(os.path.join(ROOT_PATH, 'chrome', 'VERSION')) as f:
27 for line in f.readlines():
28 key, value = line.strip().split('=')
29 if key == 'MAJOR':
30 return int(value)
31 return None
32
33
34def recent_mstones(mstone):
35 """Returns the list of milestones considered 'recent' for the given mstone.
36
37 Flag unexpiry is available only for flags that expired at recent mstones."""
38 return [mstone - 1, mstone]
39
40
41def file_header(prog_name):
42 """Returns the header to use on generated files."""
43 return """// Copyright 2020 The Chromium Authors. All rights reserved.
44// Use of this source code is governed by a BSD-style license that can be
45// found in the LICENSE file.
46
47// This is a generated file. Do not edit it! It was generated by:
48// {prog_name}
49""".format(prog_name=prog_name)
50
51
52def gen_features_impl(prog_name, mstone):
53 """Generates the definitions for the unexpiry features and the expiry-check
54 function.
55
56 This function generates the contents of a complete C++ source file,
57 which defines base::Features for unexpiration of flags from recent milestones,
58 as well as a function ExpiryEnabledForMilestone().
59 """
60 body = file_header(prog_name)
61 body += """
62#include "base/feature_list.h"
63#include "chrome/browser/unexpire_flags_gen.h"
64
65namespace flags {
66
67"""
68
69 features = [(m, 'UnexpireFlagsM' + str(m)) for m in recent_mstones(mstone)]
70 for feature in features:
71 body += 'const base::Feature k{f} {{\n'.format(f=feature[1])
72 body += ' "{f}",\n'.format(f=feature[1])
73 body += ' base::FEATURE_DISABLED_BY_DEFAULT\n'
74 body += '};\n\n'
75
76 body += """// Returns the unexpire feature for the given mstone, if any.
77const base::Feature* GetUnexpireFeatureForMilestone(int milestone) {
78 switch (milestone) {
79"""
80
81 for feature in features:
82 body += ' case {m}: return &k{f};\n'.format(m=feature[0], f=feature[1])
83 body += """ default: return nullptr;
84 }
85}
86
87} // namespace flags
88"""
89
90 return body
91
92
93def gen_features_header(prog_name, mstone):
94 """Generate a header file declaring features and the expiry predicate.
95
96 This header declares the features and function described in
97 gen_features_impl().
98 """
99 body = file_header(prog_name)
100
101 body += """
102#ifndef GEN_CHROME_BROWSER_UNEXPIRE_FLAGS_GEN_H_
103#define GEN_CHROME_BROWSER_UNEXPIRE_FLAGS_GEN_H_
104
105namespace flags {
106
107"""
108
109 for m in recent_mstones(mstone):
110 body += 'extern const base::Feature kUnexpireFlagsM{m};\n'.format(m=m)
111
112 body += """
113// Returns the base::Feature used to decide whether flag expiration is enabled
114// for a given milestone, if there is such a feature. If not, returns nullptr.
115const base::Feature* GetUnexpireFeatureForMilestone(int milestone);
116
117} // namespace flags
118
119#endif // GEN_CHROME_BROWSER_UNEXPIRE_FLAGS_GEN_H_
120"""
121
122 return body
123
124
125def gen_flags_fragment(prog_name, mstone):
126 """Generates a .inc file containing flag definitions.
127
128 This creates a C++ source fragment defining flags, which are bound to the
129 features described in gen_features_impl().
130 """
131 fragment = """
132 {{"temporary-unexpire-flags-m{m}",
133 "Temporarily unexpire M{m} flags.",
134 "Temporarily unexpire flags that expired as of M{m}. These flags will be"
135 " removed soon.",
136 kOsAll | flags_ui::kFlagInfrastructure,
137 FEATURE_VALUE_TYPE(flags::kUnexpireFlagsM{m})}},
138"""
139
140 return '\n'.join([fragment.format(m=m) for m in recent_mstones(mstone)])
141
142
143def update_file_if_stale(filename, data):
144 """Writes data to filename if data is different from file's contents on disk.
145 """
146 try:
147 disk_data = open(filename, 'r').read()
148 if disk_data == data:
149 return
150 except IOError:
151 pass
152 open(filename, 'w').write(data)
153
154
155def main():
156 mstone = get_chromium_version()
157
158 if not mstone:
159 raise ValueError('Can\'t find or understand //chrome/VERSION')
160
161 progname = sys.argv[0]
Elly Fong-Jones7ff0bab2020-04-20 20:57:51162
163 # Note the mstone - 1 here: the listed expiration mstone is the last mstone in
164 # which that flag is present, not the first mstone in which it is not present.
165 update_file_if_stale(sys.argv[1], gen_features_impl(progname, mstone - 1))
166 update_file_if_stale(sys.argv[2], gen_features_header(progname, mstone - 1))
167 update_file_if_stale(sys.argv[3], gen_flags_fragment(progname, mstone - 1))
Elly Fong-Jones4054f142020-04-17 17:12:33168
169
170if __name__ == '__main__':
171 main()