Modify how the stages and steps work #1
20
README.rst
20
README.rst
@ -20,28 +20,26 @@ Install bou with pip:
|
|||||||
Running bou
|
Running bou
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
To run bou, simply call it:
|
To run bou, simply run the command. The build file will be automatically detected.
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
$ bou
|
$ bou
|
||||||
|
|
||||||
To specify a build configuration file, use the ``-f`` option:
|
To specify a build configuration file, use the ``-f`` option.
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
$ bou -f /path/to/build.yaml
|
$ 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::
|
.. code-block::
|
||||||
|
|
||||||
$ bou build
|
$ bou build
|
||||||
$ bou test
|
$ bou test
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
By default, all stages are run, and stages are run in the order in the build configuration file.
|
|
||||||
|
|
||||||
Task Configuration
|
Task Configuration
|
||||||
------------------
|
------------------
|
||||||
@ -90,6 +88,16 @@ variables are set.
|
|||||||
- $PYTHON $SOURCE/setup.py build
|
- $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
|
Source Code
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
94
bou.py
94
bou.py
@ -13,6 +13,11 @@ ENV_VAR = re.compile(r'(\$([A-Za-z0-9_]+))')
|
|||||||
|
|
||||||
|
|
||||||
def parse_args():
|
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 = ArgumentParser()
|
||||||
parser.add_argument('-f', '--file', dest='build_file', help='Path to the build file')
|
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')
|
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):
|
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):
|
if isinstance(env, list):
|
||||||
env = {pair.split('=')[0]: pair.split('=')[1] for pair in env}
|
env = {pair.split('=')[0]: pair.split('=')[1] for pair in env}
|
||||||
env = dict(BASE_DIR=str(base_path), **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):
|
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 = config['steps'][step_name]
|
||||||
step['environment'] = config.get('environment', []) + step.get('environment', [])
|
step['environment'] = config.get('environment', []) + step.get('environment', [])
|
||||||
return step
|
return step
|
||||||
|
|
||||||
|
|
||||||
def get_steps_for_stage(config, stage_name):
|
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 = []
|
steps = []
|
||||||
for step_name in config['steps'].keys():
|
for step_name in config['steps'].keys():
|
||||||
if config['steps'][step_name]['stage'] == stage_name:
|
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):
|
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']
|
script = step['script']
|
||||||
if isinstance(script, list):
|
if isinstance(script, list):
|
||||||
script = os.linesep.join(script)
|
script = os.linesep.join(script)
|
||||||
@ -60,14 +95,49 @@ def run_step(step, base_path):
|
|||||||
|
|
||||||
|
|
||||||
def run_stage(config, stage_name, 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):
|
for step in get_steps_for_stage(config, stage_name):
|
||||||
result = run_step(step, base_path)
|
result = run_step(step, base_path)
|
||||||
if not result:
|
if not result:
|
||||||
break
|
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():
|
def get_build_file():
|
||||||
"""Determine the local build file"""
|
"""
|
||||||
|
Determine the local build file
|
||||||
|
"""
|
||||||
base_path = Path.cwd()
|
base_path = Path.cwd()
|
||||||
for child in base_path.iterdir():
|
for child in base_path.iterdir():
|
||||||
if child.name in BUILD_FILES:
|
if child.name in BUILD_FILES:
|
||||||
@ -76,7 +146,9 @@ def get_build_file():
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Run the build system"""
|
"""
|
||||||
|
Run the build system
|
||||||
|
"""
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
if args.build_file:
|
if args.build_file:
|
||||||
build_file = Path(args.build_file).resolve()
|
build_file = Path(args.build_file).resolve()
|
||||||
@ -87,18 +159,26 @@ def main():
|
|||||||
return 1
|
return 1
|
||||||
base_path = build_file.parent
|
base_path = build_file.parent
|
||||||
config = yaml.full_load(build_file.open())
|
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:
|
||||||
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)
|
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)
|
step = setup_step(config, args.stage_or_step)
|
||||||
run_step(config, step, base_path)
|
run_step(config, step, base_path)
|
||||||
else:
|
else:
|
||||||
print('"{stage}" is not a valid stage or step name'.format(stage=args.stage_or_step))
|
print('"{stage}" is not a valid stage or step name'.format(stage=args.stage_or_step))
|
||||||
return 2
|
return 2
|
||||||
else:
|
else:
|
||||||
for stage_name in config['stages']:
|
stages = config.get('stages', all_stages)
|
||||||
|
if stages:
|
||||||
|
for stage_name in stages:
|
||||||
run_stage(config, stage_name, base_path)
|
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
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
name = bou
|
name = bou
|
||||||
version = 0.0.1
|
version = 0.0.2
|
||||||
author = Raoul Snyman
|
author = Raoul Snyman
|
||||||
author_email = raoul@snyman.info
|
author_email = raoul@snyman.info
|
||||||
description = Simple YAML-driven build or task runner
|
description = Simple YAML-driven build or task runner
|
||||||
|
Loading…
Reference in New Issue
Block a user