17. Gradle編譯其他應用代碼流程(五) - 設置Task過程

接上一篇 15. Gradle編譯其他應用代碼流程(四) - Configure過程 繼續分析


一. task選擇

到了這個階段,gradle開始計算task入口是哪個? 選擇的邏輯是這樣:

  1. 如果用戶收入了task,比如這樣的指令'gradle pmd',那麼就執行pmd這個task

  2. 如果用戶沒有輸入task,比如直接輸入'gradle',那麼看有沒有默認的task

  3. 如果沒有默認的task,那就執行help這個task。大家可以試下直接輸入gradle,看看輸出什麼內容。


接下來看源代碼。

文件路徑:subprojects\core\src\main\java\org\gradle\initialization\DefaultGradleLauncher.java

private void doBuildStages(Stage upTo) {
        ...

        // After this point, the GradleLauncher cannot be reused
        stage = Stage.Build;

        // Populate task graph
        buildOperationExecutor.run("Calculate task graph", new Runnable() {
            @Override
            public void run() {
                buildConfigurationActionExecuter.select(gradle);
                if (gradle.getStartParameter().isConfigureOnDemand()) {
                    buildListener.projectsEvaluated(gradle);
                }
            }
        });

        ...
    }


文件路徑:

subprojects\core\src\main\java\org\gradle\execution\DefaultBuildConfigurationActionExecuter.java

public class DefaultBuildConfigurationActionExecuter implements BuildConfigurationActionExecuter {
    ...
    public void select(GradleInternal gradle) {
        List<BuildConfigurationAction> processingBuildActions = CollectionUtils.flattenCollections(BuildConfigurationAction.class, configurationActions, taskSelectors);
        configure(processingBuildActions, gradle, 0);
    }

    ...

    private void configure(final List<BuildConfigurationAction> processingConfigurationActions, final GradleInternal gradle, final int index) {
        if (index >= processingConfigurationActions.size()) {
            return;
        }
        BuildConfigurationAction action  = processingConfigurationActions.get(index);
        System.out.println("DefaultBuildConfigurationActionExecuter action: " + action + " index: " + index);
        /*processingConfigurationActions.get(index)*/action.configure(new BuildExecutionContext() {
            public GradleInternal getGradle() {
                return gradle;
            }

            public void proceed() {
                configure(processingConfigurationActions, gradle, index + 1);
            }

        });
    }
}


這個地方的寫法挺奇怪的,它的想法是遍歷processingConfigurationActions裏面的每個action,然後執行它的configure方法,所以它用了遞歸。

但是個人覺得直接用循環不是更簡單直接嗎?


先不去管這些,processingConfigurationActions裏面有3個成員,他們繼承自同一接口BuildConfigurationAction。

org.gradle.execution.ExcludedTaskFilteringBuildConfigurationAction@3ee68eb2 index: 0
org.gradle.execution.DefaultTasksBuildExecutionAction@49cd08f9 index: 1
org.gradle.execution.TaskNameResolvingBuildConfigurationAction@4eace42b index: 2


他們3個分別處理的事情不一樣。

a. ExcludedTaskFilteringBuildConfigurationAction用來處理不執行的task,如果用戶有配置的話。

代碼如下:

文件路徑:

subprojects\core\src\main\java\org\gradle\execution\ExcludedTaskFilteringBuildConfigurationAction.java

/**
 * A {@link BuildConfigurationAction} which filters excluded tasks.
 */
public class ExcludedTaskFilteringBuildConfigurationAction implements BuildConfigurationAction {
    ...

    public void configure(BuildExecutionContext context) {
        GradleInternal gradle = context.getGradle();
        Set<String> excludedTaskNames = gradle.getStartParameter().getExcludedTaskNames();
        if (!excludedTaskNames.isEmpty()) {
            final Set<Spec<Task>> filters = new HashSet<Spec<Task>>();
            for (String taskName : excludedTaskNames) {
                filters.add(taskSelector.getFilter(taskName));
            }
            gradle.getTaskGraph().useFilter(Specs.intersect(filters));
        }

        context.proceed();
    }
}


b. DefaultTasksBuildExecutionAction用來處理默認的task,如果用戶有輸入task,那麼就使用用戶輸入的。比如用戶輸入'gradle pmd',那麼使用的task就是pmd

如果用戶沒有輸入task,那麼就使用默認的task

如果默認task也沒有,則使用help task,比如用戶直接輸入'gradle'

文件路徑:

subprojects\core\src\main\java\org\gradle\execution\DefaultTasksBuildExecutionAction.java

public class DefaultTasksBuildExecutionAction implements BuildConfigurationAction {
    ...

    public void configure(BuildExecutionContext context) {
        StartParameter startParameter = context.getGradle().getStartParameter();
        System.out.println("DefaultTasksBuildExecutionAction configure. startParameter: " + startParameter);

        //判斷是否有輸入task?
        for (TaskExecutionRequest request : startParameter.getTaskRequests()) {
            if (!request.getArgs().isEmpty()) {
                context.proceed();
                return;
            }
        }

        //沒有輸入task,嘗試使用默認task和help task
        // Gather the default tasks from this first group project
        ProjectInternal project = context.getGradle().getDefaultProject();

        //so that we don't miss out default tasks
        projectConfigurer.configure(project);

        List<String> defaultTasks = project.getDefaultTasks();
        if (defaultTasks.size() == 0) {
            defaultTasks = Collections.singletonList(ProjectInternal.HELP_TASK);
            LOGGER.info("No tasks specified. Using default task {}", GUtil.toString(defaultTasks));
            System.out.println("No tasks specified. Using default task {}" + "-" + GUtil.toString(defaultTasks));
        } else {
            LOGGER.info("No tasks specified. Using project default tasks {}", GUtil.toString(defaultTasks));
            System.out.println("No tasks specified. Using project default tasks {}" + " - " + GUtil.toString(defaultTasks));
        }

        startParameter.setTaskNames(defaultTasks);
        context.proceed();
    }
}


c. TaskNameResolvingBuildConfigurationAction

把輸入的task(如果沒有輸入,則使用默認task或者 help)添加到executer裏面,爲真正執行做準備。

代碼路徑:

subprojects\core\src\main\java\org\gradle\execution\TaskNameResolvingBuildConfigurationAction.java

/**
 * A {@link BuildConfigurationAction} which selects tasks which match the provided names. For each name, selects all tasks in all
 * projects whose name is the given name.
 */
public class TaskNameResolvingBuildConfigurationAction implements BuildConfigurationAction {
    ...

    public void configure(BuildExecutionContext context) {
    	System.out.println("TaskNameResolvingBuildConfigurationAction configure 1");
        GradleInternal gradle = context.getGradle();
        TaskGraphExecuter executer = gradle.getTaskGraph();

        List<TaskExecutionRequest> taskParameters = gradle.getStartParameter().getTaskRequests();
        for (TaskExecutionRequest taskParameter : taskParameters) {
        	System.out.println("TaskNameResolvingBuildConfigurationAction configure 2");
            List<TaskSelector.TaskSelection> taskSelections = commandLineTaskParser.parseTasks(taskParameter);
            for (TaskSelector.TaskSelection taskSelection : taskSelections) {
                LOGGER.info("Selected primary task '{}' from project {}", taskSelection.getTaskName(), taskSelection.getProjectPath());
                System.out.println("Selected primary task '{}' from project {}" + taskSelection.getTaskName() + "-"+ taskSelection.getProjectPath());
                executer.addTasks(taskSelection.getTasks());
            }
        }

        context.proceed();
    }

}



二. 通知projectsEvaluated

if (gradle.getStartParameter().isConfigureOnDemand()) {
    buildListener.projectsEvaluated(gradle);
}


到此爲止,所有的準備工作都已經做好了,接下就要真正的執行這個task了。

  1. 配置文件加載

  2. gradle文件加載以及相應的plugin 類加載

  3. 要執行的task選擇


下一篇帖子講task的執行。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章