Skip to content

Commit

Permalink
Move reactor-tools into the core repository (reactor#1731)
Browse files Browse the repository at this point in the history
  • Loading branch information
bsideup authored and simonbasle committed Jun 4, 2019
1 parent 05de2a1 commit 8316531
Show file tree
Hide file tree
Showing 10 changed files with 927 additions and 1 deletion.
139 changes: 139 additions & 0 deletions reactor-tools/build.gradle
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)
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);
}
}

}
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);
}

}
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);
}
}
}
Loading

0 comments on commit 8316531

Please sign in to comment.