blob: 98e2f03781c310ce139f529c214b8996b658fdfe [file] [log] [blame]
Josip Sokcevic9686b2e2022-08-30 21:44:391#!/usr/bin/env python3
Avi Drissmandfd880852022-09-15 20:11:092# Copyright 2020 The Chromium Authors
Elly Fong-Jones4054f142020-04-17 17:12:333# 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."""
Avi Drissmandfd880852022-09-15 20:11:0943 return """// Copyright 2020 The Chromium Authors
Elly Fong-Jones4054f142020-04-17 17:12:3344// 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:
Daniel Cheng83f2f4b2022-09-24 17:30:5671 body += f'BASE_FEATURE(k{feature[1]},\n'
72 body += f' "{feature[1]}",\n'
73 body += f' base::FEATURE_DISABLED_BY_DEFAULT);\n\n'
Elly Fong-Jones4054f142020-04-17 17:12:3374
75 body += """// Returns the unexpire feature for the given mstone, if any.
76const base::Feature* GetUnexpireFeatureForMilestone(int milestone) {
77 switch (milestone) {
78"""
79
80 for feature in features:
81 body += ' case {m}: return &k{f};\n'.format(m=feature[0], f=feature[1])
82 body += """ default: return nullptr;
83 }
84}
85
86} // namespace flags
87"""
88
89 return body
90
91
92def gen_features_header(prog_name, mstone):
93 """Generate a header file declaring features and the expiry predicate.
94
95 This header declares the features and function described in
96 gen_features_impl().
97 """
98 body = file_header(prog_name)
99
100 body += """
101#ifndef GEN_CHROME_BROWSER_UNEXPIRE_FLAGS_GEN_H_
102#define GEN_CHROME_BROWSER_UNEXPIRE_FLAGS_GEN_H_
103
104namespace flags {
105
106"""
107
108 for m in recent_mstones(mstone):
Daniel Cheng83f2f4b2022-09-24 17:30:56109 body += f'BASE_DECLARE_FEATURE(kUnexpireFlagsM{m});\n'
Elly Fong-Jones4054f142020-04-17 17:12:33110
111 body += """
112// Returns the base::Feature used to decide whether flag expiration is enabled
113// for a given milestone, if there is such a feature. If not, returns nullptr.
114const base::Feature* GetUnexpireFeatureForMilestone(int milestone);
115
116} // namespace flags
117
118#endif // GEN_CHROME_BROWSER_UNEXPIRE_FLAGS_GEN_H_
119"""
120
121 return body
122
123
124def gen_flags_fragment(prog_name, mstone):
125 """Generates a .inc file containing flag definitions.
126
127 This creates a C++ source fragment defining flags, which are bound to the
128 features described in gen_features_impl().
129 """
Elly Fong-Jonesf8a4aa42020-08-04 15:53:30130 # Note: The exact format of the flag name (temporary-unexpire-flags-m{m}) is
131 # depended on by a hack in UnexpiredMilestonesFromStorage(). See
132 # https://crbug.com/1101828 for more details.
Elly Fong-Jones4054f142020-04-17 17:12:33133 fragment = """
134 {{"temporary-unexpire-flags-m{m}",
135 "Temporarily unexpire M{m} flags.",
136 "Temporarily unexpire flags that expired as of M{m}. These flags will be"
137 " removed soon.",
138 kOsAll | flags_ui::kFlagInfrastructure,
139 FEATURE_VALUE_TYPE(flags::kUnexpireFlagsM{m})}},
140"""
141
142 return '\n'.join([fragment.format(m=m) for m in recent_mstones(mstone)])
143
144
145def update_file_if_stale(filename, data):
146 """Writes data to filename if data is different from file's contents on disk.
147 """
148 try:
149 disk_data = open(filename, 'r').read()
150 if disk_data == data:
151 return
152 except IOError:
153 pass
154 open(filename, 'w').write(data)
155
156
157def main():
158 mstone = get_chromium_version()
159
160 if not mstone:
161 raise ValueError('Can\'t find or understand //chrome/VERSION')
162
163 progname = sys.argv[0]
Elly Fong-Jones7ff0bab2020-04-20 20:57:51164
165 # Note the mstone - 1 here: the listed expiration mstone is the last mstone in
166 # which that flag is present, not the first mstone in which it is not present.
167 update_file_if_stale(sys.argv[1], gen_features_impl(progname, mstone - 1))
168 update_file_if_stale(sys.argv[2], gen_features_header(progname, mstone - 1))
169 update_file_if_stale(sys.argv[3], gen_flags_fragment(progname, mstone - 1))
Elly Fong-Jones4054f142020-04-17 17:12:33170
171
172if __name__ == '__main__':
173 main()