| Index: recipe_engine/autoroll.py
|
| diff --git a/recipe_engine/autoroll.py b/recipe_engine/autoroll.py
|
| index ca3b71ccc4c4940873ec83c92e8832851128f803..980e62f6c35d43353c04b58647984aa5af1f5f35 100644
|
| --- a/recipe_engine/autoroll.py
|
| +++ b/recipe_engine/autoroll.py
|
| @@ -12,6 +12,8 @@ import sys
|
| from . import package
|
|
|
|
|
| +NUL = open(os.devnull, 'w')
|
| +
|
| ROOT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')
|
|
|
|
|
| @@ -23,7 +25,98 @@ def default_json_encode(o):
|
| return repr(o)
|
|
|
|
|
| -def run_simulation_test(repo_root, package_spec, additional_args=None):
|
| +# This is the path within the recipes-py repo to the per-repo recipes.py script.
|
| +# Ideally we'd read this somehow from each candidate engine repo version, but
|
| +# for now assume it lives in a fixed location within the engine.
|
| +RECIPES_PY_REL_PATH = ('doc', 'recipes.py')
|
| +
|
| +# These are the lines to look for in doc/recipes.py as well as the target repo's
|
| +# copy of that file. Any lines found between these lines will be replaced
|
| +# verbatim in the new recipes.py file.
|
| +EDIT_HEADER = '#### PER-REPO CONFIGURATION (editable) ####\n'
|
| +EDIT_FOOTER = '#### END PER-REPO CONFIGURATION ####\n'
|
| +
|
| +
|
| +def write_new_recipes_py(context, spec, repo_cfg_block):
|
| + """Uses the doc/recipes.py script from the currently-checked-out version of
|
| + the recipe_engine (in `context`) as a template, and writes it to the
|
| + recipes_dir of the destination repo (also from `context`). Replaces the lines
|
| + between the EDIT_HEADER and EDIT_FOOTER with the lines from repo_cfg_block,
|
| + verbatim.
|
| +
|
| + Args:
|
| + context (PackageContext) - The context of where to find the checked-out
|
| + recipe_engine as well as where to put the new recipes.py.
|
| + spec (PackageSpec) - The rolled spec (result of
|
| + RollCandidate.get_rolled_spec())
|
| + repo_cfg_block (list(str)) - The list of lines (including newlines)
|
| + extracted from the repo's original recipes.py file (using the
|
| + extract_repo_cfg_block function).
|
| + """
|
| + source_path = os.path.join(spec.deps['recipe_engine'].path,
|
| + *RECIPES_PY_REL_PATH)
|
| + dest_path = os.path.join(context.recipes_dir, 'recipes.py')
|
| + with open(source_path, 'rb') as source:
|
| + with open(dest_path, 'wb') as dest:
|
| + for line in source:
|
| + dest.write(line)
|
| + if line == EDIT_HEADER:
|
| + break
|
| + dest.writelines(repo_cfg_block)
|
| + for line in source:
|
| + if line == EDIT_FOOTER:
|
| + dest.write(line)
|
| + break
|
| + dest.writelines(source)
|
| + if sys.platform != 'win32':
|
| + os.chmod(dest_path, os.stat(dest_path).st_mode|0111)
|
| +
|
| +
|
| +def extract_repo_cfg_block(context):
|
| + """Extracts the lines between EDIT_HEADER and EDIT_FOOTER from the
|
| + to-be-autorolled-repo's recipes.py file.
|
| +
|
| + Args:
|
| + context (PackageContext) - The context of where to find the repo's current
|
| + recipes.py file.
|
| +
|
| + Returns list(str) - The list of lines (including newlines) which occur between
|
| + the EDIT_HEADER and EDIT_FOOTER in the repo's recipes.py file.
|
| + """
|
| + recipes_py_path = os.path.join(context.recipes_dir, 'recipes.py')
|
| + block = []
|
| + with open(recipes_py_path, 'rb') as f:
|
| + in_section = False
|
| + for line in f:
|
| + if not in_section and line == EDIT_HEADER:
|
| + in_section = True
|
| + elif in_section:
|
| + if line == EDIT_FOOTER:
|
| + break
|
| + block.append(line)
|
| + if not block:
|
| + raise ValueError('unable to find configuration section in %r' %
|
| + (recipes_py_path,))
|
| + return block
|
| +
|
| +
|
| +def fetch(repo_root, package_spec):
|
| + """
|
| + Just fetch the recipes to the newly configured version.
|
| + """
|
| + # Use _local_ recipes.py, so that it checks out the pinned recipe engine,
|
| + # rather than running recipe engine which may be at a different revision
|
| + # than the pinned one.
|
| + args = [
|
| + sys.executable,
|
| + os.path.join(repo_root, package_spec.recipes_path, 'recipes.py'),
|
| + 'fetch',
|
| + ]
|
| + subprocess.check_call(args, stdout=NUL, stderr=NUL)
|
| +
|
| +
|
| +def run_simulation_test(repo_root, package_spec, additional_args=None,
|
| + allow_fetch=False):
|
| """
|
| Runs recipe simulation test for given package.
|
|
|
| @@ -35,8 +128,10 @@ def run_simulation_test(repo_root, package_spec, additional_args=None):
|
| args = [
|
| sys.executable,
|
| os.path.join(repo_root, package_spec.recipes_path, 'recipes.py'),
|
| - 'simulation_test',
|
| ]
|
| + if not allow_fetch:
|
| + args.append('--no-fetch')
|
| + args.append('simulation_test')
|
| if additional_args:
|
| args.extend(additional_args)
|
| p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
| @@ -50,6 +145,8 @@ def process_candidates(candidates, context, config_file, package_spec):
|
| trivial = None
|
| picked_roll_details = None
|
|
|
| + repo_cfg_block = extract_repo_cfg_block(context)
|
| +
|
| print('looking for a trivial roll...')
|
|
|
| # Fill basic information about all the candidates. In later loops
|
| @@ -67,7 +164,11 @@ def process_candidates(candidates, context, config_file, package_spec):
|
| for i, candidate in enumerate(candidates):
|
| print(' processing candidate #%d... ' % (i + 1), end='')
|
|
|
| - config_file.write(candidate.get_rolled_spec().dump())
|
| + spec = candidate.get_rolled_spec()
|
| + config_file.write(spec.dump())
|
| + fetch(context.repo_root, package_spec)
|
| + write_new_recipes_py(context, spec, repo_cfg_block)
|
| +
|
| rc, output = run_simulation_test(context.repo_root, package_spec)
|
| roll_details[i]['recipes_simulation_test'] = {
|
| 'output': output,
|
| @@ -91,7 +192,10 @@ def process_candidates(candidates, context, config_file, package_spec):
|
| for i, candidate in reversed(list(enumerate(candidates))):
|
| print(' processing candidate #%d... ' % (i + 1), end='')
|
|
|
| - config_file.write(candidate.get_rolled_spec().dump())
|
| + spec = candidate.get_rolled_spec()
|
| + config_file.write(spec.dump())
|
| + fetch(context.repo_root, package_spec)
|
| + write_new_recipes_py(context, spec, repo_cfg_block)
|
|
|
| rc, output = run_simulation_test(
|
| context.repo_root, package_spec, ['train'])
|
| @@ -164,7 +268,8 @@ def main(args, repo_root, config_file):
|
| # Restore initial state. Since we could be running simulation tests
|
| # on other revisions, re-run them now as well.
|
| config_file.write(package_spec.dump())
|
| - run_simulation_test(context.repo_root, package_spec, ['train'])
|
| + run_simulation_test(context.repo_root, package_spec, ['train'],
|
| + allow_fetch=True)
|
|
|
| if args.output_json:
|
| with open(args.output_json, 'w') as f:
|
|
|