# 🧑‍🍳 Cook [![](https://github.com/tillahoffmann/cook-build/actions/workflows/main.yaml/badge.svg)](https://github.com/tillahoffmann/cook-build/actions/workflows/main.yaml) [![](https://img.shields.io/pypi/v/cook-build)](https://pypi.org/project/cook-build)

Cook is a task-centric build system with simple declarative recipes specified in Python.

## Getting Started

Tasks are declared in a `recipe.py` file using the `cook.manager.create_task` function. Each task must have a unique name, may depend on files or other tasks, and can execute an action, typically a shell command. The simple example below creates a C source file, compiles it, and executes the binary.

```python
>>> from cook import create_task

>>> create_task("src", targets=["hello.c"],
...             action="echo 'int main() { return 0; }' > hello.c")
>>> create_task("cc", dependencies=["hello.c"], targets=["hello"],
...             action="cc -o hello hello.c")
>>> create_task("hello", dependencies=["hello"], action="./hello")
```

Running `cook ls` from the command line lists all known tasks, e.g.,

```bash
$ cook ls
<task `src` @ /.../recipe.py:3>
<task `cc` @ /.../recipe.py:6>
<task `hello` @ /.../recipe.py:9>
```

Running `cook exec hello` creates the source file, compiles it, and executes the binary (using `--log-level=debug` can provide additional information).

```bash
$ cook exec hello
INFO: executing <task `src` @ /.../recipe.py:3> ...
INFO: completed <task `src` @ /.../recipe.py:3> in 0:00:...
INFO: executing <task `cc` @ /.../recipe.py:6> ...
INFO: completed <task `cc` @ /.../recipe.py:6> in 0:00:...
INFO: executing <task `hello` @ /.../recipe.py:9> ...
INFO: completed <task `hello` @ /.../recipe.py:9> in 0:00:...
```

To rerun a task, tell Cook to reset it.

```bash
$ cook reset cc
INFO: reset 1 task
```

The full set of available commands can be explored using `cook --help` as shown below.

```bash
$ cook --help
usage: cook [-h] [--recipe RECIPE] [--module MODULE] [--db DB]
            [--log-level {warning,error,info,debug}]
            {exec,ls,info,reset} ...

positional arguments:
  {exec,ls,info,reset}
    exec                Execute one or more tasks.
    ls                  List tasks.
    info                Display information about one or more tasks.
    reset               Reset the status of one or more tasks.

options:
  -h, --help            show this help message and exit
  --recipe RECIPE       file containing declarative recipe for tasks
  --module, -m MODULE   module containing declarative recipe for tasks
  --db DB               database for keeping track of assets
  --log-level {warning,error,info,debug}
                        log level
```

## Tasks Are Dumb; Contexts Are Smart

`cook.task.Task`s do not provide any functionality beyond storing metadata, including

- `targets`, the files generated by the task,
- `dependencies`, the files the task depends on,
- `action`, the `cook.actions.Action` to execute when the task is run,
- `task_dependencies`, other tasks that should be executed first,
- `location`, filename and line number where the task was defined.

All logic is handled by `cook.contexts.Context`s which are applied to each task when it is created. For example, `cook.contexts.create_group` adds all tasks created within the context to a group. This group can be executed to execute all child tasks.
