mirror of https://github.com/apache/lucene.git
192 lines
7.5 KiB
Groovy
192 lines
7.5 KiB
Groovy
import groovy.json.JsonOutput
|
|
import groovy.json.JsonSlurper
|
|
import org.apache.commons.codec.digest.DigestUtils
|
|
|
|
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
* (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
// Create common 'regenerate' task sub-tasks can hook into.
|
|
|
|
configure([
|
|
project(":lucene:analysis:common"),
|
|
project(":lucene:core"),
|
|
project(":lucene:analysis:icu"),
|
|
project(":lucene:queryparser"),
|
|
project(":lucene:analysis:kuromoji"),
|
|
project(":lucene:analysis:nori")
|
|
]) {
|
|
task regenerate() {
|
|
description "Rerun any code or static data generation tasks."
|
|
group "generation"
|
|
}
|
|
|
|
project.ext {
|
|
// This utility method implements the logic required for "persistent" incremental
|
|
// source-generating tasks. The idea is simple, the implementation quite complex.
|
|
//
|
|
// The idea is that, given source-generating task "sourceTask" we create
|
|
// a bunch of other tasks that perform checksum generation, validation and sourceTask
|
|
// skipping; example:
|
|
//
|
|
// ${sourceTask}ChecksumLoad
|
|
// ${sourceTask}ChecksumSave
|
|
// ${sourceTask}ChecksumCheck (fails if checksums are inconsistent)
|
|
// maybe${sourceTask} dependsOn [checksum-load, sourceTask, checksum-save]
|
|
//
|
|
// Checksums are persisted and computed from sourceTask's inputs/outputs. If the
|
|
// persisted checksums are identical to current checksums, sourceTask
|
|
// is skipped (via sourceTask.onlyIf { false }).
|
|
//
|
|
// Implementation-wise things get complicated because gradle doesn't have the notion
|
|
// of "ordered" task execution with respect to task AND its dependencies (we can add
|
|
// constraints to each node in the execution graph but not node-and-dependencies).
|
|
//
|
|
// sourceTask - the task to wrap
|
|
// extraConfig - a map with extra (optional) configuration options.
|
|
// andThenTasks: other tasks that should be scheduled to run after source task and
|
|
// before checksum calculation.
|
|
wrapWithPersistentChecksums = { Task sourceTask, Map<String, Object> extraConfig = [:] ->
|
|
def toList = { value ->
|
|
if (value instanceof List) {
|
|
return value
|
|
} else if (value == null) {
|
|
return []
|
|
} else {
|
|
return [ value ]
|
|
}
|
|
}
|
|
|
|
List<Object> andThenTasks = toList(extraConfig.get("andThenTasks"))
|
|
List<Object> ignoreWithSource = toList(extraConfig.get("ignoreWithSource"))
|
|
|
|
// Create checksum-loader task.
|
|
Task checksumLoadTask = tasks.create("${sourceTask.name}ChecksumLoad", {
|
|
ext {
|
|
checksumMatch = true
|
|
}
|
|
|
|
doFirst {
|
|
// Collect all of task inputs/ outputs.
|
|
FileCollection allFiles = sourceTask.inputs.files + sourceTask.outputs.files
|
|
ext.allFiles = allFiles
|
|
|
|
// Compute checksums for root-project relative paths
|
|
Map<String, String> actualChecksums = allFiles.files.collectEntries { file ->
|
|
[
|
|
sourceTask.project.rootDir.relativePath(file),
|
|
file.exists() ? new DigestUtils(DigestUtils.sha1Digest).digestAsHex(file).trim() : "--"
|
|
]
|
|
}
|
|
ext.actualChecksums = actualChecksums
|
|
|
|
// Load any previously written checksums
|
|
ext.checksumsFile = project.file("src/generated/checksums/${sourceTask.name}.json")
|
|
Map<String, String> savedChecksums = [:]
|
|
if (checksumsFile.exists()) {
|
|
savedChecksums = new JsonSlurper().parse(checksumsFile) as Map
|
|
}
|
|
ext.savedChecksums = savedChecksums
|
|
|
|
ext.checksumMatch = (savedChecksums.equals(actualChecksums))
|
|
}
|
|
})
|
|
|
|
Task checksumCheckTask = tasks.create("${sourceTask.name}ChecksumCheck", {
|
|
dependsOn checksumLoadTask
|
|
|
|
doFirst {
|
|
if (!checksumLoadTask.checksumMatch) {
|
|
// This can be made prettier but leave it verbose for now:
|
|
Map<String, String> actual = checksumLoadTask.actualChecksums
|
|
Map<String, String> expected = checksumLoadTask.savedChecksums
|
|
|
|
def same = actual.intersect(expected)
|
|
actual = actual - same
|
|
expected = expected - same
|
|
|
|
throw new GradleException("Checksums mismatch for derived resources; you might have" +
|
|
" modified a generated source file?:\n" +
|
|
"Actual:\n ${actual.entrySet().join('\n ')}\n\n" +
|
|
"Expected:\n ${expected.entrySet().join('\n ')}"
|
|
)
|
|
}
|
|
}
|
|
})
|
|
check.dependsOn checksumCheckTask
|
|
|
|
Task checksumSaveTask = tasks.create("${sourceTask.name}ChecksumSave", {
|
|
dependsOn checksumLoadTask
|
|
|
|
doFirst {
|
|
File checksumsFile = checksumLoadTask.ext.checksumsFile
|
|
checksumsFile.parentFile.mkdirs()
|
|
|
|
// Recompute checksums for root-project relative paths
|
|
Map<String, String> actualChecksums = checksumLoadTask.ext.allFiles.files.collectEntries { file ->
|
|
[
|
|
sourceTask.project.rootDir.relativePath(file),
|
|
new DigestUtils(DigestUtils.sha1Digest).digestAsHex(file).trim()
|
|
]
|
|
}
|
|
|
|
checksumsFile.setText(
|
|
JsonOutput.prettyPrint(JsonOutput.toJson(actualChecksums)), "UTF-8")
|
|
|
|
logger.warn("Updated generated file checksums for task ${sourceTask.path}.")
|
|
}
|
|
})
|
|
|
|
Task conditionalTask = tasks.create("${sourceTask.name}IfChanged", {
|
|
def deps = [
|
|
checksumLoadTask,
|
|
sourceTask,
|
|
*andThenTasks,
|
|
checksumSaveTask
|
|
].flatten()
|
|
|
|
dependsOn deps
|
|
mustRunInOrder deps
|
|
|
|
doFirst {
|
|
if (checksumLoadTask.checksumMatch) {
|
|
logger.lifecycle("Checksums consistent with sources, skipping task: ${sourceTask.path}")
|
|
}
|
|
}
|
|
})
|
|
|
|
// Copy the description and group from the source task.
|
|
project.afterEvaluate {
|
|
conditionalTask.group sourceTask.group
|
|
conditionalTask.description sourceTask.description + " (if sources changed)"
|
|
}
|
|
|
|
// Set conditional execution only if checksum mismatch occurred.
|
|
if (!gradle.startParameter.isRerunTasks()) {
|
|
project.afterEvaluate {
|
|
resolveTaskRefs([sourceTask, *ignoreWithSource, checksumSaveTask]).each { t ->
|
|
t.configure {
|
|
logger.info("Making " + t.name + " run only if " + checksumLoadTask.name + " indicates changes")
|
|
onlyIf { !checksumLoadTask.checksumMatch }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return conditionalTask
|
|
}
|
|
}
|
|
} |