diff --git a/docs/pom.xml b/docs/pom.xml index cc1bad9937fa9f..a22583d71d58d0 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -2803,10 +2803,11 @@ ${skipDocs} - io.quarkus.docs.generation.CopyJavaExamples + io.quarkus.docs.generation.CopyExampleSource ${code-example-dir} - ${project.basedir}/../integration-tests + ${project.basedir}/.. + ${project.basedir}/src/main/asciidoc ${env.MAVEN_CMD_LINE_ARGS} diff --git a/docs/src/main/asciidoc/telemetry-examples.yaml b/docs/src/main/asciidoc/telemetry-examples.yaml new file mode 100644 index 00000000000000..ad4b8cbd53c3c9 --- /dev/null +++ b/docs/src/main/asciidoc/telemetry-examples.yaml @@ -0,0 +1,3 @@ +examples: +- source: integration-tests/micrometer-prometheus/src/main/java/io/quarkus/doc/micrometer/ExampleResource.java + target: telemetry-micrometer-tutorial-example-resource.java \ No newline at end of file diff --git a/docs/src/main/asciidoc/telemetry-micrometer-tutorial.adoc b/docs/src/main/asciidoc/telemetry-micrometer-tutorial.adoc index b69ae2cb6abf17..8bac57346ef3e9 100644 --- a/docs/src/main/asciidoc/telemetry-micrometer-tutorial.adoc +++ b/docs/src/main/asciidoc/telemetry-micrometer-tutorial.adoc @@ -41,7 +41,7 @@ Let's first add a simple endpoint that calculates prime numbers. [source,java] ---- -include::{code-examples}/telemetry-micrometer-tutorial-ExampleResource.java[tags=example;!ignore;!registry;!gauge;!counter;!timer] +include::{code-examples}/telemetry-micrometer-tutorial-example-resource.java[tags=example;!ignore;!registry;!gauge;!counter;!timer] ---- Start your application in dev mode: @@ -95,7 +95,7 @@ The `MeterRegistry` can be injected into your application as follows: [source,java] ---- -include::{code-examples}/telemetry-micrometer-tutorial-ExampleResource.java[tags=registry;!gauge] +include::{code-examples}/telemetry-micrometer-tutorial-example-resource.java[tags=registry;!gauge] ---- == Add a Counter @@ -107,7 +107,7 @@ We'll add a dimensional label (also called an attribute or a tag) that will allo [source,java] ---- -include::{code-examples}/telemetry-micrometer-tutorial-ExampleResource.java[tags=counted;!ignore;!timer] +include::{code-examples}/telemetry-micrometer-tutorial-example-resource.java[tags=counted;!ignore;!timer] ---- <1> Find or create a counter called `example.prime.number` that has a `type` label with the specified value. @@ -154,7 +154,7 @@ Timers are a specialized abstraction for measuring duration. Let's add a timer t [source,java] ---- -include::{code-examples}/telemetry-micrometer-tutorial-ExampleResource.java[tags=timed;!ignore;!default] +include::{code-examples}/telemetry-micrometer-tutorial-example-resource.java[tags=timed;!ignore;!default] ---- <1> Find or create a counter called `example.prime.number` that has a `type` label with the specified value. diff --git a/docs/src/main/java/io/quarkus/docs/generation/CopyExampleSource.java b/docs/src/main/java/io/quarkus/docs/generation/CopyExampleSource.java new file mode 100755 index 00000000000000..e8ccbb845fada1 --- /dev/null +++ b/docs/src/main/java/io/quarkus/docs/generation/CopyExampleSource.java @@ -0,0 +1,171 @@ +package io.quarkus.docs.generation; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; + +public class CopyExampleSource { + + static Path docsDir() { + Path path = Paths.get(System.getProperty("user.dir")); + if (path.endsWith("docs")) { + return path; + } + return path.resolve("docs"); + } + + public Path outputPath; + public Path rootPath; + public List srcPaths; + Map allTargets = new HashMap<>(); + + // Two arguments: + // ${project.basedir}/../target/asciidoc/generated/examples ${project.basedir}/.. ${project.basedir}/src/main/asciidoc + public static void main(String[] args) throws Exception { + CopyExampleSource copyExamples = new CopyExampleSource(); + + // Required first parameter: Target output directory + if (args.length < 1) { + System.err.println("Must specify target output directory"); + System.exit(1); + } + copyExamples.outputPath = Path.of(args[0]).normalize(); + System.out.println("[INFO] Output directory: " + copyExamples.outputPath); + + // Optional second parameter: Project root directory + if (args.length > 1) { + copyExamples.rootPath = Path.of(args[1]).normalize(); + } else { + copyExamples.rootPath = docsDir().resolve("..").normalize(); + } + System.out.println("[INFO] Project root: " + copyExamples.rootPath); + + // third parameter and on .. source paths + if (args.length > 2) { + copyExamples.srcPaths = Arrays.stream(args).skip(2) + .map(x -> Path.of(x).normalize()) + .collect(Collectors.toList()); + } else { + copyExamples.srcPaths = List.of(docsDir().resolve("src/main/asciidoc").normalize()); + } + + try { + copyExamples.run(); + } catch (Exception e) { + System.err.println("Exception occurred while trying to copy examples"); + e.printStackTrace(); + System.exit(1); + } + } + + public void run() throws Exception { + Files.createDirectories(outputPath); + ObjectMapper om = new ObjectMapper(new YAMLFactory().enable(YAMLGenerator.Feature.MINIMIZE_QUOTES)) + .setVisibility(PropertyAccessor.FIELD, Visibility.ANY); + + for (Path path : srcPaths) { + Files.walkFileTree(path, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { + if (path.toString().endsWith("-examples.yaml")) { + System.out.println("[INFO] Reading: " + path); + + MappingList mapping = om.readValue(path.toFile(), MappingList.class); + + // For each example: + for (Example example : mapping.examples) { + + // Resolve the source path against the root directory + Path relativePath = Path.of(example.source); + Path sourcePath = rootPath.resolve(relativePath); + // Resolve the target path against the output directory + Path targetPath = outputPath.resolve(example.target); + + if (Files.exists(sourcePath)) { + // Record an error if the target already exists + String former = allTargets.put(example.target, example.source); + if (former != null) { + System.err.printf( + "[ERROR] Duplicate target: %s%n Previous value: %s%n New value: %s%n", + example.target, former, example.source); + + mapping.duplicateKey = true; + continue; + } + + // Make sure required target directories exist + Files.createDirectories(targetPath.getParent()); + + // Copy the source file to the target file. + // Replace {{source}} in comment lines with the relative source path + try (BufferedReader br = new BufferedReader( + new InputStreamReader(Files.newInputStream(sourcePath, StandardOpenOption.READ), + "UTF-8"))) { + try (PrintWriter bw = new PrintWriter(new OutputStreamWriter( + Files.newOutputStream(targetPath, StandardOpenOption.CREATE, + StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)))) { + String line; + while ((line = br.readLine()) != null) { + if (line.startsWith("// Source: {{source}}")) { + bw.println("// Source: " + relativePath); + } else if (line.startsWith("# Source: {{source}}")) { + bw.println("# Source: " + relativePath); + } else { + bw.println(line); + } + } + System.out.printf("[INFO] Copied %s %n to %s%n", relativePath, targetPath); + } + } catch (IOException ioe) { + System.err.printf("[ERROR] Error copying %s %n to %s%n", relativePath, + targetPath); + throw ioe; + } + } else { + System.err.println("[ERROR] Specified source file doesn't exist: " + sourcePath); + mapping.missingSource = true; + } + } + } + return FileVisitResult.CONTINUE; + } + }); + } + } + + static class MappingList { + List examples; + + @JsonIgnore + boolean missingSource = false; + + @JsonIgnore + boolean duplicateKey = false; + } + + static class Example { + String source; + String target; + } +} diff --git a/docs/src/main/java/io/quarkus/docs/generation/CopyJavaExamples.java b/docs/src/main/java/io/quarkus/docs/generation/CopyJavaExamples.java deleted file mode 100755 index 598109a3bdddc9..00000000000000 --- a/docs/src/main/java/io/quarkus/docs/generation/CopyJavaExamples.java +++ /dev/null @@ -1,63 +0,0 @@ -package io.quarkus.docs.generation; - -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -public class CopyJavaExamples { - - public Path outputPath; - public List paths; - - // ${project.basedir}/../target/asciidoc/generated/examples ${project.basedir}/../integration-tests - public static void main(String[] args) throws Exception { - if (args.length < 2) { - System.err.println("Must specify target output directory (first) followed by at least one source directory"); - System.exit(1); - } - CopyJavaExamples javaExamples = new CopyJavaExamples(); - - javaExamples.outputPath = Path.of(args[0]); - javaExamples.paths = Arrays.stream(args).skip(1) - .map(Path::of) - .collect(Collectors.toList()); - - try { - javaExamples.run(); - } catch (Exception e) { - System.err.println("Exception occurred while trying to copy java examples"); - e.printStackTrace(); - System.exit(1); - } - } - - public void run() throws Exception { - if (outputPath != null) { - Files.createDirectories(outputPath); - } - - for (Path path : paths) { - Files.walkFileTree(path, new SimpleFileVisitor<>() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - if (file.toString().contains("src/main/java/documentation/example/")) { - String name = file.toString(); - name = name.substring(name.indexOf("example/") + 8) - .replace("/", "-"); - - Files.copy(file, outputPath.resolve(name), StandardCopyOption.REPLACE_EXISTING); - } - return FileVisitResult.CONTINUE; - } - }); - } - } - -} diff --git a/integration-tests/micrometer-prometheus/src/main/java/documentation/example/telemetry/micrometer/tutorial/ExampleResource.java b/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/doc/micrometer/ExampleResource.java similarity index 93% rename from integration-tests/micrometer-prometheus/src/main/java/documentation/example/telemetry/micrometer/tutorial/ExampleResource.java rename to integration-tests/micrometer-prometheus/src/main/java/io/quarkus/doc/micrometer/ExampleResource.java index 389d302676bbb6..f66df272b1d5e6 100644 --- a/integration-tests/micrometer-prometheus/src/main/java/documentation/example/telemetry/micrometer/tutorial/ExampleResource.java +++ b/integration-tests/micrometer-prometheus/src/main/java/io/quarkus/doc/micrometer/ExampleResource.java @@ -1,8 +1,7 @@ // tag::example[] // tag::ignore[] -// This example is maintained in quarkus micrometer integration tests -// integration-tests/micrometer-prometheus/src/main/java/documentation/example/telemetry/micrometer/tutorial/ExampleResource.java -package documentation.example.telemetry.micrometer.tutorial; +// Source: {{source}} +package io.quarkus.doc.micrometer; /* // end::ignore[]