An overview of the

I started a new series. The goal of this series of learning Gradle is to thoroughly understand Gradle. The main goal is to make notes on your own understanding to prevent forgetting

Gradle Series (1) : Groovy learning

Gradle Learning series (2) : Gradle core decryption

Gradle Plugins

Gradle dependencies

Gradle Transform. Gradle Transform

Gradle learning series (6) : Gradle source code parsing

Gradle source code parsing

gradlew

First of all, we usually use the command./ gradLew assembleDebug, where gradLew is the entrance of Gradle

exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
Copy the code

This command triggers GradleWrapperMain. It also supports $@ as an argument, which is how all of our usual gradLew commands work

Now take a look at GradleWrapperMain

GradleWrapperMain

public class GradleWrapperMain {
    // Run the gradLew script command to trigger the entry
    public static void main(String[] args) throws Exception {
        // This is to get the wrapper.jar and properties files in the project directoryFile wrapperJar = wrapperJar(); File propertiesFile = wrapperProperties(wrapperJar); File rootDir = rootDir(wrapperJar); .// The following two lines are the most important
        WrapperExecutor wrapperExecutor = WrapperExecutor.forWrapperPropertiesFile(propertiesFile);

        wrapperExecutor.execute(
            args, 
            new Install(logger, 
            new Download(logger, "gradlew", wrapperVersion()), new PathAssembler(gradleUserHome)),
            new BootstrapMainStarter());
    }

Copy the code

WrapperExecutor. ForWrapperPropertiesFile is through Java Properties to parse gradle/wrapper/gradle-wrapper. Properties files such as distributionUrl

WrapperExecutor. Execute (args) is the parameter in gradLew, Install is the parameter to manage whether the local project has the gradle version specified in the wrapper, if not, parse and download it. BootstrapMainStarter is the wrapper’s actual entry point for executing Gradle. Let’s take a look at the execute method

public void execute(String[] args, Install install, BootstrapMainStarter bootstrapMainStarter) throws Exception {
    // Config is the configuration resolved by gradle-wrapper.properties
    File gradleHome = install.createDist(config);
    bootstrapMainStarter.start(args, gradleHome);
}
Copy the code

Install. CreateDist (config) download gradle Wrappe dependencies and source code Gradle /wrapper/gradle-wrapper.properties configuredistributionURL. The download addresses are the distributionPath and zipStorePath configured in gradle-wrapper.properties. ZipStorePath is where the compressed package is downloaded and distributionPath is where it is decompressed

Gradle builds consist of the following 5 processes, and the enumeration of these processes

  private static enum Stage {
        LoadSettings,
        Configure,
        TaskGraph,
        RunTasks {
            String getDisplayName() {
                return "Build";
            }
        },
        Finished;

        private Stage() {
        }

        String getDisplayName() {
            return this.name(); }}Copy the code

Gradle builds go through five processes. Let’s examine each of these processes in turn

A LoadSettings.

LoadSettings mainly loads settings.gradle file, and then creates the corresponding project.

BootstrapMainStarter. Start function is executed gradle build process, through complex call process, will eventually trigger DefaultGradleLauncher. ExecuteTasks () method, we look at the way

 public GradleInternal executeTasks() {
        this.doBuildStages(DefaultGradleLauncher.Stage.RunTasks);
        return this.gradle;
    }
Copy the code

The doBuildStages method is called

 private void doBuildStages(DefaultGradleLauncher.Stage upTo) {
        // Check that the state is not FinishPreconditions.checkArgument(upTo ! = DefaultGradleLauncher.Stage.Finished,"Stage.Finished is not supported by doBuildStages.");

        try {
            
            if (upTo == DefaultGradleLauncher.Stage.RunTasks && this.instantExecution.canExecuteInstantaneously()) {
                // Execute this method if the state is RunTasks
                this.doInstantExecution();
            } else {
                // If not RunTasks, execute the following
                this.doClassicBuildStages(upTo); }}catch (Throwable var3) {
            this.finishBuild(upTo.getDisplayName(), var3); }}Copy the code

Next look at doClassicBuildStages

 private void doClassicBuildStages(DefaultGradleLauncher.Stage upTo) {
        this.prepareSettings();
        if(upTo ! = DefaultGradleLauncher.Stage.LoadSettings) {this.prepareProjects();
            if(upTo ! = DefaultGradleLauncher.Stage.Configure) {this.prepareTaskExecution();
                if(upTo ! = DefaultGradleLauncher.Stage.TaskGraph) {this.instantExecution.saveScheduledWork();
                    this.runWork(); }}}}Copy the code

This code is divided by state, and the method that each state needs to execute is differentiated

  • When the state is LoadSettings, prepareSettings is executed by loading the setting.gralde file and creating the corresponding project
  • When the state is Configure, perform prepareProjects
  • PrepareTaskExecution is performed when the state is TaskGraph
  • When the state is RunTasks, perform instantExecution. SaveScheduledWork () and runWork ()

Let’s go ahead and look at the prepareSettings method

private void prepareSettings() {
        if (this.stage == null) {
            this.buildListener.buildStarted(this.gradle);
            this.settingsPreparer.prepareSettings(this.gradle);
            // Set the status to LoadSettings
            this.stage = DefaultGradleLauncher.Stage.LoadSettings; }}Copy the code

buildListener.buildStarted(this.gradle)

First call the buildListener. BuildStarted (enclosing gradle); Notifies the build to begin. We talked about this callback in the previous article

settingsPreparer.prepareSettings(this.gradle);

Then the prepareSettings method for DefaultSettingsPreparer is executed

public void prepareSettings(GradleInternal gradle) {
        // Run the init.gradle script
        this.initScriptHandler.executeScripts(gradle); SettingsLoader settingsLoader = gradle.getParent() ! =null ? this.settingsLoaderFactory.forNestedBuild() : this.settingsLoaderFactory.forTopLevelBuild();
        // Find and load the location of setting.gradle
        settingsLoader.findAndLoadSettings(gradle);
    }
Copy the code

PrepareSettings basically does two things

  • Run the init.gradle script
  • Locate and load setting.gradle

The findAndLoadSettings method here does a lot of things like this:

  • Find the location of setting.gradle
  • Build the contents of the buildSrc folder, which is the buildSrc plug-in mentioned earlier
  • Parsing gradle. Properites
  • The analytic setting. Gradle
  • Create a project and subproject

2. ConfigureBuild

The LoadSettings phase is the configureBuild phase, which compiles gradle scripts into classes and executes them. This phase executes the prepareProjects method

    private void prepareProjects() {
        if (this.stage == DefaultGradleLauncher.Stage.LoadSettings) {
            Prepare classlocder / /
            ClassLoaderScope baseProjectClassLoaderScope = this.buildSourceBuilder.buildAndCreateClassLoader(this.gradle);
            this.gradle.setBaseProjectClassLoaderScope(baseProjectClassLoaderScope);
            // Here the prepareProjects method for DefaultProjectsPreparer is called
            this.projectsPreparer.prepareProjects(this.gradle);
            // Reset the status to Configure
            this.stage = DefaultGradleLauncher.Stage.Configure; }}Copy the code

Next, look at the prepareProjects method for DefaultProjectsPreparer

public void prepareProjects(GradleInternal gradle) {
        this.maybeInformAboutIncubatingMode(gradle);
        this.buildLoader.load(gradle.getSettings(), gradle);
        if (gradle.getParent() == null) {
            this.buildRegistry.beforeConfigureRootBuild();
        }
        / / comment 1
        if (gradle.getStartParameter().isConfigureOnDemand()) {
            this.projectConfigurer.configure(gradle.getRootProject());
        } else {
            / / comment 2
            this.projectConfigurer.configureHierarchy(gradle.getRootProject());
            (new ProjectsEvaluatedNotifier(this.buildOperationExecutor)).notify(gradle);
        }

        this.modelConfigurationListener.onConfigure(gradle);
    }
Copy the code
  • Note 1: If the parameter configure-on-demand is specified in the gradle.properties file, only the main project and the projects needed to execute the task will be configured.
  • Note 2: If no parameter is configured, then all items are configured, and the last call isTaskPathProjectEvaluatortheconfigureHierarchymethods
 public void configureHierarchy(ProjectInternal project) {
        this.configure(project);
        Iterator var2 = project.getSubprojects().iterator();

        while(var2.hasNext()) {
            Project sub = (Project)var2.next();
            this.configure((ProjectInternal)sub); }}Copy the code

So you go through all the porject, you configure all the projects, and then the configure method calls the run method of EvaluateProject

     public void run(final BuildOperationContext context) {
            this.project.getMutationState().withMutableState(new Runnable() {
                public void run() {
                    try {
                        EvaluateProject.this.state.toBeforeEvaluate();
                        / / callback ProjectEvaluationListener beforeEvaluate interface
                        LifecycleProjectEvaluator.this.buildOperationExecutor.run(new LifecycleProjectEvaluator.NotifyBeforeEvaluate(EvaluateProject.this.project, EvaluateProject.this.state));
                        if(! EvaluateProject.this.state.hasFailure()) {
                            EvaluateProject.this.state.toEvaluate();

                            try {
                                 // 2. The default init, wrapper task and default plug-in are set in the evaluate method, and the build. Gradle script is compiled and executed
                                LifecycleProjectEvaluator.this.delegate.evaluate(EvaluateProject.this.project, EvaluateProject.this.state);
                            } catch (Exception var10) {
                                LifecycleProjectEvaluator.addConfigurationFailure(EvaluateProject.this.project, EvaluateProject.this.state, var10, context);
                            } finally {
                                EvaluateProject.this.state.toAfterEvaluate();
                                / / callback ProjectEvaluationListener afterEvaluate
                                LifecycleProjectEvaluator.this.buildOperationExecutor.run(new LifecycleProjectEvaluator.NotifyAfterEvaluate(EvaluateProject.this.project, EvaluateProject.this.state)); }}if (EvaluateProject.this.state.hasFailure()) {
                            EvaluateProject.this.state.rethrowFailure();
                        } else{ context.setResult(ConfigureProjectBuildOperationType.RESULT); }}finally {
                        EvaluateProject.this.state.configured(); }}}); }Copy the code

This method basically does three things

  • The callback ProjectEvaluationListener beforeEvaluate interface
  • evaluateSet up theInit and wrapperTwo default tasks, set the default help pluginorg.gradle.help-tasks, and compile and executebuild.gradle
  • The callback ProjectEvaluationListener afterEvaluate interface.

3. TaskGraph

The next step is to configure the Task directed graph by calling DefaultGradleLauncher’s prepareTaskExecution method to create a directed acyclic graph

 private void prepareTaskExecution() {
        if (this.stage == DefaultGradleLauncher.Stage.Configure) {
            this.taskExecutionPreparer.prepareForTaskExecution(this.gradle);
            // Change the phase to TaskGraph
            this.stage = DefaultGradleLauncher.Stage.TaskGraph; }}Copy the code

Call the next BuildOperatingFiringTaskExecutionPreparer prepareForTaskExecution

  public void prepareForTaskExecution(GradleInternal gradle) {
        this.buildOperationExecutor.run(new BuildOperatingFiringTaskExecutionPreparer.CalculateTaskGraph(gradle));
    }
Copy the code

And then the run method of CalculateTaskGraph is called

  private class CalculateTaskGraph implements RunnableBuildOperation {

        public void run(BuildOperationContext buildOperationContext) {
            // Fill the task diagram
            final TaskExecutionGraphInternal taskGraph = this.populateTaskGraph();
            buildOperationContext.setResult(new Result() {
                public List<String> getRequestedTaskPaths() {
                    return this.toTaskPaths(taskGraph.getRequestedTasks());
                }

                public List<String> getExcludedTaskPaths() {
                    return this.toTaskPaths(taskGraph.getFilteredTasks());
                }

                private List<String> toTaskPaths(Set<Task> tasks) {
                    return ImmutableSortedSet.copyOf(Collections2.transform(tasks, new Function<Task, String>() {
                        public String apply(Task task) {
                            returntask.getPath(); } })).asList(); }}); }}Copy the code

Here we call the populateTaskGraph method directly to populate the task graph, so let’s take a look at that method

 TaskExecutionGraphInternal populateTaskGraph() {
            BuildOperatingFiringTaskExecutionPreparer.this.delegate.prepareForTaskExecution(this.gradle);
            return this.gradle.getTaskGraph();
        }

Copy the code

There are calls the DefaultTaskExecutionPreparer prepareForTaskExecution method

 public void prepareForTaskExecution(GradleInternal gradle) {
        / / comment 1
        this.buildConfigurationActionExecuter.select(gradle);
        TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
        / / comment 2
        taskGraph.populate();
        this.includedBuildControllers.populateTaskGraphs();
        if (gradle.getStartParameter().isConfigureOnDemand()) {
            (new ProjectsEvaluatedNotifier(this.buildOperationExecutor)).notify(gradle); }}Copy the code

See note 1 at first, and finally call DefaultBuildConfigurationActionExecuter select method, the source code is as follows

  public void select(final GradleInternal gradle) {
        this.projectStateRegistry.withLenientState(new Runnable() {
            public void run() {
                // Create a collection
                List<BuildConfigurationAction> processingBuildActions = CollectionUtils.flattenCollections(BuildConfigurationAction.class.new Object[]{DefaultBuildConfigurationActionExecuter.this.configurationActions, DefaultBuildConfigurationActionExecuter.this.taskSelectors});
                // Then the configure method is called
                DefaultBuildConfigurationActionExecuter.this.configure(processingBuildActions, gradle, 0); }}); }Copy the code

Note that you first create a List, and then you call the configure method, so let’s look at the source code for the configure method

  private void configure(final List<BuildConfigurationAction> processingConfigurationActions, final GradleInternal gradle, final int index) {
        if (index < processingConfigurationActions.size()) {
            ((BuildConfigurationAction)processingConfigurationActions.get(index)).configure(new BuildExecutionContext() {
                public GradleInternal getGradle() {
                    return gradle;
                }

                public void proceed() {
                    DefaultBuildConfigurationActionExecuter.this.configure(processingConfigurationActions, gradle, index + 1); }}); }}Copy the code

Here you can see is removed from the List in order, and then in turn perform ExcludedTaskFilteringBuildConfigurationAction, DefaultTasksBuildExecutionAction TaskNameResolvingBuildConfigurationAction, perform the configure method of class

Let’s look at the configure methods for each of these classes in turn

ExcludedTaskFilteringBuildConfigurationAction ## configure

  public void configure(BuildExecutionContext context) {
        GradleInternal gradle = context.getGradle();
        // Get the task to be excluded
        Set<String> excludedTaskNames = gradle.getStartParameter().getExcludedTaskNames();
        if(! excludedTaskNames.isEmpty()) { Set<Spec<Task>> filters =new HashSet();
            Iterator var5 = excludedTaskNames.iterator();

            while(var5.hasNext()) {
                String taskName = (String)var5.next();
                filters.add(this.taskSelector.getFilter(taskName));
            }
            // Add tasks to the TaskGraph to filter
            gradle.getTaskGraph().useFilter(Specs.intersect(filters));
        }

        context.proceed();
    }
Copy the code

The TaskGraph is set to filter tasks that need to be excluded from the task, so that the subsequent calculation of dependencies will exclude the corresponding task

DefaultTasksBuildExecutionAction ## configure

   public void configure(BuildExecutionContext context) {
        StartParameter startParameter = context.getGradle().getStartParameter();
        Iterator var3 = startParameter.getTaskRequests().iterator();

        TaskExecutionRequest request;
        do {
            if(! var3.hasNext()) { ProjectInternal project = context.getGradle().getDefaultProject();this.projectConfigurer.configure(project);
                List<String> defaultTasks = project.getDefaultTasks();
                if (defaultTasks.size() == 0) {
                    defaultTasks = Collections.singletonList("help");
                    LOGGER.info("No tasks specified. Using default task {}", GUtil.toString(defaultTasks));
                } else {
                    LOGGER.info("No tasks specified. Using project default tasks {}", GUtil.toString(defaultTasks));
                }

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

            request = (TaskExecutionRequest)var3.next();
        } while(request.getArgs().isEmpty());

        context.proceed();
    }
Copy the code

Will the command line pass in the name of the Task? If you specify the Task to execute, then do nothing

If not specified, see if there is a defaultTask in the project, which can be specified in build.gradle with defaultTasks

If the default task does not have one, set the specified task to Help task

TaskNameResolvingBuildConfigurationAction ## configure

 public void configure(BuildExecutionContext context) {
        GradleInternal gradle = context.getGradle();
        TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
        List<TaskExecutionRequest> taskParameters = gradle.getStartParameter().getTaskRequests();
        Iterator var5 = taskParameters.iterator();

        while(var5.hasNext()) {
            TaskExecutionRequest taskParameter = (TaskExecutionRequest)var5.next();
            / / parsing task
            List<TaskSelection> taskSelections = this.commandLineTaskParser.parseTasks(taskParameter);
            Iterator var8 = taskSelections.iterator();

            // Add task to taskGraph
            while(var8.hasNext()) {
                TaskSelection taskSelection = (TaskSelection)var8.next();
                LOGGER.info("Selected primary task '{}' from project {}", taskSelection.getTaskName(), taskSelection.getProjectPath());
                taskGraph.addEntryTasks(taskSelection.getTasks());
            }
        }

        context.proceed();
    }
Copy the code

There are two main operations here

  • If the task name is specified, the task name in the Project will be selected. If the task name is not specified, the task name in the Project will be selected
  • Walk through and add all selected Tasks to the taskGraph instance. This will handle the dependencies of the task, including dependson finalizedby MustrunAfter shouldrunAfter, And then the information is stored in the org. Gradle. Execution. Taskgraph. TaskInfo

Finally back to DefaultTaskExecutionPreparer prepareForTaskExecution 2

Call the taskGraph populate method to generate a task graph based on the tasks and dependencies calculated in the previous step

Four RunTasks.

Next, look at the RunTasks phase

 private void doClassicBuildStages(DefaultGradleLauncher.Stage upTo) {
        this.prepareSettings();
        if(upTo ! = DefaultGradleLauncher.Stage.LoadSettings) {this.prepareProjects();
            if(upTo ! = DefaultGradleLauncher.Stage.Configure) {this.prepareTaskExecution();
                if(upTo ! = DefaultGradleLauncher.Stage.TaskGraph) {this.instantExecution.saveTaskGraph();
                    / / comment 1
                    this.runWork(); }}}}Copy the code

The RunTasks phase calls the runWork() method in comment 1. Let’s look at the code in detail

 private void runWork() {
        if (this.stage ! = DefaultGradleLauncher.Stage.TaskGraph) {throw new IllegalStateException("Cannot execute tasks: current stage = " + this.stage);
        } else {
            List<Throwable> taskFailures = new ArrayList();
            / / comment 1
            this.buildExecuter.execute(this.gradle, taskFailures);
            if(! taskFailures.isEmpty()) {throw new MultipleBuildFailures(taskFailures);
            } else {
                this.stage = DefaultGradleLauncher.Stage.RunTasks; }}}Copy the code

The Execute method of DefaultBuildWorkExecutor is called at note 1


 public void execute(GradleInternal gradle, Collection<? super Throwable> failures) {
        this.execute(gradle, 0, failures);
    }


 private void execute(final GradleInternal gradle, final int index, final Collection<? super Throwable> taskFailures) {
        if (index < this.executionActions.size()) {
            // Execute the execute method of the list class
            ((BuildExecutionAction)this.executionActions.get(index)).execute(new BuildExecutionContext() {
                public GradleInternal getGradle() {
                    return gradle;
                }

                public void proceed() {
                    // Get the next execution in the list
                    DefaultBuildWorkExecutor.this.execute(gradle, index + 1, taskFailures); } }, taskFailures); }}Copy the code

This is going to be called firstDryRunBuildExecutionActiontheexecutemethods

    public void execute(BuildExecutionContext context, Collection<? super Throwable> taskFailures) {
        GradleInternal gradle = context.getGradle();
        / / comment 1if (gradle.getStartParameter().isDryRun()) { Iterator var4 = gradle.getTaskGraph().getAllTasks().iterator(); while(var4.hasNext()) { Task task = (Task)var4.next(); this.textOutputFactory.create(DryRunBuildExecutionAction.class).append(((TaskInternal)task).getIdentityPath().getPath()) .append("").style(Style.ProgressStatus).append("SKIPPED").println(); } } else { context.proceed(); }}}Copy the code

Check the command line at note 1 to see if there is an argument –dry-run. If there is, skip the execution of the task and print the task name and order

Then execute SelectedTaskExecutionAction the execute method

 public void execute(BuildExecutionContext context, Collection<? super Throwable> taskFailures) {
        GradleInternal gradle = context.getGradle();
        TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
        if (gradle.getStartParameter().isContinueOnFailure()) {
            taskGraph.setContinueOnFailure(true);
        }

        taskGraph.addTaskExecutionGraphListener(new SelectedTaskExecutionAction.BindAllReferencesOfProjectsToExecuteListener());
        / / comment 1
        taskGraph.execute(taskFailures);
    }
Copy the code

In the note 1 call the DefaultTaskExecutionGraph the execute method, we look at the specific code

 public void execute(Collection<? super Throwable> failures) {
        ProjectExecutionServiceRegistry projectExecutionServices = new ProjectExecutionServiceRegistry(this.globalServices);

        try {
            / / comment 1this.executeWithServices(projectExecutionServices, failures); } finally { projectExecutionServices.close(); }}Copy the code

The executeWithServices method was called at comment 1. Take a look at the source code

   private void executeWithServices(ProjectExecutionServiceRegistry projectExecutionServices, Collection<? super Throwable> failures) {
        ...

        try {
            / / comment 1
            this.planExecutor.process(this.executionPlan, failures, new DefaultTaskExecutionGraph.BuildOperationAwareExecutionAction(this.buildOperationExecutor.getCurrentOperation(), new DefaultTaskExecutionGraph.InvokeNodeExecutorsAction(this.nodeExecutors, projectExecutionServices)));
            LOGGER.debug("Timing: Executing the DAG took "+ clock.getElapsed()); } finally { ... }}Copy the code

Planexecutor. process is called at note 1, and finally the process method of DefaultPlanExecutor is called

 public void process(ExecutionPlan executionPlan, Collection<? super Throwable> failures, Action<Node> nodeExecutor) {
        ManagedExecutor executor = this.executorFactory.create("Execution worker for '" + executionPlan.getDisplayName() + "'");

        try {
            WorkerLease parentWorkerLease = this.workerLeaseService.getCurrentWorkerLease();
            / / comment 1this.startAdditionalWorkers(executionPlan, nodeExecutor, executor, parentWorkerLease); (new DefaultPlanExecutor.ExecutorWorker(executionPlan, nodeExecutor, parentWorkerLease, this.cancellationToken, this.coordinationService)).run(); this.awaitCompletion(executionPlan, failures); } finally { executor.stop(); }}Copy the code

The startAdditionalWorkers method is called at note 1

 private void startAdditionalWorkers(ExecutionPlan executionPlan, Action<? super Node> nodeExecutor, Executor executor, WorkerLease parentWorkerLease) {
        LOGGER.debug("Using {} parallel executor threads", this.executorCount);

        for(int i = 1; i < this.executorCount; ++i) { executor.execute(new DefaultPlanExecutor.ExecutorWorker(executionPlan, nodeExecutor, parentWorkerLease, this.cancellationToken, this.coordinationService)); }}Copy the code

By default, 8 threads are used to execute tasks

Some preprocessing before executing a Task

First, call TaskExecutionListener#beforeExecute.

CatchExceptionTaskExecuter.execute // Add a try catch to prevent exceptions during execution
ExecuteAtMostOnceTaskExecuter.execute  // Check whether the task has been executed
SkipOnlyIfTaskExecuter.execute  // Check whether the onlyif condition of the task is met
SkipTaskWithNoActionsExecuter.execute  // Skip tasks that have no action. Without action, the task does not need to be executed
ResolveTaskArtifactStateTaskExecuter.execute  // Set the artifact's state
SkipEmptySourceFilesTaskExecuter.execute  // Skip tasks whose source file has been set but whose source file is empty. An empty source file indicates that the task has no resources to process
ValidatingTaskExecuter.execute()  // Verify whether the task can be executed
ResolveTaskOutputCachingStateExecuter.execute // Process the task output cache
SkipUpToDateTaskExecuter.execute  // Skip the update-to-date task
ExecuteActionsTaskExecuter.execute // Execute the task

Copy the code

Actually executing task

Final call ExecuteActionsTaskExecuter. TaskExecution execute to actually perform the task

   public WorkResult execute(@Nullable InputChangesInternal inputChanges, InputChangesContext context) {
            ....

            WorkResult var5;
            try {
                var5 = this.executeWithPreviousOutputFiles(inputChanges);
            } finally {
                outputs.setPreviousOutputFiles((FileCollection)null);
            }

            return var5;
        }

    private WorkResult executeWithPreviousOutputFiles(@Nullable InputChangesInternal inputChanges) {
            this.task.getState().setExecuting(true);

            WorkResult var2;
            try {
                ExecuteActionsTaskExecuter.LOGGER.debug("Executing actions for {}.".this.task);
                // Callback the TaskActionListener's beforeActions interface.
                ExecuteActionsTaskExecuter.this.actionListener.beforeActions(this.task);
                // The traversal execution executes all actions
                ExecuteActionsTaskExecuter.this.executeActions(this.task, inputChanges);
                var2 = this.task.getState().getDidWork() ? WorkResult.DID_WORK : WorkResult.DID_NO_WORK;
            } finally {
                this.task.getState().setExecuting(false);
                // Callback the TaskActionListener's beforeActions interface.
                ExecuteActionsTaskExecuter.this.actionListener.afterActions(this.task);
            }

            return var2;
        }
Copy the code

There are three main things that have been done here

  • Calls back the TaskActionListener’s beforeActions interface.
  • Traversal execution Executes all actions. Executing a Task is essentially executing an Action
  • Calls back the TaskActionListener’s beforeActions interface.

Five Finish.

The only important thing to do in the Finished phase is to call back to the buildListener’s buildFinished interface

Here borrow [Android training manual] Gradle – Gradle source code analysis in a flowchart, to show the order of the whole process

conclusion

The Gradle build can be summarized in the following steps

  • Parse seeting.gradle and execute it, generating a project instance
  • Parse build.gradle and execute
  • Generate a task dependency graph
  • To perform a task

reference

Mainly refer to the following blog, thank you for your efforts

Gradle source code analysis

【【 soul 7 ask 】 Deep exploration Gradle automatic building technology (5, Gradle plug-in architecture implementation principle analysis — first)