forked from reactor/reactor-core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move reactor-tools into the core repository (reactor#1731)
- Loading branch information
1 parent
05de2a1
commit 8316531
Showing
10 changed files
with
927 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/* | ||
* Copyright (c) 2019-Present Pivotal Software Inc, All Rights Reserved. | ||
* | ||
* 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 | ||
* | ||
* https://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. | ||
*/ | ||
|
||
apply plugin: 'com.github.johnrengelman.shadow' | ||
apply plugin: 'org.unbroken-dome.test-sets' | ||
|
||
description = 'Reactor Tools' | ||
|
||
testSets { | ||
jarFileTest | ||
} | ||
|
||
configurations { | ||
shaded | ||
} | ||
project.tasks.test.classpath += configurations.shaded | ||
|
||
dependencies { | ||
compile project(':reactor-core') | ||
|
||
shaded 'org.ow2.asm:asm:7.1' | ||
shaded 'org.ow2.asm:asm-util:7.1' | ||
shaded 'org.ow2.asm:asm-commons:7.1' | ||
shaded 'net.bytebuddy:byte-buddy-agent:1.9.6' | ||
for (dependency in project.configurations.shaded.dependencies) { | ||
compileOnly(dependency) | ||
} | ||
|
||
testCompile 'junit:junit:4.12' | ||
testCompile "org.assertj:assertj-core:$assertJVersion" | ||
|
||
jarFileTestCompile 'org.assertj:assertj-core:3.12.2' | ||
jarFileTestCompile 'junit:junit:4.12' | ||
} | ||
|
||
test { | ||
// Creates a JVM per test because the agent can be installed only once | ||
forkEvery = 1 | ||
maxParallelForks = 1 | ||
jvmArgs = [ | ||
"-Xverify:all", | ||
JavaVersion.current().isJava9Compatible() | ||
? "-Xlog:redefine+class*=warning" | ||
: "-XX:TraceRedefineClasses=2" | ||
] | ||
|
||
testLogging { | ||
displayGranularity 1 | ||
showStackTraces = true | ||
showStandardStreams = true | ||
exceptionFormat = 'full' | ||
events "STARTED", "PASSED", "FAILED", "SKIPPED" | ||
} | ||
} | ||
|
||
jar { | ||
archiveClassifier = 'original' | ||
} | ||
|
||
shadowJar { | ||
archiveClassifier = null | ||
|
||
dependsOn(project.tasks.jar) | ||
manifest { | ||
inheritFrom project.tasks.jar.manifest | ||
} | ||
|
||
configurations = [project.configurations.shaded] | ||
|
||
project.afterEvaluate { | ||
dependencies { | ||
def shadedDependencies = project.configurations | ||
.shaded | ||
.dependencies | ||
.collect { "${it.group}:${it.name}".toString() } | ||
.toSet() | ||
|
||
// Exclude every compile-scoped dependency (including the transitive ones) | ||
for (id in project.configurations.compile.resolvedConfiguration.resolvedArtifacts*.moduleVersion*.id) { | ||
def module = "${id.group}:${id.name}".toString() | ||
if (!shadedDependencies.contains(module)) { | ||
project.configurations.shaded.exclude(group: id.group, module: id.name) | ||
exclude(dependency(module)) | ||
} | ||
} | ||
} | ||
} | ||
|
||
exclude 'module-info.class' | ||
exclude 'META-INF/*' | ||
exclude 'META-INF/maven*/**' | ||
exclude 'META-INF/versions/*' | ||
} | ||
|
||
project.tasks.build.dependsOn(shadowJar) | ||
|
||
task relocateShadowJar(type: com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation) { | ||
target = tasks.shadowJar | ||
prefix = "reactor.tools.shaded" | ||
} | ||
|
||
tasks.shadowJar.dependsOn tasks.relocateShadowJar | ||
|
||
artifacts.archives shadowJar | ||
|
||
project.tasks.jarFileTest.configure { | ||
systemProperty("jarFile", shadowJar.outputs.files.singleFile) | ||
dependsOn(shadowJar) | ||
} | ||
project.tasks.check.dependsOn(jarFileTest) | ||
|
||
task shadedJarTest(type: Test) { | ||
testClassesDirs = sourceSets.test.output.classesDirs | ||
|
||
Set<? super File> mainOutputs = [ | ||
project.sourceSets.main.output.resourcesDir, | ||
project.sourceSets.main.java.outputDir, | ||
] | ||
|
||
classpath = shadowJar.outputs.files | ||
// Exclude main outputs since we have the shaded JAR on the classpath already | ||
classpath += sourceSets.test.runtimeClasspath.filter { !(it in mainOutputs) } | ||
|
||
dependsOn(shadowJar) | ||
} | ||
project.tasks.check.dependsOn(shadedJarTest) |
46 changes: 46 additions & 0 deletions
46
reactor-tools/src/jarFileTest/java/reactor/tools/AbstractJarFileTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
* Copyright (c) 2019-Present Pivotal Software Inc, All Rights Reserved. | ||
* | ||
* 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 | ||
* | ||
* https://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 reactor.tools; | ||
|
||
import java.net.URI; | ||
import java.nio.file.FileSystem; | ||
import java.nio.file.FileSystems; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
|
||
import static java.util.Collections.emptyMap; | ||
|
||
/** | ||
* A helper class to access the content of a shaded JAR | ||
*/ | ||
class AbstractJarFileTest { | ||
|
||
static Path root; | ||
|
||
static { | ||
try { | ||
Path jarFilePath = Paths.get(System.getProperty("jarFile")); | ||
URI jarFileUri = new URI("jar", jarFilePath.toUri().toString(), null); | ||
FileSystem fileSystem = FileSystems.newFileSystem(jarFileUri, emptyMap()); | ||
root = fileSystem.getPath("/"); | ||
} | ||
catch (Exception e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
} |
59 changes: 59 additions & 0 deletions
59
reactor-tools/src/jarFileTest/java/reactor/tools/JarFileShadingTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* Copyright (c) 2019-Present Pivotal Software Inc, All Rights Reserved. | ||
* | ||
* 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 | ||
* | ||
* https://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 reactor.tools; | ||
|
||
import java.io.IOException; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
|
||
import org.assertj.core.api.ListAssert; | ||
import org.junit.Test; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
/** | ||
* This test must be executed with Gradle because it requires a shadow JAR | ||
*/ | ||
public class JarFileShadingTest extends AbstractJarFileTest { | ||
|
||
@Test | ||
public void testPackages() throws Exception { | ||
assertThatFileList(root).containsOnly( | ||
"reactor", | ||
"META-INF" | ||
); | ||
|
||
assertThatFileList(root.resolve("reactor")).containsOnly( | ||
"tools" | ||
); | ||
} | ||
|
||
@Test | ||
public void testMetaInf() throws Exception { | ||
assertThatFileList(root.resolve("META-INF")).containsOnly( | ||
"MANIFEST.MF" | ||
); | ||
} | ||
|
||
private ListAssert<String> assertThatFileList(Path path) throws IOException { | ||
return (ListAssert) assertThat(Files.list(path)) | ||
.extracting(Path::getFileName) | ||
.extracting(Path::toString) | ||
.extracting(it -> it.endsWith("/") ? it.substring(0, it.length() - 1) : it); | ||
} | ||
|
||
} |
114 changes: 114 additions & 0 deletions
114
reactor-tools/src/main/java/reactor/tools/agent/CallSiteInfoAddingMethodVisitor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/* | ||
* Copyright (c) 2019-Present Pivotal Software Inc, All Rights Reserved. | ||
* | ||
* 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 | ||
* | ||
* https://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 reactor.tools.agent; | ||
|
||
import org.objectweb.asm.Label; | ||
import org.objectweb.asm.MethodVisitor; | ||
import org.objectweb.asm.Opcodes; | ||
import org.objectweb.asm.Type; | ||
|
||
import java.util.concurrent.atomic.AtomicBoolean; | ||
|
||
/** | ||
* Adds callSite info to every operator call (except "checkpoint"). | ||
* Before: | ||
* <pre> | ||
* Flux.just(1) | ||
* .map(it -> it) | ||
* </pre> | ||
* After: | ||
* <pre> | ||
* Flux flux = Hooks.addCallSiteInfo(Flux.just(1), "Flux.just -> MyClass.myMethod(MyClass.java:12); | ||
* flux = Hooks.addCallSiteInfo(flux.map(it -> it), "Flux.map -> MyClass.myMethod(MyClass.java:13); | ||
* </pre> | ||
* | ||
*/ | ||
class CallSiteInfoAddingMethodVisitor extends MethodVisitor { | ||
|
||
static boolean isCorePublisher(String className) { | ||
switch (className) { | ||
case "reactor/core/publisher/Flux": | ||
case "reactor/core/publisher/Mono": | ||
case "reactor/core/publisher/ParallelFlux": | ||
case "reactor/core/publisher/GroupedFlux": | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
|
||
final String currentMethod; | ||
|
||
final String currentClassName; | ||
|
||
final String currentSource; | ||
|
||
final AtomicBoolean changed; | ||
|
||
int currentLine = -1; | ||
|
||
CallSiteInfoAddingMethodVisitor( | ||
MethodVisitor visitor, | ||
String currentClassName, | ||
String currentMethod, | ||
String currentSource, | ||
AtomicBoolean changed | ||
) { | ||
super(Opcodes.ASM7, visitor); | ||
this.currentMethod = currentMethod; | ||
this.currentClassName = currentClassName; | ||
this.currentSource = currentSource; | ||
this.changed = changed; | ||
} | ||
|
||
@Override | ||
public void visitLineNumber(int line, Label start) { | ||
super.visitLineNumber(line, start); | ||
currentLine = line; | ||
} | ||
|
||
@Override | ||
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) { | ||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); | ||
if (isCorePublisher(owner)) { | ||
if ("checkpoint".equals(name)) { | ||
return; | ||
} | ||
String returnType = Type.getReturnType(descriptor).getInternalName(); | ||
if (!returnType.startsWith("reactor/core/publisher/")) { | ||
return; | ||
} | ||
|
||
changed.set(true); | ||
|
||
String callSite = String.format( | ||
"\t%s.%s\n\t%s.%s(%s:%d)\n", | ||
owner.replace("/", "."), name, | ||
currentClassName.replace("/", "."), currentMethod, currentSource, currentLine | ||
); | ||
super.visitLdcInsn(callSite); | ||
super.visitMethodInsn( | ||
Opcodes.INVOKESTATIC, | ||
"reactor/core/publisher/Hooks", | ||
"addCallSiteInfo", | ||
HooksClassVisitor.ADD_CALLSITE_INFO_METHOD, | ||
false | ||
); | ||
super.visitTypeInsn(Opcodes.CHECKCAST, returnType); | ||
} | ||
} | ||
} |
Oops, something went wrong.