Detect uninstalled dot (graphviz)

This patch detects certain errors (tested on Debian) so that if graphviz
is not installed and we try to run dot(1) the error message is more
helpful than the raw backtrace itself.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Detect unreachable steps

This patch raises UnreachableStep when constructing a flow class that
has provably unreachable steps. Such steps are probably mistakes and
should be detected by the framework.

This doesn't handle subclasses well, in the sense that if a subclass
somehow decides to alter step connections there's no way to say "this
step is dead". Such facility can be added later on though.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Fix step level assignment

This patch rewrites the algorithm used to assign step levels to actually
make it work in cases where some steps have pre-assigned levels. The
previous algorithm maintained a work list but stopped exploring as soon
as a step with a non-None level was detected. This would fail on a
simple flow like the one shown below:

 A --> B --> C

 B has pre-assigned level = 1

The new algorithm has two passes. The first pass collects all of the
pre-assigned levels and appends them as work items to a work list, while
re-setting the level of each step to None. The initial step is special
in that it has an implicit level of 1, unless overridden by explicit
level assignment.

The algorithm then proceeds to work through the work list, ensuring to
visit steps which had pre-assigned levels before visiting any other
step. At each iteration one element of the work list is removed, the
step it refers to gets level assigned (using value from the work list).
Then, still within the iteration, the algorithm appends more work items
that correspond to steps which are reachable from the current step, that
have no level assignment yet. The algorithm stops when all the work
items have been exhausted.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Allow Flow() to take arbitrary arguments

This patch allows Flow initializer to consume arbitrary keyword
arguments. Such arguments are converted to flow-wide initial state. This
makes it useful for passing 'flow arguments' easily.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Split up main to distinct functions

This patch splits the main() function into a number of dedicated
functions that make it possible to embed arrowhead runner in an existing
argparse-based application.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Bump version to 1.0a2

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Add more stuff to .gitignore

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>