banner
jzman

jzman

Coding、思考、自觉。
github

GradleシリーズのGradleタスク

前面数篇で Gradle ビルドタスクの基礎知識を学び、Project と Task という 2 つの概念を理解しました。最初に前の数記事を読むことをお勧めします:

Gradle のビルド作業は一連の Task によって完了します。本記事では Task について詳しく紹介します。主な内容は以下の通りです:

  1. 多様な方法でタスクを作成する
  2. 多様な方法でタスクにアクセスする
  3. タスクのグループ化と説明
  4. 演算子
  5. タスクの実行分析
  6. タスクの順序
  7. タスクの有効化と無効化
  8. タスクの onlyIf アサーション
  9. タスクルール

多様な方法でタスクを作成する#

Gradle では多様な方法でタスクを作成できます。タスクの作成方法は最終的に Project が提供するショートカットメソッドや、内蔵の TaskContainer が提供する create メソッドに反映されます。以下は一般的なタスク作成方法のいくつかです:

/**
 * 第一のタスク作成方法:
 * メソッドプロトタイプ:Task task(String name) throws InvalidUserDataException;
 */
//Task変数を定義してtask()メソッドで作成されたTaskを受け取る
def Task taskA = task(taskA)
//作成されたTaskを設定
taskA.doFirst {
    println "第一のタスク作成方法"
}

/**task
 * 第二のタスク作成方法:Mapパラメータで依存関係、タスクの説明、グループなどを設定可能
 * メソッドプロトタイプ:Task task(Map<String, ?> args, String name) throws InvalidUserDataException;
 */
def Task taskB = task(group: BasePlugin.BUILD_GROUP, taskB, description: "説明")
//作成されたTaskを設定
taskB.doLast {
    println "第二のタスク作成方法"
    println "タスクtaskBのグループ:${taskB.group}"
    println "タスクtaskBの説明:${taskB.description}"
}

/**
 * 第三のタスク作成方法:クロージャを使用してTaskを作成、クロージャ内の委任オブジェクトはTaskであり、Taskのすべての属性とメソッドを呼び出してTaskを設定できる
 * メソッドプロトタイプ:Task task(String name, Closure configureClosure);
 */
task taskC {
    description 'taskCの説明'
    group BasePlugin.BUILD_GROUP
    doFirst {
        println "第三のタスク作成方法"
        println "タスクtaskCのグループ:${group}"
        println "タスクtaskCの説明:${description}"
    }
}

/**
 * 第四のタスク作成方法:クロージャ内で柔軟に設定でき、Mapパラメータでも設定可能、クロージャ内の設定がMap内の同じ設定を上書きする
 * メソッドプロトタイプ:Task task(Map<String, ?> args, String name, Closure configureClosure);
 */
def Task taskD = task(group: BasePlugin.BUILD_GROUP, taskD, description: "説明") {
    description 'taskDの説明'
    group BasePlugin.UPLOAD_GROUP
    doFirst {
        println "第四のタスク作成方法"
        println "タスクtaskDのグループ:${group}"
        println "タスクtaskDの説明:${description}"
    }
}

上記はタスク作成の 4 つの方法です。使用時には適切な作成方法を選択すればよいです。上記で言及した Map 内で設定できるタスクの関連パラメータは以下の通りです:

type:既存のTaskに基づいて作成、クラスの継承に似ており、デフォルト値はDefaultTask
overwrite:既存のTaskを置き換えるかどうか、一般的にtypeと組み合わせて使用、デフォルト値はfalse
dependsOn:現在のタスクの依存関係を設定、デフォルト値は[]
action:タスクに追加されるアクションまたはクロージャ、デフォルト値はnull
description:タスクの説明、デフォルト値はnull
group:タスクのグループ、デフォルト値はnull

クロージャの方法で Task を作成すると、クロージャ内の委任オブジェクトは Task であり、クロージャ内で Task のすべての属性とメソッドを呼び出して Task を設定できます。このようにクロージャを使用したタスク作成方法はより柔軟です。また、TaskContainer を使用してタスクを作成することもできます。以下を参照してください:

//TaskContainerを使用してタスクを作成する方法
tasks.create("taskE") {
    description 'taskEの説明'
    group BasePlugin.BUILD_GROUP
    doFirst {
        println "第三のタスク作成方法"
        println "タスクtaskEのグループ:${group}"
        println "タスクtaskEの説明:${description}"
    }
}

tasks は Project の属性で、その型は TaskContainer です。したがって、tasks を通じてタスクを作成できます。もちろん、TaskContainer でタスクを作成する他のコンストラクタもあります。これでタスクの作成に関する基本的な紹介は完了です。

多様な方法でタスクにアクセスする#

作成されたタスク (Task) はプロジェクト (Project) の属性に属し、その属性名はタスク名です。この属性の型は Task です。タスク名が分かっている場合、タスク名を通じて直接そのタスクにアクセスし操作できます。タスクに対応する Task オブジェクトをアクセスし操作することも理解できます。以下を参照してください:

/**
 * タスクにアクセスする第一の方法:Task名.doLast{}
 */
task taskF {

}
taskF.doLast {
    println "タスクにアクセスする第一の方法"
}

タスクはすべて TaskContainer の create メソッドを通じて作成され、TaskContainer はタスクを作成する集合です。Project 内で tasks 属性を通じて TaskContainer にアクセスでき、tasks の型は TaskContainer です。したがって、既に作成されたタスクに対して幾何要素の方法でアクセスし、作成されたタスクの属性とメソッドにアクセスできます。以下のコードを参照してください:

/**
 * タスクにアクセスする第二の方法:TaskContainerを使用してタスクにアクセス
 */
task taskG {

}
tasks['taskG'].doLast {
    println "タスクにアクセスする第二の方法"
}

Groovy では [] も演算子であり、上記の tasks ['taskG'] の実際の意味は tasks.getAt ('taskG') です。getAt () メソッドは TaskCollection 内のメソッドであり、タスク名を通じて関連タスクにアクセスし操作できます。

また、パスを通じてタスクにアクセスする方法もあります。パスを通じてタスクにアクセスするには、findByPath と getByPath の 2 つの重要なメソッドがあります。前者は指定されたタスクが見つからない場合、null を返しますが、後者はタスクが見つからない場合、UnknowTaskException 例外をスローします。以下のコードを参照してください:

/**
 * タスクにアクセスする第三の方法:パスを使用してタスクにアクセス
 */
task taskH {
    println 'taskH'
    //パスを通じてタスクにアクセス、パラメータはパス(アクセスに成功しなかった場合、書き方は以下の通り)
    println tasks.findByPath(':GradleTask:taskG')
    //パスを通じてタスクにアクセス、パラメータはタスク名
    println tasks.findByPath('taskG')
    println tasks.getByPath('taskG')
}

上記のコードの実行結果は以下の通りです:

PS E:\Gradle\study\GradleTask> gradle taskH

> Configure project :
taskH
null
task ':taskG'
task ':taskG'


FAILURE: Build failed with an exception.

* Where:
Build file 'E:\Gradle\study\GradleTask\build.gradle' line: 98

* What went wrong:
A problem occurred evaluating root project 'GradleTask'.
> Task with path 'test' not found in root project 'GradleTask'.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

* Get more help at https://help.gradle.org

BUILD FAILED in 2s

パスを通じてタスクにアクセスする過程で、パラメータをパスとして具体的なタスクにアクセスできない場合、書き方の問題かもしれません。今後の学習で解決できることを期待します。

さらに、タスク名を通じてアクセスすることもできます。主な方法は findByName と getByName であり、違いは第三のアクセス方法と同じです。以下のコードを参照してください:

/**
 * タスクにアクセスする第四の方法:タスク名を使用してアクセス
 */
task taskJ
tasks['taskJ'].doLast {
    println 'taskJ'
    println tasks.findByName('taskJ')
    println tasks.getByName('taskJ')
}

上記ではタスクにアクセスする 4 つの方法を学びました。Gradle でのタスクアクセスの理解を通じて、具体的なプロジェクト構築において上記のタスクアクセス方法を柔軟に使用できます。

タスクのグループ化と説明#

タスクのグループ化と説明は、実際には以前の記事で既に言及され、設定されています。ここで簡単に説明します。タスクのグループ化と説明は、実際には既に作成されたタスクに対してグループとタスクの説明を設定することです。以下のように設定します:

//タスクのグループと説明
def Task task1 = task taskK
task1.group = BasePlugin.BUILD_GROUP
task1.description = 'テストタスクのグループと説明'
task1.doLast {
    println "taskKのグループ = ${group}, 説明 = ${description}"
}

以下は上記コードの実行結果です:

PS E:\Gradle\study\GradleTask> gradle taskK

> Task :taskK
taskKのグループ = build, 説明 = テストタスクのグループと説明


BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed

実行結果から、タスクの関連属性を設定した場合、タスクのすべての情報にアクセスできることがわかります。

演算子#

演算子 <<を学びます。以前のテストコードでは、テストのために常に task.doLast () メソッドを呼び出していましたが、<< 演算子を使用して doLast メソッドを置き換えることができます。つまり、doLast () メソッドは次のように書くことができます:

//<< タスク演算子
//簡略化された方法、Gradle 5.0からこの書き方は推奨されなくなりました
task taskL << {
    println "doLast"
}
//推奨される書き方
task taskL {
    doLast {
        println "doLast"
    }
}

上記の 2 つの書き方の実行結果は以下の通りです:

PS E:\Gradle\study\GradleTask> gradle taskL

> Configure project :
The Task.leftShift(Closure) method has been deprecated and is scheduled to be removed in Gradle 5.0. Please use Task.doLast(Action) instead.
        at build_6syzx8ks0l09hby4j6yn247u9.run(E:\Gradle\study\GradleTask\build.gradle:123)

> Task :taskL
doLast


BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed
PS E:\Gradle\study\GradleTask> gradle taskL

> Task :taskL
doLast


BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed
PS E:\Gradle\study\GradleTask>

出力結果から、2 つの書き方がどちらも期待した結果を出力していることがわかります。また、ログを観察すると、この簡略化された方法は Gradle 5.0 から放棄されているため、doLast の方法でタスクを設定することが推奨されます。

タスクの実行分析#

Gradle タスクの実行過程で、doFirst と doLast を使用してタスク実行前または実行後にタスク関連の設定を行うことができます。タスクを実行すると、実際にはその Task が持つアクションを実行しています。getActions () メソッドを使用して、実行可能なすべてのアクションを取得できます。以下に、CustomTask というタスクタイプを自作し、@TaskAction アノテーションで doSelf メソッドを示して Task 自体が実行するメソッドを示します。コードは以下の通りです:

//タスク実行プロセスの分析
def Task taskA = task taskB(type: CustomTask)
taskA.doFirst {
    println "タスク実行前に呼び出し:doFirst"
}

taskA.doLast {
    println "タスク実行後に呼び出し:doLast"
}

class CustomTask extends DefaultTask {
    @TaskAction
    def doSelf() {
        println "タスク自体が呼び出される:doSelf"
    }
}

上記のコードの実行結果は以下の通りです:

PS E:\Gradle\study\GradleTask2> gradle taskB

> Task :taskB
タスク実行前に呼び出し:doFirst
タスク自体が呼び出される:doSelf
タスク実行後に呼び出し:doLast


BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed

タスクの実行は実行する必要があるアクションリストを遍歴するため、doFirst に対応するアクションはアクションリストの最前面に配置し、doLast に対応するアクションはアクションリストの最後に配置する必要があります。doSelf に対応するアクションはリストの中間位置に配置することで、対応する実行順序を保証できます。以下は擬似コードです:

//タスク作成時に@TaskActionで示されたメソッドをタスク自体が実行するタスクとして使用
//この時、タスクが作成されているため、actionListにはタスク自体が実行するアクションのみが含まれます
actionList.add(0, doSelfAction)
//タスク作成後、doFirstが設定されている場合、actionListの最前面にdoFirstに対応するアクションが追加されます
//この時、doFirstに対応するアクションがactionListの最前面に追加され、タスク実行前にdoFirstメソッドが実行されることが保証されます
actionList.add(0, doFirstAction)
//タスク作成後、doLastが設定されている場合、actionListの最後にdoLastに対応するアクションが追加され、タスク実行後にdoLastメソッドが実行されることが保証されます
actionList.add(doLastAction)

タスク実行のプロセスは基本的にこのようになっています。具体的な実践の中で多くの体験を積むことが重要です。

タスクの順序#

Gradle ではタスクの順序に Task の 2 つのメソッド shouldRunAfter と mustRunAfter を使用して、どちらのタスクが先に実行されるかを簡単に制御できます:

/**
 * タスクの順序
 * taskC.shouldRunAfter(taskD):taskCはtaskDの後に実行されることを示します
 * taskC.mustRunAfter(taskD):taskCは必ずtaskDの後に実行されることを示します
 */
task taskC {
    doFirst {
        println "taskC"
    }
}
task taskD {
    doFirst {
        println "taskD"
    }
}
taskC.shouldRunAfter(taskD)

上記のコードの実行結果は以下の通りです:

PS E:\Gradle\study\GradleTask2> gradle taskC taskD

> Task :taskD
taskD

> Task :taskC
taskC


BUILD SUCCESSFUL in 2s
2 actionable tasks: 2 executed

タスクの有効化と無効化#

Task には enabled 属性があり、この属性を使用して特定のタスクを有効または無効にできます。true に設定するとそのタスクが有効になり、逆に設定すると無効になります。この属性のデフォルト値は true です。以下のように使用します:

taskA.enabled = true

タスクの onlyIf アサーション#

アサーションは条件式であり、Task オブジェクトには onlyIf メソッドがあります。このメソッドはクロージャを引数として受け取ることができ、クロージャ内のパラメータが true を返す場合、そのタスクが実行され、逆に false の場合はそのタスクが実行されません。このようにしてタスクのアサーションを通じて、どのタスクを実行する必要があるかを制御できます。以下に、パッケージングの例を通じてタスクのアサーションを学びます。コードは以下の通りです:

//タスクのonlyIfアサーション
final String BUILD_ALL = 'all'
final String BUILD_FIRST = 'first'
final String BUILD_OTHERS = 'others'

task taskTencentRelease {
    doLast {
        println "アプリ宝チャネルパッケージを作成"
    }
}

task taskBaiduRelease {
    doLast {
        println "百度携帯助手チャネルパッケージを作成"
    }
}

task taskMiuiRelease {
    doLast {
        println "小米アプリストアチャネルパッケージを作成"
    }
}

task buildTask {
    group BasePlugin.BUILD_GROUP
    description "チャネルパッケージを作成"
}

//buildTaskに依存する具体的なタスクを追加
buildTask.dependsOn taskTencentRelease, taskBaiduRelease, taskMiuiRelease

taskTencentRelease.onlyIf {
    if (project.hasProperty("buildApp")) {
        Object buildApp = project.property("buildApp")
        return BUILD_ALL == buildApp || BUILD_FIRST == buildApp
    } else {
        return true
    }
}

taskBaiduRelease.onlyIf {
    if (project.hasProperty("buildApp")) {
        Object buildApp = project.property("buildApp")
        return BUILD_ALL == buildApp || BUILD_FIRST == buildApp
    } else {
        return true
    }
}

taskMiuiRelease.onlyIf {
    if (project.hasProperty("buildApp")) {
        Object buildApp = project.property("buildApp")
        return BUILD_OTHERS == buildApp || BUILD_ALL == buildApp
    } else {
        return true
    }
}

以下は上記コードの実行結果です:

PS E:\Gradle\study\GradleTask2> gradle -PbuildApp=first buildTask

> Task :taskBaiduRelease
百度携帯助手チャネルパッケージを作成

> Task :taskTencentRelease
アプリ宝チャネルパッケージを作成


BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
PS E:\Gradle\study\GradleTask2> gradle -PbuildApp=others buildTask

> Task :taskMiuiRelease
小米アプリストアチャネルパッケージを作成


BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed
PS E:\Gradle\study\GradleTask2> gradle -PbuildApp=all buildTask

> Task :taskBaiduRelease
百度携帯助手チャネルパッケージを作成

> Task :taskMiuiRelease
小米アプリストアチャネルパッケージを作成

> Task :taskTencentRelease
アプリ宝チャネルパッケージを作成


BUILD SUCCESSFUL in 1s
3 actionable tasks: 3 executed

上記のように、buildTask を実行する際に Project に buildApp 属性を設定し、buildApp の異なる値を利用して onlyIf を通じて異なるチャネルパッケージのカスタムビルド戦略を実現しました。実際の開発において参考にして使用できます。

また、上記のコード実行コマンドの書き方に注意してください。具体的には以下の通りです:

//ここでbuildAppと=の後の値othersはキーと値のペアの関係であり、コマンドを使用してタスクを実行する際に-Pコマンドの省略形を使用できます
//-Pは現在のProjectにK-Vの属性キーと値のペアを指定するため、-PK=Vを指定します
gradle -PbuildApp=others buildTask

タスクルール#

作成されたタスクはすべて TaskContain 内にあり、Project の属性 tasks からタスク名に基づいて取得したいタスクを取得できます。TaskContain の addRule メソッドを使用して、対応するタスクルールを追加できます。以下のコードを参照してください:

//タスクルール
tasks.addRule("このルールの説明") {
    //クロージャ内では通常->をパラメータとコードブロックの間の区切りとして使用します
    String taskName ->
        task(taskName) {
            doLast {
                println "${taskName} は存在しません"
            }
        }
}

task taskTest {
    dependsOn taskX
}

上記のコードの実行結果は以下の通りです:

PS E:\Gradle\study\GradleTask2> gradle taskTest

> Task :taskX
taskX は存在しません


BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

特定の特殊なタスク処理を指定しない場合、エラーが発生しますが、処理を行うと関連するメッセージが出力されます。Gradle タスクの理解と学習はここまでです。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。