Gradle 源码分析(四)

1. 写在前面

Gradle源码分析(三)一文中,我们分析了Gradle构建流程的 Configure 阶段,这里将分析 TaskGraph 阶段(gradle 源码版本为 5.6.4)。

2. TaskGraph

2.1 整体实现

这里我整理了 TaskGraph 阶段的一些主要操作,并绘制了调用链的时序图。如果对源码不感兴趣的同学只需要看这一部分的内容即可。

2.1.1 时序图

这里只绘制了关键的方法链,一些比较细的在源码部分有说到。


TaskGraph 时序图.png

2.1.2 主要操作

TaskGraph 阶段 Gradle 主要做了下面这些事情。

  1. 执行 ExcludedTaskFilteringBuildConfigurationAction,这里会解析 -x--exclude-task 参数指定需要过滤的 tasks;
  2. 执行 DefaultTaskBuildExecutionAction,这里在没有指定需要执行的 tasks 时,给 default project 设置 default tasks,并给 StartParameter 设置执行的 tasks;
  3. 执行 TaskNameResolvingBuildConfigurationAction,这里会解析查找符合条件的 tasks ,并添加到 TaskGraph 中(tasks之间的依赖关系解析比如 dependsOn 就是在这里做的);
  4. 填充 TaskGraph,生成 task 的有向无环图;
  5. 如果是指定了 --configure-on-demand 参数,调用 BuildListenerprojectsEvaluated()

2.2 源码分析

2.2.1 执行 ExcludedTaskFilteringBuildConfigurationAction

TaskGraph 过程是发生在 DefaultGradleLauncherprepareTaskExecution(),先来看看它的源码。

// DefaultGradleLauncher.java
private void prepareTaskExecution() {
    if (stage == Stage.Configure) {
        taskExecutionPreparer.prepareForTaskExecution(gradle);
        // ...
    }
}

这里的 taskExecutionPreparer 是通过反射调用的 GradleScopeServicescreateTaskExecutionPreparer()

// GradleScopeServices.java
TaskExecutionPreparer createTaskExecutionPreparer(BuildConfigurationActionExecuter buildConfigurationActionExecuter, IncludedBuildControllers includedBuildControllers, BuildOperationExecutor buildOperationExecutor) {
    return new BuildOperatingFiringTaskExecutionPreparer(
        new DefaultTaskExecutionPreparer(buildConfigurationActionExecuter, includedBuildControllers, buildOperationExecutor),
        buildOperationExecutor);
}

BuildOperatingFiringTaskExecutionPreparer 对象,来看看其 prepareForTaskExecution()

// BuildOperatingFiringTaskExecutionPreparer.java
public void prepareForTaskExecution(GradleInternal gradle) {
    buildOperationExecutor.run(new CalculateTaskGraph(gradle));
}

private class CalculateTaskGraph implements RunnableBuildOperation {

    @Override
    public void run(BuildOperationContext buildOperationContext) {
        final TaskExecutionGraphInternal taskGraph = populateTaskGraph();
        // ...
    }

    TaskExecutionGraphInternal populateTaskGraph() {
        // 调用到了 DefaultTaskExecutionPreparer 的 prepareForTaskExecution()
        delegate.prepareForTaskExecution(gradle);
        return gradle.getTaskGraph();
    }
}

可以看到,最终会调用到 DefaultTaskExecutionPreparerprepareForTaskExecution(),再来看看它的源码。

// DefaultTaskExecutionPreparer.java
public void prepareForTaskExecution(GradleInternal gradle) {
    buildConfigurationActionExecuter.select(gradle);
    // ... 省略部分代码
}

这里的 buildConfigurationActionExecuter 是通过反射调用的 GradleScopeServicescreateBuildConfigurationActionExecuter(),来看看其源码。

// GradleScopeServices.java
BuildConfigurationActionExecuter createBuildConfigurationActionExecuter(CommandLineTaskParser commandLineTaskParser, TaskSelector taskSelector, ProjectConfigurer projectConfigurer, ProjectStateRegistry projectStateRegistry) {
    List<BuildConfigurationAction> taskSelectionActions = new LinkedList<BuildConfigurationAction>();
    // 添加 DefaultTasksBuildExecutionAction
    taskSelectionActions.add(new DefaultTasksBuildExecutionAction(projectConfigurer));
    // 添加 TaskNameResolvingBuildConfigurationAction
    taskSelectionActions.add(new TaskNameResolvingBuildConfigurationAction(commandLineTaskParser));
    // 添加 ExcludedTaskFilteringBuildConfigurationAction
    return new DefaultBuildConfigurationActionExecuter(Arrays.asList(new ExcludedTaskFilteringBuildConfigurationAction(taskSelector)), taskSelectionActions, projectStateRegistry);
}

DefaultBuildConfigurationActionExecuter 对象。注意这里的三个比较重要的 BuildConfigurationAction

  • DefaultTasksBuildExecutionAction
  • TaskNameResolvingBuildConfigurationAction
  • ExcludedTaskFilteringBuildConfigurationAction

先看看 DefaultBuildConfigurationActionExecuterselect()

// DefaultBuildConfigurationActionExecuter.java
public void select(final GradleInternal gradle) {
    projectStateRegistry.withLenientState(new Runnable() {
        @Override
        public void run() {
            // 1. 会调用到这里
            List<BuildConfigurationAction> processingBuildActions = CollectionUtils.flattenCollections(BuildConfigurationAction.class, configurationActions, taskSelectors);
            // 2. 这里会遍历 processingBuildActions 分别调用它们的 configure()
            configure(processingBuildActions, gradle, 0);
        }
    });
}

private void configure(final List<BuildConfigurationAction> processingConfigurationActions, final GradleInternal gradle, final int index) {
    if (index >= processingConfigurationActions.size()) {
        return;
    }
    processingConfigurationActions.get(index).configure(new BuildExecutionContext() {
        @Override
        public void proceed() {
            configure(processingConfigurationActions, gradle, index + 1);
        }
    });
}

select() 里面经过 CollectionUtils.flattenCollections() 处理后,三个 BuildConfigurationAction 的顺序是这样的。

  1. ExcludedTaskFilteringBuildConfigurationAction
  2. DefaultTasksBuildExecutionAction
  3. TaskNameResolvingBuildConfigurationAction

接着调用了 configure() 遍历所有的 BuildConfigurationAction,并调用他们的 configure()。也就是说首先会执行 ExcludedTaskFilteringBuildConfigurationActionconfigure(),来看看它做了什么。

// ExcludedTaskFilteringBuildConfigurationAction.java
public void configure(BuildExecutionContext context) {
    GradleInternal gradle = context.getGradle();
    // 1. 这里会获取通过参数 -x 或者 --exclude-task 指定的 tasks
    Set<String> excludedTaskNames = gradle.getStartParameter().getExcludedTaskNames();
    if (!excludedTaskNames.isEmpty()) {
        final Set<Spec<Task>> filters = new HashSet<Spec<Task>>();
        for (String taskName : excludedTaskNames) {
            // 2. 解析这些 tasks,封装成 Spec<Task>
            filters.add(taskSelector.getFilter(taskName));
        }
        // 3. 通过 useFilter() 将 Spec 设置给 TaskGraph
        gradle.getTaskGraph().useFilter(Specs.intersect(filters));
    }
    // 4. 调用下一个 BuildConfigurationAction 的 configure()
    context.proceed();
}

可以看到,ExcludedTaskFilteringBuildConfigurationAction 的流程如下:

  1. 获取通过参数 -x 或者 --exclude-task 指定的需要过滤的 tasks;
  2. 遍历这些 tasks,进行解析后封装成 Spec<Task>
  3. 通过 useFilter() 设置给 TaskGraph,为后面构建 TaskGraph 做准备;
  4. 调用下一个 BuildConfigurationActionconfigure()

这里主要看一下 taskSelector.getFilter(taskName) 的解析过程;taskSelectorTaskSelector 的实例,来看看其 getFilter() 的源码。

// TaskSelector.java
public Spec<Task> getFilter(String path) {
    // 1. 调用 taskPathResolver 的 resolvePath 解析 task
    final ResolvedTaskPath taskPath = taskPathResolver.resolvePath(path, gradle.getDefaultProject());
    if (!taskPath.isQualified()) {
        ProjectInternal targetProject = taskPath.getProject();
        // 2. 配置task依赖的project
        configurer.configure(targetProject);
        if (taskNameResolver.tryFindUnqualifiedTaskCheaply(taskPath.getTaskName(), taskPath.getProject())) {
            // 能找到确切的则直接返回,这种能直接通过 path 过滤 task,避免配置 sub projects
            return new TaskPathSpec(targetProject, taskPath.getTaskName());
        }
    }

    // 3. 调用 getSelection() 找 project  (必要时也会查找 sub project) 下所有符合的 tasks
    final Set<Task> selectedTasks = getSelection(path, gradle.getDefaultProject()).getTasks();
    return new Spec<Task>() {
        @Override
        public boolean isSatisfiedBy(Task element) {
            return !selectedTasks.contains(element);
        }
    };
}

private TaskSelection getSelection(String path, ProjectInternal project) {
    ResolvedTaskPath taskPath = taskPathResolver.resolvePath(path, project);
    ProjectInternal targetProject = taskPath.getProject();
    if (taskPath.isQualified()) {
        // path 指定有具体的 project,比如 :app:clean,则配置具体的 project
        configurer.configure(targetProject);
    } else {
        // path 没有指定具体的 project,比如 clean,则配置 project 和 sub project
        configurer.configureHierarchy(targetProject);
    }
    // 查找所有符合条件的 tasks
    TaskSelectionResult tasks = taskNameResolver.selectWithName(taskPath.getTaskName(), taskPath.getProject(), !taskPath.isQualified());
    if (tasks != null) {
        return new TaskSelection(taskPath.getProject().getPath(), path, tasks);
    }
    // 查找所有符合条件的 tasks
    Map<String, TaskSelectionResult> tasksByName = taskNameResolver.selectAll(taskPath.getProject(), !taskPath.isQualified());
    NameMatcher matcher = new NameMatcher();
    String actualName = matcher.find(taskPath.getTaskName(), tasksByName.keySet());
    if (actualName != null) {
        return new TaskSelection(taskPath.getProject().getPath(), taskPath.getPrefix() + actualName, tasksByName.get(actualName));
    }

    throw new TaskSelectionException(matcher.formatErrorMessage("task", taskPath.getProject()));
}

getFilter() 方法的逻辑也很清晰;

  1. 调用 TaskPathResolverresolvePath() 解析 task;
  2. 必要时调用 configure() 对 task 所依赖的 project 进行配置。这里可能有的童鞋会存在些许疑问,在 Gradle 的 Configure 阶段明明已经配置过了 project,为什么这里还要再配置一次;举个栗子,比如在 app 目录下执行 .././gradlew clean --configure-on-demand,在 Configure 阶段因为有 --configure-on-demand 参数,只会配置 root project,而 clean task 所依赖的 app project 并没有经过配置,所以这里需要有这个逻辑防止所执行的 task 依赖的 project 没有进行配置的情况;
  3. 调用 getSelection() 找所有符合的 tasks,并封装成 Spec<Task> 返回。

这里主要看下 resolvePath() 的源码。

// TaskPathResolver.java
public ResolvedTaskPath resolvePath(String path, ProjectInternal startFrom) {
    ProjectInternal project;
    String taskName; //eg. 'someTask' or 'sT'
    String prefix; //eg. '', ':' or ':foo:bar'
    
    // 如果 path 包含有 : 分隔符,比如 :app:assembleDebug
    if (path.contains(Project.PATH_SEPARATOR)) {
        // 拿最后一个 : 的索引
        int idx = path.lastIndexOf(Project.PATH_SEPARATOR);
        // taskName = assembleDebug
        taskName = path.substring(idx + 1);
        // prefix = :app:
        prefix = path.substring(0, idx+1);
        // projectPath = :app
        String projectPath = Project.PATH_SEPARATOR.equals(prefix) ? prefix : path.substring(0, idx);
        // 找 project
        project = projectFinder.findProject(projectPath, startFrom);
    } else {
        // 如果path 就是纯粹的 taskName,比如 clean
        // project = default project
        project = startFrom;
        // taskName = clean 
        taskName = path;
        // prefix = ""
        prefix = "";
    }
    return new ResolvedTaskPath(prefix, taskName, project);
}

2.2.2 执行 DefaultTaskBuildExecutionAction

执行完 ExcludedTaskFilteringBuildConfigurationActionconfigure(),紧接着就是执行 DefaultTaskBuildExecutionActionconfigure() 了,来看看其源码。

// DefaultTaskBuildExecutionAction.java
public void configure(BuildExecutionContext context) {
    StartParameter startParameter = context.getGradle().getStartParameter();

    // 1. 首先看有没有指定执行的 task,如果有指定执行的 task,则直接返回;比如 ./gradlew clean,指定了需要执行 clean task,这里的 args 即 clean
    for (TaskExecutionRequest request : startParameter.getTaskRequests()) {
        if (!request.getArgs().isEmpty()) {
            context.proceed();
            return;
        }
    }

    // 2. 如果没有指定要执行的task,则获取 default project 的 default tasks,比如执行 ./gradlew ,这种就是没有指定执行的 task
    ProjectInternal project = context.getGradle().getDefaultProject();
    projectConfigurer.configure(project);
    List<String> defaultTasks = project.getDefaultTasks();

    if (defaultTasks.size() == 0) {
        // 3. 如果 default project 没有设置 default tasks,则指定为 help task
        defaultTasks = Collections.singletonList(ProjectInternal.HELP_TASK);
        LOGGER.info("No tasks specified. Using default task {}", GUtil.toString(defaultTasks));
    } else {
        // 4. 如果 default project 有设置 default tasks,则使用设置的 default tasks
        LOGGER.info("No tasks specified. Using project default tasks {}", GUtil.toString(defaultTasks));
    }
    // 5. 设置需要执行的 tasks
    startParameter.setTaskNames(defaultTasks);
    // 6. 调用下一个 BuildConfigurationAction 的 configure()
    context.proceed();
}

DefaultTaskBuildExecutionAction 的逻辑也十分的清晰:

  1. 先判断是否有指定需要执行的 task,如果有指定,则直接返回,比如 ./gradlew clean,这种就是指定了执行 clean task;
  2. 如果没有指定则需要执行的 task,比如 ./gradlew,则获取 default project 的 default tasks,如果没有设置 default tasks,则使用 help task 作为 default tasks;
  3. 如果有设置 default tasks,则不作操作;
  4. 给 StartParameter 指定需要执行的 tasks,即 default tasks;
  5. 调用下一个 BuildConfigurationActionconfigure()

举个简单的栗子方便理解。在 app 下执行 .././gradlew 脚本,这个时候 default project 即 app 对应的 project。在执行到 DefaultTaskBuildExecutionAction 的时候,因为 app 的 build.gradle 里面是没有配置 default tasks 的,所以这里会设置 help task 为 default task,也就是上面命令执行 task 实际上是 help task。

help task.png

这个时候,修改 app 的 build.gradle 。

Task hello = task("hello") {
    doLast {
        println("hello, gradle")
    }
}
List<String> tasks = new ArrayList<String>()
tasks.add(hello.name)
setDefaultTasks(tasks)

通过 setDefaultTasks() 设置 default tasks 是 hello task。这个时候再执行 .././gradlew 脚本,它执行的就是 hello task。

hello task.png

2.2.3 执行 TaskNameResolvingBuildConfigurationAction

执行完 DefaultTaskBuildExecutionActionconfigure(),紧接着就是执行 TaskNameResolvingBuildConfigurationActionconfigure() 了,来看看其源码。

// TaskNameResolvingBuildConfigurationAction.java
public void configure(BuildExecutionContext context) {
    GradleInternal gradle = context.getGradle();
    TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
    // 1. 获取指定执行的 TaskExecutionRequest
    List<TaskExecutionRequest> taskParameters = gradle.getStartParameter().getTaskRequests();
    for (TaskExecutionRequest taskParameter : taskParameters) {
        // 2. 解析 task,查找符合的 tasks
        List<TaskSelector.TaskSelection> taskSelections = commandLineTaskParser.parseTasks(taskParameter);
        for (TaskSelector.TaskSelection taskSelection : taskSelections) {
            // 3. 添加所有符合的 tasks 到 TaskGraph
            taskGraph.addEntryTasks(taskSelection.getTasks());
        }
    }

    context.proceed();
}

这里先看一下 commandLineTaskParser.parseTasks(taskParameter) 的解析过程。

// CommandLineTaskParser.java
public List<TaskSelector.TaskSelection> parseTasks(TaskExecutionRequest taskExecutionRequest) {
    List<TaskSelector.TaskSelection> out = Lists.newArrayList();
    // 比如 :app:clean,args 即 [:app:clean]
    List<String> remainingPaths = new LinkedList<String>(taskExecutionRequest.getArgs());
    while (!remainingPaths.isEmpty()) {
        String path = remainingPaths.remove(0);
        // 和 getFilter() 里面一样,调用 getSelection() 查找所有符合的 tasks
        TaskSelector.TaskSelection selection = taskSelector.getSelection(taskExecutionRequest.getProjectPath(), taskExecutionRequest.getRootDir(), path);
        Set<Task> tasks = selection.getTasks();
        remainingPaths = taskConfigurer.configureTasks(tasks, remainingPaths);
        out.add(selection);
    }
    return out;
}

举个栗子,比如在 app 下面执行 .././gradlew :app:clean,这里的 taskExecutionRequest.getArgs()[:app:clean],然后会根据这个 path 去查找所有符合的 tasks,再添加到 TaskGraph 里面。

看完解析过程,再来看看添加过程 taskGraph.addEntryTasks(taskSelection.getTasks())taskGraphDefaultTaskExecutionGraph,来看看其 addEntryTasks()

// DefaultTaskExecutionGraph.java
public void addEntryTasks(Iterable<? extends Task> tasks) {
    Set<Task> taskSet = new LinkedHashSet<Task>();
    for (Task task : tasks) {
        taskSet.add(task);
        requestedTasks.add(task);
    }
    // 调用 DefaultExecutionPlan.addEntryTasks()
    executionPlan.addEntryTasks(taskSet);
    // task graph 标记为 DIRTY 状态
    graphState = GraphState.DIRTY;
}

这里主要做了两件事情:

  1. 调用 DefaultExecutionPlanaddEntryTasks()
  2. TaskGraph 的状态标记为 DIRTY

而这里的 addEntryTasks() 就会处理 task 之间的依赖关系,比如 dependsOn等。

// DefaultExecutionPlan.java
public void addEntryTasks(Collection<? extends Task> tasks) {
    final Deque<Node> queue = new ArrayDeque<Node>();
    Set<Node> nodesInUnknownState = Sets.newLinkedHashSet();

    List<Task> sortedTasks = new ArrayList<Task>(tasks);
    Collections.sort(sortedTasks);
    for (Task task : sortedTasks) {
        TaskNode node = taskNodeFactory.getOrCreateNode(task);
        if (node.isMustNotRun()) {
            requireWithDependencies(node);
        } else if (filter.isSatisfiedBy(task)) {
            // 这里就是前面 ExcludedTaskFilteringBuildConfigurationAction 获取到的需要过滤的 
            node.require();
        }
        entryTasks.add(node);
        queue.add(node);
    }

    final Set<Node> visiting = Sets.newHashSet();

    while (!queue.isEmpty()) {
        Node node = queue.getFirst();
        // 已经处理过了
        if (node.getDependenciesProcessed()) {
            queue.removeFirst();
            continue;
        }

        boolean filtered = !nodeSatisfiesTaskFilter(node);
        // 过滤掉
        if (filtered) {
            queue.removeFirst();
            // 标记为处理
            node.dependenciesProcessed();
            node.doNotRequire();
            filteredNodes.add(node);
            continue;
        }

        if (visiting.add(node)) {
            node.prepareForExecution();
            // 主要是这个方法,里面处理依赖关系
            node.resolveDependencies(dependencyResolver, new Action<Node>() {
                @Override
                public void execute(Node targetNode) {
                    if (!visiting.contains(targetNode)) {
                        queue.addFirst(targetNode);
                    }
                }
            });
            if (node.isRequired()) {
                for (Node successor : node.getDependencySuccessors()) {
                    if (nodeSatisfiesTaskFilter(successor)) {
                        successor.require();
                    }
                }
            } else {
                nodesInUnknownState.add(node);
            }
        } else {
            queue.removeFirst();
            visiting.remove(node);
            node.dependenciesProcessed();
        }
    }
    resolveNodesInUnknownState(nodesInUnknownState);
}

重点看一下 node.resolveDependencies();这里的 node 是通过 TaskNodeFactorygetOrCreateNode() 创建的。

// TaskNodeFactory.java
public TaskNode getOrCreateNode(Task task) {
    TaskNode node = nodes.get(task);
    if (node == null) {
        if (task.getProject().getGradle() == thisBuild) {
            node = new LocalTaskNode((TaskInternal) task);
        } else {
            node = new TaskInAnotherBuild((TaskInternal) task, currentBuildId, taskGraph);
        }
        nodes.put(task, node);
    }
    return node;
}

LocalTaskNode 对象,来看看其 resolveDependencies()

// LocalTaskNode.java
public void resolveDependencies(TaskDependencyResolver dependencyResolver, Action<Node> processHardSuccessor) {
    // dependsOn 的解析
    for (Node targetNode : getDependencies(dependencyResolver)) {
        addDependencySuccessor(targetNode);
        processHardSuccessor.execute(targetNode);
    }
    // finalizedBy 的解析
    for (Node targetNode : getFinalizedBy(dependencyResolver)) {
        if (!(targetNode instanceof TaskNode)) {
            throw new IllegalStateException("Only tasks can be finalizers: " + targetNode);
        }
        addFinalizerNode((TaskNode) targetNode);
        processHardSuccessor.execute(targetNode);
    }
    // mustRunAfter 的解析
    for (Node targetNode : getMustRunAfter(dependencyResolver)) {
        addMustSuccessor(targetNode);
    }
    // shouldRunAfter 的解析
    for (Node targetNode : getShouldRunAfter(dependencyResolver)) {
        addShouldSuccessor(targetNode);
    }
}

可以看到 task 的依赖关系解析就是在这里做的。

2.2.4 填充 TaskGraph

回到 DefaultTaskExecutionPreparerprepareForTaskExecution(),继续往下看。

// DefaultTaskExecutionPreparer.java
public void prepareForTaskExecution(GradleInternal gradle) {
    buildConfigurationActionExecuter.select(gradle);

    TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
    // 计算有向无环图
    taskGraph.populate();
    // ...
}

这里会调用了 DefaultTaskExecutionGraphpopulate(),来看看其源码。

// DefaultTaskExecutionGraph.java
public void populate() {
    ensurePopulated();
}

private void ensurePopulated() {
    switch (graphState) {
        // ...
        case DIRTY:
            executionPlan.determineExecutionPlan();
            allTasks = null;
            graphState = GraphState.POPULATED;
            return;
        // ...
    }
}

在前面添加 task 的时候,已经将 graphState 标记为了 DIRTY 状态,所以这里会走到 executionPlan.determineExecutionPlan()executionPlanDefaultExecutionPlan 的实例,来看看其 determineExecutionPlan()

// DefaultExecutionPlan.java
public void determineExecutionPlan() {
    LinkedList<NodeInVisitingSegment> nodeQueue = Lists.newLinkedList(Iterables.transform(entryTasks, new Function<TaskNode, NodeInVisitingSegment>() {
        private int index;

        @Override
        @SuppressWarnings("NullableProblems")
        public NodeInVisitingSegment apply(TaskNode taskNode) {
            return new NodeInVisitingSegment(taskNode, index++);
        }
    }));
    int visitingSegmentCounter = nodeQueue.size();

    HashMultimap<Node, Integer> visitingNodes = HashMultimap.create();
    Deque<GraphEdge> walkedShouldRunAfterEdges = new ArrayDeque<GraphEdge>();
    Deque<Node> path = new ArrayDeque<Node>();
    Map<Node, Integer> planBeforeVisiting = Maps.newHashMap();

    while (!nodeQueue.isEmpty()) {
        NodeInVisitingSegment nodeInVisitingSegment = nodeQueue.peekFirst();
        int currentSegment = nodeInVisitingSegment.visitingSegment;
        Node node = nodeInVisitingSegment.node;

        if (node.isIncludeInGraph() || nodeMapping.contains(node)) {
            nodeQueue.removeFirst();
            visitingNodes.remove(node, currentSegment);
            maybeRemoveProcessedShouldRunAfterEdge(walkedShouldRunAfterEdges, node);
            continue;
        }

        boolean alreadyVisited = visitingNodes.containsKey(node);
        visitingNodes.put(node, currentSegment);

        if (!alreadyVisited) {
            recordEdgeIfArrivedViaShouldRunAfter(walkedShouldRunAfterEdges, path, node);
            removeShouldRunAfterSuccessorsIfTheyImposeACycle(visitingNodes, nodeInVisitingSegment);
            takePlanSnapshotIfCanBeRestoredToCurrentTask(planBeforeVisiting, node);

            for (Node successor : node.getAllSuccessorsInReverseOrder()) {
                if (visitingNodes.containsEntry(successor, currentSegment)) {
                    if (!walkedShouldRunAfterEdges.isEmpty()) {
                        GraphEdge toBeRemoved = walkedShouldRunAfterEdges.pop();
                        TaskNode sourceTask = (TaskNode) toBeRemoved.from;
                        TaskNode targetTask = (TaskNode) toBeRemoved.to;
                        sourceTask.removeShouldSuccessor(targetTask);
                        restorePath(path, toBeRemoved);
                        restoreQueue(nodeQueue, visitingNodes, toBeRemoved);
                        restoreExecutionPlan(planBeforeVisiting, toBeRemoved);
                        break;
                    } else {
                        onOrderingCycle(successor, node);
                    }
                }
                nodeQueue.addFirst(new NodeInVisitingSegment(successor, currentSegment));
            }
            path.push(node);
        } else {
            nodeQueue.removeFirst();
            maybeRemoveProcessedShouldRunAfterEdge(walkedShouldRunAfterEdges, node);
            visitingNodes.remove(node, currentSegment);
            path.pop();
            nodeMapping.add(node);

            MutationInfo mutations = getOrCreateMutationsOf(node);
            for (Node dependency : node.getDependencySuccessors()) {
                getOrCreateMutationsOf(dependency).consumingNodes.add(node);
                mutations.producingNodes.add(dependency);
            }

            Project project = node.getProject();
            if (project != null) {
                projectLocks.put(project, getOrCreateProjectLock(project));
            }

            for (Node finalizer : node.getFinalizers()) {
                if (!visitingNodes.containsKey(finalizer)) {
                    int position = finalizerTaskPosition(finalizer, nodeQueue);
                    nodeQueue.add(position, new NodeInVisitingSegment(finalizer, visitingSegmentCounter++));
                }
            }
        }
    }
    executionQueue.clear();
    Iterables.addAll(executionQueue, nodeMapping);
}

这个方法就是填充 TaskGraph,生成 task 的有向无环图。

2.2.5 必要时调用 BuildListenerprojectsEvaluated()

继续往下看 DefaultTaskExecutionPreparerprepareForTaskExecution()

// DefaultTaskExecutionPreparer.java
public void prepareForTaskExecution(GradleInternal gradle) {
    buildConfigurationActionExecuter.select(gradle);

    TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
    taskGraph.populate();

    includedBuildControllers.populateTaskGraphs();
    
    // 如果是 --configure-on-demand 的情况下,是在这里调用的 projectEvaluated
    if (gradle.getStartParameter().isConfigureOnDemand()) {
        new ProjectsEvaluatedNotifier(buildOperationExecutor).notify(gradle);
    }
}

生成 task 的有向无环图后,会判断是否有指定 --configure-on-demand 参数,如果有指定,则调用 BuildListenerprojectEvaluated() ,因为在 Configure 阶段,--configure-on-demand 只会对 root project 进行配置,如果对 Configure 阶段不太熟悉的,可以先看看 Gradle源码分析(三)

最后,回到 DefaultGradleLauncherprepareTaskExecution()

// DefaultGradleLauncher.java
private void prepareTaskExecution() {
    if (stage == Stage.Configure) {
        taskExecutionPreparer.prepareForTaskExecution(gradle);
        // 解析完 tasks 填充 tasks 有向无环图后,将状态设置为 TaskGraph
        stage = Stage.TaskGraph;
    }
}

执行完上述流程后会将 Gradle 状态设置为 TaskGraph。至此,Gradle 的 TaskGraph 阶段就分析完了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249