diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f33c929..d50f9d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,3 +24,5 @@ jobs: - name: Publish run: | ./gradlew publish + cd jafar-gradle-plugin + ./gradlew publish diff --git a/demo/build.gradle b/demo/build.gradle index 817f3b9..d64b0ae 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -33,10 +33,17 @@ tasks.build { dependencies { implementation project(':parser') implementation 'org.jctools:jctools-core:4.0.1' - implementation 'com.github.ben-manes.caffeine:caffeine:3.1.5' implementation 'org.openjdk.jmc:flightrecorder:8.3.1' } test { useJUnitPlatform() } + +generateJafarTypes { + overwrite = false + eventTypeFilter { + it == 'jdk.ExecutionSample' + } + targetPackage = 'io.jafar.demo.types' +} \ No newline at end of file diff --git a/demo/src/main/java/io/jafar/demo/ExecutionSampleEvent.java b/demo/src/main/java/io/jafar/demo/ExecutionSampleEvent.java deleted file mode 100644 index a17e25b..0000000 --- a/demo/src/main/java/io/jafar/demo/ExecutionSampleEvent.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.jafar.demo; - -import io.jafar.parser.api.JfrField; -import io.jafar.parser.api.JfrType; -import io.jafar.parser.api.types.JFRStackTrace; -import io.jafar.parser.api.types.JFRThread; - -@JfrType("jdk.ExecutionSample") -public interface ExecutionSampleEvent { - long startTime(); - - JFRThread eventThread(); - JFRThread sampledThread(); - JFRStackTrace stackTrace(); -} diff --git a/demo/src/main/java/io/jafar/demo/Main.java b/demo/src/main/java/io/jafar/demo/Main.java index 35fd1f2..b5a9fda 100644 --- a/demo/src/main/java/io/jafar/demo/Main.java +++ b/demo/src/main/java/io/jafar/demo/Main.java @@ -1,5 +1,6 @@ package io.jafar.demo; +import io.jafar.demo.types.JFRExecutionSample; import io.jafar.parser.api.HandlerRegistration; import io.jafar.parser.api.JafarParser; import jdk.jfr.consumer.EventStream; @@ -61,7 +62,7 @@ private static void runWithJmc(File file, LongAccumulator sum, AtomicInteger cnt private static void runWithJafar(File file, LongAccumulator sum, AtomicInteger cnt) throws Exception { try (JafarParser p = JafarParser.open(file.getPath())) { - HandlerRegistration h1 = p.handle(ExecutionSampleEvent.class, (event, ctl) -> { + HandlerRegistration h1 = p.handle(JFRExecutionSample.class, (event, ctl) -> { if (event.sampledThread() == null) { throw new RuntimeException(); } diff --git a/gradle-plugin/build.gradle b/jafar-gradle-plugin/build.gradle similarity index 77% rename from gradle-plugin/build.gradle rename to jafar-gradle-plugin/build.gradle index 083caaf..abedccd 100644 --- a/gradle-plugin/build.gradle +++ b/jafar-gradle-plugin/build.gradle @@ -2,10 +2,11 @@ plugins { id 'java-gradle-plugin' id 'groovy' id 'maven-publish' + id 'io.github.gradle-nexus.publish-plugin' version '2.0.0' } group = "io.btrace" -version = project.hasProperty("jafar_version") ? project.jafar_version : rootProject.version +version = "0.0.1-SNAPSHOT" repositories { mavenLocal() @@ -67,3 +68,12 @@ publishing { } } +nexusPublishing { + repositories { + sonatype { + username = project.hasProperty("sonatype.user") ? project.property("sonatype.user") : System.getenv("SONATYPE_USERNAME") + password = project.hasProperty("sonatype.password") ? project.property("sonatype.password") : System.getenv("SONATYPE_PASSWORD") + } + } +} + diff --git a/jafar-gradle-plugin/gradle.properties b/jafar-gradle-plugin/gradle.properties new file mode 100644 index 0000000..fb373e8 --- /dev/null +++ b/jafar-gradle-plugin/gradle.properties @@ -0,0 +1,2 @@ +sonatype.user=XXSEjG1P +sonatype.password=P5w7F2tDqHdOO5CDCbyK66t1dV93Owtudyaibs2k30mL diff --git a/gradle-plugin/gradle/wrapper/gradle-wrapper.jar b/jafar-gradle-plugin/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from gradle-plugin/gradle/wrapper/gradle-wrapper.jar rename to jafar-gradle-plugin/gradle/wrapper/gradle-wrapper.jar diff --git a/gradle-plugin/gradle/wrapper/gradle-wrapper.properties b/jafar-gradle-plugin/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from gradle-plugin/gradle/wrapper/gradle-wrapper.properties rename to jafar-gradle-plugin/gradle/wrapper/gradle-wrapper.properties diff --git a/gradle-plugin/gradlew b/jafar-gradle-plugin/gradlew similarity index 100% rename from gradle-plugin/gradlew rename to jafar-gradle-plugin/gradlew diff --git a/gradle-plugin/gradlew.bat b/jafar-gradle-plugin/gradlew.bat similarity index 100% rename from gradle-plugin/gradlew.bat rename to jafar-gradle-plugin/gradlew.bat diff --git a/gradle-plugin/settings.gradle b/jafar-gradle-plugin/settings.gradle similarity index 100% rename from gradle-plugin/settings.gradle rename to jafar-gradle-plugin/settings.gradle diff --git a/gradle-plugin/src/main/groovy/io/jafar/gradle/TypeGeneratorPlugin.groovy b/jafar-gradle-plugin/src/main/groovy/io/jafar/gradle/TypeGeneratorPlugin.groovy similarity index 56% rename from gradle-plugin/src/main/groovy/io/jafar/gradle/TypeGeneratorPlugin.groovy rename to jafar-gradle-plugin/src/main/groovy/io/jafar/gradle/TypeGeneratorPlugin.groovy index 1996865..089ec8b 100644 --- a/gradle-plugin/src/main/groovy/io/jafar/gradle/TypeGeneratorPlugin.groovy +++ b/jafar-gradle-plugin/src/main/groovy/io/jafar/gradle/TypeGeneratorPlugin.groovy @@ -4,11 +4,14 @@ import io.jafar.utils.TypeGenerator import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.provider.Property +import org.gradle.api.file.DirectoryProperty + +import java.util.function.Predicate class TypeGeneratorPlugin implements Plugin { @Override void apply(Project project) { - def extension = project.extensions.create('generateSources', GenerateSourcesExtension, project) + def extension = project.extensions.create('generateJafarTypes', GenerateJafarTypesExtension, project) project.afterEvaluate { if (project.hasProperty('jafar.input')) { @@ -26,7 +29,7 @@ class TypeGeneratorPlugin implements Plugin { // Define inputs and outputs for task up-to-date checks inputs.file(extension.inputFile).optional(true) - outputs.dir(generatedSourcesDir) + outputs.dir(extension.outputDir.orElse(project.layout.buildDirectory.dir("generated/sources/jafar/src/main"))) doLast { if (!extension.inputFile.isPresent()) { @@ -36,13 +39,22 @@ class TypeGeneratorPlugin implements Plugin { } def input = extension.inputFile.isPresent() ? extension.inputFile.get() : null - def output = generatedSourcesDir + def output = extension.outputDir.orElse(project.layout.buildDirectory.dir("generated/sources/jafar/src/main")).get().asFile + def overwrite = extension.overwrite.getOrElse(false) + def targetPackage = extension.targetPackage.getOrElse("io.jafar.parser.api.types") + // Ensure output directory exists output.mkdirs() + Predicate predicate = null + if (extension.eventTypeFilter.isPresent()) { + def filterClosure = extension.eventTypeFilter.get() + predicate = filterClosure as Predicate // Convert Closure to Predicate + } + // Instantiate and execute TypeGenerator - def generator = new TypeGenerator(input?.toPath(), output.toPath()) + def generator = new TypeGenerator(input?.toPath(), output.toPath(), targetPackage, overwrite, predicate) generator.generate() } } @@ -57,11 +69,23 @@ class TypeGeneratorPlugin implements Plugin { } // Extension to configure the input file - static class GenerateSourcesExtension { + static class GenerateJafarTypesExtension { final Property inputFile + final DirectoryProperty outputDir + final Property targetPackage + final Property overwrite + final Property> eventTypeFilter - GenerateSourcesExtension(Project project) { + GenerateJafarTypesExtension(Project project) { inputFile = project.objects.property(File) + outputDir = project.objects.directoryProperty() + targetPackage = project.objects.property(String) + overwrite = project.objects.property(Boolean) + eventTypeFilter = project.objects.property(Closure) + } + + void eventTypeFilter(Closure eventTypeFilterClosure) { + this.eventTypeFilter.set(eventTypeFilterClosure) } } } \ No newline at end of file diff --git a/parser/src/main/java/io/jafar/parser/api/types/JFRClass.java b/parser/src/main/java/io/jafar/parser/api/types/JFRClass.java deleted file mode 100644 index 6389a7f..0000000 --- a/parser/src/main/java/io/jafar/parser/api/types/JFRClass.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.jafar.parser.api.types; - -import io.jafar.parser.api.JfrField; -import io.jafar.parser.api.JfrIgnore; -import io.jafar.parser.api.JfrType; - -@JfrType("java.lang.Class") -public interface JFRClass { - JFRSymbol name(); - @JfrField("package") JFRPackage pkg(); - int modifiers(); - boolean hidden(); - - @JfrIgnore - default String tostring() { - StringBuilder sb = new StringBuilder(); - JFRPackage pkg = pkg(); - if (pkg != null) { - sb.append(pkg.string()).append("."); - } - sb.append(name().string()); - return sb.toString(); - } -} diff --git a/parser/src/main/java/io/jafar/parser/api/types/JFRClassLoader.java b/parser/src/main/java/io/jafar/parser/api/types/JFRClassLoader.java deleted file mode 100644 index 8003c6a..0000000 --- a/parser/src/main/java/io/jafar/parser/api/types/JFRClassLoader.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.jafar.parser.api.types; - -import io.jafar.parser.api.JfrType; - -@JfrType("jdk.types.ClassLoader") -public interface JFRClassLoader { - JFRClass type(); - JFRSymbol name(); -} diff --git a/parser/src/main/java/io/jafar/parser/api/types/JFREvent.java b/parser/src/main/java/io/jafar/parser/api/types/JFREvent.java deleted file mode 100644 index 1f9f525..0000000 --- a/parser/src/main/java/io/jafar/parser/api/types/JFREvent.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.jafar.parser.api.types; - -public interface JFREvent { - long startTime(); - JFRThread eventThread(); - JFRStackTrace stackTrace(); -} diff --git a/parser/src/main/java/io/jafar/parser/api/types/JFRExecutionSample.java b/parser/src/main/java/io/jafar/parser/api/types/JFRExecutionSample.java deleted file mode 100644 index 0f92e48..0000000 --- a/parser/src/main/java/io/jafar/parser/api/types/JFRExecutionSample.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.jafar.parser.api.types; - -import io.jafar.parser.api.JfrType; - -@JfrType("jdk.ExecutionSample") -public interface JFRExecutionSample extends JFREvent { - JFRThread sampledThread(); - JFRStackTrace stackTrace(); - JFRThreadState state(); -} diff --git a/parser/src/main/java/io/jafar/parser/api/types/JFRFrameType.java b/parser/src/main/java/io/jafar/parser/api/types/JFRFrameType.java deleted file mode 100644 index 626058e..0000000 --- a/parser/src/main/java/io/jafar/parser/api/types/JFRFrameType.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.jafar.parser.api.types; - -import io.jafar.parser.api.JfrType; - -@JfrType("jdk.types.FrameType") -public interface JFRFrameType { - String description(); -} diff --git a/parser/src/main/java/io/jafar/parser/api/types/JFRMethod.java b/parser/src/main/java/io/jafar/parser/api/types/JFRMethod.java deleted file mode 100644 index f75631b..0000000 --- a/parser/src/main/java/io/jafar/parser/api/types/JFRMethod.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.jafar.parser.api.types; - -import io.jafar.parser.api.JfrIgnore; -import io.jafar.parser.api.JfrType; - -@JfrType("jdk.types.Method") -public interface JFRMethod { - JFRClass type(); - JFRSymbol name(); - JFRSymbol descriptor(); - int modifiers(); - boolean hidden(); - - @JfrIgnore - default String string() { - return String.format("%s.%s%s", type().tostring(), name().string(), descriptor().string()); - } -} diff --git a/parser/src/main/java/io/jafar/parser/api/types/JFRModule.java b/parser/src/main/java/io/jafar/parser/api/types/JFRModule.java deleted file mode 100644 index 769fa7d..0000000 --- a/parser/src/main/java/io/jafar/parser/api/types/JFRModule.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.jafar.parser.api.types; - -import io.jafar.parser.api.JfrType; - -@JfrType("jdk.types.Module") -public interface JFRModule { - JFRSymbol name(); - JFRSymbol version(); - JFRSymbol location(); - JFRClassLoader classLoader(); -} diff --git a/parser/src/main/java/io/jafar/parser/api/types/JFRPackage.java b/parser/src/main/java/io/jafar/parser/api/types/JFRPackage.java deleted file mode 100644 index fcc7987..0000000 --- a/parser/src/main/java/io/jafar/parser/api/types/JFRPackage.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.jafar.parser.api.types; - -import io.jafar.parser.api.JfrIgnore; -import io.jafar.parser.api.JfrType; - -@JfrType("jdk.types.Package") -public interface JFRPackage { - JFRSymbol name(); - JFRModule module(); - boolean exported(); - - @JfrIgnore - default String string() { - return name().string(); - } -} diff --git a/parser/src/main/java/io/jafar/parser/api/types/JFRStackFrame.java b/parser/src/main/java/io/jafar/parser/api/types/JFRStackFrame.java deleted file mode 100644 index f39f5d2..0000000 --- a/parser/src/main/java/io/jafar/parser/api/types/JFRStackFrame.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.jafar.parser.api.types; - -import io.jafar.parser.api.JfrIgnore; -import io.jafar.parser.api.JfrType; - -@JfrType("jdk.types.StackFrame") -public interface JFRStackFrame { - JFRFrameType frameType(); - int lineNumber(); - int bytecodeIndex(); - JFRMethod method(); - - @JfrIgnore - default String string() { - return String.format("%s:%d", method().string(), lineNumber()); - } -} diff --git a/parser/src/main/java/io/jafar/parser/api/types/JFRStackTrace.java b/parser/src/main/java/io/jafar/parser/api/types/JFRStackTrace.java deleted file mode 100644 index dbea334..0000000 --- a/parser/src/main/java/io/jafar/parser/api/types/JFRStackTrace.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.jafar.parser.api.types; - -import io.jafar.parser.api.JfrType; - -@JfrType("jdk.types.StackTrace") -public interface JFRStackTrace { - boolean truncated(); - JFRStackFrame[] frames(); -} diff --git a/parser/src/main/java/io/jafar/parser/api/types/JFRSymbol.java b/parser/src/main/java/io/jafar/parser/api/types/JFRSymbol.java deleted file mode 100644 index 5dcbd9b..0000000 --- a/parser/src/main/java/io/jafar/parser/api/types/JFRSymbol.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.jafar.parser.api.types; - -import io.jafar.parser.api.JfrType; - -@JfrType("jdk.types.Symbol") -public interface JFRSymbol { - String string(); -} diff --git a/parser/src/main/java/io/jafar/parser/api/types/JFRThread.java b/parser/src/main/java/io/jafar/parser/api/types/JFRThread.java deleted file mode 100644 index 41a5153..0000000 --- a/parser/src/main/java/io/jafar/parser/api/types/JFRThread.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.jafar.parser.api.types; - -import io.jafar.parser.api.JfrType; - -@JfrType("java.lang.Thread") -public interface JFRThread { - long osThreadId(); - long javaThreadId(); - String osName(); - String javaName(); - boolean virtual(); -} diff --git a/parser/src/main/java/io/jafar/parser/api/types/JFRThreadState.java b/parser/src/main/java/io/jafar/parser/api/types/JFRThreadState.java deleted file mode 100644 index 5809374..0000000 --- a/parser/src/main/java/io/jafar/parser/api/types/JFRThreadState.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.jafar.parser.api.types; - -import io.jafar.parser.api.JfrType; - -@JfrType("jdk.types.ThreadState") -public interface JFRThreadState { - String name(); -} diff --git a/parser/src/main/java/io/jafar/utils/TypeGenerator.java b/parser/src/main/java/io/jafar/utils/TypeGenerator.java index f89abf2..23ae6b1 100644 --- a/parser/src/main/java/io/jafar/utils/TypeGenerator.java +++ b/parser/src/main/java/io/jafar/utils/TypeGenerator.java @@ -12,20 +12,27 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.HashSet; -import java.util.Objects; import java.util.Set; +import java.util.function.Predicate; public final class TypeGenerator { private final Path jfr; private final Path output; + private final String pkg; + private final boolean overwrite; + private final Predicate eventTypeFilter; - public TypeGenerator(Path jfr, Path output) throws IOException{ + public TypeGenerator(Path jfr, Path output, String targetPackage, boolean overwrite, Predicate eventTypeFilter) throws IOException{ if (!Files.isDirectory(output) || !Files.exists(output)) { throw new IllegalArgumentException("Output directory does not exist: " + output); } this.jfr = jfr; - this.output = output.resolve("io/jafar/parser/api/types"); + this.pkg = targetPackage; + this.output = output.resolve(targetPackage.replace('.', '/')); + this.overwrite = overwrite; + this.eventTypeFilter = eventTypeFilter; Files.createDirectories(this.output); } @@ -40,21 +47,27 @@ public void generate() throws Exception { private void generateFromRuntime() throws Exception { Set generated = new HashSet<>(); FlightRecorder.getFlightRecorder().getEventTypes().forEach(et -> { - try { - Files.writeString(output.resolve("JFR" + getSimpleName(et.getName()) + ".java"), generateTypeFromEvent(et, generated)); - } catch (IOException e) { - throw new RuntimeException(e); + if (eventTypeFilter == null || eventTypeFilter.test(et.getName())) { + try { + Path target = output.resolve("JFR" + getSimpleName(et.getName()) + ".java"); + if (overwrite || !Files.exists(target)) { + Files.writeString(target, generateTypeFromEvent(et, generated), StandardOpenOption.CREATE_NEW); + } + } catch (IOException e) { + throw new RuntimeException(e); + + } } }); } private String generateTypeFromEvent(EventType et, Set generatedTypes) { StringBuilder sb = new StringBuilder(); - sb.append("package io.jafar.parser.api.types;\n"); + sb.append("package ").append(pkg).append(";\n"); sb.append("\n"); sb.append("import io.jafar.parser.api.*;\n"); - sb.append("@JfrType(\"").append(et.getName()).append("\")\n"); - sb.append("public interface JFR").append(getSimpleName(et.getName())).append(" extends JFREvent").append(" {\n"); + sb.append("@JfrType(\"").append(et.getName()).append("\")\n\n"); + sb.append("public interface JFR").append(getSimpleName(et.getName())).append(" {\n"); et.getFields().forEach(field -> { try { writeTypeFromField(field, generatedTypes); @@ -83,7 +96,10 @@ private void writeTypeFromField(ValueDescriptor f, Set generatedTypes) t if (data != null) { String typeName = f.getTypeName(); String targetName = isPrimitiveName(typeName) ? typeName : "JFR" + getSimpleName(typeName); - Files.writeString(output.resolve(targetName + ".java"), data); + Path target = output.resolve(targetName + ".java"); + if (overwrite || !Files.exists(target)) { + Files.writeString(output.resolve(targetName + ".java"), data, StandardOpenOption.CREATE_NEW); + } } } @@ -95,10 +111,10 @@ private String getTypeFromField(ValueDescriptor field, Set generatedType if (generatedTypes.add(typeName)) { StringBuilder sb = new StringBuilder(); - sb.append("package io.jafar.parser.api.types;\n"); + sb.append("package ").append(pkg).append(";\n"); sb.append("\n"); sb.append("import io.jafar.parser.api.*;\n"); - sb.append("@JfrType(\"").append(typeName).append("\")\n"); + sb.append("@JfrType(\"").append(typeName).append("\")\n\n"); sb.append("public interface JFR").append(getSimpleName(typeName)).append(" {\n"); field.getFields().forEach(subfield -> { try { @@ -146,7 +162,9 @@ private void writeClass(MetadataClass metadataClass) { } try { Path classFile = output.resolve(getClassName(metadataClass) + ".java"); - Files.writeString(classFile, generateClass(metadataClass)); + if (overwrite || !Files.exists(classFile)) { + Files.writeString(classFile, generateClass(metadataClass), StandardOpenOption.CREATE_NEW); + } } catch (IOException e) { throw new RuntimeException(e); } @@ -154,14 +172,11 @@ private void writeClass(MetadataClass metadataClass) { private String generateClass(MetadataClass clazz) { StringBuilder sb = new StringBuilder(); - sb.append("package io.jafar.parser.api.types;\n"); + sb.append("package ").append(pkg).append(";\n"); sb.append("\n"); sb.append("import io.jafar.parser.api.*;\n"); - sb.append("@JfrType(\"").append(clazz.getName()).append("\")\n"); + sb.append("@JfrType(\"").append(clazz.getName()).append("\")\n\n"); sb.append("public interface ").append(getClassName(clazz)); - if (isEvent(clazz)) { - sb.append(" extends JFREvent"); - } sb.append(" {\n"); for (MetadataField field : clazz.getFields()) { String fldName = sanitizeFieldName(field.getName()); diff --git a/rebuild_plugin.sh b/rebuild_plugin.sh index 9d83037..4d61bb8 100755 --- a/rebuild_plugin.sh +++ b/rebuild_plugin.sh @@ -1,8 +1,10 @@ #!/usr/bin/env bash +set -e + ./gradlew :parser:publishToMavenLocal ( - cd gradle-plugin || exit - ./gradlew publishToMavenLocal + cd jafar-gradle-plugin || exit + ./gradlew clean publishToMavenLocal ) \ No newline at end of file