1. 寫在前面
在 Gradle源碼分析(三)一文中既绕,我們分析了Gradle構(gòu)建流程的
Configure
階段,這里將分析TaskGraph
階段(gradle 源碼版本為 5.6.4)芥被。
2. TaskGraph
2.1 整體實現(xiàn)
這里我整理了 TaskGraph
階段的一些主要操作,并繪制了調(diào)用鏈的時序圖纫溃。如果對源碼不感興趣的同學(xué)只需要看這一部分的內(nèi)容即可沪羔。
2.1.1 時序圖
這里只繪制了關(guān)鍵的方法鏈,一些比較細(xì)的在源碼部分有說到壁榕。
2.1.2 主要操作
TaskGraph
階段 Gradle 主要做了下面這些事情矛紫。
- 執(zhí)行
ExcludedTaskFilteringBuildConfigurationAction
,這里會解析-x
或--exclude-task
參數(shù)指定需要過濾的 tasks牌里; - 執(zhí)行
DefaultTaskBuildExecutionAction
颊咬,這里在沒有指定需要執(zhí)行的 tasks 時务甥,給 default project 設(shè)置 default tasks,并給StartParameter
設(shè)置執(zhí)行的 tasks喳篇; - 執(zhí)行
TaskNameResolvingBuildConfigurationAction
敞临,這里會解析查找符合條件的 tasks ,并添加到TaskGraph
中(tasks之間的依賴關(guān)系解析比如 dependsOn 就是在這里做的)麸澜; - 填充
TaskGraph
挺尿,生成 task 的有向無環(huán)圖; - 如果是指定了
--configure-on-demand
參數(shù)炊邦,調(diào)用BuildListener
的projectsEvaluated()
编矾。
2.2 源碼分析
2.2.1 執(zhí)行 ExcludedTaskFilteringBuildConfigurationAction
TaskGraph
過程是發(fā)生在 DefaultGradleLauncher
的 prepareTaskExecution()
,先來看看它的源碼馁害。
// DefaultGradleLauncher.java
private void prepareTaskExecution() {
if (stage == Stage.Configure) {
taskExecutionPreparer.prepareForTaskExecution(gradle);
// ...
}
}
這里的 taskExecutionPreparer
是通過反射調(diào)用的 GradleScopeServices
的 createTaskExecutionPreparer()
窄俏。
// 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() {
// 調(diào)用到了 DefaultTaskExecutionPreparer 的 prepareForTaskExecution()
delegate.prepareForTaskExecution(gradle);
return gradle.getTaskGraph();
}
}
可以看到凹蜈,最終會調(diào)用到 DefaultTaskExecutionPreparer
的 prepareForTaskExecution()
,再來看看它的源碼忍啸。
// DefaultTaskExecutionPreparer.java
public void prepareForTaskExecution(GradleInternal gradle) {
buildConfigurationActionExecuter.select(gradle);
// ... 省略部分代碼
}
這里的 buildConfigurationActionExecuter
是通過反射調(diào)用的 GradleScopeServices
的 createBuildConfigurationActionExecuter()
仰坦,來看看其源碼。
// 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
先看看 DefaultBuildConfigurationActionExecuter
的 select()
。
// DefaultBuildConfigurationActionExecuter.java
public void select(final GradleInternal gradle) {
projectStateRegistry.withLenientState(new Runnable() {
@Override
public void run() {
// 1. 會調(diào)用到這里
List<BuildConfigurationAction> processingBuildActions = CollectionUtils.flattenCollections(BuildConfigurationAction.class, configurationActions, taskSelectors);
// 2. 這里會遍歷 processingBuildActions 分別調(diào)用它們的 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()
里面經(jīng)過 CollectionUtils.flattenCollections()
處理后白粉,三個 BuildConfigurationAction
的順序是這樣的传泊。
ExcludedTaskFilteringBuildConfigurationAction
DefaultTasksBuildExecutionAction
TaskNameResolvingBuildConfigurationAction
接著調(diào)用了 configure()
遍歷所有的 BuildConfigurationAction
,并調(diào)用他們的 configure()
鸭巴。也就是說首先會執(zhí)行 ExcludedTaskFilteringBuildConfigurationAction
的 configure()
眷细,來看看它做了什么。
// ExcludedTaskFilteringBuildConfigurationAction.java
public void configure(BuildExecutionContext context) {
GradleInternal gradle = context.getGradle();
// 1. 這里會獲取通過參數(shù) -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 設(shè)置給 TaskGraph
gradle.getTaskGraph().useFilter(Specs.intersect(filters));
}
// 4. 調(diào)用下一個 BuildConfigurationAction 的 configure()
context.proceed();
}
可以看到溪椎,ExcludedTaskFilteringBuildConfigurationAction
的流程如下:
- 獲取通過參數(shù)
-x
或者--exclude-task
指定的需要過濾的 tasks; - 遍歷這些 tasks恬口,進(jìn)行解析后封裝成
Spec<Task>
校读; - 通過
useFilter()
設(shè)置給TaskGraph
,為后面構(gòu)建TaskGraph
做準(zhǔn)備祖能; - 調(diào)用下一個
BuildConfigurationAction
的configure()
歉秫。
這里主要看一下 taskSelector.getFilter(taskName)
的解析過程;taskSelector
是 TaskSelector
的實例养铸,來看看其 getFilter()
的源碼雁芙。
// TaskSelector.java
public Spec<Task> getFilter(String path) {
// 1. 調(diào)用 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. 調(diào)用 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()
方法的邏輯也很清晰蟆淀;
- 調(diào)用
TaskPathResolver
的resolvePath()
解析 task; - 必要時調(diào)用
configure()
對 task 所依賴的 project 進(jìn)行配置澡匪。這里可能有的童鞋會存在些許疑問熔任,在 Gradle 的Configure
階段明明已經(jīng)配置過了 project,為什么這里還要再配置一次仙蛉;舉個栗子笋敞,比如在 app 目錄下執(zhí)行.././gradlew clean --configure-on-demand
,在 Configure 階段因為有--configure-on-demand
參數(shù)荠瘪,只會配置 root project,而 clean task 所依賴的 app project 并沒有經(jīng)過配置赛惩,所以這里需要有這個邏輯防止所執(zhí)行的 task 依賴的 project 沒有進(jìn)行配置的情況哀墓; - 調(diào)用
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 執(zhí)行 DefaultTaskBuildExecutionAction
執(zhí)行完 ExcludedTaskFilteringBuildConfigurationAction
的 configure()
吠各,緊接著就是執(zhí)行 DefaultTaskBuildExecutionAction
的 configure()
了,來看看其源碼勉抓。
// DefaultTaskBuildExecutionAction.java
public void configure(BuildExecutionContext context) {
StartParameter startParameter = context.getGradle().getStartParameter();
// 1. 首先看有沒有指定執(zhí)行的 task贾漏,如果有指定執(zhí)行的 task,則直接返回藕筋;比如 ./gradlew clean纵散,指定了需要執(zhí)行 clean task,這里的 args 即 clean
for (TaskExecutionRequest request : startParameter.getTaskRequests()) {
if (!request.getArgs().isEmpty()) {
context.proceed();
return;
}
}
// 2. 如果沒有指定要執(zhí)行的task隐圾,則獲取 default project 的 default tasks伍掀,比如執(zhí)行 ./gradlew ,這種就是沒有指定執(zhí)行的 task
ProjectInternal project = context.getGradle().getDefaultProject();
projectConfigurer.configure(project);
List<String> defaultTasks = project.getDefaultTasks();
if (defaultTasks.size() == 0) {
// 3. 如果 default project 沒有設(shè)置 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 有設(shè)置 default tasks蜜笤,則使用設(shè)置的 default tasks
LOGGER.info("No tasks specified. Using project default tasks {}", GUtil.toString(defaultTasks));
}
// 5. 設(shè)置需要執(zhí)行的 tasks
startParameter.setTaskNames(defaultTasks);
// 6. 調(diào)用下一個 BuildConfigurationAction 的 configure()
context.proceed();
}
DefaultTaskBuildExecutionAction
的邏輯也十分的清晰:
- 先判斷是否有指定需要執(zhí)行的 task,如果有指定盐碱,則直接返回把兔,比如
./gradlew clean
沪伙,這種就是指定了執(zhí)行 clean task; - 如果沒有指定則需要執(zhí)行的 task垛贤,比如
./gradlew
焰坪,則獲取 default project 的 default tasks,如果沒有設(shè)置 default tasks聘惦,則使用 help task 作為 default tasks某饰; - 如果有設(shè)置 default tasks,則不作操作善绎;
- 給 StartParameter 指定需要執(zhí)行的 tasks黔漂,即 default tasks;
- 調(diào)用下一個
BuildConfigurationAction
的configure()
禀酱。
舉個簡單的栗子方便理解炬守。在 app 下執(zhí)行 .././gradlew 腳本,這個時候 default project 即 app 對應(yīng)的 project剂跟。在執(zhí)行到 DefaultTaskBuildExecutionAction
的時候减途,因為 app 的 build.gradle 里面是沒有配置 default tasks 的,所以這里會設(shè)置 help task 為 default task曹洽,也就是上面命令執(zhí)行 task 實際上是 help task鳍置。
這個時候,修改 app 的 build.gradle 送淆。
Task hello = task("hello") {
doLast {
println("hello, gradle")
}
}
List<String> tasks = new ArrayList<String>()
tasks.add(hello.name)
setDefaultTasks(tasks)
通過 setDefaultTasks()
設(shè)置 default tasks 是 hello task税产。這個時候再執(zhí)行 .././gradlew 腳本,它執(zhí)行的就是 hello task偷崩。
2.2.3 執(zhí)行 TaskNameResolvingBuildConfigurationAction
執(zhí)行完 DefaultTaskBuildExecutionAction
的 configure()
辟拷,緊接著就是執(zhí)行 TaskNameResolvingBuildConfigurationAction
的 configure()
了,來看看其源碼阐斜。
// TaskNameResolvingBuildConfigurationAction.java
public void configure(BuildExecutionContext context) {
GradleInternal gradle = context.getGradle();
TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
// 1. 獲取指定執(zhí)行的 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() 里面一樣羽杰,調(diào)用 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 下面執(zhí)行 .././gradlew :app:clean到推,這里的 taskExecutionRequest.getArgs()
為 [:app:clean]
考赛,然后會根據(jù)這個 path 去查找所有符合的 tasks,再添加到 TaskGraph
里面莉测。
看完解析過程颜骤,再來看看添加過程 taskGraph.addEntryTasks(taskSelection.getTasks())
,taskGraph
是 DefaultTaskExecutionGraph
捣卤,來看看其 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);
}
// 調(diào)用 DefaultExecutionPlan.addEntryTasks()
executionPlan.addEntryTasks(taskSet);
// task graph 標(biāo)記為 DIRTY 狀態(tài)
graphState = GraphState.DIRTY;
}
這里主要做了兩件事情:
- 調(diào)用
DefaultExecutionPlan
的addEntryTasks()
八孝; - 將
TaskGraph
的狀態(tài)標(biāo)記為DIRTY
。
而這里的 addEntryTasks()
就會處理 task 之間的依賴關(guān)系鸠项,比如 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();
// 已經(jīng)處理過了
if (node.getDependenciesProcessed()) {
queue.removeFirst();
continue;
}
boolean filtered = !nodeSatisfiesTaskFilter(node);
// 過濾掉
if (filtered) {
queue.removeFirst();
// 標(biāo)記為處理
node.dependenciesProcessed();
node.doNotRequire();
filteredNodes.add(node);
continue;
}
if (visiting.add(node)) {
node.prepareForExecution();
// 主要是這個方法,里面處理依賴關(guān)系
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 是通過 TaskNodeFactory
的 getOrCreateNode()
創(chuàng)建的楼入。
// 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 的依賴關(guān)系解析就是在這里做的嘉熊。
2.2.4 填充 TaskGraph
回到 DefaultTaskExecutionPreparer
的 prepareForTaskExecution()
,繼續(xù)往下看扬舒。
// DefaultTaskExecutionPreparer.java
public void prepareForTaskExecution(GradleInternal gradle) {
buildConfigurationActionExecuter.select(gradle);
TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
// 計算有向無環(huán)圖
taskGraph.populate();
// ...
}
這里會調(diào)用了 DefaultTaskExecutionGraph
的 populate()
阐肤,來看看其源碼。
// DefaultTaskExecutionGraph.java
public void populate() {
ensurePopulated();
}
private void ensurePopulated() {
switch (graphState) {
// ...
case DIRTY:
executionPlan.determineExecutionPlan();
allTasks = null;
graphState = GraphState.POPULATED;
return;
// ...
}
}
在前面添加 task 的時候讲坎,已經(jīng)將 graphState
標(biāo)記為了 DIRTY
狀態(tài)孕惜,所以這里會走到 executionPlan.determineExecutionPlan()
,executionPlan
是 DefaultExecutionPlan
的實例晨炕,來看看其 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 的有向無環(huán)圖府瞄。
2.2.5 必要時調(diào)用 BuildListener
的 projectsEvaluated()
繼續(xù)往下看 DefaultTaskExecutionPreparer
的 prepareForTaskExecution()
。
// DefaultTaskExecutionPreparer.java
public void prepareForTaskExecution(GradleInternal gradle) {
buildConfigurationActionExecuter.select(gradle);
TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
taskGraph.populate();
includedBuildControllers.populateTaskGraphs();
// 如果是 --configure-on-demand 的情況下碘箍,是在這里調(diào)用的 projectEvaluated
if (gradle.getStartParameter().isConfigureOnDemand()) {
new ProjectsEvaluatedNotifier(buildOperationExecutor).notify(gradle);
}
}
生成 task 的有向無環(huán)圖后遵馆,會判斷是否有指定 --configure-on-demand
參數(shù),如果有指定丰榴,則調(diào)用 BuildListener
的 projectEvaluated()
货邓,因為在 Configure
階段,--configure-on-demand
只會對 root project 進(jìn)行配置四濒,如果對 Configure
階段不太熟悉的换况,可以先看看 Gradle源碼分析(三)。
最后盗蟆,回到 DefaultGradleLauncher
的 prepareTaskExecution()
戈二。
// DefaultGradleLauncher.java
private void prepareTaskExecution() {
if (stage == Stage.Configure) {
taskExecutionPreparer.prepareForTaskExecution(gradle);
// 解析完 tasks 填充 tasks 有向無環(huán)圖后,將狀態(tài)設(shè)置為 TaskGraph
stage = Stage.TaskGraph;
}
}
執(zhí)行完上述流程后會將 Gradle 狀態(tài)設(shè)置為 TaskGraph
喳资。至此觉吭,Gradle 的 TaskGraph
階段就分析完了。