Gradle 基础学习(三) 认识Command-Line Interface

Gradle命令行接口

除了IDE外,我们主要通过Gradle命令行接口来运行Gradle任务和管理Gradle项目。

下面是Gradle命令行使用的一些参考,熟悉后建议实际项目中使用Gradle Wrapper,gradle用法都可以替换为gradlew (macOS / Linux) 或gradlew.bat (windows)。

Gradle命令行格式

gradle [taskName...] [--option-name...]

选项可以在任务名称之前和之后 

gradle [--option-name...] [taskName...] 

多个任务之间用空格分隔 

gradle [taskName1 taskName2...] [--option-name...] 

接受值的选项和参数之间使用=号, 不用=也可以,但不推荐。 

gradle [...] --console=plain 

启用行为的选项具有长格式选项,其反义用--no-指定。 

gradle [...] --build-cache

gradle [...] --no-build-cache

许多长格式选项有等价的简写,比如 

gradle --help

gradle -h

命令行用法 

执行任务(tasks) 

执行任务是Gradle最重要也是最常用的,Gradle项目的整个构建流程就是由多个任务按照正确顺序执行来完成的。

在Gradle多项目构建中,有一个项目路径的概念

项目路径具有以下模式: 它以一个可选的冒号(:)开头,表示根项目。

项目路径的其余部分是项目名称的冒号分隔序列,其中,下一个项目是前一个项目的子项目:

:sub-project-1 

表示的是根项目下的sub-project-1子项目,默认对应的文件布局就是sub-project-1目录。 

现在我们在根项目上执行一个名为myTask的任务:

$ gradle :myTask

 这会执行myTask任务,以及它的所有依赖项。在执行它之前,先执行依赖项。

在根项目上执行子项目中的任务:

$ gradle :subproject:taskName 等效于 $ gradle subproject:taskName

此时,子项目前面的开头冒号可省略。

从根目录执行一个只包含名称的任务,那么整个项目中只要是这个名称的任务都会被执行。

比如我们在根项目和app、app2子项目的构建脚本文件里都注册了myTask任务,从根项目执行下面命令:

$ gradle myTask

> Configure project :

> Configure project :app

> Task :myTask UP-TO-DATE

> Task :app:myTask UP-TO-DATE

> Task :app2:myTask UP-TO-DATE

 可以看到根项目和子项目的myTask都执行了。

所以,如果不确定某个任务是不是唯一的,最好还是使用项目路径的形式,这样我们可以明确知道要执行什么任务。

从子项目里执行任务:

$ cd subproject

$ gradle taskName

$ gradle myTask

> Task :app:myTask UP-TO-DATE

Skipping task ':app:myTask' as it has no actions.

BUILD SUCCESSFUL in 1s

 从子目录使用Gradle Wrapper命令为 ../gradlew taskName 

只执行了子项目中的任务,和在根目录下不同,后者会执行全部子项目中的taskName。

子项目中如果使用冒号开头,比如$ gradle :taskName,执行的则是根项目的taskName,因为前面说过冒号代表根项目。

为任务提供选项

在任务名后加空格,--作为选项的前缀

$ gradle exampleTask --exampleOption=exampleValue 

从内置选项中消除任务选项的歧义

Gradle不会阻止任务使用与内建选项冲突的选项,像 --profile 或 --help。 

但允许我们在命令行中的任务名称前使用--分隔符来消除内置选项和任务选项的冲突:

 $ gradle [--built-in-option-name...] -- [taskName...] [--task-option-name...] 

假如mytask任务会接受一个名为profile的选项:

在gradle mytask --profile中, Gradle接受--profile作为内置的gradle选项

在gradle -- mytask --profile=value中, Gradle传递--profile作为任务选项

执行多个任务

我们可以指定多个任务,任务的依赖关系决定了执行顺序,没有依赖的任务可能会在命令行中列出的顺序之前执行。

比如我们在app的构建脚本中定义taskA,taskB,taskA依赖taskB:

tasks.register("taskB") {
	println("register app taskB")
    doFirst {
        // Task action = Execution code
        // Run before exiting actions
        println("app taskB doFirst")
    }
}

tasks.register("taskA") {
	println("register app taskA")
	dependsOn(tasks.taskB)
    doFirst {
        // Task action = Execution code
        // Run before exiting actions
        println("app taskA doFirst")
    }

}

然后命令行中的任务顺序是taskA taskB,执行:

$ gradle taskA taskB

register app taskA

register app taskB

> Task :app:taskB

app taskB doFirst

> Task :app:taskA

app taskA doFirst

BUILD SUCCESSFUL in 1s

1 actionable task: 1 executed

看到taskB先执行了,因为依赖要求执行taskA之前,先要执行taskB。

如果是相互独立的任务,以下命令会按照他们在命令行中的顺序执行:

$ gradle test deploy 

命令行顺序安全性 

有时候,两个task之间没有依赖关系,但是对两个task的执行顺序却有所要求。

例如,下面的命令中,clean和build分别是负责清理和构建的任务,没有依赖关系,Gradle总是会先执行clean再build,因为build之后执行clean是不对的,clean会删除build的输出。

$ gradle clean build 或者 $ gradle build clean 

Gradle会通过内部规则排序任务来尊重任务顺序的安全性。

任务排序和任务依赖之间的主要区别在于,排序规则不会影响将执行哪些任务,只会影响它们的执行顺序。

任务排序在许多场景中都很有用:

强制执行任务的顺序:比如build 永远不会在clean 之前运行。

在构建的早期运行构建验证:例如,在开始发布构建工作之前验证我是否拥有正确的凭据。

通过在长时间验证任务之前运行快速验证任务来更快地获得反馈:例如,单元测试应该在集成测试之前运行。

聚合特定类型的所有任务的结果的任务:例如测试报告任务组合所有已执行测试任务的输出。

 在 Gradle 中,提供了两个用于控制任务执行顺序的方法mustRunAfter 和 shouldRunAfter 。这两个方法都用于定义任务之间的依赖关系,但它们有不同的行为和语义。

mustRunAfter 

用于确保一个任务在另一个任务之后运行。如果两个任务之间没有直接的依赖关系,并且你希望一个任务在另一个任务之后执行,你可以使用 mustRunAfter。这个方法创建了一个“软依赖”,即如果可能的话,Gradle 会尽量保证这个顺序,但它并不强制要求这个顺序。

如果因为某些原因(比如任务之间的直接依赖关系或其他任务的执行顺序),Gradle 不能保证 mustRunAfter 指定的顺序,它仍然会尝试执行构建。在这种情况下,Gradle 可能会输出一个警告,说明它没有按照预期的顺序执行任务。

shouldRunAfter

shouldRunAfter 与 mustRunAfter 类似,也是用于指定任务执行顺序的。然而,shouldRunAfter 创建的是一个“更软的依赖”。它表达的是一个建议,告诉 Gradle 如果可能的话,尽量按照这个顺序执行任务。但是,如果因为其他原因(如直接依赖关系)导致这个顺序不能实现,Gradle 会忽略这个建议,并且不会输出任何警告。

在实践中,使用 mustRunAfter 和 shouldRunAfter 时需要谨慎,因为过度使用这些软依赖可能会导致构建逻辑变得复杂且难以维护。最好通过明确的依赖关系(使用 dependsOn 或其他依赖配置方法)来定义任务之间的顺序。这样,Gradle 可以更准确地确定任务的执行顺序,并且构建逻辑也更加清晰和可预测。

从执行中排除任务

我们可以使用-x或--exclude-task命令行选项并提供任务名称排除一个任务,排除的任务不会被执行:

$ gradle dist --exclude-task test

> Task :compile

compiling source

> Task :dist

building the distribution

BUILD SUCCESSFUL in 0s

2 actionable tasks: 2 executed

 Figure 1. Simple Task Graph

在这个例子中,我们看到test没有执行,尽管dist依赖它。test任务的依赖项,比如compileTest,也不会被执行。其他任务所依赖的test的依赖项(例如compile)仍然会被执行。

排除test,会排除test自身以及只被test依赖的任务。

强制执行任务

Gradle提供了许多优化方式来加速构建, Gradle会检查这些任务,如果任务能够重用上次执行的输出,就会跳过执行,标记为UP-TO-DATE或FROM-CACHE等。

命令行选项--rerun-tasks可以告诉Gradle忽略这些up-to-date之类的检查, 重新执行任务以及任务的依赖项。

$ gradle test --rerun-tasks

这有点像执行 gradle clean test,但不删除build的输出。

或者使用内置的task选项--rerun告诉Gradle需要重新运行一个特定的任务。

在一个任务失败后继续构建 

默认情况下,当任何任务执行失败时,Gradle 都会立即中止执行并标记构建为失败。这种设计有几个优点:

  1. 快速反馈:当任务失败时立即停止构建,开发者可以更快地得到反馈,从而可以更早地开始调查问题。
  2. 避免级联失败:有些任务可能依赖于其他任务的输出。如果一个任务失败,那么依赖于它的任务也很可能失败。继续执行这些后续任务可能会产生额外的错误,这些错误可能会掩盖原始问题的真正原因。
  3. 简化错误诊断:当构建在第一个失败的任务处停止时,开发者可以更容易地确定问题的根源,而不是在多个失败的任务中迷失。

然而,在某些特殊情况下,开发者可能希望即使某些任务失败,也要继续执行其他任务。例如,他们可能想要收集多个独立任务的输出,或者他们可能正在运行一组测试,并希望即使某些测试失败也继续执行其他测试。

在这种情况下,Gradle 提供了 --continue 或 -C 选项,允许开发者覆盖默认行为。 

使用 --continue 选项,Gradle 会尝试执行每一个任务,前提是该任务所有依赖项都执行成功,失败的,那么依赖它的其他任务不会执行(避免出现上面说的级联失败)。

$ gradle test --continue 

例如,如果被测代码中存在编译错误,则test不会运行,因为测试任务依赖于compilation任务。Gradle会在构建结束时输出每个遇到的失败。

需要注意,即使使用了 --continue,失败的任务仍然会被标记为失败,并且整个构建过程最终也会被标记为失败。

名称缩写

在命令行上指定任务时,我们可以不必提供任务的全名,只提供足够的任务名称来唯一地标识任务。

例如,gradle che就足以让Gradle识别为要执行check任务。

缩写同样可以应用在项目名称上

运行gradle lib:che命令来执行library子项目里的check任务。

对于更复杂的缩写,可以使用驼峰大小写模式。这些模式被扩展以匹配camel case和kebab case名称。例如,模式foBa(或fB)匹配fooBar和foo-bar。

更具体一点,就是您可以使用gradle mAL:cT命令在my-awesome-library子项目中运行compileTest任务。

$ gradle mAL:cT

> Task :my-awesome-library:compileTest

compiling unit tests

BUILD SUCCESSFUL in 0s

1 actionable task: 1 executed

缩写也可以与-x (--exclude-task)命令行选项一起使用。

跟踪名称扩展 

对于复杂的项目,使用缩写名时,一个错别字就可能导致执行意想不到的任务。

使用 INFO 或者 更详细的 日志记录,输出中将包含有关项目和任务名称展开的额外信息。

比如在前面例子中执行的gradle mAL:cT命令,我们将看到以下日志信息:

No exact project with name ':mAL' has been found. Checking for abbreviated names.

Found exactly one project that matches the abbreviated name ':mAL': ':my-awesome-library'.

No exact task with name ':cT' has been found. Checking for abbreviated names.

Found exactly one task name, that matches the abbreviated name ':cT': ':compileTest'.

常见任务 

在Gradle中,有一些常见的任务是经常在构建过程中使用的。这些任务涵盖了编译源代码、运行测试、生成文档、打包发布等构建生命周期的不同阶段。

下面是一些Gradle中常见的任务:

执行构建
这是一个聚合任务,它会根据项目的类型和配置来执行所有必要的构建任务。对于Java项目,这通常包括编译源代码、运行测试、生成文档和打包JAR文件等:

$ gradle build

运行应用程序
该任务组装应用程序并执行一些脚本或二进制文件:

$ gradle run

运行所有检查
该任务执行所有验证任务(包括测试和检查):

$ gradle check

清理输出
这个任务会删除构建目录(通常是build/),移除所有之前构建产生的文件和目录,从而导致后续任务执行需要大量额外构建时间:

$ gradle clean

测试任务
运行项目的单元测试:

$ gradle test

项目报告 

Gradle提供了几个内置任务来显示构建的具体细节,这对我们理解构建结构和依赖关系以及调试问题很有用。

查看项目结构
这个任务会列出当前 Gradle 多项目构建的所有子项目,以层次结构显示:

$ gradle projects

> Task :projects

------------------------------------------------------------

Root project 'HelloGradle'

------------------------------------------------------------

Root project 'HelloGradle'

+--- Project ':app'

\--- Project ':app2'

查看可用任务清单
运行这个任务会列出当前项目的所有可见任务(那些分配了group的任务):

$ gradle tasks

> Task :tasks

Build tasks

-----------

assemble - Assembles the outputs of this project.

Build Setup tasks

-----------------

init - Initializes a new Gradle build.

Distribution tasks

------------------

assembleDist - Assembles the main distributions

Documentation tasks

-------------------

javadoc - Generates Javadoc API documentation for the main source code.

这些任务是按照分组显示的,比如上面的assemble任务属于任务组Build Setup,短横线后面的“Assembles the outputs of this project. ”是这个任务的描述。

对于那些没有指定group的任务,我们称为隐藏任务,通过在tasks任务中使用--all选项可以列举出所有可用任务,包括隐藏任务,这些没有group的任务会列出在Other分组下, 比如myHideTask:

$ gradle tasks --all

> Task :tasks

Build tasks

-----------

assemble - Assembles the outputs of this project.

Build Setup tasks

-----------------

init - Initializes a new Gradle build.

Distribution tasks

------------------

assembleDist - Assembles the main distributions

Documentation tasks

-------------------

javadoc - Generates Javadoc API documentation for the main source code.

Other tasks

-----------

compileJava - Compiles main Java source.

myHideTask

我们可以使用--group选项只显示这个分组的任务:

$ gradle tasks --group="build setup"

> Task :tasks

------------------------------------------------------------

Tasks runnable from root project 'HelloGradle'

------------------------------------------------------------

Build Setup tasks

-----------------

init - Initializes a new Gradle build.

wrapper - Generates Gradle wrapper files.

To see all tasks and more detail, run gradlew tasks --all

To see more detail about a task, run gradlew help --task <task>

BUILD SUCCESSFUL in 4s

1 actionable task: 1 executed

显示任务使用详情
运行 gradle help --task someTask 查看一个特定任务的详细信息:

$ gradle  -q help --task compileJava

Detailed task information for compileJava

Paths

     :compileJava

     :app2:compileJava

     :app:compileJava

Type

     JavaCompile (org.gradle.api.tasks.compile.JavaCompile)

Options

     --rerun     Causes the task to be re-run even if up-to-date.

Description

     Compiles main Java source.

Group

     -

这份信息里包含了完整的任务路劲、任务类型、可能的命令行任务选项、描述等。 

显示项目依赖关系

运行依赖项任务将为您提供所选项目的依赖项列表,该列表按配置细分。对于每个配置,该配置的直接依赖关系和传递依赖关系显示在树状图中。

$ gradle dependencies

> Task :app:dependencies

------------------------------------------------------------

Project ':app'

------------------------------------------------------------

compileClasspath - Compile classpath for source set 'main'.

+--- project :model

|    \--- org.json:json:20220924

+--- com.google.inject:guice:5.1.0

|    +--- javax.inject:javax.inject:1

|    +--- aopalliance:aopalliance:1.0

|    \--- com.google.guava:guava:30.1-jre -> 28.2-jre

|         +--- com.google.guava:failureaccess:1.0.1

|         +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava

|         +--- com.google.code.findbugs:jsr305:3.0.2

|         +--- org.checkerframework:checker-qual:2.10.0 -> 3.28.0

|         +--- com.google.errorprone:error_prone_annotations:2.3.4

|         \--- com.google.j2objc:j2objc-annotations:1.3

+--- com.google.inject:guice:{strictly 5.1.0} -> 5.1.0 (c)

+--- org.json:json:{strictly 20220924} -> 20220924 (c)

+--- javax.inject:javax.inject:{strictly 1} -> 1 (c)

+--- aopalliance:aopalliance:{strictly 1.0} -> 1.0 (c)

+--- com.google.guava:guava:{strictly [28.0-jre, 28.5-jre]} -> 28.2-jre (c)

+--- com.google.guava:guava:{strictly 28.2-jre} -> 28.2-jre (c)

+--- com.google.guava:failureaccess:{strictly 1.0.1} -> 1.0.1 (c)

+--- com.google.guava:listenablefuture:{strictly 9999.0-empty-to-avoid-conflict-with-guava} -> 9999.0-empty-to-avoid-conflict-with-guava (c)

+--- com.google.code.findbugs:jsr305:{strictly 3.0.2} -> 3.0.2 (c)

+--- org.checkerframework:checker-qual:{strictly 3.28.0} -> 3.28.0 (c)

+--- com.google.errorprone:error_prone_annotations:{strictly 2.3.4} -> 2.3.4 (c)

\--- com.google.j2objc:j2objc-annotations:{strictly 1.3} -> 1.3 (c)

Gradle守护进程选项 

使用Gradle守护进程来运行构建
Gradle Daemon是一个后台进程,它在构建过程中为Gradle提供性能优化。当Gradle开始一个构建任务时,默认会启动一个Gradle Daemon(如果没有守护进程在运行或现有守护进程繁忙)来处理构建任务。构建完成后,Daemon进程会在后台保持运行,并处于IDLE空闲状态。这样在下一次构建时,会先尝试重用空闲的Daemon,不必重新创建和配置构建环境,从而大大提高了构建速度。

--daemon                启用(默认行为

 --no-daemon        不启用

可以在gradle.properties文件中设置以下属性禁用Gradle Daemon:

org.gradle.daemon=false 

停止所有正在运行的Gradle Daemons
Gradle Daemon是安全的,并且通常不需要用户干预。然而在某些情况下,如遇到内存泄漏或守护进程异常崩溃,你可能需要手动停止Gradle Daemon:

$ gradle --stop

Stopping Daemon(s)

1 Daemon stopped

查看正在运行和最近停止的gradle守护进程 

$ gradle --status

       PID     STATUS       INFO

 93032      IDLE            8.2

 92212       STOPPED  (stop command received)

日志选项 

设置日志级别

在Gradle构建时,我们在控制台会看到各种日志信息,可以使用以下选项自定义Gradle日志记录的详细程度,依次是最不详细到最详细。

-q, --quiet         只记录错误

-w, --warn         设置日志级别为“警告”

-i, --info             设置日志级别为“信息”

-d, --debug       调试模式(最详细的日志级别,包括正常的堆栈跟踪)

也可以通过Gradle 属性设置:

-Dorg.gradle.logging.level=(quiet,warn,lifecycle,info,debug)

如果不指定,默认日志级别是lifecycle,通常包含了关于构建过程的重要信息,如任务的开始和结束,以及构建过程中的关键事件。

引导创建新项目

在项目目录下运行内置的gradle init任务来创建一个新的Gradle构建:

$ gradle init

运行内置的gradle wrapper任务来创建Gradle Wrapper :

$ gradle wrapper

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值