Dovetail FAQ

Invoking Dovetail from the command line

How do I...

... shorten the command-line if I keep using the same arguments?

You can set up default arguments in Configuration files.

... switch off configuration file items from the command line?

(for example, when I have set nested to true/a task/virtualenv/etc in the Dovetail configuration file)

All the Dovetail configuration file options (except clear) can be disabled from the command line:

  • Use -nn to disable nesting
  • -e '' or --virtualenv '' to disable virtualenv
  • dovetail '' will print the list of tasks in the build file (you must include the '' otherwise the default task will run)

... set environment variable values so they are visible to all tasks?

Set up a configuration file and set them in the [Environment] section. See configuration-files.

... tell what kind of error Dovetail failed with?

The Dovetail command line process returns the following value as it exits:

  • 0: Successful build/print warranty/print license

  • 1: Build failed due to an error in the build, for example:
    • Task raising an exception or
    • a directive failing a Task (e.g. @fail_if_skipped)
  • 2: Invalid command line options (syntax error)

  • 32-63: Semantic error or environment error in command line options

  • 32: General error; no task specified

  • 33: Invalid build file - it does not exist, is not a Python file or is otherwise invalid

  • 34: Invalid virtual environment specified (doesn’t exist or cannot be created)

  • 35: Invalid Task specified. Doesn’t exist in the build file

  • 254: Bootstrap failure: unable to start dovetail in a virtual environment

  • 255: System failure running build

Detecting the build environment

How do I...

... determine if I am running in Dovetail?

Check if environment variable DOVETAIL_VERSION is set.

... run/skip tasks on different platforms? OS? Python versions?

Dovetail sets a number of Environment variables that can be interrogated with the Env predicate in a @do_if or @skip_if

Developing tasks

How do I...

... pass arguments to a task?

Dovetail does not support function arguments in tasks.

Instead we recommend passing values between tasks:

  • within the same file - use global variables
  • between different build files - use environment variables.

... fail a running task - should I raise an exception?

Yes - that is a great way of failing the task. Remember to include a descriptive error message. This is discussed in Exception thrown within a task.

You can also build logic into a @fail_if directive, but this will run only after your function has completed.

Files and directories

How do I...

... create a build script with a filename not ending in .py?

You cannot - it’s a rule in Python that all Python source files must have the .py extension. Since a build file is just a Python script, Dovetail inherits this rule.

... include a build file in the parent directory of the master build file

Simple answer: The design of the build requires that the entire build occurs in or under the directory of the main build file. This is a design limitation to ensure that all loaded tasks have valid, non-conflicting Python package names.

Complex answer: You can still import python files from the Python system path, and these will be recognized by Dovetail for basic functions. However:

  • These imports do require that there is an __init__.py file present which make the directory look like package source.

  • BuildModule (the Dovetail loader) will not load tasks from such files

  • And therefore, to use functions in the import, you would need to wrap them in a function in the build file that is doing the import, eg:

    import my_package
    
    @task
    def imported_task():
        return my_package.my_task()
    

... find the build root from within a build script?

When a build is started, the build root is set in the environment variable DOVETAIL_BUILD_ROOT.

The build may be different from the parent directory of __file__ if the build script is loaded by a master build script (either in the same directory or perhaps in a parent directory). So, given on which script is run, the build root for a given task may be different. Beware!

... know which directory a task will run in?

Just before the main body of a task is run, Dovetail ensures that the current working directory (:func:os.getcwd) is the directory in which the build script is located (__file__).

You can modify this behaviour with the @cwd directive.

... get a task to run in the calling task’s directory?

Add the directive: @cwd(None)

This tells Dovetail to switch off the working directory functionality for that task.

Virtualenv

How do I...

... pass additional configuration arguments to Virtualenv?

Dovetail has direct support for only the --clear parameter of virtualenv. If you need to pass more specific parameters, you can use one of several techniques documented by virtualenv:

  • Environment variables , eg VIRTUALENV_USE_DISTRIBUTE=true is exactly the same as using the --distribute command line option.
  • virtualenv.ini configuration file containing the settings.

... use a virtualenv bootstrap script?

This is not yet implemented.

Developing predicates and directives

... Get more expressive messages from @do_if, @fail_if and @skip_if?

Dovetail’s @do_if, @skip_if and @fail_if directives take an optional extra argument - message - for this purpose. For example:

@skip_if(predicate_1, predicate_2, …, message="Zorg application is partially installed")

Alternatively, you can define your own Predicate callable and customize the __str__ method, e.g.:

class ZorgFullyInstalled(object):
    def __call__(self):
         # Your logic here

    def __str__(self):
         return "Zorg is installed"

... fail a custom predicate or directive?

If you want to fail a task, you can throw an exception in the task. However, if you have written your own predicate or directive, there are two types of error condition:

  1. Normal condition: Where the system meets a condition expected by the developer or the predicate or directive, and the predicate or directive can’t continue, but this situation is expected. For example, the directive needs a file in a particular location, but it’s missing.

    In this case, call Execution.fail() to mark the task as failed. The current task will be marked as FAILED, and the build will fail in the normal manner.

    Do not throw an exception.

  2. Fatal error: Where there is an unexpected exception, that is the developer of the predicate or directive did not know that this condition would happen, by definition it’s not going to be handled. Let this exception propagate. This will cause Dovetail to fail with a system exception as described in Errors in Dovetail or third-party decorators or predicates. Note that, in this case, the post-actions of the task and parent tasks will not be called.