saker.build Documentation TaskDoc JavaDoc Packages
Task context is the primary interface for tasks to interact with the build runtime.

Task context provides the functions to handle task execution appropriately. The task context is responsible for, but not limited to providing the following functionality:

  • Starting tasks
  • Getting task results and handling dependencies
  • Providing access to task deltas
  • Reporting dependencies (e.g. file, task, etc...)
  • Providing access to task related I/O
  • Specifying work directories (e.g. build and working directory)
  • Accessing outputs from previous runs
  • File mirroring to local storage
  • Performing other task execution related operations

Each executed task have their own private task context.

Each task is run with a non-empty set of build deltas that triggered its execution. For tasks which are executed for the first time, DeltaType.NEW_TASK is used. For tasks which already run previously will have their build deltas calculated. Deltas can be semantically separated into two categories:

  • Executional deltas
  • File change deltas

Executional deltas are related to task execution control. See possible DeltaType enumerations which do not have FILE in their names.

File deltas which represent any file related changes compared to the last execution.

Important aspect of deltas is that they are calculated in two phases. First any non-file deltas are determined (e.g. checking property dependency changes, checking if any input dependency task has changed, etc...), then if no changes were detected, file deltas will be calculated. If there are any non-file deltas, then the computation of the file deltas will be deferred until they are accessed by the executed task.
By keeping this in mind, task implementations should wait for any input tasks first, and after that they should check for any file related changes. (This workflow should be kept even when deltas are not accessed. Wait for input tasks first, then examine files.)

We can examine the importance of this by taking a look at the following example:

The duty of task A is to create a file based on its configuration, let's say a.txt. Task B has task A as an input dependency, will examine a.txt and produce its result.
Let's assume that both tasks had previous runs, and examine the two scenarios where the above workflow is kept, and violated. The task A and task B is started concurrently in the build system.

  • When the workflow is kept, the task B will start with a delta of DeltaType.TASK_CHANGE as the output task A cannot be determined, and is still running. Task B waits for task A to finish, and checks the file deltas for any change. The file deltas are computed by the build runtime, and a change in a.txt is correctly detected. Task B and A both produce correct outputs.
  • When the workflow is violated: Task B starts, and checks for the file deltas. Task A has not yet finished. The build runtime computes the file deltas, and sees that a.txt still have the same contents as it is expected for task B. Task B will decide that the file is up to date, and wait for task A to finish as it is its input dependency as well. As the tasks run concurrently, task A updates the file a.txt and finishes. The waiting by task B for task A completes, and task B finishes as well.
    In the end we see that task B didn't recalculate its outputs based on the changes of a.txt as it didn't notice the changes for it, because it decided to check the file deltas before waiting for its input dependency tasks.

    This behaviour results in incorrect clean and incremental builds, and will result in ambiguous build results.

As an emphasis one more time, the core workflow for a task consists of first waiting for any input task dependencies, and then handling file related calculations.
If a task decides to have different task input dependencies based on contents of any file, then that is an erroneous implementation.

The build runtime will emit a warning on a best-effort basis (it tries to always check this requirement, but might not always detect it) when this workflow is violated.

Waiting for tasks which you've transitively started from this task itself does not violate this workflow.

Tasks can report file dependencies which state the expected content for a given path. File dependencies can have arbitary nullable tags specified which can be used to semantically partition the files for the task and handle incremental builds more easily. If a file dependency is reported with a given tag, then in case of changes, the resulting FileChangeDelta will have the specified tag assigned to it.

It is also possible to query file deltas based on tags to make the tasks able to work on a set of changes detected by the build runtime.

Simple file tag example based on an use-case for C++ compilation:

The task reports input dependency header files (.h) with the HEADER tag and compilation units (.cpp) with the SOURCE tag.
When the task is next time rerun, it can check for changes in the header files and source files separately. If it sees that no changes occurred to any header files (via getting deltas for the HEADER tag), then it can skip cross-examining which sources used the modified headers. In this case it will only need to get the file deltas for the SOURCE tag and recompile the affected sources.
This mechanism allows easier paralellization, separation of concerns and increased performance.
(See TaskFileDeltas.getFileDeltasWithTag(Object))

Task contexts provide access to a private standard I/O streams for the task. The standard output can be used to provide information to the user during task execution. For more information see getStandardOut(), getStandardErr(), getStandardIn().

The task context provides functions to mirror the files from the in-memory hierarchy to the local file system. File mirroring is the process of taking a file and persisting it to the local file system. This is required as some tasks might choose to implement their features by invoking external processes, which have no access to the in-memory hierarchy.
Good example for this can be C++ compilation: A task would take the source files and header directories, and mirror them to the local file system. As a result of mirroring, the files will have a Path through which they can be accessed externally. The task starts the C++ compiler processes with the received mirror paths as their arguments. After running the compilation, the task can retrieve the results from the file system, and instantiate the in-memory file representation for the build execution.

File mirroring is a necessary feature, as there are scenarios when the in-memory files have no direct local file system file associated with them. One specific scenario for this is when remote execution is used to invoke a task.

The process of file mirroring will not persist a file twice if it has a path that should reside on the local file system. This means that mirroring is basically 'free' performance-wise when a file is local file system compatible, but only needs to do any work when a more complicated build setup is used. The execution context uses the SakerFile synchronization algorithm to persist the mirrored files, so files with same contents will not require unnecessary I/O operations.

The task context provides a way for deriving data from files based on their contents, and caching these datas to be used by multiple tasks. This can be useful when multiple tasks might access the same computed data from files as unnecessary redundant computations can be avoided. See computeFileContentData(SakerFile, FileDataComputer<T>).

Methods of this class may throw (but not required in all cases) IllegalTaskOperationException if it detects that they are being called after the corresponding task execution has finished. References to task contexts should not be retained after the task execution is over.

The getTaskUtilities() method provides access to an utility class which consists of methods that can improve performance when handling multiple dependencies, files, and related operations. The use of this class is especially recommended when designing remote executable tasks.

The TaskUtils static utility class provides utility functions for common operations for tasks.

Clients should not implement this interface.

Methods
public void
Signals an error during the execution of this task to the build runtime.
public void
Acquires the execution-wide lock for accessing the standard I/O.
public <T> T
Computes some data based on a contents of a file.
public ExecutionContext
Gets the execution context which is used to run this task.
public TaskFileDeltas
Gets a file delta collection for all possible file delta types.
public TaskFileDeltas
Gets a file delta collection for the given delta type.
public Set<extends BuildDelta>
Gets the set of deltas which contain no file deltas.
public NavigableMap<SakerPath, SakerFile>
Gets the current state of collected files for a previously reported file addition dependency.
public NavigableMap<SakerPath, ? extends SakerFile>
Gets the current state of previously reported file input dependencies for a given tag.
public NavigableMap<SakerPath, ? extends SakerFile>
Gets the current state of previously reported file output dependencies for a given tag.
public <T> T
Gets the output of the task from the previous run.
public <T> T
Gets the previously set task output for the given tag.
public TaskProgressMonitor
Gets the progress monitor for this task.
public SecretInputReader
Gets the input reader that can be used to read secret input from the user.
public ByteSink
Gets the standard error for this task.
public ByteSource
Gets the standard input for this task.
public ByteSink
Gets the standard output for this task.
public default TaskDependencyFuture<?>
Gets a dependency future handle for the specified task.
public TaskFuture<?>
Gets a future handle for the specified task.
public TaskIdentifier
Gets the task identifier which was used to start this task.
public default Object
Gets the task result for the given task identifier.
public TaskExecutionUtilities
Gets the utility class for this task context.
public void
Notifies the build system that a file at the given path was externally modified.
public ContentDescriptor
Notifies the build system that a file at the given path was externally modified and retrieves the content descriptor for the path.
public default Path
Mirrors a file with all children, recursively if the file is a directory.
public Path
Mirrors a file to the local file system.
public void
Prints a line of string to the standard output of this task.
public void
Releases the previously acquired execution-wide lock for accessing the standard I/O.
public void
Stores a line of string to be replayed for the task if it is not re-run due to no incremental changes.
public <T> void
reportEnvironmentDependency(EnvironmentProperty<T> environmentproperty, T expectedvalue)
Reports an environment dependency for this task to the build runtime.
public <T> void
reportExecutionDependency(ExecutionProperty<T> executionproperty, T expectedvalue)
Reports an execution property dependency for this task to the build runtime.
public void
Reports an IDE configuration for this task.
public void
Reports an unhandled exception that occurred during the execution of the task for informational purposes.
public void
Reports a file addition dependency for this task to the build runtime.
public void
Reports a file input content dependency for this task to the build runtime.
public void
Reports a file output content dependency for this task to the build runtime.
public void
Sets the task output change detector for this task.
public void
setMetaData(String metadataid, Object value)
Sets an arbitrary meta-data as a result of this task.
public void
Sets the line display identifier for this task.
public void
Sets the output of the task for a given tag.
public <R> InnerTaskResults<R>
Starts an inner task to execute in the context of this task.
public <R> TaskFuture<R>
startTask(TaskIdentifier taskid, TaskFactory<R> taskfactory, TaskExecutionParameters parameters)
Starts a task for execution.
public abstract void abortExecution(@RMISerializeThrowable cause) throws NullPointerException
Signals an error during the execution of this task to the build runtime.

Calling this function will set a pending cause exception for the task result. Tasks which retrieve the result of this task will receive this exception.

The execution of this task will continue, and the task may still return an object from the Task.run(TaskContext) method. This task result will not be visible to other tasks, but this task can still retrieve it using getPreviousTaskOutput(Class<T>) when it is run next time.

For inner tasks, calling this function will return this exception via the InnerTaskResultHolder.getExceptionIfAny(), and the inner task may also return an object as a result, which is available via InnerTaskResultHolder.getResult().

Aborting excecution using this functions is preferable to throwing an exception directly when the task is able to handle previously thrown exceptions in the next run.

If the task uses this function to abort, then any results produced by the current run will be visible in the next one. The base for delta calculation will be the current run instead of the last previously successfully finished run.

It is useful to use this function when the task actually finishes its calculations successfully, but it is required to abort due to a semantic build error.

This method may be called multiple times. The first exception that is used to call this method will be the cause of the task execution exception, and any further exceptions will be added as suppressed exceptions.

causeThe abortion cause exception which should be reported.
NullPointerExceptionIf the cause is null.
Acquires the execution-wide lock for accessing the standard I/O.

Acquiring the lock will prevent any access to the standard I/O streams of the execution by other tasks. This means that the locker will have exclusive access to the input and output of the execution. Any output that is produced by concurrent tasks will be written out when this task releases the lock.

The lock is task execution based and not thread based. This means that the lock can be acquired on one thread and can be released on an other thread. Trying to acquire the lock multiple times will result in an exception.

It is recommended to acquire this lock when the task wants to display information that is necessary to be grouped together. Without locking, the lines printed to the output streams might be interlaced with the output of concurrent tasks.

It is required to acquire the lock to access the standard input. If the task wants to read input from the standard input stream and the lock is not acquired, then an exception will be thrown. This is to prevent misalignment of typed data from the user by concurrent output writing, and due to the fact that the standard input is one single shared stream of input for all concurrent tasks.

InterruptedExceptionIf the current thread is interrupted.
TaskStandardIOLockIllegalStateExceptionIf the lock was already acquired by this task.
Computes some data based on a contents of a file.

The execution context will ensure that a given data for a file and a computer is only computed once during an execution.

The computed datas will be cached during the execution. The cache uses the content descriptor, path of the file, and the computer as a key to the cached datas. Files which are not attached to any parents will not have their computed datas cached.

Multiple concurrent computation can run for a given file, but only one computation will run at the same time for file data computers that equal.

TThe computed data type.
fileThe file for data computation.
computerThe computer to use for deriving the data.
The computed data.
IOExceptionIn case of I/O error.
NullPointerExceptionIf any of the parameters are null or the computer computes null value.
RuntimeExceptionIf the data computer throws a runtime exception. The exception is directly relayed to the caller.
Gets the execution context which is used to run this task.
The execution context.
Gets a file delta collection for all possible file delta types.

The returned container will include all file deltas regardless of DeltaType.

Important: Calling this method will trigger the computation of file deltas. Any input dependency tasks should be waited for before calling this method. By waiting for tasks after file delta computation, you risk the file deltas being incorrectly reported which can result in incorrect incremental builds. See TaskContext documentation for more info.

The complete file delta collection.
public abstract TaskFileDeltas getFileDeltas(DeltaType deltatype) throws NullPointerException
Gets a file delta collection for the given delta type.

The resulting container will only include deltas which type matches the given parameter.

If the parameter is not a file change related DeltaType then an empty container will be returned.

Important: Calling this method will trigger the computation of file deltas. Any input dependency tasks should be waited for before calling this method. By waiting for tasks after file delta computation, you risk the file deltas being incorrectly reported which can result in incorrect incremental builds. See TaskContext documentation for more info.

deltatypeThe delta type to match.
The file delta container for the given delta type.
NullPointerExceptionIf the delta type is null.
Gets the set of deltas which contain no file deltas.
An unmodifiable set of non-file deltas.
Gets the current state of collected files for a previously reported file addition dependency.

The resulting map will have the same entries as if the dependency was used to collect the files themselves. The resulting map was used to compute the deltas for the task.

Calling this method instead of collecting the files manually can result in performance increase as it can avoid duplicate computations.

If the file addition dependency was not reported in the previous run, null will be returned.

Important: Calling this method will trigger the computation of file deltas. Any input dependency tasks should be waited for before calling this method. By waiting for tasks after file delta computation, you risk the file deltas being incorrectly reported which can result in incorrect incremental builds. See TaskContext documentation for more info.

dependencyThe previously reported file addition dependency.
An unmodifiable map of files which were collected based on the parameter dependency or null if the dependency was not reported previously.
NullPointerExceptionIf the dependency is null.
Gets the current state of previously reported file input dependencies for a given tag.

The resulting map will have one entry for every input file reported previously. The resulting map contains the files which were used to compute deltas for the task.

It is recommended to get the files using this method if there are no deltas for the given tag, as it can avoid unnecessary computations by the task.

Important: Calling this method will trigger the computation of file deltas. Any input dependency tasks should be waited for before calling this method. By waiting for tasks after file delta computation, you risk the file deltas being incorrectly reported which can result in incorrect incremental builds. See TaskContext documentation for more info.

tagAn arbitrary nullable tag. See TaskContext documentation for more info.
An unmodifiable map of files which were reported as inputs. null values mean the file doesn't exist at a given path.
Gets the current state of previously reported file output dependencies for a given tag.

The resulting map will have one entry for every output file reported previously. The resulting map contains the files which were used to compute deltas for the task.

Important: Calling this method will trigger the computation of file deltas. Any input dependency tasks should be waited for before calling this method. By waiting for tasks after file delta computation, you risk the file deltas being incorrectly reported which can result in incorrect incremental builds. See TaskContext documentation for more info.

tagAn arbitrary nullable tag. See TaskContext documentation for more info.
An unmodifiable map of files which were reported as outputs. null values mean the file doesn't exist at a given path.
public abstract <T> T getPreviousTaskOutput(Class<T> type) throws NullPointerException
Gets the output of the task from the previous run.
TThe expected type of the previous output.
typeThe type to check if the previous output is an instance of.
The result of the previous run. null if the task was not run before this execution, it returned null, or it is not an instance of the specified type.
NullPointerExceptionIf tag or type is null.
Gets the previously set task output for the given tag.
TThe expected type of the value.
tagThe tag to retrieve the associated value for.
typeThe type to check if the associated value is an instance of.
The value which was associated to the specified tag. null if the task was not run before this execution, the value was not found, or it is not an instance of the specified type.
NullPointerExceptionIf tag or type is null.
Gets the progress monitor for this task.

The progress monitor can be used to check if the execution has been cancelled externally.

The progress monitor. (Never null.)
Gets the input reader that can be used to read secret input from the user.

The returned reader can be used to prompt the user to enter data in a secret way. This usually means that the characters the user enters will not be directly displayed on the computer screen, but will be hidden. (E.g. the console doesn't echo back the characters, or using a password text box.)

Reading functions on the returned result may lock the standard IO lock before reading the secret input, but may not based on the implementation.

Callers must handle the case if the secret reader is not available. This usually means that the build execution was configured in a way that direct input reading is not possible. (E.g. during a CI (continuous integration) build.)

The secret input reader or null if not available.
Gets the standard error for this task.

The standard error is private to the currently executed task. It is buffered, but unlike the standard out, will not be flushed during the execution of the task, only after it has finished. It will be flushed as a block of bytes and will not be interlaced with concurrently executing tasks.

The display identifier is not prepended to the lines of this output. The contents written to standard err will not be replayed when the task is not rerun due to no deltas.

The returned sink is not thread-safe, the caller must ensure proper synchronization, otherwise bytes written to the sink may be lost, or scrambled.

The standard error for this task.
IllegalTaskOperationExceptionIf this method is called after the task has finished.
Gets the standard input for this task.

The standard input is shared by all concurrently running tasks in the same build environment. The current task must lock on the standard I/O lock via acquireStandardIOLock() before calling any reading functions on the returned stream. Not locking will result in a TaskStandardIOLockIllegalStateException when calling reading functions.

The standard input and output can be both used when the lock is acquired to provide an interactive interface to the user.

The standard input for the build execution.
IllegalTaskOperationExceptionIf this method is called after the task has finished.
Gets the standard output for this task.

The standard output is private to the currently executed task. It is buffered, and is flushed when the execution sees it as a best opportunity. The buffering occurs on a per-line basis, no partially finished lines will be printed, unless the execution-wide standard I/O lock is acquired.

The bytes written to this stream is examined and every line is prepended with the currently set display identifier. (See setStandardOutDisplayIdentifier(String))

The bytes written to this stream is not replayed to the user if the task is not rerun due to no deltas. To print information which are replayed use println(String).

When buffered lines are flushed from this stream they might be interlaced with output lines of concurrently executing tasks. They might be interlaced, but they will not be mangled.

The standard output for this task.
IllegalTaskOperationExceptionIf this method is called after the task has finished.
Gets a dependency future handle for the specified task.

The task is not required to be started, or exist in the build runtime as of the calling of this function. Futures can be obtained to not yet started tasks as well.

Same as:

 getTaskFuture(taskid).getAsDependencyFuture();
 
taskidThe task identifier.
The dependency future handle for the task.
NullPointerExceptionIf the task identifier is null.
Gets a future handle for the specified task.

The task is not required to be started, or exist in the build runtime as of the calling of this function. Futures can be obtained to not yet started tasks as well.

taskidThe task identifier.
The future handle for the task.
NullPointerExceptionIf the task identifier is null.
Gets the task identifier which was used to start this task.
The task identifier of this task.
Gets the task result for the given task identifier.

This method waits for the specified task if needed, and works the same way as TaskFuture.get().

If this method throws a TaskExecutionFailedException, it is considered to be a valid return scenario. A dependency on the the associated task will be installed as if a return value was returned.

Callers should handle the possiblity of tasks returning StructuredTaskResult instances.

taskidThe task identifier to retrieve the results for.
The result of the task execution. Only null if the task returned null as a result.
TaskExecutionExceptionIn case of any exceptions related to the task execution.
NullPointerExceptionif the task identifier is null.
Gets the utility class for this task context.

The utility instance provides bulk operations, utility functions, and extensions for working with task context.

Usage of this is especially recommended when designing remote executable tasks.

The task utilities exist for the purpose of keeping the TaskContext interface clean and functions which could bloat the interface are implemented in the utilities instance.

The utility instance.
public abstract void invalidate(PathKey pathkey) throws NullPointerException
Notifies the build system that a file at the given path was externally modified.

This method needs to be called when tasks decides to externally modify files which are referenced by the build system.
External modifications include:

  • Modifying a file using an external process. (E.g. spawning an external compiler process)
  • Using direct Java I/O APIs to modify files. E.g. File, Path and related classes.
  • Directly modifying files using file providers.
  • Other file modifications that aren't done through the SakerFile API.
This method is required to be called so synchronization of the in-memory file hierarchy can work correctly.

If task implementations forget to call this method, the synchronization of the files might not work as expected. Synchronizations might be skipped, while the file contents won't be the same as expected.

Generally if task implementations do not overwrite files multiple times, and keep intermediate files separate, they don't need to expect failures. Tasks should aim to mainly use the SakerFile API or if they really need to, only work with the local file system.

If task implementations only use SakerFile.synchronize() and related functions, they don't need to call this.

Calling this method will not modify the SakerFile in-memory hierarchy in any way.

Internal implementation note: This function invalidates the specified handle for the content database. As the content database can cache file disk contents, this method needs to be called so the cached data is invalidated. If this method is not called, then the content database might not re-check the disk contents before synchronization. In that case the synchronization will be skipped, even though it should happen.

When remote execution (via clusters) are used, this method will invalidate the local cache content database and the main content database as well. In some cases it can happen that the content database on the actual file system where the file resides will not be invalidated. This can happen when a task on cluster A modifies a file on cluster B. It is a very insignificant edge-case and it it strongly discouraged to configure an execution where such a scenario can happen.

pathkeyThe path key to the file.
NullPointerExceptionIf the path key is null.
Notifies the build system that a file at the given path was externally modified and retrieves the content descriptor for the path.

This method works the same way as invalidate(PathKey), but reads the content descriptor at the given path after the invalidation.

pathkeyThe path key to the file.
The current content descriptor for the path, or null if the file doesn't exist.
NullPointerExceptionIf the path key is null.
Mirrors a file with all children, recursively if the file is a directory.

Same as calling:

 mirror(file, DirectoryVisitPredicate.everything());
 
fileThe file to mirror.
The path to the mirrored file.
IOExceptionIn case of I/O error.
NullPointerExceptionIf file is null.
FileMirroringUnavailableExceptionIf file mirroring is not available for this file.
Mirrors a file to the local file system.

If the file is a directory, then the parameter predicate will be used to select the files to mirror.

See TaskContext documentation for more information about mirroring.

fileThe file to miror.
synchpredicateThe predicate to use for mirroring. If this is null, DirectoryVisitPredicate.everything() will be used.
The path to the mirrored file.
IOExceptionIn case of I/O error.
NullPointerExceptionIf file is null.
FileMirroringUnavailableExceptionIf file mirroring is not available for this file.
Prints a line of string to the standard output of this task.

The lines printed using this function will be replayed if the task is not executed again due to no incremental changes.

The line is automatically prepended by the display identifier if set.

To display uniformly formatted data, we recommend using SakerLog logging functions.

The argument line will be automatically appended with a line ending character(s).

lineThe line to print.
NullPointerExceptionIf the line is null
IllegalTaskOperationExceptionIf this method is called after the task has finished.
Releases the previously acquired execution-wide lock for accessing the standard I/O.

When the lock is released all partially finished lines of getStandardOut() will be ended.

TaskStandardIOLockIllegalStateExceptionIf the lock was not acquired.
Stores a line of string to be replayed for the task if it is not re-run due to no incremental changes.

This method works the same way as println(String), however, it doesn't actually print the line to the output. It only stores the line to be printed if the task is not executed again due to no incremental changes.

lineThe line to print.
NullPointerExceptionIf the line is null
IllegalTaskOperationExceptionIf this method is called after the task has finished.
Reports an environment dependency for this task to the build runtime.

This method records the dependency value for the given property for the execution runtime. When the task is executed next time in an incremental manner, the current value for the property will be compared to the expected value. If it changed, an appropriate delta will be triggered and the task will be rerun.

TThe type of the property
environmentpropertyThe environment property.
expectedvalueThe expected value of the property.
NullPointerExceptionIf the property is null.
IllegalTaskOperationExceptionIf the property dependency was reported multiple times and they do not equal.
Reports an execution property dependency for this task to the build runtime.

This method records the dependency value for the given property for the execution runtime. When the task is executed next time in an incremental manner, the current value for the property will be compared to the expected value. If it changed, an appropriate delta will be triggered and the task will be rerun.

TThe type of the property
executionpropertyThe execution property.
expectedvalueThe expected value of the property.
NullPointerExceptionIf the property is null.
IllegalTaskOperationExceptionIf the property dependency was reported multiple times and they do not equal.
Reports an IDE configuration for this task.

IDE configurations can be considered as meta-data from the tasks which can be used to properly configure an editor for IDE related features.

Tasks are not required to always report IDE configurations, it can be toggled by the user using execution parameters. If a task decides to adhere these configuration changes, make sure to report an execution dependency, so the task is rerun when the parameter changes. (See IDEConfigurationRequiredExecutionProperty)

configurationThe IDE configuration.
NullPointerExceptionIf the configuration is null.
public abstract void reportIgnoredException(ExceptionView e)
Reports an unhandled exception that occurred during the execution of the task for informational purposes.

Unhandled exceptions do not modify the operation of the task or the build execution. The build system may present these to the user to debug or analyze possible inconsistent build output.

Ignoring an exception should not modify the output of a task in any way.

One good example for an ignored exception is one thrown during verbose logging to the standard output. When the task tries to write some verbose information about the execution output, but it fails with an exception, then the task might choose to ignore the thrown exception, as it doesn't modify the result of the task in any way, but only the displayed information to the user.

The build system may handle the ignored exceptions in an implementation dependent way.

If the parameter is null, a NullPointerException will be ignored.

eThe exception.
Reports a file addition dependency for this task to the build runtime.

The build executor will collect the files for the dependency next time the task is incrementally run. If it detects any added files, then an appropriate delta will be triggered, and the task will be rerun.

Important: The task needs to report any used files as input dependencies via reportInputFileDependency(Object, SakerPath, ContentDescriptor), else a delta will be triggered for the unreported files as well next time the task is run.

Example:
The task reports a file addition dependency, and reports the file A as input.
The user adds file B as a new file. Next time the task is incrementally run, the build executor collects the files, and will report file B as an addition with the appropriate delta and rerun the task.
If the task didn't report file A, then the build executor would report file A as an addition, even though it is not newly added. It is important to report the files the task uses as input dependency.

A file addition dependency can be reported multiple times, with different tags as well.

tagAn arbitrary nullable tag. See TaskContext documentation for more info.
dependencyThe dependency to report.
NullPointerExceptionIf dependency is null.
Reports a file input content dependency for this task to the build runtime.

The build executor will check if the contents of the file at the given path have changed next time the task is incrementally run. If it detects changes, then an appropriate delta will be triggered, and the task will be rerun.

When an input dependency is reported multiple times with the same path and tag, then the actually recorded contents is chosen in an implementation dependent manner, and no exception is thrown.

See getTaskUtilities() for reporting bulk file dependencies, or working with file instances directly.

tagAn arbitrary nullable tag. See TaskContext documentation for more info.
pathThe path of the file. If relative, it will be resolved against the current task working directory.
expectedcontentThe expected content of the file. null is treated as if the file is expected to not exist.
NullPointerExceptionIf path is null.
Reports a file output content dependency for this task to the build runtime.

The build executor will check if the contents of the file at the given path have changed next time the task is incrementally run. If it detects changes, then an appropriate delta will be triggered, and the task wil be rerun.

When an output dependency is reported multiple times with the same path and tag, then the actually recorded contents is chosen in an implementation dependent manner, and no exception is thrown

It is recommended that all output files are under the build directory, unless explicitly specified by the user.

The reported output files are not automatically synchronized by the build runtime. (See SakerFile.synchronize())

See getTaskUtilities() for reporting bulk file dependencies, or working with file instances directly.

tagAn arbitrary nullable tag. See TaskContext documentation for more info.
pathThe path of the file. If relative, it will be resolved against the current task working directory.
expectedcontentThe expected content of the file. null is treated as if the file is expected to not exist.
NullPointerExceptionIf path is null.
Sets the task output change detector for this task.

Setting an output change detector for the self task can result in skipping rerunning the tasks which depend on this task. The set detector should report the output unchanged if the object returned from Task.run(TaskContext) can be considered as unchanged from an external perspective.

The task can report themselves as unchanged, if output files of the task changed, but the information held in the output object remained the same. Usually EqualityTaskOutputChangeDetector is used with this method instantiated with the returned output object.

A very simple example for this:
A task calculates the sum of two input integers. In the first run it calculates 1 + 3. The input integers change for the next build, and the task will now calculate 2 + 2.
As the outputs of the task is the same, setting a self change detector can result in not rerunning any other tasks which depend on this.

changedetectorThe output change detector to set.
IllegalTaskOperationExceptionIf the change detector was already set for this task. (This method can be called only once.)
NullPointerExceptionIf the change detector is null.
public abstract void setMetaData(String metadataid, @RMISerializeObject value) throws NullPointerException
Sets an arbitrary meta-data as a result of this task.

Meta-datas can be used by the executing environment (e.g. IDEs, custom launchers) to extract information from the executed tasks.

metadataidThe identifier of the meta-data. Should follow package naming conventions.
valueThe value to set as meta-data.
NullPointerExceptionIf any of the parameters are null.
Sets the line display identifier for this task.

The line display identifier is prepended to each line printed to the standard output during the execution. The identifier format is surrounded by brackets. (E.g. [<identifier>])

The display identifier is not printed to the standard error output.

displayidThe display id to set. Pass null to disable it.
IllegalTaskOperationExceptionIf this method is called after the task has finished.
Sets the output of the task for a given tag.

Arbitrary tag-value pairs can be set as a task output which can be retrieved in a later execution when the task is incrementally invoked.

The tags and values should be preferrably Externalizable, but at least Serializable.

The build system does not handle these tags and values in a special way. They only serve a purpose of storing arbitrary data between incremental executions of the same task.

The tags should implement Object.equals(Object) and Object.hashCode(). If this method is called multiple times with the same tag, then the latter value will be associated with the given tag.

tagAn arbitrary tag to associate the value with.
valueThe value to set.
NullPointerExceptionIf tag or value is null.
Starts an inner task to execute in the context of this task.

This method will start an inner task execution using the given task factory and parameters.

Inner tasks are handled in a completely different way as plain tasks. The are ought to be treated as a simple function that runs in the same task context as this task. When you start an inner task, the build system will instantiate a task object from the task factory, and run it with the same task context as this for its parameter. Any depedencies, and operations that the inner task executes will behave the same way if the caller task executed it.

Inner tasks don't have a task identifier. They are not tracked by the build system, and they are not automatically rerun when incremental changes are detected. The build system will not store the inner tasks between executions, and will not emit deltas if the associated task factories are changed.

As they don't have a task identifier, they are allowed to execute multiple times. As they are only valid in the context of the enclosing task, they are allowed to share state between them in regards to the enclosing task context.

The main reason of using inner tasks is to fine-grain the performance of a composite task. As inner tasks can share state, it may be beneficial for a task to split up its work into smaller inner tasks while possibly dispatching the work to remote clusters or balancing the load with computation tokens.

The build system will handle the additional methods of TaskFactory which specify where and how the task can be invoked. The capabilities of the tasks are taken into account when invoking inner tasks.

Inner tasks cannot be cacheable. As they are not explicitly tracked by the build system, caching them is not allowed. If you need to cache inner tasks, consider using normal subtasks instead.

If the inner task reports computation tokens, then the enclosing task must report the TaskFactory.CAPABILITY_INNER_TASKS_COMPUTATIONAL capability to ensure proper operation. This is in order to ensure that the enclosing task complies with the restrictions that computation token usage imposes.

Inner tasks may be declared to be short, in which case they behave the same way normal tasks would work. They are invoked a single time and are not duplicated (see below). Generally, using short inner tasks have limited use-cases, as the work the inner task does can be executed directly in the enclosing task.

Inner tasks can select their execution environment the same way as normal tasks do. See TaskFactory.getExecutionEnvironmentSelector(). The execution environment selector will be used to find only one suitable environment. When duplication is used, any further execution environments will be chosen automatically based on the reported qualifier properties. If all of the qualifier properties match on a candidate environment, it will be added to the duplicateable environments without checking the suitability again with the environment selector.
Note: The qualifier environment properties will not be automatically added as a dependency for the task.

The inner task is being run based on the above mentioned capabilities and the execution parameters of this function. When specified so using the parameters, the inner tasks can be duplicated to other build clusters used by the current build execution. In this case the build system will dispatch the tasks to the appropriate clusters and execute them possibly multiple times on each one. This process is called duplication.

Inner task duplication occurrs with respect to the selected suitable execution environments and reported computation tokens. Duplication is useful when the enclosing task can divide its work up in a way that one execution unit will correspond to one inner task, but doesn't care about where the task is being executed. In this case the task can use as much computational resources that is available to it, therefore maximizing the build performance.

The result of this function is an object that provides access to the results of the inner tasks. The returned object can have zero, single, or multiple results of the inner tasks. As the number of times the task is invoked dependends on the specified execution parameters, it cannot be determined how many times the inner task will actually be duplicated. The returned object can be thought as an iterator on the results of the inner tasks.

The enclosing tasks are not required to wait for the completions of the inner tasks. If the Task.run(TaskContext) method of the enclosing task finishes before all of the inner tasks complete, the build system will wait for the inner tasks to complete, and then deem the enclosing task to be finished. When such scenario happens, the inner task duplications are automatically cancelled if the execution parameters permit. If any inner tasks throw an exception during the finalization of the enclosing task will cause the enclosing task to fail as a result.

Inner task factories are not required to implement any serialization related functionality, only of there is remote execution involved. In that case the caller should make sure to properly transfer the task factory and any shared states over RMI.

RThe result type of the inner task execution.
taskfactoryThe inner task factory to execute.
parametersThe execution parameters for the inner task or null to use the defaults.
The results object for the started inner task(s).
NullPointerExceptionIf the task factory is null.
InvalidTaskInvocationConfigurationExceptionIf the task factory reports conflicting/invalid configuration for inner tasks.
TaskEnvironmentSelectionFailedExceptionIf the task factory failed to select a suitable environment to execute on. This exception may be delayed until the first call to InnerTaskResults.getNext().
InnerTaskInitializationExceptionIf the starting of the inner tasks failed on the all of the selected execution environments.
Starts a task for execution.

Calling this method will post the specified task for execution to the build runtime. The time of execution is unspecified, can be run instantly, delayed to a later time, or started concurrently.

This method will raise a TaskIdentifierConflictException if the task with the same identifier was already started previously (by this or an other task) and the specified task factories does not equal. Important: It will not raise an exception if a task was already started previously but the execution parameters are different. If one needs to execute some task that relies on specific execution parameters, then the relevant parts of the execution parameters should be included in the task identifier as well.

For more convenient methods to start tasks, see getTaskUtilities().

RThe result type of the started task.
taskidThe identifier for the task.
taskfactoryThe task factory to use for the started task.
parametersThe task execution parameters, or null to use the defaults.
A future handle for the started task.
TaskIdentifierConflictExceptionIf a task with the same identifier is already started and the task factories does not equal.
NullPointerExceptionIf task identifier or task factory is null.
IllegalTaskOperationExceptionIf the task identifier is the same as the caller.