start method

Future start(
  1. Iterable invocations, {
  2. bool dontRun = false,
})

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 StateError('Grinder instances are not re-usable');
  }

  invocations = invocations.map((invocation) =>
      invocation is String ? TaskInvocation(invocation) : invocation);

  final startTime = DateTime.now();

  if (invocations.isEmpty) {
    var defaultTask = this.defaultTask;
    if (defaultTask != null) {
      invocations = [TaskInvocation(defaultTask.name)];
    } else if (!dontRun) {
      throw GrinderException('Tried to call non-existent default task.');
    }
    if (invocations.isEmpty) return Future.value();
  }

  // Verify that all named tasks exist.
  for (var invocation in invocations) {
    var name = invocation.name;
    if (getTask(name) == null) {
      throw GrinderException("task '$name' doesn't exist");
    }
  }

  // Verify that there aren't any duplicate names.
  final names = <String>{};

  for (final task in _tasks) {
    if (names.contains(task.name)) {
      throw GrinderException("task '${task.name}' is defined twice");
    }
    names.add(task.name);
  }

  // Verify that all referenced tasks exist.
  for (final task in tasks) {
    for (var invocation in task.depends) {
      if (getTask(invocation.name) == null) {
        throw GrinderException(
            "task '${invocation.name}' referenced by $task, doesn't exist");
      }
    }
  }

  _calculateAllDeps();

  // Verify that there are no dependency cycles.
  for (final task in tasks) {
    if (getAllDependencies(task)
        .any((invocation) => invocation.name == task.name)) {
      throw GrinderException('Task $task has a dependency cycle.\n'
          "  $task ==> ${getAllDependencies(task).join(', ')}");
    }
  }

  for (final TaskInvocation invocation in invocations) {
    _postOrder(invocation);
  }

  if (!dontRun) {
    log('grinder running ${_invocationOrder.join(' ')}');
    log('');

    return Future.forEach(_invocationOrder, (TaskInvocation task) {
      return _invokeTask(task);
    }).then((_) {
      final elapsed = DateTime.now().difference(startTime);
      log('finished in ${(elapsed.inMilliseconds ~/ 100) / 10} seconds');
    });
  } else {
    return Future.value();
  }
}