当 运行 gradle task inside map loop 任务是 运行 only after the script
When running gradle task inside map loop the task is running only after the script
我正在使用 docker 插件构建我的 docker 图片,
我有一个包含多重服务的项目,但它是一个单片机,所以我只有一个 build.gradle 文件。
我想做的是使用地图循环构建所有图像,
但是在构建项目时,只构建了地图中的最后一个元素。
这些是 build.gradle 文件的相关部分:
plugins {
id 'java'
id 'application'
id 'maven'
id 'distribution'
id 'maven-publish'
//docker-plugin
id 'com.palantir.docker' version '0.25.0'
}
group = 'com.company.scheduler'
version '4.0.0-SNAPSHOT'
//Handle release version scenario
def PublishedVersion
def buildNumber
if (version ==~ /(?s).*SNAPSHOT.*/) { //Check if SNAPSHOT/Release version
if ("$System.env.BUILD_NUMBER" == null) {buildNumber = '0'} else {buildNumber = "$System.env.BUILD_NUMBER"}
PublishedVersion = version
} else {
if ("$System.env.BUILD_NUMBER" == null) {buildNumber = '0'} else {buildNumber = "$System.env.BUILD_NUMBER"}
PublishedVersion = version + '-' + buildNumber
}
mainClassName = 'com.company.scheduler'
dependencies {
compile group: 'com.coralogix.sdk', name: 'coralogix-sdk', version: '2.0.3'
}
def serviceOptionMap = [ "utility-meters": "utility_meters_import_plugins",
"weather": "weather_importer"
]
serviceOptionMap.each { k, v ->
docker {
def service_id="${k}"
def artifact_start_script="${v}"
println 'artifact_start_script: ' + artifact_start_script
println 'service_id: ' + service_id
name "47957039666.dkr.ecr.us-east-1.amazonaws.com/panpwr/service-gradle/${service_id}:$PublishedVersion"
//if (version ==~ /(?s).*SNAPSHOT.*/) {tag "$version", "47957039666.dkr.ecr.us-east-1.amazonaws.com/panpwr/ev/${project.name}:latest"}
copySpec.from("build/distributions").into(".")
dockerfile file("${rootProject.projectDir}/Dockerfile")
buildArgs([ARTIFACT_ID: "${service_id}", PANPWR_VERSION: "$PublishedVersion", ARTIFACT_START_SCRIPT: "$artifact_start_script"])
labels(["service-name": "${service_id}", "service-version": "$PublishedVersion"])
pull false //TODO: change to true
noCache false
println 'built docker image: ' + service_id
}
}
这是构建输出:
> Configure project :scheduled-tasks
artifact_start_script: utility_meters_import_plugins
service_id: utility-meters
built docker image: utility-meters
artifact_start_script: weather_importer
service_id: weather
built docker image: weather
> Task :scheduled-tasks:dockerClean
> Task :scheduled-tasks:dockerPrepare
> Task :scheduled-tasks:docker
BUILD SUCCESSFUL in 5s
3 actionable tasks: 3 executed
10:16:39 AM: Task execution finished 'docker'.
当我查看本地图片时,我只能看到第二张图片:
$ docker images | grep gradle
47957039666.dkr.ecr.us-east-1.amazonaws.com/panpwr/service-gradle/weather 4.0.0-SNAPSHOT 729a926206ed 20 hours ago 1.11GB
这是对 Gradle 工作原理的常见误解。虽然实际构建脚本是以命令式方式评估的(如常见的 Groovy 脚本),但任务概念在某种程度上是声明性的:
Gradle区分配置阶段和执行阶段。在配置阶段,评估构建脚本并配置任务。在执行阶段,所有需要的任务都被执行。必需任务是使用命令行及其(传递)依赖项指定的任务。
当构建脚本作者使用 println
来了解任务的执行方式时,这种误解常常变得明显,但所有 println
语句都是在 配置阶段 评估的.
让我们看一下您的具体问题。你有一个循环,在那个循环里面你有类似 docker { ... }
的东西。在你的标题中它说“运行ning gradle task inside map loop”,所以你认为 docker { ... }
运行 是一个任务,但这是不正确的。 docker
是您示例中的任务是正确的,但您的代码不会 运行 (或执行)任务,您的代码只是配置任务。评估构建脚本后,Gradle 将从所有任务及其配置的任务依赖项(dependsOn
语句)设置任务图。使用此任务图,Gradle 将确定所需的任务并执行它们。
现在,知道任务 docker
没有被执行而只是被配置,你的代码的问题就很明显了:任务的第二个配置覆盖了第一个配置。顺便说一句,这与循环无关,您可以随后应用两个配置并获得相同的结果:
docker {
name "first"
dockerfile file("first/Dockerfile")
}
docker {
name "second"
dockerfile file("second/Dockerfile")
}
然而,您的方法的实际问题是完全不同的:在 Gradle 中,每个任务将在构建中 仅执行一次 。这意味着,您将无法 运行 任务 docker
两次来创建两个 docker 图像。您要么需要配置任务,使其在一次执行中创建两个 docker 图像,要么以某种方式生成两个相同类型的不同任务。我不熟悉你使用的插件,所以我不知道它是否支持这两种方法中的一种。
您可以看看 Benjamin Muschko 的 Gradle Docker Plugin,它允许您根据需要创建任意数量的 DockerBuildImage
类型的任务。
原来是这个插件doesn't support building multiple images,
因此,我最终为每个使用此插件仅创建 docker 图像的服务创建了一个 sub-module。
所以这几乎是结构:
├── Dockerfile
├── app1
│ └── build.gradle
├── app2
│ └── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle-user-home
├── gradlew
├── build.gradle
这是子模块的简单 gradle.build:
plugins {
//docker-plugin
id 'com.palantir.docker' version '0.25.0'
}
version '4.0.0-SNAPSHOT'
//Handle release version scenario
def PublishedVersion
def buildNumber
if (version ==~ /(?s).*SNAPSHOT.*/) { //Check if SNAPSHOT/Release version
if ("$System.env.BUILD_NUMBER" == null) {buildNumber = '0'} else {buildNumber = "$System.env.BUILD_NUMBER"}
PublishedVersion = version
} else {
if ("$System.env.BUILD_NUMBER" == null) {buildNumber = '0'} else {buildNumber = "$System.env.BUILD_NUMBER"}
PublishedVersion = version + '-' + buildNumber
}
docker {
name "47957039666.dkr.ecr.us-east-1.amazonaws.com/panpwr/service-gradle/${project.name}:$PublishedVersion"
copySpec.from("${rootProject.projectDir}/scheduled-tasks/build/distributions").into(".")
dockerfile file("${rootProject.projectDir}/Dockerfile")
buildArgs([ARTIFACT_ID: "${project.name}", PANPWR_VERSION: "$PublishedVersion", ARTIFACT_START_SCRIPT: "${project.name}"])
labels(["service-name": "${project.name}", "service-version": "$PublishedVersion"])
pull true
noCache false
println 'built docker image: ' + project.name
}
publishing {
publications {
dockerPublication(MavenPublication) {
from components.docker
artifactId project.name + "-docker"
}
}
}
并且 运行 根项目上的 docker 任务会创建所有 docker 图像:
./gradlew clean build docker -g gradle-user-home
我正在使用 docker 插件构建我的 docker 图片, 我有一个包含多重服务的项目,但它是一个单片机,所以我只有一个 build.gradle 文件。 我想做的是使用地图循环构建所有图像, 但是在构建项目时,只构建了地图中的最后一个元素。
这些是 build.gradle 文件的相关部分:
plugins {
id 'java'
id 'application'
id 'maven'
id 'distribution'
id 'maven-publish'
//docker-plugin
id 'com.palantir.docker' version '0.25.0'
}
group = 'com.company.scheduler'
version '4.0.0-SNAPSHOT'
//Handle release version scenario
def PublishedVersion
def buildNumber
if (version ==~ /(?s).*SNAPSHOT.*/) { //Check if SNAPSHOT/Release version
if ("$System.env.BUILD_NUMBER" == null) {buildNumber = '0'} else {buildNumber = "$System.env.BUILD_NUMBER"}
PublishedVersion = version
} else {
if ("$System.env.BUILD_NUMBER" == null) {buildNumber = '0'} else {buildNumber = "$System.env.BUILD_NUMBER"}
PublishedVersion = version + '-' + buildNumber
}
mainClassName = 'com.company.scheduler'
dependencies {
compile group: 'com.coralogix.sdk', name: 'coralogix-sdk', version: '2.0.3'
}
def serviceOptionMap = [ "utility-meters": "utility_meters_import_plugins",
"weather": "weather_importer"
]
serviceOptionMap.each { k, v ->
docker {
def service_id="${k}"
def artifact_start_script="${v}"
println 'artifact_start_script: ' + artifact_start_script
println 'service_id: ' + service_id
name "47957039666.dkr.ecr.us-east-1.amazonaws.com/panpwr/service-gradle/${service_id}:$PublishedVersion"
//if (version ==~ /(?s).*SNAPSHOT.*/) {tag "$version", "47957039666.dkr.ecr.us-east-1.amazonaws.com/panpwr/ev/${project.name}:latest"}
copySpec.from("build/distributions").into(".")
dockerfile file("${rootProject.projectDir}/Dockerfile")
buildArgs([ARTIFACT_ID: "${service_id}", PANPWR_VERSION: "$PublishedVersion", ARTIFACT_START_SCRIPT: "$artifact_start_script"])
labels(["service-name": "${service_id}", "service-version": "$PublishedVersion"])
pull false //TODO: change to true
noCache false
println 'built docker image: ' + service_id
}
}
这是构建输出:
> Configure project :scheduled-tasks
artifact_start_script: utility_meters_import_plugins
service_id: utility-meters
built docker image: utility-meters
artifact_start_script: weather_importer
service_id: weather
built docker image: weather
> Task :scheduled-tasks:dockerClean
> Task :scheduled-tasks:dockerPrepare
> Task :scheduled-tasks:docker
BUILD SUCCESSFUL in 5s
3 actionable tasks: 3 executed
10:16:39 AM: Task execution finished 'docker'.
当我查看本地图片时,我只能看到第二张图片:
$ docker images | grep gradle
47957039666.dkr.ecr.us-east-1.amazonaws.com/panpwr/service-gradle/weather 4.0.0-SNAPSHOT 729a926206ed 20 hours ago 1.11GB
这是对 Gradle 工作原理的常见误解。虽然实际构建脚本是以命令式方式评估的(如常见的 Groovy 脚本),但任务概念在某种程度上是声明性的:
Gradle区分配置阶段和执行阶段。在配置阶段,评估构建脚本并配置任务。在执行阶段,所有需要的任务都被执行。必需任务是使用命令行及其(传递)依赖项指定的任务。
当构建脚本作者使用 println
来了解任务的执行方式时,这种误解常常变得明显,但所有 println
语句都是在 配置阶段 评估的.
让我们看一下您的具体问题。你有一个循环,在那个循环里面你有类似 docker { ... }
的东西。在你的标题中它说“运行ning gradle task inside map loop”,所以你认为 docker { ... }
运行 是一个任务,但这是不正确的。 docker
是您示例中的任务是正确的,但您的代码不会 运行 (或执行)任务,您的代码只是配置任务。评估构建脚本后,Gradle 将从所有任务及其配置的任务依赖项(dependsOn
语句)设置任务图。使用此任务图,Gradle 将确定所需的任务并执行它们。
现在,知道任务 docker
没有被执行而只是被配置,你的代码的问题就很明显了:任务的第二个配置覆盖了第一个配置。顺便说一句,这与循环无关,您可以随后应用两个配置并获得相同的结果:
docker {
name "first"
dockerfile file("first/Dockerfile")
}
docker {
name "second"
dockerfile file("second/Dockerfile")
}
然而,您的方法的实际问题是完全不同的:在 Gradle 中,每个任务将在构建中 仅执行一次 。这意味着,您将无法 运行 任务 docker
两次来创建两个 docker 图像。您要么需要配置任务,使其在一次执行中创建两个 docker 图像,要么以某种方式生成两个相同类型的不同任务。我不熟悉你使用的插件,所以我不知道它是否支持这两种方法中的一种。
您可以看看 Benjamin Muschko 的 Gradle Docker Plugin,它允许您根据需要创建任意数量的 DockerBuildImage
类型的任务。
原来是这个插件doesn't support building multiple images, 因此,我最终为每个使用此插件仅创建 docker 图像的服务创建了一个 sub-module。 所以这几乎是结构:
├── Dockerfile
├── app1
│ └── build.gradle
├── app2
│ └── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle-user-home
├── gradlew
├── build.gradle
这是子模块的简单 gradle.build:
plugins {
//docker-plugin
id 'com.palantir.docker' version '0.25.0'
}
version '4.0.0-SNAPSHOT'
//Handle release version scenario
def PublishedVersion
def buildNumber
if (version ==~ /(?s).*SNAPSHOT.*/) { //Check if SNAPSHOT/Release version
if ("$System.env.BUILD_NUMBER" == null) {buildNumber = '0'} else {buildNumber = "$System.env.BUILD_NUMBER"}
PublishedVersion = version
} else {
if ("$System.env.BUILD_NUMBER" == null) {buildNumber = '0'} else {buildNumber = "$System.env.BUILD_NUMBER"}
PublishedVersion = version + '-' + buildNumber
}
docker {
name "47957039666.dkr.ecr.us-east-1.amazonaws.com/panpwr/service-gradle/${project.name}:$PublishedVersion"
copySpec.from("${rootProject.projectDir}/scheduled-tasks/build/distributions").into(".")
dockerfile file("${rootProject.projectDir}/Dockerfile")
buildArgs([ARTIFACT_ID: "${project.name}", PANPWR_VERSION: "$PublishedVersion", ARTIFACT_START_SCRIPT: "${project.name}"])
labels(["service-name": "${project.name}", "service-version": "$PublishedVersion"])
pull true
noCache false
println 'built docker image: ' + project.name
}
publishing {
publications {
dockerPublication(MavenPublication) {
from components.docker
artifactId project.name + "-docker"
}
}
}
并且 运行 根项目上的 docker 任务会创建所有 docker 图像:
./gradlew clean build docker -g gradle-user-home