-
Notifications
You must be signed in to change notification settings - Fork 335
Expand file tree
/
Copy pathMuzzleTask.kt
More file actions
154 lines (138 loc) · 5.62 KB
/
MuzzleTask.kt
File metadata and controls
154 lines (138 loc) · 5.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package datadog.gradle.plugin.muzzle.tasks
import datadog.gradle.plugin.muzzle.MuzzleAction
import datadog.gradle.plugin.muzzle.MuzzleDirective
import datadog.gradle.plugin.muzzle.MuzzleExtension
import datadog.gradle.plugin.muzzle.allMainSourceSet
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.FileCollection
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.invocation.BuildInvocationDetails
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.jvm.toolchain.JavaToolchainService
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.property
import org.gradle.workers.WorkerExecutor
import javax.inject.Inject
@CacheableTask
abstract class MuzzleTask @Inject constructor(
objects: ObjectFactory,
providers: ProviderFactory,
) : AbstractMuzzleTask() {
override fun getDescription(): String = if (muzzleDirective.isPresent) {
"Run instrumentation muzzle on ${muzzleDirective.get().name} dependency"
} else {
"Run instrumentation muzzle on compile time dependencies"
}
@get:Inject
abstract val javaToolchainService: JavaToolchainService
@get:Inject
abstract val invocationDetails: BuildInvocationDetails
@get:Inject
abstract val workerExecutor: WorkerExecutor
@get:InputFiles
@get:Classpath
abstract val muzzleBootstrap: Property<Configuration>
@get:InputFiles
@get:Classpath
abstract val muzzleTooling: Property<Configuration>
@get:InputFiles
@get:Classpath
protected val agentClassPath = providers.provider { createAgentClassPath(project) }
@get:InputFiles
@get:Classpath
protected val muzzleClassPath = providers.provider { createMuzzleClassPath(project, name) }
@get:Input
@get:Optional
val muzzleDirective: Property<MuzzleDirective> = objects.property()
@get:OutputFile
val result: RegularFileProperty = objects.fileProperty().convention(
project.layout.buildDirectory.file("reports/$name.txt")
)
@TaskAction
fun muzzle() {
when {
// Version-specific task: created by MuzzlePlugin for each resolved artifact.
muzzleDirective.isPresent -> {
assertMuzzle(muzzleDirective.get())
}
// Fallback for the root "muzzle" lifecycle task when no pass{} directives are
// declared. In that case there are no version-specific pass tasks, so we assert
// the instrumentation against its own compile-time classpath as a basic sanity check.
!project.extensions.getByType<MuzzleExtension>().directives.any { it.assertPass } -> {
project.logger.info("No muzzle pass directives configured. Asserting pass against instrumentation compile-time dependencies")
assertMuzzle()
}
}
}
private fun assertMuzzle(muzzleDirective: MuzzleDirective? = null) {
val workQueue = if (muzzleDirective?.javaVersion != null) {
val javaLauncher = javaToolchainService.launcherFor {
languageVersion.set(JavaLanguageVersion.of(muzzleDirective.javaVersion!!))
}.get()
// Note process isolation leaks gradle dependencies to the child process
// and may need additional code on muzzle plugin to filter those out
// See https://github.com/gradle/gradle/issues/33987
workerExecutor.processIsolation {
forkOptions {
// datadog.trace.agent.tooling.muzzle.MuzzleVersionScanPlugin needs reflective access to ClassLoader.findLoadedClass
if(javaLauncher.metadata.languageVersion > JavaLanguageVersion.of(9)) {
jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED")
}
executable(javaLauncher.executablePath)
}
}
} else {
// noIsolation worker is OK for muzzle tasks as their checks will inspect classes outline
// and should not be impacted by the actual running JDK.
workerExecutor.noIsolation()
}
workQueue.submit(MuzzleAction::class.java) {
buildStartedTime.set(invocationDetails.buildStartedTime)
bootstrapClassPath.setFrom(muzzleBootstrap)
toolingClassPath.setFrom(muzzleTooling)
instrumentationClassPath.setFrom(agentClassPath.get())
testApplicationClassPath.setFrom(muzzleClassPath.get())
if (muzzleDirective != null) {
assertPass.set(muzzleDirective.assertPass)
this.muzzleDirective.set(muzzleDirective.name ?: muzzleDirective.module)
} else {
assertPass.set(true)
}
resultFile.set(result)
}
}
private fun createAgentClassPath(project: Project): FileCollection {
project.logger.info("Creating agent classpath for $project")
val cp = project.files()
cp.from(project.allMainSourceSet.map { it.runtimeClasspath })
if (project.logger.isInfoEnabled) {
cp.forEach { project.logger.info("-- $it") }
}
return cp
}
private fun createMuzzleClassPath(project: Project, muzzleTaskName: String): FileCollection {
project.logger.info("Creating muzzle classpath for $muzzleTaskName")
val cp = project.files()
val config = if (muzzleTaskName == "muzzle") {
project.configurations.named("compileClasspath").get()
} else {
project.configurations.named(muzzleTaskName).get()
}
cp.from(config)
if (project.logger.isInfoEnabled) {
cp.forEach { project.logger.info("-- $it") }
}
return cp
}
}