1#!/usr/bin/env python3 2 3# Copyright 2022 gRPC authors. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16""" 17Generate experiment related code artifacts. 18 19Invoke as: tools/codegen/core/gen_experiments.py 20Experiment definitions are in src/core/lib/experiments/experiments.yaml 21""" 22 23from __future__ import print_function 24 25import argparse 26import sys 27 28import experiments_compiler as exp 29import yaml 30 31DEFAULTS = { 32 'broken': 'false', 33 False: 'false', 34 True: 'true', 35 'debug': 'kDefaultForDebugOnly', 36} 37 38FINAL_RETURN = { 39 'broken': 'return false;', 40 False: 'return false;', 41 True: 'return true;', 42 'debug': '\n#ifdef NDEBUG\nreturn false;\n#else\nreturn true;\n#endif\n', 43} 44 45FINAL_DEFINE = { 46 'broken': None, 47 False: None, 48 True: '#define %s', 49 'debug': '#ifndef NDEBUG\n#define %s\n#endif', 50} 51 52BZL_LIST_FOR_DEFAULTS = { 53 'broken': None, 54 False: 'off', 55 True: 'on', 56 'debug': 'dbg', 57} 58 59 60def ParseCommandLineArguments(args): 61 """Wrapper for argparse command line arguments handling. 62 63 Args: 64 args: List of command line arguments. 65 66 Returns: 67 Command line arguments namespace built by argparse.ArgumentParser(). 68 """ 69 # formatter_class=argparse.ArgumentDefaultsHelpFormatter is not used here 70 # intentionally, We want more formatting than this class can provide. 71 flag_parser = argparse.ArgumentParser() 72 flag_parser.add_argument( 73 '--check', 74 action='store_false', 75 help='If specified, disables checking experiment expiry dates', 76 ) 77 flag_parser.add_argument( 78 '--disable_gen_hdrs', 79 action='store_true', 80 help='If specified, disables generation of experiments hdr files', 81 ) 82 flag_parser.add_argument( 83 '--disable_gen_srcs', 84 action='store_true', 85 help='If specified, disables generation of experiments source files', 86 ) 87 flag_parser.add_argument( 88 '--disable_gen_bzl', 89 action='store_true', 90 help='If specified, disables generation of experiments.bzl file', 91 ) 92 return flag_parser.parse_args(args) 93 94 95args = ParseCommandLineArguments(sys.argv[1:]) 96 97with open('src/core/lib/experiments/experiments.yaml') as f: 98 attrs = yaml.safe_load(f.read()) 99 100with open('src/core/lib/experiments/rollouts.yaml') as f: 101 rollouts = yaml.safe_load(f.read()) 102 103compiler = exp.ExperimentsCompiler(DEFAULTS, FINAL_RETURN, FINAL_DEFINE, 104 BZL_LIST_FOR_DEFAULTS) 105 106experiment_annotation = "gRPC Experiments: " 107for attr in attrs: 108 exp_definition = exp.ExperimentDefinition(attr) 109 if not exp_definition.IsValid(args.check): 110 sys.exit(1) 111 experiment_annotation += exp_definition.name + ':0,' 112 if not compiler.AddExperimentDefinition(exp_definition): 113 print("Experiment = %s ERROR adding" % exp_definition.name) 114 sys.exit(1) 115 116if len(experiment_annotation) > 2000: 117 print("comma-delimited string of experiments is too long") 118 sys.exit(1) 119 120for rollout_attr in rollouts: 121 if not compiler.AddRolloutSpecification(rollout_attr): 122 print("ERROR adding rollout spec") 123 sys.exit(1) 124 125if not args.disable_gen_hdrs: 126 print("Generating experiments headers") 127 compiler.GenerateExperimentsHdr('src/core/lib/experiments/experiments.h') 128 129if not args.disable_gen_srcs: 130 print("Generating experiments srcs") 131 compiler.GenerateExperimentsSrc('src/core/lib/experiments/experiments.cc') 132 133if not args.disable_gen_bzl: 134 print("Generating experiments.bzl") 135 compiler.GenExperimentsBzl('bazel/experiments.bzl') 136