🧑‍🍳 Cook
==========

.. image:: https://github.com/tillahoffmann/cook-build/actions/workflows/main.yaml/badge.svg
    :target: https://github.com/tillahoffmann/cook-build/actions/workflows/main.yaml
.. image:: https://img.shields.io/pypi/v/cook-build
    :target: 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 :code:`recipe.py` file using the :func:`~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.

.. doctest::

    >>> from cook import create_task

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

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

.. shtest::
    :cwd: examples/getting_started

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

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

.. shtest::
    :cwd: examples/getting_started
    :stderr:

    $ 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.

.. shtest::
    :cwd: examples/getting_started
    :stderr:

    $ cook reset cc
    INFO: reset 1 task

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

.. sh:: cook --help

Tasks Are Dumb; Contexts Are Smart
----------------------------------

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

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

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

.. toctree::
    :hidden:
    :maxdepth: 1

    docs/interface
