From 9e1a48d6117be45ef86cc537e515e59df09dfe10 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 4 Jun 2021 23:46:17 -0700 Subject: [PATCH] Modify how the stages and steps work --- README.rst | 20 ++++++++---- bou.py | 96 +++++++++++++++++++++++++++++++++++++++++++++++++----- setup.cfg | 2 +- 3 files changed, 103 insertions(+), 15 deletions(-) diff --git a/README.rst b/README.rst index 3a1be3e..3b01373 100644 --- a/README.rst +++ b/README.rst @@ -20,28 +20,26 @@ Install bou with pip: Running bou ----------- -To run bou, simply call it: +To run bou, simply run the command. The build file will be automatically detected. .. code-block:: $ bou -To specify a build configuration file, use the ``-f`` option: +To specify a build configuration file, use the ``-f`` option. .. code-block:: $ bou -f /path/to/build.yaml -To specify a stage or a step to run, just add it to the command +To specify a stage or a step to run, just add it to the command. Stages take priority over steps, so if you have a +stage and a step with the same name, the stage will be run. .. code-block:: $ bou build $ bou test -.. note:: - - By default, all stages are run, and stages are run in the order in the build configuration file. Task Configuration ------------------ @@ -90,6 +88,16 @@ variables are set. - $PYTHON $SOURCE/setup.py build +Stages and Steps +---------------- + +If no steps or stages are specified, by default bou will attempt to run the following, in order: + + 1. All of the stages in the ``stages`` section of the task configuration + 2. If no stages are specified in the task config, all of the stages discovered in the steps + 3. If no stages are found, all of the steps + + Source Code ----------- diff --git a/bou.py b/bou.py index f7519be..dae323f 100755 --- a/bou.py +++ b/bou.py @@ -13,6 +13,11 @@ ENV_VAR = re.compile(r'(\$([A-Za-z0-9_]+))') def parse_args(): + """ + Parse command line arguments, and return an object with all the arguments + + :return: A namespace object with all the supplied arguments + """ parser = ArgumentParser() parser.add_argument('-f', '--file', dest='build_file', help='Path to the build file') parser.add_argument('stage_or_step', nargs='?', default=None, help='Run a particular stage or step') @@ -20,7 +25,14 @@ def parse_args(): def setup_env(env, base_path): - """Set up the environment dictionary, resolving shell variables""" + """ + Set up the environment dictionary, resolving shell variables + + :param env: The environment list or dictionary + :param base_path: The base path that the build runs in + + :return: A merged dictionary of environment variables + """ if isinstance(env, list): env = {pair.split('=')[0]: pair.split('=')[1] for pair in env} env = dict(BASE_DIR=str(base_path), **env) @@ -33,13 +45,28 @@ def setup_env(env, base_path): def setup_step(config, step_name): - """Prepare a step for usage""" + """ + Prepare a step for usage + + :param config: The build configuration + :param step_name: The name of the step to prepare + + :return: A step object + """ step = config['steps'][step_name] step['environment'] = config.get('environment', []) + step.get('environment', []) return step def get_steps_for_stage(config, stage_name): + """ + Get all the steps for a particular stage + + :param config: The build configuration + :param stage_name: The name of the stage + + :return: A list of step objects + """ steps = [] for step_name in config['steps'].keys(): if config['steps'][step_name]['stage'] == stage_name: @@ -48,6 +75,14 @@ def get_steps_for_stage(config, stage_name): def run_step(step, base_path): + """ + Run a particular step + + :param step: The step (as a dictionary) + :param base_path: The base path to run this in + + :return: Return True if the step passed, or False if the step failed + """ script = step['script'] if isinstance(script, list): script = os.linesep.join(script) @@ -60,14 +95,49 @@ def run_step(step, base_path): def run_stage(config, stage_name, base_path): + """ + Run all the steps in a particular stage + + :param config: The build configuration + :param stage_name: The stage to run + :param base_path: The base path of the build + """ for step in get_steps_for_stage(config, stage_name): result = run_step(step, base_path) if not result: break +def get_all_stages(config): + """ + Return all the stages available in the build configuration + + :param config: The build configuration + + :return: A list of stages + """ + stages = config.get('stages', []) + for step_name, step in config['steps'].items(): + if step['stage'] not in stages: + stages.append(step['stage']) + return stages + + +def get_all_steps(config): + """ + Return all the steps available in the build configuration + + :param config: The build configuration + + :return: A list of steps + """ + return list(config.get('steps', {}).keys()) + + def get_build_file(): - """Determine the local build file""" + """ + Determine the local build file + """ base_path = Path.cwd() for child in base_path.iterdir(): if child.name in BUILD_FILES: @@ -76,7 +146,9 @@ def get_build_file(): def main(): - """Run the build system""" + """ + Run the build system + """ args = parse_args() if args.build_file: build_file = Path(args.build_file).resolve() @@ -87,18 +159,26 @@ def main(): return 1 base_path = build_file.parent config = yaml.full_load(build_file.open()) + all_stages = get_all_stages(config) + all_steps = get_all_steps(config) if args.stage_or_step: - if args.stage_or_step in config['stages']: + if args.stage_or_step in all_stages: run_stage(config, args.stage_or_step, base_path) - elif args.stage_or_step in config['steps'].keys(): + elif args.stage_or_step in all_steps: step = setup_step(config, args.stage_or_step) run_step(config, step, base_path) else: print('"{stage}" is not a valid stage or step name'.format(stage=args.stage_or_step)) return 2 else: - for stage_name in config['stages']: - run_stage(config, stage_name, base_path) + stages = config.get('stages', all_stages) + if stages: + for stage_name in stages: + run_stage(config, stage_name, base_path) + else: + for step_name in all_steps: + step = setup_step(config, step_name) + run_step(config, step, base_path) return 0 diff --git a/setup.cfg b/setup.cfg index f7679b4..fefd0f8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = bou -version = 0.0.1 +version = 0.0.2 author = Raoul Snyman author_email = raoul@snyman.info description = Simple YAML-driven build or task runner