
org.gradle.performance.BaseJavalSourceFileUpdater.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2016 the original author or authors.
*
* Licensed 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.
*/
package org.gradle.performance
import org.apache.commons.io.FileUtils
import org.gradle.performance.fixture.BuildExperimentInvocationInfo
import org.gradle.performance.fixture.BuildExperimentListener
import org.gradle.performance.fixture.BuildExperimentListenerAdapter
import org.gradle.performance.fixture.BuildExperimentRunner
import org.gradle.performance.measure.MeasuredOperation
abstract class BaseJavalSourceFileUpdater extends BuildExperimentListenerAdapter {
protected File projectDir
protected List projects
protected List projectsWithDependencies
protected int projectCount
protected Map> dependencies
protected Map> reverseDependencies
protected final Set updatedFiles = []
protected final SourceUpdateCardinality cardinality
BaseJavalSourceFileUpdater(SourceUpdateCardinality cardinality = SourceUpdateCardinality.ONE_FILE) {
this.cardinality = cardinality
}
protected static int perc(int perc, int total) {
(int) Math.ceil(total * (double) perc / 100d)
}
protected static File backupFileFor(File file) {
new File(file.parentFile, "${file.name}~")
}
protected void createBackupFor(File file) {
updatedFiles << file
FileUtils.copyFile(file, backupFileFor(file), true)
}
private void restoreFiles() {
updatedFiles.each { File file ->
restoreFile(file)
}
updatedFiles.clear()
}
protected static void restoreFile(File file) {
println "Restoring $file"
def backup = backupFileFor(file)
FileUtils.copyFile(backup, file, true)
backup.delete()
}
@Override
void beforeInvocation(BuildExperimentInvocationInfo invocationInfo) {
if (projectDir != invocationInfo.projectDir) {
projectDir = invocationInfo.projectDir
projects = projectDir.listFiles().findAll { it.directory && it.name.startsWith('project') }.sort { it.name }
projectCount = projects.size()
// forcefully delete build directories (so that dirty local runs do not interfere with results)
projects.each { pDir ->
FileUtils.deleteDirectory(new File(pDir, 'build'))
}
// make sure execution is consistent independently of time
Collections.shuffle(projects, new Random(31 * projectCount))
// restore stale backup files in case a build was interrupted
cleanup()
// retrieve the dependencies in an exploitable form
def generatedDepsMetadata = new File(projectDir, 'generated-deps.groovy')
if (generatedDepsMetadata.exists()) {
dependencies = new GroovyShell().evaluate(generatedDepsMetadata)
} else {
dependencies = [:]
}
reverseDependencies = [:].withDefault { [] }
dependencies.each { p, deps ->
deps.each {
reverseDependencies[it] << p
}
}
projectsWithDependencies = projects.findAll { File it ->
reverseDependencies[projectId(it)]
}
}
if (!updatedFiles.isEmpty()) {
restoreFiles()
} else if (invocationInfo.phase != BuildExperimentRunner.Phase.WARMUP) {
updateFiles()
}
}
protected abstract void updateFiles()
@Override
void afterInvocation(BuildExperimentInvocationInfo invocationInfo, MeasuredOperation operation, BuildExperimentListener.MeasurementCallback measurementCallback) {
if (invocationInfo.iterationNumber == invocationInfo.iterationMax) {
println "Last iteration complete"
cleanup()
}
}
void cleanup() {
projectDir?.eachFileRecurse { file ->
if (file.name.endsWith('~')) {
restoreFile(new File(file.parentFile, file.name - '~'))
}
}
updatedFiles.clear()
}
protected Set affectedProjects(File subproject) {
Set dependents = reverseDependencies[projectId(subproject)] as Set
Set transitiveClosure = new HashSet<>(dependents)
int size = -1
while (size != transitiveClosure.size()) {
size = transitiveClosure.size()
def newDeps = []
transitiveClosure.each {
newDeps.addAll(reverseDependencies[it])
}
transitiveClosure.addAll(newDeps)
}
println "Changes will transitively affect projects ${transitiveClosure.join(' ')}"
dependents
}
protected static int projectId(File pDir) {
Integer.valueOf(pDir.name - 'project')
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy