Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 81 additions & 74 deletions buildSrc/src/main/groovy/MuzzlePlugin.groovy
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import static MuzzleAction.createClassLoader

import org.apache.maven.repository.internal.MavenRepositorySystemUtils
import org.eclipse.aether.DefaultRepositorySystemSession
import org.eclipse.aether.RepositorySystem
Expand All @@ -20,6 +18,7 @@ import org.eclipse.aether.version.Version
import org.gradle.api.Action
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
Expand All @@ -30,6 +29,7 @@ import org.gradle.api.invocation.BuildInvocationDetails
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.TaskProvider
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.jvm.toolchain.JavaToolchainService
import org.gradle.workers.WorkAction
Expand Down Expand Up @@ -93,36 +93,31 @@ class MuzzlePlugin implements Plugin<Project> {
def toolingProject = childProjects.get('agent-tooling')
project.extensions.create("muzzle", MuzzleExtension, project.objects)

def muzzleBootstrap = project.configurations.create('muzzleBootstrap', {
def muzzleBootstrap = project.configurations.register('muzzleBootstrap', {
canBeConsumed: false
canBeResolved: true
})
def muzzleTooling = project.configurations.create('muzzleTooling', {
def muzzleTooling = project.configurations.register('muzzleTooling', {
canBeConsumed: false
canBeResolved: true
})
project.dependencies.add('muzzleBootstrap', bootstrapProject)
project.dependencies.add('muzzleTooling', toolingProject)

project.dependencies.add(muzzleBootstrap.name, bootstrapProject)
project.dependencies.add(muzzleTooling.name, toolingProject)

project.evaluationDependsOn ':dd-java-agent:agent-bootstrap'
project.evaluationDependsOn ':dd-java-agent:agent-tooling'

// compileMuzzle compiles all projects required to run muzzle validation.
// Not adding group and description to keep this task from showing in `gradle tasks`.
def compileMuzzle = project.task('compileMuzzle')
compileMuzzle.dependsOn(toolingProject.tasks.named("compileJava"))
project.afterEvaluate {
project.tasks.matching {
it.name =~ /\Ainstrument(Main)?(_.+)?(Java|Scala|Kotlin)/
}.all {
compileMuzzle.dependsOn(it)
}
TaskProvider<Task> compileMuzzle = project.tasks.register('compileMuzzle') {
it.dependsOn(project.tasks.withType(InstrumentTask))
it.dependsOn bootstrapProject.tasks.named("compileJava")
it.dependsOn bootstrapProject.tasks.named("compileMain_java11Java")
it.dependsOn toolingProject.tasks.named("compileJava")
}
compileMuzzle.dependsOn bootstrapProject.tasks.compileJava
compileMuzzle.dependsOn bootstrapProject.tasks.compileMain_java11Java
compileMuzzle.dependsOn toolingProject.tasks.compileJava

project.task(['type': MuzzleTask], 'muzzle') {
def muzzleTask = project.tasks.register('muzzle', MuzzleTask) {
description = "Run instrumentation muzzle on compile time dependencies"
doLast {
if (!project.muzzle.directives.any { it.assertPass }) {
Expand All @@ -133,23 +128,23 @@ class MuzzlePlugin implements Plugin<Project> {
dependsOn compileMuzzle
}

project.task(['type': MuzzleTask], 'printReferences') {
project.tasks.register('printReferences', MuzzleTask) {
description = "Print references created by instrumentation muzzle"
doLast {
printMuzzle(project)
}
dependsOn compileMuzzle
}
project.task(['type': MuzzleTask], 'generateMuzzleReport') {

project.tasks.register('generateMuzzleReport', MuzzleTask) {
description = "Print instrumentation version report"
doLast {
dumpVersionRanges(project)
}
dependsOn compileMuzzle
}


project.task(['type': MuzzleTask], 'mergeMuzzleReports') {
project.tasks.register('mergeMuzzleReports', MuzzleTask) {
description = "Merge generated version reports in one unique csv"
doLast {
mergeReports(project)
Expand All @@ -174,35 +169,37 @@ class MuzzlePlugin implements Plugin<Project> {
final RepositorySystemSession session = newRepositorySystemSession(system)
project.afterEvaluate {
// use runAfter to set up task finalizers in version order
Task runAfter = project.tasks.muzzle
// runLast is the last task to finish, so we can time the execution
Task runLast = runAfter
TaskProvider<Task> runAfter = muzzleTask
for (MuzzleDirective muzzleDirective : project.muzzle.directives) {
project.getLogger().info("configured $muzzleDirective")

if (muzzleDirective.coreJdk) {
runLast = runAfter = addMuzzleTask(muzzleDirective, null, project, runAfter, muzzleBootstrap, muzzleTooling)
runAfter = addMuzzleTask(muzzleDirective, null, project, runAfter, muzzleBootstrap, muzzleTooling)
} else {
def range = resolveVersionRange(muzzleDirective, system, session)
runLast = muzzleDirectiveToArtifacts(muzzleDirective, range).inject(runLast) { last, Artifact singleVersion ->
for (Artifact singleVersion : muzzleDirectiveToArtifacts(muzzleDirective, range)) {
runAfter = addMuzzleTask(muzzleDirective, singleVersion, project, runAfter, muzzleBootstrap, muzzleTooling)
}
if (muzzleDirective.assertInverse) {
runLast = inverseOf(muzzleDirective, system, session).inject(runLast) { last1, MuzzleDirective inverseDirective ->
muzzleDirectiveToArtifacts(inverseDirective, resolveVersionRange(inverseDirective, system, session)).inject(last1) { last2, Artifact singleVersion ->
for (MuzzleDirective inverseDirective : inverseOf(muzzleDirective, system, session)) {
def inverseRange = resolveVersionRange(inverseDirective, system, session)
for (Artifact singleVersion : (muzzleDirectiveToArtifacts(inverseDirective, inverseRange))) {
runAfter = addMuzzleTask(inverseDirective, singleVersion, project, runAfter, muzzleBootstrap, muzzleTooling)
}
}
}
}
}
def timingTask = project.task("muzzle-end") {
def timingTask = project.tasks.register("muzzle-end") {
doLast {
long endTime = System.currentTimeMillis()
generateResultsXML(project, endTime - startTime)
}
}
runLast.finalizedBy(timingTask)
// last muzzle task to run
runAfter.configure {
finalizedBy(timingTask)
}
}
}

Expand Down Expand Up @@ -236,7 +233,7 @@ class MuzzlePlugin implements Plugin<Project> {
Map<String, TestedArtifact> map = new TreeMap<>()
def versionScheme = new GenericVersionScheme()
dir.eachFileMatch(~/.*\.csv/) { file ->
file.eachLine { line, nb ->
file.eachLine { line, nb ->
if (nb == 1) {
// skip header
return
Expand All @@ -255,7 +252,6 @@ class MuzzlePlugin implements Plugin<Project> {
dumpVersionsToCsv(project, map)
}


private static void dumpVersionRanges(Project project) {
final RepositorySystem system = newRepositorySystem()
final RepositorySystemSession session = newRepositorySystemSession(system)
Expand Down Expand Up @@ -318,9 +314,9 @@ class MuzzlePlugin implements Plugin<Project> {
FileCollection cp = project.files()
project.getLogger().info("Creating muzzle classpath for $muzzleTaskName")
if ('muzzle' == muzzleTaskName) {
cp += project.configurations.compileClasspath
cp += project.configurations.named("compileClasspath").get()
} else {
cp += project.configurations.getByName(muzzleTaskName)
cp += project.configurations.named(muzzleTaskName).get()
}
if (project.getLogger().isInfoEnabled()) {
cp.forEach { project.getLogger().info("-- $it") }
Expand Down Expand Up @@ -431,52 +427,61 @@ class MuzzlePlugin implements Plugin<Project> {
*
* @return The created muzzle task.
*/
private static Task addMuzzleTask(MuzzleDirective muzzleDirective, Artifact versionArtifact, Project instrumentationProject, Task runAfter, Configuration muzzleBootstrap, Configuration muzzleTooling) {
def taskName
private static TaskProvider<Task> addMuzzleTask(
MuzzleDirective muzzleDirective,
Artifact versionArtifact,
Project instrumentationProject,
TaskProvider<Task> runAfter,
NamedDomainObjectProvider<Configuration> muzzleBootstrap,
NamedDomainObjectProvider<Configuration> muzzleTooling
) {
def muzzleTaskName
if (muzzleDirective.coreJdk) {
taskName = "muzzle-Assert$muzzleDirective"
muzzleTaskName = "muzzle-Assert$muzzleDirective"
} else {
taskName = "muzzle-Assert${muzzleDirective.assertPass ? "Pass" : "Fail"}-$versionArtifact.groupId-$versionArtifact.artifactId-$versionArtifact.version${muzzleDirective.name ? "-${muzzleDirective.getNameSlug()}" : ""}"
muzzleTaskName = "muzzle-Assert${muzzleDirective.assertPass ? "Pass" : "Fail"}-$versionArtifact.groupId-$versionArtifact.artifactId-$versionArtifact.version${muzzleDirective.name ? "-${muzzleDirective.getNameSlug()}" : ""}"
}
def config = instrumentationProject.configurations.create(taskName)

if (!muzzleDirective.coreJdk) {
def depId = "$versionArtifact.groupId:$versionArtifact.artifactId:$versionArtifact.version"
if (versionArtifact.classifier) {
depId += ":" + versionArtifact.classifier
}
def dep = instrumentationProject.dependencies.create(depId) {
transitive = true
}
// The following optional transitive dependencies are brought in by some legacy module such as log4j 1.x but are no
// longer bundled with the JVM and have to be excluded for the muzzle tests to be able to run.
dep.exclude group: 'com.sun.jdmk', module: 'jmxtools'
dep.exclude group: 'com.sun.jmx', module: 'jmxri'
// Also exclude specifically excluded dependencies
for (String excluded : muzzleDirective.excludedDependencies) {
String[] parts = excluded.split(':')
dep.exclude group: parts[0], module: parts[1]
}

config.dependencies.add(dep)
}
for (String additionalDependency : muzzleDirective.additionalDependencies) {
config.dependencies.add(instrumentationProject.dependencies.create(additionalDependency) { dep ->
instrumentationProject.configurations.register(muzzleTaskName) { Configuration taskConfig ->
if (!muzzleDirective.coreJdk) {
def depId = "$versionArtifact.groupId:$versionArtifact.artifactId:$versionArtifact.version"
if (versionArtifact.classifier) {
depId += ":" + versionArtifact.classifier
}
def dep = instrumentationProject.dependencies.create(depId) {
transitive = true
}
// The following optional transitive dependencies are brought in by some legacy module such as log4j 1.x but are no
// longer bundled with the JVM and have to be excluded for the muzzle tests to be able to run.
dep.exclude group: 'com.sun.jdmk', module: 'jmxtools'
dep.exclude group: 'com.sun.jmx', module: 'jmxri'
// Also exclude specifically excluded dependencies
for (String excluded : muzzleDirective.excludedDependencies) {
String[] parts = excluded.split(':')
dep.exclude group: parts[0], module: parts[1]
}
dep.transitive = true
})

taskConfig.dependencies.add(dep)
}
for (String additionalDependency : muzzleDirective.additionalDependencies) {
taskConfig.dependencies.add(instrumentationProject.dependencies.create(additionalDependency) { dep ->
for (String excluded : muzzleDirective.excludedDependencies) {
String[] parts = excluded.split(':')
dep.exclude group: parts[0], module: parts[1]
}
dep.transitive = true
})
}
}

def muzzleTask = instrumentationProject.task(['type': MuzzleTask], taskName) {
def muzzleTask = instrumentationProject.tasks.register(muzzleTaskName, MuzzleTask) {
doLast {
assertMuzzle(muzzleBootstrap, muzzleTooling, instrumentationProject, muzzleDirective)
}
}

runAfter.finalizedBy(muzzleTask)
runAfter.configure {
finalizedBy(muzzleTask)
}
muzzleTask
}

Expand Down Expand Up @@ -710,10 +715,12 @@ abstract class MuzzleTask extends DefaultTask {
@javax.inject.Inject
abstract WorkerExecutor getWorkerExecutor()

void assertMuzzle(Configuration muzzleBootstrap,
Configuration muzzleTooling,
Project instrumentationProject,
MuzzleDirective muzzleDirective = null) {
public void assertMuzzle(
NamedDomainObjectProvider<Configuration> muzzleBootstrap,
NamedDomainObjectProvider<Configuration> muzzleTooling,
Project instrumentationProject,
MuzzleDirective muzzleDirective = null
) {
def workQueue
String javaVersion = muzzleDirective?.javaVersion
if (javaVersion) {
Expand All @@ -730,8 +737,8 @@ abstract class MuzzleTask extends DefaultTask {
}
workQueue.submit(MuzzleAction.class, parameters -> {
parameters.buildStartedTime.set(invocationDetails.buildStartedTime)
parameters.bootstrapClassPath.setFrom(muzzleBootstrap)
parameters.toolingClassPath.setFrom(muzzleTooling)
parameters.bootstrapClassPath.setFrom(muzzleBootstrap.get())
parameters.toolingClassPath.setFrom(muzzleTooling.get())
parameters.instrumentationClassPath.setFrom(MuzzlePlugin.createAgentClassPath(instrumentationProject))
parameters.testApplicationClassPath.setFrom(MuzzlePlugin.createMuzzleClassPath(instrumentationProject, name))
if (muzzleDirective) {
Expand All @@ -743,7 +750,7 @@ abstract class MuzzleTask extends DefaultTask {
})
}

void printMuzzle(Project instrumentationProject) {
public void printMuzzle(Project instrumentationProject) {
FileCollection cp = instrumentationProject.sourceSets.main.runtimeClasspath
ClassLoader cl = new URLClassLoader(cp*.toURI()*.toURL() as URL[], null as ClassLoader)
Method printMethod = cl.loadClass('datadog.trace.agent.tooling.muzzle.MuzzleVersionScanPlugin')
Expand Down