start method
Start the build process and run all the tasks in the calculated build order.
start should be called once and only once; i.e., Grinder instances are not re-usable.
Items in invocations can either be String names of tasks to invoke, or
full TaskInvocations.
The dontRun parameter can be used to audit the grinder file, without
actually executing any targets.
Throws GrinderException if named tasks don't exist, or there are cycles in the dependency graph.
Implementation
Future start(Iterable invocations, {bool dontRun: false}) {
if (!dontRun && _taskDeps != null) {
throw new StateError("Grinder instances are not re-usable");
}
invocations = invocations.map((invocation) =>
invocation is String ? new TaskInvocation(invocation) : invocation);
DateTime startTime = new DateTime.now();
if (invocations.isEmpty) {
if (defaultTask != null) {
invocations = [new TaskInvocation(defaultTask.name)];
} else if (!dontRun) {
throw new GrinderException('Tried to call non-existent default task.');
}
if (invocations.isEmpty) return new Future.value();
}
// Verify that all named tasks exist.
for (var invocation in invocations) {
var name = invocation.name;
if (getTask(name) == null) {
throw new GrinderException("task '$name' doesn't exist");
}
}
// Verify that there aren't any duplicate names.
Set<String> names = new Set();
for (GrinderTask task in _tasks) {
if (names.contains(task.name)) {
throw new GrinderException("task '${task.name}' is defined twice");
}
names.add(task.name);
}
// Verify that all referenced tasks exist.
for (GrinderTask task in tasks) {
for (var invocation in task.depends) {
if (getTask(invocation.name) == null) {
throw new GrinderException(
"task '${invocation.name}' referenced by ${task}, doesn't exist");
}
}
}
_calculateAllDeps();
// Verify that there are no dependency cycles.
for (GrinderTask task in tasks) {
if (getAllDependencies(task)
.any((invocation) => invocation.name == task.name)) {
throw new GrinderException("Task ${task} has a dependency cycle.\n"
" ${task} ==> ${getAllDependencies(task).join(', ')}");
}
}
invocations.forEach((i) => _postOrder(i as TaskInvocation));
if (!dontRun) {
log('grinder running ${_invocationOrder.join(' ')}');
log('');
return Future.forEach(_invocationOrder, (TaskInvocation task) {
return _invokeTask(task);
}).then((_) {
final Duration elapsed = new DateTime.now().difference(startTime);
log('finished in ${(elapsed.inMilliseconds ~/ 100) / 10} seconds');
});
} else {
return new Future.value();
}
}