Java Use the task-setting tutorial in the Automated deployment tool Gradle _java

Source: Internet
Author: User
Tags closure documentation jcenter

Tasks
The following code shows three Gradle tasks, which will explain the difference later.

 Task MyTask {
 println "Hello, world!"
 }

 Task MyTask {
 Dolast {
 println "Hello, world!"
 }
 }

 Task MyTask << {
 println "Hello, world!"
 }

My goal is to create a task that will print out "Hello, world!" when it executes. When I first created a task, I guessed that it should be written like this:

 Task MyTask {
 println "Hello, world!"
 }

Now, try to execute this mytask, enter Gradle mytask at the command line, and print as follows:

 user$ gradle mytask
 Hello, world!
 : MyTask up-to-date

This task looks like it's working. It printed "Hello, world!".
But it's not really what it looks like. Now let's see why. At the command line, enter Gradle tasks to view all available tasks.

 user$ gradle Tasks
 Hello, world!
 : Tasks

 ------------------------------------------------------------ All
 tasks runnable from root project
 ------------------------------------------------------------

 Build the Setup tasks
 -----------------
 init-initializes a new gradle build. [incubating]
 ..........

Wait, why "Hello, world!" Did you print it out? I just wanted to see what tasks were available and did not perform any custom task!
The reason is simply that the Gradle task has two major phases in its lifecycle: Configuration and execution.
Maybe my words are not very accurate, but it does help me understand tasks.

The task is configured first before the task is executed Gradle. So the question is, how do I know which code in my task is being executed during the configuration and which code is running while the task is executing? The answer is that the code at the top of the task is the configuration code, such as:

 Task MyTask {
 def name = "Pavel"//<--this line of code executes
 println "Hello, world!" in the configuration phase <--This line of code will also be executed at the configuration stage
 }

That's why when I perform gradle tasks, I print out "Hello, world!." -Because the configuration code was executed. But that's not the effect I want, I Want "Hello, world!." It only prints when I explicitly call MyTask. The easiest way to achieve this effect is to use the Task#dolast () method.

 Task MyTask {
 def text = ' Hello, world! '//configure my task
 dolast {
 println text//this be executed when my Task is called
 }
 }

Now, "Hello, world!." It will only be printed when I perform Gradle mytask. Cool, now that I know how to configure and make tasks do the right thing. There is also a question, in the first instance, what does the third task's << symbol mean?

 Task MyTask2 << {
 println "Hello, world!" 
 }

This is actually just a dolast version of the syntax sugar. It works the same way as the following:

 Task MyTask {
 Dolast {
 println ' Hello, world! '//this is executed as my task is called
 }
 }

However, all the code in this notation is in the execution section, and there is no code for the configuration part, so it is better suited to tasks that are not configured by the simple small. Once your task needs to be configured, use the Dolast version.

Grammar

Gradle scripts are written using the groovy language. Groovy's syntax is a bit like Java, and I hope you can accept it.
If you are already familiar with groovy, you can skip this section.
There is a very important concept in groovy that you need to understand –closure (closures)

Closures

Closure is the key to our understanding of gradle. Closure is a separate block of code that can receive parameters, return values, or be assigned to variables. And Java in the callable interface, future similar, also like function pointers, how convenient for you to understand all good ...

The key is that the code executes when you call it, not when it is created. Look at an example of a closure:

def myclosure = {println ' Hello world! '}

Execute our closure
myclosure ()

#output: Hello world!

The following is a closure that receives the parameters:

def myclosure = {String str-> println str}

//execute our closure
myclosure (' Hello world! ')

#output: Hello world!

If closure only receives one parameter, you can use it to reference this parameter:

def myclosure = {println it}

//execute our closure
myclosure (' Hello world! ')

#output: Hello world!

Closure to receive multiple parameters:

def myclosure = {String str, int num-> println "$STR: $num"}

//execute our closure
myclosure (' My String ', 21 )

#output: My string:21

In addition, the type of the parameter is optional, and the example above can be abbreviated as follows:

def myclosure = {str, num-> println "$STR: $num"}

//execute our closure
myclosure (' My string ',)

#outp Ut:my string:21

It's cool. The variables in the current context can be used in closure. By default, the current context is the class in which closure was created:

def myVar = ' Hello world! '
def myclosure = {println MyVar}
myclosure ()

#output: Hello world!

Another cool point is that the context of the closure can be changed through Closure#setdelegate (). This feature is useful:

def myclosure = {println MyVar}//i ' m referencing MyVar from MyClass class
MyClass m = new MyClass ()
Myclosure.set Delegate (m)
myclosure ()

class MyClass {
 def myVar = ' Hello from myclass! '
}

#output: Hello from myclass!

As you will see, MyVar does not exist when the closure is created. This is not a problem, because when we execute closure, in the context of closure, MyVar exists. In this example. Because I changed its context to m before executing closure, so MyVar is present.

Pass the closure as a parameter

The benefit of closure is that it can be passed to different methods that can help us decouple execution logic. In the previous example I have shown how to pass closure to an instance of a class. Below we'll look at the various ways to receive closure as parameters:

1. Receive only one parameter, and the parameter is closure method: MyMethod (Myclosure)
2. If the method receives only one parameter, parentheses can be omitted: MyMethod myclosure
3. You can use inline Closure:mymethod {println ' Hello world '}
4. Methods of receiving two parameters: MyMethod (arg1, Myclosure)
5. Similar to 4, singular closure are inline: MyMethod (arg1, {println ' Hello World '})
6. If the last argument is closure, it can be taken from the small brackets: MyMethod (arg1) {println ' Hello world '}

Here I just want to remind you, 3 and 6 of the wording is not look familiar?

Gradle Example

Now that we know the basic syntax, how do we use it in the Gradle script? Let's look at the following example:

Buildscript {
 repositories {
 jcenter ()
 }
 dependencies {
 classpath ' com.android.tools.build: gradle:1.2.3 '
 }
}

allprojects {
 repositories {
 jcenter ()
 }
}

Knowing the syntax of groovy, is the example above well understood?
The first is a Buildscript method that receives a closure:

def buildscript (Closure Closure)

Next is the Allprojects method, which also receives a closure parameter:

def allprojects (Closure Closure)

The others are similar ...

It seems a lot easier now, but there's still one thing that doesn't make sense: Where are these methods defined? The answer is project.

Project

This is a key to understanding Gradle scripts.

The statement block at the top of the build script is delegated to the instance of project
This means that project is exactly where I'm looking.
Search the Buildscript method on the document page of project and find the buildscript{} script block. Wait, what the hell is script blocks? According to the documentation:

Script block is the only way to receive closure as a parameter
Continue reading Buildscript's documentation, which says delegates To:scripthandler from Buildscript. In other words, we pass to the closure of the Buildscript method, and the final execution context is scripthandler. In the above example, the closure that we passed to Buildscript called the repositories (closure) and dependencies (closure) methods. Since closure was entrusted to the Scripthandler, then we went to Scripthandler to find the dependencies method.

void dependencies (Closure configureclosure) was found, depending on the document, dependencies is used to configure the dependencies of the script. and dependencies finally commissioned to the Dependencyhandler.

See how widely the gradles is used by delegates. It's important to understand a delegate.

Script blocks

By default, many script blocks are predefined in project, but the Gradle plug-in allows us to define new script blocks!
This means that if you send some {...} at the top of the build script, but you can't find the script blocks or the method in the Gradle document, most of the cases are script blocks from the plugin definition.

Android Script Block

Let's take a look at the default Android App/build.gradle file:

Apply plugin: ' Com.android.application '

android {
 compilesdkversion
 buildtoolsversion "22.0.1"

 defaultconfig {
 ApplicationID "Com.trickyandroid.testapp"
 minsdkversion
 targetsdkversion
 Versioncode 1
 versionname "1.0"
 }
 buildtypes {release
 {
 minifyenabled false
 Proguardfiles getdefaultproguardfile (' proguard-android.txt '), ' Proguard-rules.pro '}}}


Task order

I noticed that most of the problems I encountered while using gradle were related to the order in which the tasks were executed. Obviously, if my build works better, if my task is done at the right time. Let's take a closer look at how to change the order in which tasks are executed.

DependsOn

I think the most straightforward way to illustrate your task's reliance on other tasks is to use the DependsOn method.
For example, the following scenario, where task a already exists, we want to add a task B that must be executed after a is executed:

This is a very simple scenario, assuming that A and B are defined as follows:

Task A << {println ' Hello from a '}
task B << {println ' Hello from B '}

Just a simple call to B.dependson A is OK.
This means that as soon as I perform task B,task a will execute first.

paveldudka$ Gradle b
: A
hello from a
: b
Hello from B

Alternatively, you can declare its dependencies in the configuration area of a task:

Task a << {println ' Hello from a '}
task B {
 DependsOn a
 dolast {
 println ' Hello from B ' 
 }
   }

What if we want to insert our task in an already existing task dependency?

The process is similar to just now. Assume that the following task dependencies already exist:

Task A << {println ' Hello from a '}
task B << {println ' Hello from B '}
task C << {println ' Hell O from C '}

b.dependson A
C.dependson B

To join our new task.

Task B1 << {println ' Hello from B1 '}
b1.dependson B
C.dependson B1

Output:

paveldudka$ gradle C
: A
hello from a
: b
Hello from b
: B1
Hello to B1
: C
Hello from C

Note that DependsOn adds a task to a dependent collection, so it is no problem to rely on multiple tasks.

Task B1 << {println ' Hello from B1 '}
b1.dependson B
B1.dependson Q

Output:

paveldudka$ gradle B1
: A
hello from a
: b
Hello from b
: q
Hello from q
: B1
Hello from B1

Mustrunafter

Now suppose I have another task, which relies on two other tasks. Here I use a real scene where I have two tasks, a task for unit tests, and a task for a UI test. Another task is to run all the tests, and it relies on the previous two tasks.

Task Unit << {println ' Hello to Tests '}
task ui << {println ' Hello from UI tests '}
task tests & lt;< {println ' Hello from all tests! '}

Tests.dependson Unit
Tests.dependson UI

Output:

paveldudka$ Gradle tests
: UI
Hello from UI tests
: unit
Hello to Unit tests
: Tests
Hello From all tests!

Although Unitest and UI test sub execute before the test task, the order in which the Unit and UI two tasks are executed is not guaranteed. Although this is now done in alphabetical order, this is dependent on the implementation of the Gradle, and your code must not rely on this order.
Because the UI test time is much longer than the unit test time, I want the unit test to execute first. One solution is to make the UI task dependent on the unit task.

Task Unit << {println ' Hello to Tests '}
task ui << {println ' Hello from UI tests '}
task tests & lt;< {println ' Hello from all tests! '}

Tests.dependson unit
Tests.dependson UI
Ui.dependson//<--I added this dependency

Output:

paveldudka$ gradle tests
: unit
Hello to Unit tests
: UI
Hello from UI tests
: Tests
Hello From all tests!

The unit test is now executed before the UI test.
But there's a nasty problem here, and my UI test doesn't really depend on the unit test. I want to be able to execute the UI test separately, but every time I execute the UI test, I do the unit test first.
It's going to take a mustrunafter here. Mustrunafter does not add dependencies, it simply tells Gradle the priority of execution if two tasks exist at the same time. For example, we can specify Ui.mustrunafter unit here so that if the UI task and the unit task exist at the same time, Gradle will execute unit test first, and if only the Gradle UI is executed, the unit task will not be executed.

Task Unit << {println ' Hello to Tests '}
task ui << {println ' Hello from UI tests '}
task tests & lt;< {println ' Hello from all tests! '}

Tests.dependson unit
Tests.dependson UI
Ui.mustrunafter

Output:

paveldudka$ gradle tests
: unit
Hello to Unit tests
: UI
Hello from UI tests
: Tests
Hello From all tests!

Dependencies are shown below:

Mustrunafter is still an experimental function in Gradle2.4.
Finalizedby

Now that we have two task,unit and UI, assuming that these two tasks will output the test report, now I want to combine the two test reports into one:

Task Unit << {println ' Hello to Tests '}

task ui << {println ' Hello from UI tests '}
task tests & lt;< {println ' Hello from all tests! '}
Task Mergereports << {println ' Merging test reports '}

Tests.dependson unit
Tests.dependson UI
Ui.mustrunafter Unit
Mergereports.dependson tests

Now if I want to get a test report for the UI and unit, it's OK to execute the task Mergereports.

paveldudka$ gradle mergereports
: unit
Hello to Unit tests
: UI
Hello from UI tests
: Tests
Hello from all tests!
: mergereports
merging test reports

This task can work, but it looks so stupid. Mergereports from the user's point of view is not particularly good. I want to execute the tests task to get a test report without having to know the existence of mergereports. Of course I can move the logic of the merge to the tests task, but I don't want to make the tests task too bloated, and I continue to put the logic of the merge in the Mergereports task.
Finalizeby came to rescue. As the name suggests, Finalizeby is a task to be executed after a task has been executed. Modify our script as follows:

Task Unit << {println ' Hello to Tests '}
task ui << {println ' Hello from UI tests '}
task tests & lt;< {println ' Hello from all tests! '}
Task Mergereports << {println ' Merging test reports '}

Tests.dependson unit
Tests.dependson UI
Ui.mustrunafter Unit
Mergereports.dependson tests

tests.finalizedby mergereports

Now execute the tests task to get the test report:

paveldudka$ gradle tests
: unit
Hello to Unit tests
: UI
Hello from UI tests
: Tests
Hello from all tests!
: mergereports
merging test reports

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.