From 1da7e31d12e74835c0ad206684302ec84f6f8f1c Mon Sep 17 00:00:00 2001 From: Andy Damevin Date: Fri, 14 Jun 2024 13:36:57 +0200 Subject: [PATCH] Introduce batch mode --- .../statiq/deployment/StatiqProcessor.java | 42 +--------- .../src/main/resources/dev-ui/qwc-statiq.js | 71 ++++++++++------- .../ROOT/pages/includes/quarkus-statiq.adoc | 38 ++++++++- .../quarkiverse/statiq/it/StatiqResource.java | 5 +- .../src/main/resources/application.properties | 5 +- .../statiq/it/StatiqResourceTest.java | 29 ++----- .../src/test/resources/application.properties | 2 + pom.xml | 2 +- .../runtime/FixedStaticPagesProvider.java | 17 +++- .../statiq/runtime}/StatiqConfig.java | 15 +++- .../statiq/runtime/StatiqGenerator.java | 79 +++++++++++++++---- .../statiq/runtime/StatiqGeneratorConfig.java | 30 ------- .../statiq/runtime/StatiqPage.java | 63 +++++++++++++-- .../statiq/runtime/StatiqPages.java | 2 +- .../statiq/runtime/StatiqRecorder.java | 20 +---- .../runtime/devui/StatiqJsonRPCService.java | 7 ++ .../statiq/runtime/util/PathUtils.java | 32 ++++++++ 17 files changed, 281 insertions(+), 178 deletions(-) create mode 100644 integration-tests/src/test/resources/application.properties rename {deployment/src/main/java/io/quarkiverse/statiq/deployment => runtime/src/main/java/io/quarkiverse/statiq/runtime}/StatiqConfig.java (68%) delete mode 100644 runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqGeneratorConfig.java create mode 100644 runtime/src/main/java/io/quarkiverse/statiq/runtime/util/PathUtils.java diff --git a/deployment/src/main/java/io/quarkiverse/statiq/deployment/StatiqProcessor.java b/deployment/src/main/java/io/quarkiverse/statiq/deployment/StatiqProcessor.java index 90188e27..642a0dac 100644 --- a/deployment/src/main/java/io/quarkiverse/statiq/deployment/StatiqProcessor.java +++ b/deployment/src/main/java/io/quarkiverse/statiq/deployment/StatiqProcessor.java @@ -2,25 +2,16 @@ import static java.util.function.Predicate.not; -import java.nio.file.Path; import java.util.*; -import jakarta.inject.Singleton; - -import io.quarkiverse.statiq.runtime.FixedStaticPagesProvider; -import io.quarkiverse.statiq.runtime.StatiqGenerator; -import io.quarkiverse.statiq.runtime.StatiqGeneratorConfig; -import io.quarkiverse.statiq.runtime.StatiqRecorder; +import io.quarkiverse.statiq.runtime.*; import io.quarkus.arc.deployment.AdditionalBeanBuildItem; -import io.quarkus.arc.deployment.SyntheticBeanBuildItem; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.ExecutionTime; import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.builditem.FeatureBuildItem; import io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem; -import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem; -import io.quarkus.vertx.http.deployment.RouteBuildItem; import io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem; import io.quarkus.vertx.http.deployment.spi.StaticResourcesBuildItem; @@ -33,18 +24,6 @@ FeatureBuildItem feature() { return new FeatureBuildItem(FEATURE); } - @BuildStep - @Record(ExecutionTime.STATIC_INIT) - SyntheticBeanBuildItem produceGeneratorConfig(StatiqConfig config, OutputTargetBuildItem outputTarget, - StatiqRecorder recorder) { - final Path outputDir = outputTarget.getOutputDirectory().resolve(config.outputDir()); - return SyntheticBeanBuildItem.configure(StatiqGeneratorConfig.class) - .scope(Singleton.class) - .runtimeValue(recorder.createGeneratorConfig(config.fixed().orElse(List.of()), - outputDir.toAbsolutePath().toString())) - .done(); - } - @BuildStep void produceBeans(BuildProducer additionalBeanProducer) { additionalBeanProducer.produce(AdditionalBeanBuildItem.unremovableOf(StatiqGenerator.class)); @@ -55,6 +34,7 @@ void produceBeans(BuildProducer additionalBeanProducer) @Record(ExecutionTime.RUNTIME_INIT) void initHandler(List notFoundPageDisplayableEndpoints, StaticResourcesBuildItem staticResourcesBuildItem, + OutputTargetBuildItem outputTarget, StatiqRecorder recorder) { Set staticPaths = new HashSet<>(); if (staticResourcesBuildItem != null) { @@ -67,23 +47,7 @@ void initHandler(List notFoundPageDisp .toList()); } recorder.setStatiqPages(staticPaths); - } - - @BuildStep - @Record(ExecutionTime.RUNTIME_INIT) - void initHandler(BuildProducer routes, - NonApplicationRootPathBuildItem nonApplicationRootPath, - StatiqRecorder recorder) { - - final RouteBuildItem route = nonApplicationRootPath.routeBuilder() - .management() - .blockingRoute() - .route("statiq/generate") - .handler(recorder.createGenerateHandler()) - .build(); - - routes.produce(route); - + recorder.setOutputTarget(outputTarget.getOutputDirectory().toAbsolutePath().toString()); } } diff --git a/deployment/src/main/resources/dev-ui/qwc-statiq.js b/deployment/src/main/resources/dev-ui/qwc-statiq.js index 96a189b4..61830ef2 100644 --- a/deployment/src/main/resources/dev-ui/qwc-statiq.js +++ b/deployment/src/main/resources/dev-ui/qwc-statiq.js @@ -10,6 +10,7 @@ import '@vaadin/checkbox'; import '@vaadin/grid'; import { columnBodyRenderer } from '@vaadin/grid/lit.js'; import '@vaadin/grid/vaadin-grid-sort-column.js'; +import '@qomponent/qui-alert'; export class QwcStatiq extends LitElement { @@ -66,38 +67,50 @@ export class QwcStatiq extends LitElement { _renderTable() { return html` - - - - - - - - - - - - - + + + + + + + + + + + + + `; } + _generate() { + this.jsonRpc.generate().then(jsonRpcResponse => { + alert("Statiq generation succeeded in directory: " + jsonRpcResponse.result); + }); + } + _fileRenderer(page) { return html`${page.outputPath}`; } diff --git a/docs/modules/ROOT/pages/includes/quarkus-statiq.adoc b/docs/modules/ROOT/pages/includes/quarkus-statiq.adoc index 5c470afc..7229ce20 100644 --- a/docs/modules/ROOT/pages/includes/quarkus-statiq.adoc +++ b/docs/modules/ROOT/pages/includes/quarkus-statiq.adoc @@ -10,7 +10,7 @@ h|[[quarkus-statiq_configuration]]link:#quarkus-statiq_configuration[Configurati h|Type h|Default -a|icon:lock[title=Fixed at build time] [[quarkus-statiq_quarkus-statiq-fixed]]`link:#quarkus-statiq_quarkus-statiq-fixed[quarkus.statiq.fixed]` +a| [[quarkus-statiq_quarkus-statiq-fixed]]`link:#quarkus-statiq_quarkus-statiq-fixed[quarkus.statiq.fixed]` [.description] @@ -27,7 +27,7 @@ endif::add-copy-button-to-env-var[] | -a|icon:lock[title=Fixed at build time] [[quarkus-statiq_quarkus-statiq-output-dir]]`link:#quarkus-statiq_quarkus-statiq-output-dir[quarkus.statiq.output-dir]` +a| [[quarkus-statiq_quarkus-statiq-output-dir]]`link:#quarkus-statiq_quarkus-statiq-output-dir[quarkus.statiq.output-dir]` [.description] @@ -43,4 +43,38 @@ endif::add-copy-button-to-env-var[] --|string |`statiq` + +a| [[quarkus-statiq_quarkus-statiq-batch]]`link:#quarkus-statiq_quarkus-statiq-batch[quarkus.statiq.batch]` + + +[.description] +-- +Build as a CLI to export the static website + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_STATIQ_BATCH+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_STATIQ_BATCH+++` +endif::add-copy-button-to-env-var[] +--|boolean +|`false` + + +a| [[quarkus-statiq_quarkus-statiq-timeout]]`link:#quarkus-statiq_quarkus-statiq-timeout[quarkus.statiq.timeout]` + + +[.description] +-- +Timeout for generation in seconds + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_STATIQ_TIMEOUT+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_STATIQ_TIMEOUT+++` +endif::add-copy-button-to-env-var[] +--|long +|`30` + |=== \ No newline at end of file diff --git a/integration-tests/src/main/java/io/quarkiverse/statiq/it/StatiqResource.java b/integration-tests/src/main/java/io/quarkiverse/statiq/it/StatiqResource.java index 939af33c..92ad5257 100644 --- a/integration-tests/src/main/java/io/quarkiverse/statiq/it/StatiqResource.java +++ b/integration-tests/src/main/java/io/quarkiverse/statiq/it/StatiqResource.java @@ -46,8 +46,9 @@ public String hello(@QueryParam("name") String name) { @Transactional StatiqPages produce() { return new StatiqPages(List.of( - new StatiqPage("/statiq?name=foo"), - new StatiqPage("/statiq?name=bar"))); + StatiqPage.builder().html("/statiq?name=foo-html").build(), + StatiqPage.builder().path("/statiq?name=foo").build(), + StatiqPage.builder().path("/statiq?name=bar").build())); } } diff --git a/integration-tests/src/main/resources/application.properties b/integration-tests/src/main/resources/application.properties index 7cac9e75..08fba159 100644 --- a/integration-tests/src/main/resources/application.properties +++ b/integration-tests/src/main/resources/application.properties @@ -1,4 +1 @@ -quarkus.statiq.fixed=/,/static/**,/assets/**,/some-page -quarkus.management.enabled=true -%dev.quarkus.management.enabled=false -quarkus.management.test-port=9000 \ No newline at end of file +quarkus.statiq.fixed=/,/static/**,/assets/**,/some-page \ No newline at end of file diff --git a/integration-tests/src/test/java/io/quarkiverse/statiq/it/StatiqResourceTest.java b/integration-tests/src/test/java/io/quarkiverse/statiq/it/StatiqResourceTest.java index 1af6cd5f..90a33bcd 100644 --- a/integration-tests/src/test/java/io/quarkiverse/statiq/it/StatiqResourceTest.java +++ b/integration-tests/src/test/java/io/quarkiverse/statiq/it/StatiqResourceTest.java @@ -1,6 +1,5 @@ package io.quarkiverse.statiq.it; -import static io.restassured.RestAssured.given; import static java.nio.file.Files.exists; import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -9,37 +8,21 @@ import org.junit.jupiter.api.Test; -import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.main.Launch; +import io.quarkus.test.junit.main.QuarkusMainTest; -@QuarkusTest +@QuarkusMainTest public class StatiqResourceTest { @Test - public void testHelloEndpoint() { - given() - .when().get("/statiq?name=statiq") - .then() - .statusCode(200) - .body(is("Hello statiq")); - } - - @Test + @Launch(value = {}, exitCode = 0) public void testGenerate() { - given() - .baseUri("http://localhost:9000") - .when().get("/q/statiq/generate") - .then() - .statusCode(200) - .body(startsWith("Generated in:")) - .body(endsWith("/target/statiq")); - assertTrue(exists(Path.of("target/statiq/index.html"))); assertTrue(exists(Path.of("target/statiq/some-page"))); + assertTrue(exists(Path.of("target/statiq/statiq-name-foo-html/index.html"))); assertTrue(exists(Path.of("target/statiq/statiq-name-bar"))); assertTrue(exists(Path.of("target/statiq/statiq-name-foo"))); assertTrue(exists(Path.of("target/statiq/assets/vector.svg"))); - - // FIXME: this will work with next web-bundler release - //assertTrue(exists(Path.of("target/statiq/static/logo.svg"))); + assertTrue(exists(Path.of("target/statiq/static/logo.svg"))); } } diff --git a/integration-tests/src/test/resources/application.properties b/integration-tests/src/test/resources/application.properties new file mode 100644 index 00000000..fbf4a581 --- /dev/null +++ b/integration-tests/src/test/resources/application.properties @@ -0,0 +1,2 @@ +quarkus.statiq.batch=true +quarkus.log.category."io.quarkiverse.statiq".level=DEBUG \ No newline at end of file diff --git a/pom.xml b/pom.xml index 1cc3e915..958ba707 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ 17 UTF-8 UTF-8 - 3.10.1 + 3.11.2 diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/FixedStaticPagesProvider.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/FixedStaticPagesProvider.java index 5871a8e3..f2803030 100644 --- a/runtime/src/main/java/io/quarkiverse/statiq/runtime/FixedStaticPagesProvider.java +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/FixedStaticPagesProvider.java @@ -13,8 +13,9 @@ @Singleton public class FixedStaticPagesProvider { + private static String targetDir; @Inject - StatiqGeneratorConfig config; + StatiqConfig config; private static volatile Set staticPaths; @@ -22,22 +23,30 @@ public static void setStaticPaths(Set staticPaths) { FixedStaticPagesProvider.staticPaths = staticPaths; } + public static void setOutputTarget(String targetDir) { + FixedStaticPagesProvider.targetDir = targetDir; + } + + public static String targetDir() { + return targetDir; + } + @Produces @Singleton StatiqPages produce() { List statiqPages = new ArrayList<>(); - for (String p : config.fixedPaths) { + for (String p : config.fixed().orElse(List.of())) { if (!isGlobPattern(p) && p.startsWith("/")) { // fixed paths are directly added - statiqPages.add(new StatiqPage(p, PageType.FIXED)); + statiqPages.add(StatiqPage.builder().path(p).fixed().build()); continue; } // Try to detect fixed paths from glob pattern for (String staticPath : staticPaths) { PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + p); if (matcher.matches(Path.of(staticPath))) { - statiqPages.add(new StatiqPage(staticPath, PageType.FIXED)); + statiqPages.add(StatiqPage.builder().fixed().path(staticPath).build()); } } } diff --git a/deployment/src/main/java/io/quarkiverse/statiq/deployment/StatiqConfig.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqConfig.java similarity index 68% rename from deployment/src/main/java/io/quarkiverse/statiq/deployment/StatiqConfig.java rename to runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqConfig.java index d61aae06..f04e5870 100644 --- a/deployment/src/main/java/io/quarkiverse/statiq/deployment/StatiqConfig.java +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqConfig.java @@ -1,4 +1,4 @@ -package io.quarkiverse.statiq.deployment; +package io.quarkiverse.statiq.runtime; import java.util.List; import java.util.Optional; @@ -9,7 +9,7 @@ import io.smallrye.config.WithDefault; @ConfigMapping(prefix = "quarkus.statiq") -@ConfigRoot(phase = ConfigPhase.BUILD_TIME) +@ConfigRoot(phase = ConfigPhase.RUN_TIME) public interface StatiqConfig { /** @@ -25,4 +25,15 @@ public interface StatiqConfig { @WithDefault("statiq") String outputDir(); + /** + * Build as a CLI to export the static website + */ + @WithDefault("false") + boolean batch(); + + /** + * Timeout for generation in seconds + */ + @WithDefault("30") + long timeout(); } diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqGenerator.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqGenerator.java index afb6f510..eb705f45 100644 --- a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqGenerator.java +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqGenerator.java @@ -1,41 +1,73 @@ package io.quarkiverse.statiq.runtime; import java.nio.file.Path; +import java.time.Duration; import java.util.*; import java.util.concurrent.CompletionStage; import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; +import org.jboss.logging.Logger; + +import io.quarkiverse.statiq.runtime.util.PathUtils; import io.quarkus.arc.All; +import io.quarkus.logging.Log; +import io.quarkus.runtime.LaunchMode; +import io.quarkus.runtime.Quarkus; +import io.quarkus.runtime.StartupEvent; +import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig; +import io.quarkus.vertx.http.runtime.HttpConfiguration; import io.smallrye.mutiny.Uni; import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.file.FileSystem; -import io.vertx.core.http.HttpServerRequest; import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.client.HttpResponse; import io.vertx.ext.web.client.WebClient; @ApplicationScoped public class StatiqGenerator implements Handler { + + private static final Logger LOGGER = Logger.getLogger(StatiqGenerator.class); private final Instance vertx; - private final StatiqGeneratorConfig config; + private final StatiqConfig config; + + private final HttpConfiguration httpConfiguration; + + private final HttpBuildTimeConfig httpBuildTimeConfig; private WebClient client; private final List statiqPages; @Inject - public StatiqGenerator(final Instance vertx, final StatiqGeneratorConfig config, + public StatiqGenerator(final Instance vertx, final StatiqConfig config, HttpConfiguration httpConfiguration, + HttpBuildTimeConfig httpBuildTimeConfig, @All final List statiqPages) { this.vertx = vertx; this.config = config; + this.httpConfiguration = httpConfiguration; + this.httpBuildTimeConfig = httpBuildTimeConfig; this.statiqPages = statiqPages.stream().map(StatiqPages::pages).flatMap(List::stream) .sorted(Comparator.comparing(StatiqPage::outputPath)).toList(); } + void onStart(@Observes StartupEvent ev) { + if (config.batch()) { + generate().subscribe().with(t -> { + LOGGER.info("Statiq generation succeeded in directory: " + outputDir()); + Quarkus.asyncExit(); + }, Log::error); + } + } + + public String outputDir() { + return PathUtils.join(FixedStaticPagesProvider.targetDir(), config.outputDir()); + } + private WebClient client() { if (client == null) { client = WebClient.create(vertx.get()); @@ -45,22 +77,32 @@ private WebClient client() { @Override public void handle(RoutingContext event) { + generate().subscribe().with(t -> { + event.response().setStatusCode(200); + event.response().end("Generated in: " + outputDir()); + }, event::fail); + } + + public Uni> generate() { final FileSystem fs = vertx.get().fileSystem(); final List> all = new ArrayList<>(); - final Path outputDir = Path.of(config.outputDir).toAbsolutePath(); + final Path outputDir = Path.of(outputDir()).toAbsolutePath(); for (StatiqPage page : this.statiqPages) { - all.add(Uni.createFrom().completionStage(() -> fetchContent(event.request(), page.path())) + all.add(Uni.createFrom().completionStage(() -> fetchContent(page.path())) .chain(r -> { final Path targetPath = outputDir.resolve(page.outputPath()); return Uni.createFrom() .completionStage(() -> fs.mkdirs(targetPath.getParent().toString()).toCompletionStage()) - .chain(() -> Uni.createFrom().completionStage(fs - .writeFile(targetPath.toString(), r.bodyAsBuffer()).toCompletionStage())); + .chain(() -> { + LOGGER.debugf("Statiq is writing %s", targetPath.toString()); + return Uni.createFrom().completionStage(fs + .writeFile(targetPath.toString(), r.bodyAsBuffer()).toCompletionStage()); + }); })); } - Uni.createFrom().completionStage(() -> fs.exists(outputDir.toString()).compose(r -> { + return Uni.createFrom().completionStage(() -> fs.exists(outputDir.toString()).compose(r -> { if (r) { return fs.deleteRecursive(outputDir.toString(), true); } else { @@ -68,15 +110,22 @@ public void handle(RoutingContext event) { } }).toCompletionStage()) .chain(() -> Uni.join().all(all).andFailFast()) - .subscribe().with(t -> { - event.response().setStatusCode(200); - event.response().end("Generated in: " + config.outputDir); - }, event::fail); - + .ifNoItem().after(Duration.ofSeconds(config.timeout())) + .fail(); } - private CompletionStage> fetchContent(HttpServerRequest request, String path) { - return client().get(request.localAddress().port(), "localhost", path) + private CompletionStage> fetchContent(String path) { + LOGGER.debugf("Statiq is fetching %s", path); + final String host; + final int port; + if (LaunchMode.current() == LaunchMode.TEST) { + host = httpConfiguration.testHost.orElse(httpConfiguration.host); + port = httpConfiguration.testPort; + } else { + host = httpConfiguration.host; + port = httpConfiguration.port; + } + return client().get(port, host, PathUtils.join(httpBuildTimeConfig.rootPath, path)) .send().toCompletionStage(); } diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqGeneratorConfig.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqGeneratorConfig.java deleted file mode 100644 index 6d6999b8..00000000 --- a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqGeneratorConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.quarkiverse.statiq.runtime; - -import java.util.List; -import java.util.Objects; - -public class StatiqGeneratorConfig { - - public List fixedPaths; - public String outputDir; - - public StatiqGeneratorConfig(List fixedPaths, String outputDir) { - this.fixedPaths = fixedPaths; - this.outputDir = outputDir; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - StatiqGeneratorConfig that = (StatiqGeneratorConfig) o; - return Objects.equals(fixedPaths, that.fixedPaths) && Objects.equals(outputDir, that.outputDir); - } - - @Override - public int hashCode() { - return Objects.hash(fixedPaths, outputDir); - } -} diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPage.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPage.java index c59d001f..ddc77bde 100644 --- a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPage.java +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPage.java @@ -1,17 +1,19 @@ package io.quarkiverse.statiq.runtime; +import static io.quarkiverse.statiq.runtime.util.PathUtils.addTrailingSlash; + import java.util.regex.Pattern; -public record StatiqPage(String path, PageType type, String outputPath) { +public final record StatiqPage(String path, String outputPath, PageType type) { private static final Pattern NON_FILE_CHARS = Pattern.compile("[^a-zA-Z0-9\\\\/.]"); - public StatiqPage(String path, PageType type) { - this(path, type, defaultOutputPath(path)); + private StatiqPage(StatiqPageBuilder builder) { + this(builder.path, builder.outputPath, builder.type); } - public StatiqPage(String path) { - this(path, PageType.PROVIDED); + public static StatiqPageBuilder builder() { + return new StatiqPageBuilder(); } public static String defaultOutputPath(String path) { @@ -21,9 +23,6 @@ public static String defaultOutputPath(String path) { } else if (NON_FILE_CHARS.matcher(path).find()) { statiqPath = cleanPath(statiqPath); } - if (statiqPath.startsWith("/")) { - statiqPath = statiqPath.substring(1); - } return statiqPath; } @@ -31,4 +30,52 @@ private static String cleanPath(String statiqPath) { return NON_FILE_CHARS.matcher(statiqPath).replaceAll("-"); } + public String path() { + return path; + } + + public PageType type() { + return type; + } + + public String outputPath() { + return outputPath; + } + + public static class StatiqPageBuilder { + String path; + PageType type = PageType.PROVIDED; + String outputPath = null; + + public StatiqPageBuilder path(String path) { + this.path = path; + return this; + } + + StatiqPageBuilder fixed() { + this.type = PageType.FIXED; + return this; + } + + public StatiqPageBuilder html(String path) { + this.path = path; + this.outputPath = defaultOutputPath(addTrailingSlash(path)); + return this; + } + + public StatiqPageBuilder outputPath(String outputPath) { + this.outputPath = outputPath; + return this; + } + + public StatiqPage build() { + if (outputPath == null) { + outputPath = defaultOutputPath(path); + } + if (outputPath.startsWith("/")) { + outputPath = outputPath.substring(1); + } + return new StatiqPage(this); + } + } } diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPages.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPages.java index 6fce1218..91bfa682 100644 --- a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPages.java +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqPages.java @@ -9,4 +9,4 @@ public static List merge(List statiqPages) { return statiqPages.stream().map(StatiqPages::pages).flatMap(List::stream) .sorted(Comparator.comparing(StatiqPage::outputPath)).toList(); } -} \ No newline at end of file +} diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqRecorder.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqRecorder.java index 261f79c9..71385d34 100644 --- a/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqRecorder.java +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/StatiqRecorder.java @@ -1,33 +1,17 @@ package io.quarkiverse.statiq.runtime; -import java.util.List; import java.util.Set; -import io.quarkus.arc.Arc; -import io.quarkus.arc.InstanceHandle; -import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.annotations.Recorder; -import io.vertx.core.Handler; -import io.vertx.ext.web.RoutingContext; @Recorder public class StatiqRecorder { - public RuntimeValue createGeneratorConfig(List fixedPaths, String outputDir) { - return new RuntimeValue<>() { - @Override - public StatiqGeneratorConfig getValue() { - return new StatiqGeneratorConfig(fixedPaths, outputDir); - } - }; - } - public void setStatiqPages(Set staticPaths) { FixedStaticPagesProvider.setStaticPaths(staticPaths); } - public Handler createGenerateHandler() { - final InstanceHandle generatorInstanceHandle = Arc.container().instance(StatiqGenerator.class); - return generatorInstanceHandle.get(); + public void setOutputTarget(String outputDirectory) { + FixedStaticPagesProvider.setOutputTarget(outputDirectory); } } diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/devui/StatiqJsonRPCService.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/devui/StatiqJsonRPCService.java index afcf4de3..2e0f8b76 100644 --- a/runtime/src/main/java/io/quarkiverse/statiq/runtime/devui/StatiqJsonRPCService.java +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/devui/StatiqJsonRPCService.java @@ -1,6 +1,7 @@ package io.quarkiverse.statiq.runtime.devui; import java.util.List; +import java.util.Map; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -10,6 +11,7 @@ import io.quarkiverse.statiq.runtime.StatiqPages; import io.quarkus.arc.All; import io.smallrye.common.annotation.Blocking; +import io.smallrye.mutiny.Uni; @ApplicationScoped public class StatiqJsonRPCService { @@ -31,4 +33,9 @@ public int getStatiqCount() { return getStatiqPages().size(); } + public Uni generate() { + Map config = Map.of("quarkus.http.port", "8081"); + return generator.generate().map(a -> generator.outputDir()); + } + } diff --git a/runtime/src/main/java/io/quarkiverse/statiq/runtime/util/PathUtils.java b/runtime/src/main/java/io/quarkiverse/statiq/runtime/util/PathUtils.java new file mode 100644 index 00000000..605a729c --- /dev/null +++ b/runtime/src/main/java/io/quarkiverse/statiq/runtime/util/PathUtils.java @@ -0,0 +1,32 @@ +package io.quarkiverse.statiq.runtime.util; + +public final class PathUtils { + + public static String toUnixPath(String path) { + return path.replaceAll("\\\\", "/"); + } + + public static String prefixWithSlash(String path) { + return path.startsWith("/") ? path : "/" + path; + } + + public static String surroundWithSlashes(String path) { + return prefixWithSlash(addTrailingSlash(path)); + } + + public static String addTrailingSlash(String path) { + return path.endsWith("/") ? path : path + "/"; + } + + public static String join(String path1, String path2) { + return addTrailingSlash(path1) + removeLeadingSlash(path2); + } + + public static String removeLeadingSlash(String path) { + return path.startsWith("/") ? path.substring(1) : path; + } + + public static String removeTrailingSlash(String path) { + return path.endsWith("/") ? path.substring(0, path.length() - 1) : path; + } +}