generate_projects.py
Go to the documentation of this file.
1 # Copyright 2015 gRPC authors.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import argparse
16 import glob
17 import multiprocessing
18 import os
19 import pickle
20 import shutil
21 import sys
22 import tempfile
23 from typing import Dict, List, Union
24 
25 import _utils
26 import yaml
27 
28 PROJECT_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..",
29  "..")
30 os.chdir(PROJECT_ROOT)
31 # TODO(lidiz) find a better way for plugins to reference each other
32 sys.path.append(os.path.join(PROJECT_ROOT, 'tools', 'buildgen', 'plugins'))
33 
34 # from tools.run_tests.python_utils import jobset
36  os.path.join(PROJECT_ROOT, 'tools', 'run_tests', 'python_utils',
37  'jobset.py'))
38 
39 PREPROCESSED_BUILD = '.preprocessed_build'
40 test = {} if os.environ.get('TEST', 'false') == 'true' else None
41 
42 assert sys.argv[1:], 'run generate_projects.sh instead of this directly'
43 parser = argparse.ArgumentParser()
44 parser.add_argument('build_files',
45  nargs='+',
46  default=[],
47  help="build files describing build specs")
48 parser.add_argument('--templates',
49  nargs='+',
50  default=[],
51  help="mako template files to render")
52 parser.add_argument('--output_merged',
53  '-m',
54  default='',
55  type=str,
56  help="merge intermediate results to a file")
57 parser.add_argument('--jobs',
58  '-j',
59  default=multiprocessing.cpu_count(),
60  type=int,
61  help="maximum parallel jobs")
62 parser.add_argument('--base',
63  default='.',
64  type=str,
65  help="base path for generated files")
66 args = parser.parse_args()
67 
68 
69 def preprocess_build_files() -> _utils.Bunch:
70  """Merges build yaml into a one dictionary then pass it to plugins."""
71  build_spec = dict()
72  for build_file in args.build_files:
73  with open(build_file, 'r') as f:
74  _utils.merge_json(build_spec,
75  yaml.load(f.read(), Loader=yaml.FullLoader))
76  # Executes plugins. Plugins update the build spec in-place.
77  for py_file in sorted(glob.glob('tools/buildgen/plugins/*.py')):
78  plugin = _utils.import_python_module(py_file)
79  plugin.mako_plugin(build_spec)
80  if args.output_merged:
81  with open(args.output_merged, 'w') as f:
82  f.write(yaml.dump(build_spec))
83  # Makes build_spec sort of immutable and dot-accessible
84  return _utils.to_bunch(build_spec)
85 
86 
87 def generate_template_render_jobs(templates: List[str]) -> List[jobset.JobSpec]:
88  """Generate JobSpecs for each one of the template rendering work."""
89  jobs = []
90  base_cmd = [sys.executable, 'tools/buildgen/_mako_renderer.py']
91  for template in sorted(templates, reverse=True):
92  root, f = os.path.split(template)
93  if os.path.splitext(f)[1] == '.template':
94  out_dir = args.base + root[len('templates'):]
95  out = os.path.join(out_dir, os.path.splitext(f)[0])
96  if not os.path.exists(out_dir):
97  os.makedirs(out_dir)
98  cmd = base_cmd[:]
99  cmd.append('-P')
100  cmd.append(PREPROCESSED_BUILD)
101  cmd.append('-o')
102  if test is None:
103  cmd.append(out)
104  else:
105  tf = tempfile.mkstemp()
106  test[out] = tf[1]
107  os.close(tf[0])
108  cmd.append(test[out])
109  cmd.append(args.base + '/' + root + '/' + f)
110  jobs.append(jobset.JobSpec(cmd, shortname=out,
111  timeout_seconds=None))
112  return jobs
113 
114 
115 def main() -> None:
116  templates = args.templates
117  if not templates:
118  for root, _, files in os.walk('templates'):
119  for f in files:
120  templates.append(os.path.join(root, f))
121 
122  build_spec = preprocess_build_files()
123  with open(PREPROCESSED_BUILD, 'wb') as f:
124  pickle.dump(build_spec, f)
125 
126  err_cnt, _ = jobset.run(generate_template_render_jobs(templates),
127  maxjobs=args.jobs)
128  if err_cnt != 0:
129  print('ERROR: %s error(s) found while generating projects.' % err_cnt,
130  file=sys.stderr)
131  sys.exit(1)
132 
133  if test is not None:
134  for s, g in test.items():
135  if os.path.isfile(g):
136  assert 0 == os.system('diff %s %s' % (s, g)), s
137  os.unlink(g)
138  else:
139  assert 0 == os.system('diff -r %s %s' % (s, g)), s
140  shutil.rmtree(g, ignore_errors=True)
141 
142 
143 if __name__ == "__main__":
144  main()
_utils.to_bunch
Any to_bunch(Any var)
Definition: tools/buildgen/_utils.py:42
generate_projects.preprocess_build_files
_utils.Bunch preprocess_build_files()
Definition: generate_projects.py:69
_utils.merge_json
None merge_json(Union[Mapping, List] dst, Union[Mapping, List] add)
Definition: tools/buildgen/_utils.py:57
generate_projects.main
None main()
Definition: generate_projects.py:115
main
Definition: main.py:1
_utils.import_python_module
types.ModuleType import_python_module(str path)
Definition: tools/buildgen/_utils.py:24
generate_projects.generate_template_render_jobs
List[jobset.JobSpec] generate_template_render_jobs(List[str] templates)
Definition: generate_projects.py:87
open
#define open
Definition: test-fs.c:46
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:59:23