A tiny build automation tool.
Project description
Coxbuild is a tiny python-script-based build automation tool, an alternative to make, psake and so on.
Supported features:
- Task
- Dependency
- Pre / Post condition
- Lifecycle hooks
- Setup / Teardown
- Before / After
- Event-based build as a long-run service
Extensions:
- Python
- Shell
- Git
- Node.js
- .NET
Install
pip install coxbuild
Usage
Coxbuild build itself by itself, see here for details.
Write Schema (buildcox.py)
from coxbuild.schema import task, depend # this line can be omitted
@task()
def pre():
print("pre task")
@depend(pre)
@task()
def default():
pass
Run
coxbuild
[-D <working directory = '.'>]
[-f <file name = 'buildcox.py'>]
[task names = 'default']
# Run default schema and default task
coxbuild
# equivalent to
coxbuild -D . -f buildcox.py default
# Run in other directory
coxbuild -D path/to/other
# Run using other file
coxbuild -f other.py
# Run specified task
coxbuild task1 task2
Schema Specification
Task
Use task
decorator to define a (named) task.
@task()
def use_function_name_as_task_name(): pass
@task("custom-task-name")
async def use_custom_name():
"""task document"""
pass
@task()
async def cost_time():
print("cost time")
await asyncio.sleep(0.5)
# default task
@task()
def default(): pass
Task can have parameters, see Before/After Hook section for details.
Do NOT use
setup
andteardown
as task parameter name. These parameter names are used by coxbuild.
Builtin tasks:
Name | Description |
---|---|
:list |
List all defined tasks |
:serve |
Start event-based service |
Dependency
Use depend
decorator to define task dependency (you can use full name or instance of the task).
@task()
def t1(): pass
@task("t2")
def t2(): pass
@depend("t1", t2)
@task()
def default(): pass
Group
Use group
decorator to add namespace to task names (prevent from name conflicting).
ns1task = group("ns1")
ns2task = group("ns2")
# task name: 'ns1:name'
@ns1task()
def name(): pass
# task name: 'ns2:name'
@ns2task()
def name(): pass
group
can be nested.
nstask = group("ns1", group("sub"))
# task name: 'ns1:sub:name'
@nstask()
def name(): pass
Pre/Post Condition
Use precondition
to decide whether to run the task, and use postcondition
to check the task works well.
@precond(lambda: True)
@postcond(lambda: True)
@task()
def t(): pass
Before/After Hook
Use before
hook to do something before task initializing, configure task arguments and decide whether to run the task.
Use after
hook to do something after task finishing, and check task result.
@before(task1)
def before_task1(context: TaskContext):
print(context.task.name)
context.args.extend([1, 2, 3])
context.kwds.update(a=1, b=2)
# return False to ignore this task
@after(task1)
def after_task1(context: TaskContext, result: TaskResult):
pass
Use
before
andafter
decorator with NO arguments to hook pipeline events.
Use pipeline before
/after
hooks to configure and check all tasks globally.
@before()
def pipeline_before(context: TaskContext):
if context.task.name != "default":
context.args.extend(["a", "b", "c"])
context.kwds.update(p="p")
# return False to ignore this task
@after()
def pipeline_after(context: TaskContext, result: TaskResult):
pass
Setup/Teardown
Use setup
hook to do something before task body (in task execution scope).
Use teardown
hook to do something after task body (in task execution scope, even some exception raises in task body).
These hooks have the same parameters as the task body.
@setup(task2)
def setup_task2(*args, **kwds):
pass
@teardown(task1)
def teardown_task1(*args, **kwds):
pass
Use
setup
andteardown
decorator with NO arguments to hook pipeline events.
Use setup
hook to do something before pipeline, and decide whether to run the pipeline.
Use teardown
hook to do something after pipeline, and check pipeline result.
@setup()
def setup_pipeline(context: PipelineContext):
# return False to cancel pipeline
pass
@teardown()
def teardown_pipeline(context: PipelineContext, result: PipelineResult):
pass
Lifecycle Events
The execution scope in written in parentheses.
- Pipeline Setup (Pipeline)
- Task 1
- Pipeline Before (Pipeline)
- Task Before (Pipeline)
- Task Precondition (Task)
- Task Setup (Task)
- Task Body (Task)
- Task Teardown (Task)
- Task Setup (Task)
- Task Postcondition (Task)
- Task Precondition (Task)
- Task After (Pipeline)
- Task Before (Pipeline)
- Pipeline After (Pipeline)
- Pipeline Before (Pipeline)
- Task 2
- ... (as same as Task 1)
- Task 1
- Pipeline Teardown (Pipeline)
Go here to see how to hook these events and how they work.
# See how lifecycle events occur
coxbuild -D test/demo -f lifecycle.py
Event
You can schedule some build when event occurs.
Coxbuild provides some builtin events in coxbuild.events
module, each event return an awaitable iterator, i.e. event generator.
The event handlers are running asynchronously, so use async function and asyncio.sleep()
instead of sync time.sleep()
.
from coxbuild.events import repeat, onceevent, once
from coxbuild.events.datetime import attime
@onceevent
async def e():
print(datetime.now())
await asyncio.sleep(0.5)
@on(repeat(e, 2))
def do():
print(datetime.now())
print("done")
@on(once(attime(datetime.now() + timedelta(seconds=1))))
def do_pipeline_at_next_second():
pipeline("task1", task2)
@on(delay(timedelta(seconds=1)))
async def async_handler():
print("before")
await asyncio.sleep(1)
print("after")
Example for watching filesystem changes, see here.
To start the long-run service, use builtin task :serve
.
coxbuild :serve
Library
Task
Use Task to do something and get result with running metadata (exception, duration, and so on).
task: Task
# execute task individually (no pipeline, without dependencies and registered hooks)
result = await task(
*args, **kwds,
setup=setup_hook,
teardown=teardown_hook)
Pipeline
Use Pipeline to run managed tasks with dependencies and hooks.
You can access the default pipeline by variable pipeline
in schema.
pipeline: Pipeline
tasklist: list[Task|str] = [task1, "task2"]
# execute tasks and their dependencies
result = await pipeline(*tasklist)
Extensions
Python
import coxbuild.extensions.python.all
Shell
import coxbuild.extensions.shell
Node.js
import coxbuild.extensions.nodejs
.NET
import coxbuild.extensions.dotnet
Git
import coxbuild.extensions.git
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.