56def parse(repo_root, recipes_cfg_path):
57 """Parse is a lightweight a recipes.cfg file parser.
60 repo_root (str) - native path to the root of the repo we're trying to run
62 recipes_cfg_path (str) - native path to the recipes.cfg file to process.
65 engine_dep (EngineDep|None): The recipe_engine dependency, or None, if the
66 current repo IS the recipe_engine.
67 recipes_path (str) - native path to where the recipes live inside of the
68 current repo (i.e. the folder containing `recipes/` and/or
71 with open(recipes_cfg_path,
'r', encoding=
'utf-8')
as file:
72 recipes_cfg = json.load(file)
75 if (version := recipes_cfg[
'api_version']) != 2:
80 repo_name = recipes_cfg.get(
'repo_name')
82 repo_name = recipes_cfg[
'project_id']
83 if repo_name ==
'recipe_engine':
84 return None, recipes_cfg.get(
'recipes_path',
'')
86 engine = recipes_cfg[
'deps'][
'recipe_engine']
88 if 'url' not in engine:
90 'Required field "url" in dependency "recipe_engine" not found',
93 engine.setdefault(
'revision',
'')
94 engine.setdefault(
'branch',
'refs/heads/main')
95 recipes_path = recipes_cfg.get(
'recipes_path',
'')
98 if not engine[
'branch'].startswith(
'refs/'):
99 engine[
'branch'] =
'refs/heads/' + engine[
'branch']
101 recipes_path = os.path.join(repo_root,
102 recipes_path.replace(
'/', os.path.sep))
104 except KeyError
as ex:
138 """This extracts a subset of the arguments that this bootstrap script cares
139 about. Currently this consists of:
140 * an override for the recipe engine in the form of `-O recipe_engine=/path`
141 * the --package option.
143 override_prefix =
'recipe_engine='
145 parser = argparse.ArgumentParser(add_help=
False)
146 parser.add_argument(
'-O',
'--project-override', action=
'append')
147 parser.add_argument(
'--package', type=os.path.abspath)
148 args, _ = parser.parse_known_args(argv)
149 for override
in args.project_override
or ():
150 if override.startswith(override_prefix):
151 return override[len(override_prefix):], args.package
152 return None, args.package
156 """Checks out the recipe_engine repo pinned in recipes.cfg.
158 Returns the path to the recipe engine repo.
160 dep, recipes_path = parse(repo_root, recipes_cfg_path)
163 return os.path.join(repo_root, recipes_path)
167 if not engine_path
and url.startswith(
'file://'):
168 engine_path = urlparse.urlparse(url).path
171 revision = dep.revision
175 engine_path = os.path.join(recipes_path,
'.recipe_deps',
'recipe_engine')
183 stdout=subprocess.DEVNULL,
184 stderr=subprocess.DEVNULL)
185 except subprocess.CalledProcessError:
188 stdout=subprocess.DEVNULL)
192 except subprocess.CalledProcessError:
193 index_lock = os.path.join(engine_path,
'.git',
'index.lock')
195 os.remove(index_lock)
196 except OSError
as exc:
197 if exc.errno != errno.ENOENT:
198 logging.warning(
'failed to remove %r, reset will fail: %s',
210 for required_binary
in REQUIRED_BINARIES:
211 if not shutil.which(required_binary):
212 return f
'Required binary is not found on PATH: {required_binary}'
214 if '--verbose' in sys.argv:
215 logging.getLogger().setLevel(logging.INFO)
218 engine_override, recipes_cfg_path =
parse_args(args)
222 repo_root = os.path.dirname(
223 os.path.dirname(os.path.dirname(recipes_cfg_path)))
228 cwd=os.path.abspath(os.path.dirname(__file__))).strip())
229 repo_root = os.path.abspath(repo_root).
decode()
230 recipes_cfg_path = os.path.join(repo_root,
'infra',
'config',
'recipes.cfg')
231 args = [
'--package', recipes_cfg_path] + args
232 engine_path =
checkout_engine(engine_override, repo_root, recipes_cfg_path)
234 vpython =
'vpython3' + _BAT
235 if not shutil.which(vpython):
236 return f
'Required binary is not found on PATH: {vpython}'
244 os.environ.pop(
"PYTHONPATH",
None)
247 debugger = os.environ.get(
'RECIPE_DEBUGGER',
'')
248 if debugger.startswith(
'pycharm'):
249 spec =
'.pycharm.vpython3'
250 elif debugger.startswith(
'vscode'):
251 spec =
'.vscode.vpython3'
256 os.path.join(engine_path, spec),
258 os.path.join(engine_path,
'recipe_engine',
'main.py'),
265 signal.signal(signal.SIGBREAK, signal.SIG_IGN)
266 signal.signal(signal.SIGINT, signal.SIG_IGN)
267 signal.signal(signal.SIGTERM, signal.SIG_IGN)
270 os.execvp(argv[0], argv)