===========
Hello World
===========

The first thing to do is to create a Taskblaster repository.
This can be done with `tb init` command:

.. tbinit:: hello_world

.. tbshellcommand:: tb init

This will create a directory called `tree/` which eventually will contain all of the
tasks. It will also create a hidden `.taskblaster` directory. This directory contains
the registry database where metadata, such as the state of each task, is stored for efficient access.
The user should never edit any files in this directory on their own.

You may view several other important paths using the `tb info` command:

.. tbshellcommand:: tb info

A simple workflow with a single task
-------------------------------------

Create a file called workflow.py:

.. tbfile:: workflow.py

.. literalinclude:: workflow.py

Here the class `Workflow` is the workflow that will be executed. It contains
a single task `hello` which will run the Python function `greet` with the
kwargs `greeting` and `whom` defined by the input to the workflow. The function
`greet` is assumed to be located in a file `tasks.py` in the main working
directory. The function `workflow` defines that the `Workflow` class should
be executed using the default argument for greeting and whom='`world`'.

The next step is thus to create the file called `tasks.py` with the function `greet`.

.. tbfile:: tasks.py

.. literalinclude:: tasks.py

You can now run the workflow:

.. tbshellcommand:: tb workflow workflow.py

This generates some tasks.  To see at any time what tasks are there, use:

.. tbshellcommand:: tb ls

You can see that a task `hello` has been created and added to the tree.

Use ``tb view <path to view>`` to see more detailed information about tasks:

.. tbshellcommand:: tb view .

Here you can e.g. see the status of the task and what input arguments that were
provided. Note that the task has only been added to the tree and has not yet
been executed (it is  in the `new` state).

To execute the task you need to run it using the `tb run` command:

.. tbshellcommand:: tb run .

ls shows it is now in the `done` state:

.. tbshellcommand:: tb ls

You can now view the output:

.. tbshellcommand:: tb view .

Congratulations, you finished your first small TaskBlaster workflow!

Adding new Tasks
----------------

To add a new task to an existing workflow tree we edit the original
`workflow.py` script and save it to a new file `workflow2.py`.

.. tbfile:: workflow2.py

.. literalinclude:: workflow2.py

You can now see what happens when you run the workflow:

.. tbshellcommand:: tb workflow workflow2.py

Try running ls:

.. tbshellcommand:: tb ls

As you can see, the old task `hello` is still `done`, but there is a new task in
the `new` state in the tree.


Run the new task

.. tbshellcommand:: tb run .

.. tbshellcommand:: tb ls

The task is now marked as `done` and you can view the output with `tb view`.


.. _conflict_tutorial:

Creating a conflict
--------------------

We will now investigate what happens if we change the input to the workflow.
Change the input argument `whom` in `workflow2.py`

.. tbfile:: workflow3.py

.. literalinclude:: workflow3.py

and save it as a new file `workflow3.py`.

Now run the workflow

.. tbshellcommand:: tb workflow workflow3.py

You are informed that there is a conflict for the task `hello`.
You can also view the information about the conflict using the `ls` command

.. tbshellcommand:: tb ls -c sfcC

The additional argument `-c sfcC` specifies that we want to see the state,
directory, conflict state and conflict info (try `tb ls --help` to see all
options). From the output we can see which state that has a conflict and what
the previous input to the function was. Note that the `state` of the task is
still `done`, so no output files have been deleted. The conflict state is
merely information to the user on which tasks that are affected by the change
of input parameters. We can choose to change the conflict state to `resolved`,
meaning that we have noticed that there is a conflict but want to continue to
do calculations for this task based on the old input parameters.

.. tbshellcommand:: tb resolve tree/hello

.. tbshellcommand:: tb ls -csfcC

The conflict state has now changed to `resolved`. If we change our minds we can
mark it as conflict again

.. tbshellcommand:: tb unresolve tree/hello

.. tbshellcommand:: tb ls -csfcC

If we decide that we still want to go with the old input parameters we can run
the old workflow again.

.. tbshellcommand:: tb workflow workflow2.py

.. tbshellcommand:: tb ls -csfcC

and we can see that the conflict has disappeared.

However, suppose we want to run the task with the new input. We then have to
unrun the task to first put it in the new state. This will delete the output
from the task.

.. tbshellcommand:: tb unrun tree/hello --force

.. tbshellcommand:: tb ls -csfcC

The task is now in the new state. Rerun workflow3 to apply the new input parameters:

.. tbshellcommand:: tb workflow workflow3.py

You can now see that the conflict has disappeared and the state has changed
to `new`. With `tb view` you can also verify that the output has been deleted.
It is now possible to run the task with the new input parameters:

.. tbshellcommand:: tb run tree/hello

and verify that the input as well as output has been updated

.. tbshellcommand:: tb view tree/hello
