Compare commits
No commits in common. "f43e7341bbc7f890b92112e20e7c6da1a2ccded3" and "4e0de9904c9f174cbb938825637cab583bb942e8" have entirely different histories.
f43e7341bb
...
4e0de9904c
@ -8,8 +8,7 @@ updated to the same version in `cli/build.gradle`.
|
|||||||
## Version-bumping
|
## Version-bumping
|
||||||
|
|
||||||
Update the version of the project in `buildSrc/src/main/groovy/ssg-common.gradle`. Then update the references to the
|
Update the version of the project in `buildSrc/src/main/groovy/ssg-common.gradle`. Then update the references to the
|
||||||
`cli` and `api` projects in `ssg-gradle-plugin/src/main/java/com/jessebrault/ssg/gradle/SsgGradlePlugin.java`. Finally,
|
`cli` and `api` projects in `ssg-gradle-plugin/src/main/java/com/jessebrault/ssg/gradle/SsgGradlePlugin.java`.
|
||||||
update the version in the `cli` project for the cli info message.
|
|
||||||
|
|
||||||
## Publishing
|
## Publishing
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import groowt.view.component.web.WebViewComponent;
|
|
||||||
import io.github.classgraph.ScanResult;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public interface ComponentClassScanner {
|
|
||||||
Set<Class<? extends WebViewComponent>> getWebViewComponentClasses(ScanResult scanResult);
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.ssg.page.Page;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public class ConsolePageWriter implements PageWriter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(Page page, File outputDir, String renderedPage) {
|
|
||||||
System.out.println("--- Page " + page.getPath() + " ---");
|
|
||||||
System.out.println(renderedPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import groowt.view.component.web.WebViewComponent;
|
|
||||||
import io.github.classgraph.ClassInfoList;
|
|
||||||
import io.github.classgraph.ScanResult;
|
|
||||||
import jakarta.inject.Inject;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
|
|
||||||
public class DefaultComponentClassScanner implements ComponentClassScanner {
|
|
||||||
|
|
||||||
private final ExecutorService executorService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public DefaultComponentClassScanner(ExecutorService executorService) {
|
|
||||||
this.executorService = executorService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<Class<? extends WebViewComponent>> getWebViewComponentClasses(ScanResult scanResult) {
|
|
||||||
final ClassInfoList classInfoList = scanResult.getClassesImplementing(WebViewComponent.class);
|
|
||||||
final Set<Class<? extends WebViewComponent>> results = ConcurrentHashMap.newKeySet();
|
|
||||||
|
|
||||||
// fork
|
|
||||||
final List<CompletableFuture<Void>> futures = classInfoList.stream().map(classInfo ->
|
|
||||||
CompletableFuture.runAsync(() ->
|
|
||||||
results.add(classInfo.loadClass(WebViewComponent.class)),
|
|
||||||
executorService
|
|
||||||
)).toList();
|
|
||||||
|
|
||||||
// join
|
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.di.ObjectFactory;
|
|
||||||
import com.jessebrault.di.RegistryObjectFactory;
|
|
||||||
import com.jessebrault.ssg.buildscript.BuildSpec;
|
|
||||||
import com.jessebrault.ssg.di.GlobalsExtension;
|
|
||||||
import com.jessebrault.ssg.di.ModelsExtension;
|
|
||||||
import com.jessebrault.ssg.di.TextsExtension;
|
|
||||||
import jakarta.inject.Inject;
|
|
||||||
|
|
||||||
import static com.jessebrault.di.BindingUtil.named;
|
|
||||||
import static com.jessebrault.di.BindingUtil.toSingleton;
|
|
||||||
|
|
||||||
public class DefaultObjectFactoryConfigurator implements ObjectFactoryConfigurator {
|
|
||||||
|
|
||||||
private final TextsGetter textsGetter;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public DefaultObjectFactoryConfigurator(TextsGetter textsGetter) {
|
|
||||||
this.textsGetter = textsGetter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configure(RegistryObjectFactory registryObjectFactory, BuildSpec buildSpec) {
|
|
||||||
registryObjectFactory.configureRegistry(registry -> {
|
|
||||||
// texts
|
|
||||||
final var textsExtension = new TextsExtension();
|
|
||||||
textsExtension.getAllTexts().addAll(this.textsGetter.getTexts(buildSpec));
|
|
||||||
registry.addExtension(textsExtension);
|
|
||||||
|
|
||||||
// models
|
|
||||||
final var modelsExtension = new ModelsExtension();
|
|
||||||
modelsExtension.getAllModels().addAll(buildSpec.getModels().get(() ->
|
|
||||||
new SsgException("the models Property in " + buildSpec.getName()
|
|
||||||
+ " must contain at least an empty set.")
|
|
||||||
));
|
|
||||||
registry.addExtension(modelsExtension);
|
|
||||||
|
|
||||||
// globals
|
|
||||||
final var globalsExtension = new GlobalsExtension();
|
|
||||||
globalsExtension.getGlobals().putAll(buildSpec.getGlobals().get(() ->
|
|
||||||
new SsgException("the globals Property in " + buildSpec.getName()
|
|
||||||
+ " must contain at least an empty set.")
|
|
||||||
));
|
|
||||||
registry.addExtension(globalsExtension);
|
|
||||||
|
|
||||||
// various others
|
|
||||||
registry.bind(named("buildName", String.class), toSingleton(buildSpec.getName()));
|
|
||||||
registry.bind(named("siteName", String.class), toSingleton(buildSpec.getSiteName().get(() ->
|
|
||||||
new SsgException("the siteName Property in " + buildSpec.getName() + " must be set.")
|
|
||||||
)));
|
|
||||||
registry.bind(named("baseUrl", String.class), toSingleton(buildSpec.getBaseUrl().get(() ->
|
|
||||||
new SsgException("the baseUrl Property in " + buildSpec.getName() + " must be set.")
|
|
||||||
)));
|
|
||||||
|
|
||||||
registry.bind(WvcCompilerFactory.class, toSingleton(buildSpec.getWvcCompilerFactory().get(() ->
|
|
||||||
new SsgException("the wvcCompilerFactory Property in " + buildSpec.getName() + " must be set.")
|
|
||||||
)));
|
|
||||||
|
|
||||||
// self binding
|
|
||||||
registry.bind(ObjectFactory.class, toSingleton(registryObjectFactory));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
package com.jessebrault.ssg
|
|
||||||
|
|
||||||
import com.jessebrault.di.RegistryObjectFactory
|
|
||||||
import com.jessebrault.ssg.view.SkipTemplate
|
|
||||||
import com.jessebrault.ssg.view.WvcPageView
|
|
||||||
import groowt.view.component.factory.ComponentFactories
|
|
||||||
import groowt.view.component.web.DefaultWebViewComponentContext
|
|
||||||
import groowt.view.component.web.WebViewComponent
|
|
||||||
import groowt.view.component.web.WebViewComponentContext
|
|
||||||
import groowt.view.component.web.WebViewComponentScope
|
|
||||||
|
|
||||||
class DefaultPageContextFactory implements PageContextFactory {
|
|
||||||
|
|
||||||
protected WebViewComponent makeComponent(
|
|
||||||
RegistryObjectFactory objectFactory,
|
|
||||||
Class<? extends WebViewComponent> wvcClass,
|
|
||||||
Map attr,
|
|
||||||
Object[] args
|
|
||||||
) {
|
|
||||||
if (!attr.isEmpty() && args.length > 0) {
|
|
||||||
return objectFactory.createInstance(wvcClass, attr, *args)
|
|
||||||
} else if (!attr.isEmpty()) {
|
|
||||||
return objectFactory.createInstance(wvcClass, attr)
|
|
||||||
} else if (args.length > 0) {
|
|
||||||
return objectFactory.createInstance(wvcClass, *args)
|
|
||||||
} else {
|
|
||||||
return objectFactory.createInstance(wvcClass)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
WebViewComponentContext makeContext(
|
|
||||||
WvcPageView wvcPageView,
|
|
||||||
RegistryObjectFactory buildObjectFactory,
|
|
||||||
Set<Class<? extends WebViewComponent>> allWvcClasses
|
|
||||||
) {
|
|
||||||
new DefaultWebViewComponentContext().tap {
|
|
||||||
configureRootScope(WebViewComponentScope) {
|
|
||||||
// custom components
|
|
||||||
allWvcClasses.each { wvcClass ->
|
|
||||||
//noinspection GroovyAssignabilityCheck
|
|
||||||
add(wvcClass, ComponentFactories.ofClosureClassType(wvcClass) { Map attr, Object[] args ->
|
|
||||||
// instantiate component and set context
|
|
||||||
WebViewComponent component = makeComponent(buildObjectFactory, wvcClass, attr, args)
|
|
||||||
component.context = wvcPageView.context
|
|
||||||
|
|
||||||
// set the template
|
|
||||||
if (component.componentTemplate == null && !wvcClass.isAnnotationPresent(SkipTemplate)) {
|
|
||||||
def wvcCompilerFactory = buildObjectFactory.get(WvcCompilerFactory)
|
|
||||||
def wvcCompiler = wvcCompilerFactory.getWvcCompiler()
|
|
||||||
def compileResult = wvcCompiler.compileTemplate(
|
|
||||||
wvcClass,
|
|
||||||
wvcClass.simpleName + 'Template.wvc'
|
|
||||||
)
|
|
||||||
if (compileResult.isRight()) {
|
|
||||||
component.componentTemplate = compileResult.getRight()
|
|
||||||
} else {
|
|
||||||
def left = compileResult.getLeft()
|
|
||||||
throw new RuntimeException(left.message, left.exception)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return component
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.di.ObjectFactory;
|
|
||||||
import com.jessebrault.di.RegistryObjectFactory;
|
|
||||||
import com.jessebrault.fp.either.Either;
|
|
||||||
import com.jessebrault.ssg.page.Page;
|
|
||||||
import com.jessebrault.ssg.util.Diagnostic;
|
|
||||||
import com.jessebrault.ssg.view.PageView;
|
|
||||||
import com.jessebrault.ssg.view.WvcPageView;
|
|
||||||
import groowt.view.component.web.WebViewComponent;
|
|
||||||
import jakarta.inject.Inject;
|
|
||||||
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class DefaultPageRenderer implements PageRenderer {
|
|
||||||
|
|
||||||
private final PageContextFactory pageContextFactory;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public DefaultPageRenderer(PageContextFactory pageContextFactory) {
|
|
||||||
this.pageContextFactory = pageContextFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Either<Diagnostic, String> renderPage(
|
|
||||||
Page page,
|
|
||||||
String baseUrl,
|
|
||||||
RegistryObjectFactory buildObjectFactory,
|
|
||||||
Set<Class<? extends WebViewComponent>> allWvcClasses
|
|
||||||
) {
|
|
||||||
// create the view
|
|
||||||
final Either<Diagnostic, PageView> viewResult = page.createView();
|
|
||||||
if (viewResult.isLeft()) {
|
|
||||||
return Either.left(viewResult.getLeft());
|
|
||||||
}
|
|
||||||
final PageView pageView = viewResult.getRight();
|
|
||||||
|
|
||||||
// prepare for rendering
|
|
||||||
// set props
|
|
||||||
pageView.setPageTitle(page.getName());
|
|
||||||
pageView.setUrl(baseUrl + page.getPath());
|
|
||||||
|
|
||||||
// set context if WvcPageView
|
|
||||||
if (pageView instanceof WvcPageView wvcPageView) {
|
|
||||||
wvcPageView.setContext(this.pageContextFactory.makeContext(wvcPageView, buildObjectFactory, allWvcClasses));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render page
|
|
||||||
final var sw = new StringWriter();
|
|
||||||
try {
|
|
||||||
pageView.renderTo(sw);
|
|
||||||
} catch (Exception exception) {
|
|
||||||
return Either.left(new Diagnostic(
|
|
||||||
"There was an exception while rendering " + page.getName() + " as " + pageView.getClass().getName(),
|
|
||||||
exception
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Either.right(sw.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.di.ObjectFactory;
|
|
||||||
import com.jessebrault.ssg.page.DefaultWvcPage;
|
|
||||||
import com.jessebrault.ssg.page.Page;
|
|
||||||
import com.jessebrault.ssg.page.PageFactory;
|
|
||||||
import com.jessebrault.ssg.page.PageSpec;
|
|
||||||
import com.jessebrault.ssg.view.PageView;
|
|
||||||
import io.github.classgraph.AnnotationInfo;
|
|
||||||
import io.github.classgraph.ClassInfoList;
|
|
||||||
import io.github.classgraph.ScanResult;
|
|
||||||
import jakarta.inject.Inject;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
|
|
||||||
public class DefaultPageScanner implements PageScanner {
|
|
||||||
|
|
||||||
private final ExecutorService executorService;
|
|
||||||
private final WvcCompilerFactory wvcCompilerFactory;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public DefaultPageScanner(ExecutorService executorService, WvcCompilerFactory wvcCompilerFactory) {
|
|
||||||
this.executorService = executorService;
|
|
||||||
this.wvcCompilerFactory = wvcCompilerFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<Page> getAllPages(ScanResult scanResult, ObjectFactory buildObjectFactory) {
|
|
||||||
final Set<Page> results = ConcurrentHashMap.newKeySet();
|
|
||||||
|
|
||||||
// Start fetching single pages
|
|
||||||
final ClassInfoList pageViewInfoList = scanResult.getClassesImplementing(PageView.class);
|
|
||||||
final List<CompletableFuture<Void>> pageViewFutures = pageViewInfoList.stream()
|
|
||||||
.map(classInfo -> {
|
|
||||||
return CompletableFuture.runAsync(() -> {
|
|
||||||
final AnnotationInfo annotationInfo = classInfo.getAnnotationInfo(PageSpec.class);
|
|
||||||
if (annotationInfo != null) {
|
|
||||||
final PageSpec pageSpec = (PageSpec) annotationInfo.loadClassAndInstantiate();
|
|
||||||
results.add(new DefaultWvcPage(Map.of(
|
|
||||||
"name", pageSpec.name(),
|
|
||||||
"path", pageSpec.path(),
|
|
||||||
"fileExtension", pageSpec.fileExtension(),
|
|
||||||
"viewType", classInfo.loadClass(),
|
|
||||||
"templateResource", pageSpec.templateResource().isEmpty()
|
|
||||||
? classInfo.getSimpleName() + "Template.wvc"
|
|
||||||
: pageSpec.templateResource(),
|
|
||||||
"objectFactory", buildObjectFactory,
|
|
||||||
"wvcCompiler", this.wvcCompilerFactory.getWvcCompiler()
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}, this.executorService);
|
|
||||||
})
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
// Start fetching page factories
|
|
||||||
final ClassInfoList pageFactoryInfoList = scanResult.getClassesImplementing(PageFactory.class);
|
|
||||||
final List<CompletableFuture<Void>> pageFactoryFutures = pageFactoryInfoList.stream()
|
|
||||||
.map(classInfo -> {
|
|
||||||
return CompletableFuture.runAsync(() -> {
|
|
||||||
final Class<? extends PageFactory> pageFactoryClass = classInfo.loadClass(PageFactory.class);
|
|
||||||
final PageFactory pageFactory = buildObjectFactory.createInstance(pageFactoryClass);
|
|
||||||
final Collection<Page> pages = pageFactory.create();
|
|
||||||
results.addAll(pages);
|
|
||||||
}, this.executorService);
|
|
||||||
})
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
// join
|
|
||||||
final List<CompletableFuture<Void>> allFutures = new ArrayList<>();
|
|
||||||
allFutures.addAll(pageViewFutures);
|
|
||||||
allFutures.addAll(pageFactoryFutures);
|
|
||||||
|
|
||||||
CompletableFuture.allOf(allFutures.toArray(new CompletableFuture[0])).join();
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -183,6 +183,8 @@ class DefaultStaticSiteGenerator implements StaticSiteGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
Collection<Diagnostic> doBuild(
|
Collection<Diagnostic> doBuild(
|
||||||
|
File projectDir,
|
||||||
|
String buildName,
|
||||||
String buildScriptFqn,
|
String buildScriptFqn,
|
||||||
Map<String, String> buildScriptCliArgs
|
Map<String, String> buildScriptCliArgs
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -1,25 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.ssg.buildscript.BuildSpec;
|
|
||||||
import com.jessebrault.ssg.text.Text;
|
|
||||||
import com.jessebrault.ssg.text.TextSupplier;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class DefaultTextsGetter implements TextsGetter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<Text> getTexts(BuildSpec buildSpec) {
|
|
||||||
final Set<TextSupplier> textSuppliers = buildSpec.getTextSuppliers().get(() ->
|
|
||||||
new SsgException("The textSuppliers Property in " + buildSpec.getName()
|
|
||||||
+ " must contain at least an empty Set.")
|
|
||||||
);
|
|
||||||
final Set<Text> texts = new HashSet<>();
|
|
||||||
for (final var textSupplier : textSuppliers) {
|
|
||||||
texts.addAll(textSupplier.get());
|
|
||||||
}
|
|
||||||
return texts;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.ssg.view.WvcCompiler;
|
|
||||||
import groovy.lang.GroovyClassLoader;
|
|
||||||
import groowt.view.component.compiler.SimpleComponentTemplateClassFactory;
|
|
||||||
import jakarta.inject.Inject;
|
|
||||||
|
|
||||||
public class DefaultWvcCompilerFactory implements WvcCompilerFactory {
|
|
||||||
|
|
||||||
private final GroovyClassLoader groovyClassLoader;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public DefaultWvcCompilerFactory(GroovyClassLoader groovyClassLoader) {
|
|
||||||
this.groovyClassLoader = groovyClassLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WvcCompiler getWvcCompiler() {
|
|
||||||
return new WvcCompiler(this.groovyClassLoader, new SimpleComponentTemplateClassFactory(this.groovyClassLoader));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.ssg.page.Page;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class FilePageWriter implements PageWriter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(Page page, File outputDir, String renderedPage) {
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
outputDir.mkdirs();
|
|
||||||
|
|
||||||
// calculate target path
|
|
||||||
final List<String> pathParts = new ArrayList<>(Arrays.asList(page.getPath().split("/"))); // because Arrays.asList returns immutable
|
|
||||||
if (page.getPath().endsWith("/")) {
|
|
||||||
pathParts.add("index");
|
|
||||||
}
|
|
||||||
|
|
||||||
final String head = pathParts.getFirst();
|
|
||||||
final List<String> tail = pathParts.size() > 1 ? pathParts.subList(1, pathParts.size()) : List.of();
|
|
||||||
|
|
||||||
final Path path = Path.of(head, tail.toArray(String[]::new));
|
|
||||||
final File outputFile = new File(outputDir, path + page.getFileExtension());
|
|
||||||
|
|
||||||
// make dirs and write
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
outputFile.getParentFile().mkdirs();
|
|
||||||
|
|
||||||
try (final FileWriter writer = new FileWriter(outputFile)) {
|
|
||||||
writer.write(renderedPage);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,140 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.di.BindingUtil;
|
|
||||||
import com.jessebrault.di.RegistryObjectFactory;
|
|
||||||
import com.jessebrault.fp.either.Either;
|
|
||||||
import com.jessebrault.ssg.buildscript.BuildSpec;
|
|
||||||
import com.jessebrault.ssg.buildscript.BuildSpecFactory;
|
|
||||||
import com.jessebrault.ssg.di.PagesExtension;
|
|
||||||
import com.jessebrault.ssg.di.SelfPageExtension;
|
|
||||||
import com.jessebrault.ssg.page.Page;
|
|
||||||
import com.jessebrault.ssg.util.Diagnostic;
|
|
||||||
import groovy.lang.GroovyClassLoader;
|
|
||||||
import groowt.view.component.web.WebViewComponent;
|
|
||||||
import io.github.classgraph.ClassGraph;
|
|
||||||
import io.github.classgraph.ScanResult;
|
|
||||||
import jakarta.inject.Inject;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
|
|
||||||
public class JDefaultStaticSiteGenerator implements StaticSiteGenerator {
|
|
||||||
|
|
||||||
private final BuildSpecFactory buildSpecFactory;
|
|
||||||
private final ObjectFactoryConfigurator objectFactoryConfigurator;
|
|
||||||
private final GroovyClassLoader groovyClassLoader;
|
|
||||||
private final ExecutorService executorService;
|
|
||||||
private final PageScanner pageScanner;
|
|
||||||
private final ComponentClassScanner componentClassScanner;
|
|
||||||
private final PageRenderer pageRenderer;
|
|
||||||
private final PageWriter pageWriter;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public JDefaultStaticSiteGenerator(
|
|
||||||
BuildSpecFactory buildSpecFactory,
|
|
||||||
ObjectFactoryConfigurator objectFactoryConfigurator,
|
|
||||||
GroovyClassLoader groovyClassLoader,
|
|
||||||
ExecutorService executorService,
|
|
||||||
PageScanner pageScanner,
|
|
||||||
ComponentClassScanner componentClassScanner,
|
|
||||||
PageRenderer pageRenderer,
|
|
||||||
PageWriter pageWriter
|
|
||||||
) {
|
|
||||||
this.buildSpecFactory = buildSpecFactory;
|
|
||||||
this.objectFactoryConfigurator = objectFactoryConfigurator;
|
|
||||||
this.groovyClassLoader = groovyClassLoader;
|
|
||||||
this.executorService = executorService;
|
|
||||||
this.pageScanner = pageScanner;
|
|
||||||
this.componentClassScanner = componentClassScanner;
|
|
||||||
this.pageRenderer = pageRenderer;
|
|
||||||
this.pageWriter = pageWriter;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<Diagnostic> doBuild(String buildScriptFqn, Map<String, String> buildScriptCliArgs) {
|
|
||||||
// Get build spec
|
|
||||||
final BuildSpec buildSpec = this.buildSpecFactory.getBuildSpec(buildScriptFqn, buildScriptCliArgs);
|
|
||||||
|
|
||||||
// Prepare object factory for rendering pages and components
|
|
||||||
final RegistryObjectFactory buildObjectFactory = buildSpec.getObjectFactory().get(() ->
|
|
||||||
new SsgException("objectFactory Provider in " + buildSpec.getName() + " must be set.")
|
|
||||||
);
|
|
||||||
this.objectFactoryConfigurator.configure(buildObjectFactory, buildSpec);
|
|
||||||
|
|
||||||
// ClassGraph scan of base packages
|
|
||||||
final Set<String> basePackages = buildSpec.getBasePackages().get(() ->
|
|
||||||
new SsgException("basePackages Provider in " + buildSpec.getName() + " must be at least an empty Set.")
|
|
||||||
);
|
|
||||||
final ClassGraph classGraph = new ClassGraph()
|
|
||||||
.enableAnnotationInfo()
|
|
||||||
.addClassLoader(this.groovyClassLoader);
|
|
||||||
for (final String basePackage : basePackages) {
|
|
||||||
classGraph.acceptPackages(basePackage);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get all pages and components from scan
|
|
||||||
final Set<Page> pages = ConcurrentHashMap.newKeySet();
|
|
||||||
final Set<Class<? extends WebViewComponent>> componentClasses = ConcurrentHashMap.newKeySet();
|
|
||||||
|
|
||||||
try (final ScanResult scanResult = classGraph.scan()) {
|
|
||||||
// fork
|
|
||||||
final CompletableFuture<Void> pagesFuture = CompletableFuture.runAsync(
|
|
||||||
() -> pages.addAll(this.pageScanner.getAllPages(scanResult, buildObjectFactory)),
|
|
||||||
this.executorService
|
|
||||||
);
|
|
||||||
final CompletableFuture<Void> componentsFuture = CompletableFuture.runAsync(
|
|
||||||
() -> componentClasses.addAll(this.componentClassScanner.getWebViewComponentClasses(scanResult)),
|
|
||||||
this.executorService
|
|
||||||
);
|
|
||||||
|
|
||||||
// join
|
|
||||||
CompletableFuture.allOf(pagesFuture, componentsFuture).join();
|
|
||||||
}
|
|
||||||
|
|
||||||
// final ObjectFactory configuration to add all pages/components found AND self page extension
|
|
||||||
buildObjectFactory.configureRegistry(registry -> {
|
|
||||||
final var pagesExtension = new PagesExtension();
|
|
||||||
pagesExtension.getAllPages().addAll(pages);
|
|
||||||
registry.addExtension(pagesExtension);
|
|
||||||
|
|
||||||
registry.bind(BindingUtil.named("allWvc", Set.class), BindingUtil.toSingleton(componentClasses));
|
|
||||||
|
|
||||||
registry.addExtension(new SelfPageExtension());
|
|
||||||
});
|
|
||||||
|
|
||||||
// render each page
|
|
||||||
final Set<Diagnostic> diagnostics = ConcurrentHashMap.newKeySet();
|
|
||||||
|
|
||||||
final List<CompletableFuture<Void>> renderAndWriteFutures = pages.stream()
|
|
||||||
.map(page -> CompletableFuture.runAsync(() -> {
|
|
||||||
final Either<Diagnostic, String> renderResult = this.pageRenderer.renderPage(
|
|
||||||
page,
|
|
||||||
buildSpec.getBaseUrl().get(() ->
|
|
||||||
new SsgException("baseUrl Provider in " + buildSpec.getName() + " must be set.")
|
|
||||||
),
|
|
||||||
buildObjectFactory,
|
|
||||||
componentClasses
|
|
||||||
);
|
|
||||||
if (renderResult.isLeft()) {
|
|
||||||
diagnostics.add(renderResult.getLeft());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.pageWriter.write(
|
|
||||||
page,
|
|
||||||
buildSpec.getOutputDir().get(() ->
|
|
||||||
new SsgException("outputDir Provider in " + buildSpec.getName() + " must be set.")
|
|
||||||
),
|
|
||||||
renderResult.getRight()
|
|
||||||
);
|
|
||||||
}, this.executorService))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
CompletableFuture.allOf(renderAndWriteFutures.toArray(new CompletableFuture[0])).join();
|
|
||||||
|
|
||||||
return diagnostics;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.di.RegistryObjectFactory;
|
|
||||||
import com.jessebrault.ssg.buildscript.BuildSpec;
|
|
||||||
|
|
||||||
public interface ObjectFactoryConfigurator {
|
|
||||||
void configure(RegistryObjectFactory registryObjectFactory, BuildSpec buildSpec);
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.di.ObjectFactory;
|
|
||||||
import com.jessebrault.di.RegistryObjectFactory;
|
|
||||||
import com.jessebrault.ssg.view.WvcPageView;
|
|
||||||
import groowt.view.component.web.WebViewComponent;
|
|
||||||
import groowt.view.component.web.WebViewComponentContext;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public interface PageContextFactory {
|
|
||||||
WebViewComponentContext makeContext(
|
|
||||||
WvcPageView wvcPageView,
|
|
||||||
RegistryObjectFactory buildObjectFactory,
|
|
||||||
Set<Class<? extends WebViewComponent>> allWvcClasses
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.di.RegistryObjectFactory;
|
|
||||||
import com.jessebrault.fp.either.Either;
|
|
||||||
import com.jessebrault.ssg.page.Page;
|
|
||||||
import com.jessebrault.ssg.util.Diagnostic;
|
|
||||||
import groowt.view.component.web.WebViewComponent;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public interface PageRenderer {
|
|
||||||
Either<Diagnostic, String> renderPage(
|
|
||||||
Page page,
|
|
||||||
String baseUrl,
|
|
||||||
RegistryObjectFactory buildObjectFactory,
|
|
||||||
Set<Class<? extends WebViewComponent>> allWvcClasses
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.di.ObjectFactory;
|
|
||||||
import com.jessebrault.ssg.page.Page;
|
|
||||||
import io.github.classgraph.ScanResult;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public interface PageScanner {
|
|
||||||
Set<Page> getAllPages(ScanResult scanResult, ObjectFactory buildObjectFactory);
|
|
||||||
}
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.ssg.page.Page;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public interface PageWriter {
|
|
||||||
void write(Page page, File outputDir, String renderedPage);
|
|
||||||
}
|
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package com.jessebrault.ssg
|
||||||
|
|
||||||
|
import com.jessebrault.ssg.util.Diagnostic
|
||||||
|
|
||||||
|
interface StaticSiteGenerator {
|
||||||
|
Collection<Diagnostic> doBuild(
|
||||||
|
File projectDir,
|
||||||
|
String buildName,
|
||||||
|
String buildScriptFqn,
|
||||||
|
Map<String, String> buildScriptCliArgs
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -1,13 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.ssg.util.Diagnostic;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public interface StaticSiteGenerator {
|
|
||||||
Collection<Diagnostic> doBuild(
|
|
||||||
String buildScriptFqn,
|
|
||||||
Map<String, String> buildScriptCliArgs
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.ssg.buildscript.BuildSpec;
|
|
||||||
import com.jessebrault.ssg.text.Text;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public interface TextsGetter {
|
|
||||||
Set<Text> getTexts(BuildSpec buildSpec);
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.ssg.view.WvcCompiler;
|
|
||||||
|
|
||||||
public interface WvcCompilerFactory {
|
|
||||||
WvcCompiler getWvcCompiler();
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
package com.jessebrault.ssg;
|
|
||||||
|
|
||||||
import com.jessebrault.ssg.view.WvcPageView;
|
|
||||||
import groowt.view.component.web.WebViewComponentContext;
|
|
||||||
|
|
||||||
public interface WvcContextFactory {
|
|
||||||
WebViewComponentContext getContext(WvcPageView currentPage);
|
|
||||||
}
|
|
||||||
@ -25,7 +25,6 @@ abstract class BuildScriptBase extends Script {
|
|||||||
private Closure buildClosure = { }
|
private Closure buildClosure = { }
|
||||||
private File projectRoot
|
private File projectRoot
|
||||||
private String buildName
|
private String buildName
|
||||||
private Map<String, String> cliArgs
|
|
||||||
|
|
||||||
/* --- Instance DSL helpers --- */
|
/* --- Instance DSL helpers --- */
|
||||||
|
|
||||||
@ -74,12 +73,4 @@ abstract class BuildScriptBase extends Script {
|
|||||||
this.buildClosure
|
this.buildClosure
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> getCliArgs() {
|
|
||||||
return cliArgs
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCliArgs(Map<String, String> cliArgs) {
|
|
||||||
this.cliArgs = cliArgs
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
package com.jessebrault.ssg.buildscript;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public interface BuildScriptFactory {
|
|
||||||
BuildScriptBase getAndRunBuildScript(String scriptFqn, Map<String, String> scriptCliArgs);
|
|
||||||
}
|
|
||||||
@ -5,12 +5,13 @@ import groovy.transform.NullCheck
|
|||||||
import groovy.transform.TupleConstructor
|
import groovy.transform.TupleConstructor
|
||||||
|
|
||||||
import java.util.function.Function
|
import java.util.function.Function
|
||||||
|
import java.util.function.Supplier
|
||||||
|
|
||||||
@NullCheck
|
@NullCheck
|
||||||
@TupleConstructor(includeFields = true)
|
@TupleConstructor(includeFields = true)
|
||||||
class BuildScriptToBuildSpecConverter {
|
class BuildScriptToBuildSpecConverter {
|
||||||
|
|
||||||
private final BuildScriptFactory buildScriptFactory
|
private final BuildScriptGetter buildScriptGetter
|
||||||
private final Function<String, BuildDelegate> buildDelegateFactory
|
private final Function<String, BuildDelegate> buildDelegateFactory
|
||||||
|
|
||||||
protected BuildSpec getFromDelegate(String name, BuildDelegate delegate) {
|
protected BuildSpec getFromDelegate(String name, BuildDelegate delegate) {
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
package com.jessebrault.ssg.buildscript
|
package com.jessebrault.ssg.buildscript
|
||||||
|
|
||||||
import com.jessebrault.di.RegistryObjectFactory
|
|
||||||
import com.jessebrault.fp.provider.Provider
|
|
||||||
import com.jessebrault.ssg.WvcCompilerFactory
|
|
||||||
import com.jessebrault.ssg.model.Model
|
import com.jessebrault.ssg.model.Model
|
||||||
import com.jessebrault.ssg.text.TextSupplier
|
import com.jessebrault.ssg.text.TextConverter
|
||||||
import groovy.transform.EqualsAndHashCode
|
import groovy.transform.EqualsAndHashCode
|
||||||
import groovy.transform.NullCheck
|
import groovy.transform.NullCheck
|
||||||
|
import com.jessebrault.di.RegistryObjectFactory
|
||||||
|
import com.jessebrault.fp.provider.Provider
|
||||||
|
|
||||||
import static com.jessebrault.ssg.util.ObjectUtil.requireProvider
|
import static com.jessebrault.ssg.util.ObjectUtil.requireProvider
|
||||||
import static com.jessebrault.ssg.util.ObjectUtil.requireString
|
import static com.jessebrault.ssg.util.ObjectUtil.requireString
|
||||||
@ -22,9 +21,9 @@ final class BuildSpec {
|
|||||||
final Provider<File> outputDir
|
final Provider<File> outputDir
|
||||||
final Provider<Map<String, Object>> globals
|
final Provider<Map<String, Object>> globals
|
||||||
final Provider<Set<Model>> models
|
final Provider<Set<Model>> models
|
||||||
final Provider<Set<TextSupplier>> textSuppliers
|
final Provider<Set<File>> textsDirs
|
||||||
final Provider<RegistryObjectFactory> objectFactory
|
final Provider<Set<TextConverter>> textConverters
|
||||||
final Provider<WvcCompilerFactory> wvcCompilerFactory
|
final Provider<RegistryObjectFactory.Builder> objectFactoryBuilder
|
||||||
|
|
||||||
@SuppressWarnings('GroovyAssignabilityCheck')
|
@SuppressWarnings('GroovyAssignabilityCheck')
|
||||||
BuildSpec(Map args) {
|
BuildSpec(Map args) {
|
||||||
@ -35,15 +34,15 @@ final class BuildSpec {
|
|||||||
this.outputDir = requireProvider(args.outputDir)
|
this.outputDir = requireProvider(args.outputDir)
|
||||||
this.globals = requireProvider(args.globals)
|
this.globals = requireProvider(args.globals)
|
||||||
this.models = requireProvider(args.models)
|
this.models = requireProvider(args.models)
|
||||||
this.textSuppliers = requireProvider(args.textSuppliers)
|
this.textsDirs = requireProvider(args.textsDirs)
|
||||||
this.objectFactory = requireProvider(args.objectFactory)
|
this.textConverters = requireProvider(args.textConverters)
|
||||||
this.wvcCompilerFactory = requireProvider(args.wvcCompilerFactory)
|
this.objectFactoryBuilder = requireProvider(args.objectFactoryBuilder)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String toString() {
|
String toString() {
|
||||||
"Build(name: ${this.name}, basePackages: $basePackages, siteName: $siteName, " +
|
"Build(name: ${this.name}, basePackages: $basePackages, siteName: $siteName, " +
|
||||||
"baseUrl: $baseUrl, outputDir: $outputDir, textSuppliers: $textSuppliers)"
|
"baseUrl: $baseUrl, outputDir: $outputDir, textsDirs: $textsDirs)"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
package com.jessebrault.ssg.buildscript;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public interface BuildSpecFactory {
|
|
||||||
BuildSpec getBuildSpec(String scriptFqn, Map<String, String> scriptCliArgs);
|
|
||||||
}
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
package com.jessebrault.ssg.buildscript;
|
|
||||||
|
|
||||||
import groovy.lang.GroovyClassLoader;
|
|
||||||
import jakarta.inject.Inject;
|
|
||||||
import jakarta.inject.Named;
|
|
||||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class DefaultBuildScriptFactory implements BuildScriptFactory {
|
|
||||||
|
|
||||||
private final GroovyClassLoader groovyClassLoader;
|
|
||||||
private final List<URL> scriptBaseUrls;
|
|
||||||
private final File projectDir;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public DefaultBuildScriptFactory(
|
|
||||||
GroovyClassLoader groovyClassLoader,
|
|
||||||
@Named("scriptBaseUrls") List<URL> scriptBaseUrls,
|
|
||||||
@Named("projectDir") File projectDir
|
|
||||||
) {
|
|
||||||
this.groovyClassLoader = groovyClassLoader;
|
|
||||||
this.scriptBaseUrls = scriptBaseUrls;
|
|
||||||
this.projectDir = projectDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected GroovyClassLoader getScriptClassLoader() {
|
|
||||||
// set up gcl with our base script class
|
|
||||||
final var compilerConfiguration = new CompilerConfiguration();
|
|
||||||
compilerConfiguration.setScriptBaseClass(BuildScriptBase.class.getName());
|
|
||||||
final var scriptGroovyClassLoader = new GroovyClassLoader(
|
|
||||||
this.groovyClassLoader,
|
|
||||||
compilerConfiguration
|
|
||||||
);
|
|
||||||
|
|
||||||
// add urls where to find scripts
|
|
||||||
for (final var url : this.scriptBaseUrls) {
|
|
||||||
scriptGroovyClassLoader.addURL(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
return scriptGroovyClassLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BuildScriptBase getAndRunBuildScript(String scriptFqn, Map<String, String> scriptCliArgs) {
|
|
||||||
try (final GroovyClassLoader scriptClassLoader = this.getScriptClassLoader()) {
|
|
||||||
// Get script instance
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
final Class<? extends BuildScriptBase> scriptClass = (Class<? extends BuildScriptBase>)
|
|
||||||
scriptClassLoader.loadClass(scriptFqn, true, true);
|
|
||||||
final BuildScriptBase script = scriptClass.getConstructor().newInstance();
|
|
||||||
|
|
||||||
// configure props
|
|
||||||
script.setProjectRoot(this.projectDir);
|
|
||||||
script.setBuildName(scriptFqn);
|
|
||||||
script.setCliArgs(scriptCliArgs);
|
|
||||||
|
|
||||||
// run
|
|
||||||
script.run();
|
|
||||||
|
|
||||||
return script;
|
|
||||||
} catch (IOException | ClassNotFoundException | NoSuchMethodException | InstantiationException |
|
|
||||||
IllegalAccessException | InvocationTargetException exception) {
|
|
||||||
throw new RuntimeException(exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
package com.jessebrault.ssg.buildscript;
|
|
||||||
|
|
||||||
import com.jessebrault.ssg.buildscript.delegates.BuildDelegate;
|
|
||||||
import com.jessebrault.ssg.buildscript.delegates.BuildDelegateConfigurator;
|
|
||||||
import com.jessebrault.ssg.buildscript.delegates.BuildDelegateConverter;
|
|
||||||
import jakarta.inject.Inject;
|
|
||||||
import jakarta.inject.Named;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Deque;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class DefaultBuildSpecFactory implements BuildSpecFactory {
|
|
||||||
|
|
||||||
private final BuildScriptFactory buildScriptFactory;
|
|
||||||
private final BuildDelegateConfigurator buildDelegateConfigurator;
|
|
||||||
private final BuildDelegateConverter buildDelegateConverter;
|
|
||||||
private final File projectDir;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public DefaultBuildSpecFactory(
|
|
||||||
BuildScriptFactory buildScriptFactory,
|
|
||||||
BuildDelegateConfigurator buildDelegateConfigurator,
|
|
||||||
BuildDelegateConverter buildDelegateConverter,
|
|
||||||
@Named("projectDir") File projectDir
|
|
||||||
) {
|
|
||||||
this.buildScriptFactory = buildScriptFactory;
|
|
||||||
this.buildDelegateConfigurator = buildDelegateConfigurator;
|
|
||||||
this.buildDelegateConverter = buildDelegateConverter;
|
|
||||||
this.projectDir = projectDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected BuildSpec doConvert(String scriptFqn, Map<String, String> scriptCliArgs, BuildScriptBase script) {
|
|
||||||
// 1. Make hierarchy as a stack
|
|
||||||
final Deque<BuildScriptBase> buildHierarchy = new LinkedList<>();
|
|
||||||
buildHierarchy.push(script);
|
|
||||||
@Nullable String extending = script.getExtending();
|
|
||||||
while (extending != null) {
|
|
||||||
final BuildScriptBase from = this.buildScriptFactory.getAndRunBuildScript(extending, scriptCliArgs);
|
|
||||||
buildHierarchy.push(from);
|
|
||||||
extending = from.getExtending();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go through the stack from top to bottom, using the same delegate
|
|
||||||
final BuildDelegate buildDelegate = new BuildDelegate(this.projectDir);
|
|
||||||
this.buildDelegateConfigurator.configure(buildDelegate, scriptFqn);
|
|
||||||
while (!buildHierarchy.isEmpty()) {
|
|
||||||
final BuildScriptBase from = buildHierarchy.pop();
|
|
||||||
from.getBuildClosure().setDelegate(buildDelegate);
|
|
||||||
from.getBuildClosure().run();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.buildDelegateConverter.convert(scriptFqn, buildDelegate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BuildSpec getBuildSpec(String scriptFqn, Map<String, String> scriptCliArgs) {
|
|
||||||
final BuildScriptBase script = this.buildScriptFactory.getAndRunBuildScript(scriptFqn, scriptCliArgs);
|
|
||||||
return this.doConvert(scriptFqn, scriptCliArgs, script);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,19 +1,35 @@
|
|||||||
package com.jessebrault.ssg.buildscript.delegates
|
package com.jessebrault.ssg.buildscript.delegates
|
||||||
|
|
||||||
|
import com.jessebrault.ssg.model.Model
|
||||||
|
import com.jessebrault.ssg.model.Models
|
||||||
|
import com.jessebrault.ssg.text.MarkdownTextConverter
|
||||||
|
import com.jessebrault.ssg.text.TextConverter
|
||||||
|
import com.jessebrault.ssg.util.PathUtil
|
||||||
|
import com.jessebrault.di.DefaultRegistryObjectFactory
|
||||||
import com.jessebrault.di.RegistryObjectFactory
|
import com.jessebrault.di.RegistryObjectFactory
|
||||||
import com.jessebrault.fp.property.DefaultProperty
|
import com.jessebrault.fp.property.DefaultProperty
|
||||||
import com.jessebrault.fp.property.Property
|
import com.jessebrault.fp.property.Property
|
||||||
|
import com.jessebrault.fp.provider.DefaultProvider
|
||||||
import com.jessebrault.fp.provider.NamedProvider
|
import com.jessebrault.fp.provider.NamedProvider
|
||||||
import com.jessebrault.fp.provider.Provider
|
import com.jessebrault.fp.provider.Provider
|
||||||
import com.jessebrault.ssg.WvcCompilerFactory
|
|
||||||
import com.jessebrault.ssg.model.Model
|
|
||||||
import com.jessebrault.ssg.model.Models
|
|
||||||
import com.jessebrault.ssg.text.TextSupplier
|
|
||||||
|
|
||||||
|
import java.nio.file.Path
|
||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
|
|
||||||
final class BuildDelegate {
|
final class BuildDelegate {
|
||||||
|
|
||||||
|
static BuildDelegate withDefaults(String buildName, File projectDir) {
|
||||||
|
new BuildDelegate(projectDir).tap {
|
||||||
|
basePackages.convention = [] as Set<String>
|
||||||
|
outputDir.convention = PathUtil.resolve(projectDir, Path.of('dist', buildName.split(/\\./)))
|
||||||
|
globals.convention = [:]
|
||||||
|
models.convention = [] as Set<Model>
|
||||||
|
textsDirs.convention = [new File(projectDir, 'texts')] as Set<File>
|
||||||
|
textConverters.convention = [new MarkdownTextConverter()] as Set<TextConverter>
|
||||||
|
objectFactoryBuilder.convention = DefaultRegistryObjectFactory.Builder.withDefaults()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final File projectDir
|
final File projectDir
|
||||||
|
|
||||||
final Property<Set<String>> basePackages = DefaultProperty.<Set<String>>empty(Set)
|
final Property<Set<String>> basePackages = DefaultProperty.<Set<String>>empty(Set)
|
||||||
@ -22,11 +38,12 @@ final class BuildDelegate {
|
|||||||
final Property<File> outputDir = DefaultProperty.empty(File)
|
final Property<File> outputDir = DefaultProperty.empty(File)
|
||||||
final Property<Map<String, Object>> globals = DefaultProperty.<Map<String, Object>>empty(Map)
|
final Property<Map<String, Object>> globals = DefaultProperty.<Map<String, Object>>empty(Map)
|
||||||
final Property<Set<Model>> models = DefaultProperty.<Set<Model>>empty(Set)
|
final Property<Set<Model>> models = DefaultProperty.<Set<Model>>empty(Set)
|
||||||
final Property<Set<TextSupplier>> textSuppliers = DefaultProperty.<Set<TextSupplier>>empty(Set)
|
final Property<Set<File>> textsDirs = DefaultProperty.<Set<File>>empty(Set)
|
||||||
final Property<RegistryObjectFactory> objectFactory = DefaultProperty.empty(RegistryObjectFactory)
|
final Property<Set<TextConverter>> textConverters = DefaultProperty.<Set<TextConverter>>empty(Set)
|
||||||
final Property<WvcCompilerFactory> wvcCompilerFactory = DefaultProperty.empty(WvcCompilerFactory)
|
final Property<RegistryObjectFactory.Builder> objectFactoryBuilder =
|
||||||
|
DefaultProperty.empty(RegistryObjectFactory.Builder)
|
||||||
|
|
||||||
BuildDelegate(File projectDir) {
|
private BuildDelegate(File projectDir) {
|
||||||
this.projectDir = projectDir
|
this.projectDir = projectDir
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,12 +109,24 @@ final class BuildDelegate {
|
|||||||
this.models.configure { it.add(Models.ofNamedProvider(namedProvider)) }
|
this.models.configure { it.add(Models.ofNamedProvider(namedProvider)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
void textSupplier(TextSupplier toAdd) {
|
void textsDir(File textsDir) {
|
||||||
this.textSuppliers.configure { it.add(toAdd) }
|
this.textsDirs.configure { it.add(textsDir) }
|
||||||
}
|
}
|
||||||
|
|
||||||
void textSuppliers(TextSupplier... toAdd) {
|
void textsDirs(File... textsDirs) {
|
||||||
this.textSuppliers.configure { it.addAll(toAdd) }
|
textsDirs.each { this.textsDir(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
void textConverter(TextConverter textConverter) {
|
||||||
|
this.textConverters.configure { it.add(textConverter) }
|
||||||
|
}
|
||||||
|
|
||||||
|
void textConverters(TextConverter... textConverters) {
|
||||||
|
textConverters.each { this.textConverter(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
void objectFactoryBuilder(RegistryObjectFactory.Builder builder) {
|
||||||
|
this.objectFactoryBuilder.set(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
package com.jessebrault.ssg.buildscript.delegates;
|
|
||||||
|
|
||||||
public interface BuildDelegateConfigurator {
|
|
||||||
void configure(BuildDelegate buildDelegate, String buildName);
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
package com.jessebrault.ssg.buildscript.delegates;
|
|
||||||
|
|
||||||
import com.jessebrault.ssg.buildscript.BuildSpec;
|
|
||||||
|
|
||||||
public interface BuildDelegateConverter {
|
|
||||||
BuildSpec convert(String buildName, BuildDelegate buildDelegate);
|
|
||||||
}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
package com.jessebrault.ssg.buildscript.delegates
|
|
||||||
|
|
||||||
import com.jessebrault.di.DefaultRegistryObjectFactory
|
|
||||||
import com.jessebrault.ssg.WvcCompilerFactory
|
|
||||||
import com.jessebrault.ssg.model.Model
|
|
||||||
import com.jessebrault.ssg.text.TextSupplier
|
|
||||||
import com.jessebrault.ssg.text.TextsDirMarkdownTextSupplier
|
|
||||||
import com.jessebrault.ssg.util.PathUtil
|
|
||||||
import jakarta.inject.Inject
|
|
||||||
import jakarta.inject.Named
|
|
||||||
|
|
||||||
import java.nio.file.Path
|
|
||||||
|
|
||||||
class DefaultBuildDelegateConfigurator implements BuildDelegateConfigurator {
|
|
||||||
|
|
||||||
private final File projectDir
|
|
||||||
private final TextsDirMarkdownTextSupplier textsDirMarkdownTextSupplier
|
|
||||||
private final WvcCompilerFactory wvcCompilerFactory
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
DefaultBuildDelegateConfigurator(
|
|
||||||
@Named('projectDir') File projectDir,
|
|
||||||
TextsDirMarkdownTextSupplier textsDirMarkdownTextSupplier,
|
|
||||||
WvcCompilerFactory wvcCompilerFactory
|
|
||||||
) {
|
|
||||||
this.projectDir = projectDir
|
|
||||||
this.textsDirMarkdownTextSupplier = textsDirMarkdownTextSupplier
|
|
||||||
this.wvcCompilerFactory = wvcCompilerFactory
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void configure(BuildDelegate buildDelegate, String buildName) {
|
|
||||||
buildDelegate.tap {
|
|
||||||
basePackages.convention = [] as Set<String>
|
|
||||||
outputDir.convention = PathUtil.resolve(this.projectDir, Path.of('dist', buildName.split(/\\./)))
|
|
||||||
globals.convention = [:]
|
|
||||||
models.convention = [] as Set<Model>
|
|
||||||
textSuppliers.convention = [this.textsDirMarkdownTextSupplier] as Set<TextSupplier>
|
|
||||||
objectFactory.convention = DefaultRegistryObjectFactory.Builder.withDefaults().build()
|
|
||||||
wvcCompilerFactory.convention = this.wvcCompilerFactory
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
package com.jessebrault.ssg.buildscript.delegates
|
|
||||||
|
|
||||||
import com.jessebrault.ssg.buildscript.BuildSpec
|
|
||||||
|
|
||||||
class DefaultBuildDelegateConverter implements BuildDelegateConverter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
BuildSpec convert(String buildName, BuildDelegate delegate) {
|
|
||||||
return new BuildSpec(
|
|
||||||
name: buildName,
|
|
||||||
basePackages: delegate.basePackages,
|
|
||||||
siteName: delegate.siteName,
|
|
||||||
baseUrl: delegate.baseUrl,
|
|
||||||
outputDir: delegate.outputDir,
|
|
||||||
globals: delegate.globals,
|
|
||||||
models: delegate.models,
|
|
||||||
textSuppliers: delegate.textSuppliers,
|
|
||||||
objectFactory: delegate.objectFactory,
|
|
||||||
wvcCompilerFactory: delegate.wvcCompilerFactory
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
package com.jessebrault.ssg.text;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface TextSupplier {
|
|
||||||
Collection<Text> get();
|
|
||||||
}
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
package com.jessebrault.ssg.text;
|
|
||||||
|
|
||||||
import jakarta.inject.Inject;
|
|
||||||
import jakarta.inject.Named;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class TextsDirMarkdownTextSupplier implements TextSupplier {
|
|
||||||
|
|
||||||
private final File projectDir;
|
|
||||||
private final ExecutorService executorService;
|
|
||||||
private final MarkdownTextConverter markdownTextConverter;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TextsDirMarkdownTextSupplier(
|
|
||||||
@Named("projectDir") File projectDir,
|
|
||||||
ExecutorService executorService,
|
|
||||||
MarkdownTextConverter markdownTextConverter
|
|
||||||
) {
|
|
||||||
this.projectDir = projectDir;
|
|
||||||
this.executorService = executorService;
|
|
||||||
this.markdownTextConverter = markdownTextConverter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<Text> get() {
|
|
||||||
final Path textsDir = Paths.get(projectDir.getAbsolutePath(), "texts");
|
|
||||||
final Collection<Text> results = ConcurrentHashMap.newKeySet();
|
|
||||||
if (Files.exists(textsDir)) {
|
|
||||||
try (final Stream<Path> walkStream = Files.walk(textsDir)){
|
|
||||||
final List<CompletableFuture<Void>> textFutures = walkStream
|
|
||||||
.map(path -> {
|
|
||||||
return CompletableFuture.runAsync(() -> {
|
|
||||||
if (path.toString().endsWith(".md")) {
|
|
||||||
results.add(this.markdownTextConverter.convert(textsDir.toFile(), path.toFile()));
|
|
||||||
}
|
|
||||||
}, this.executorService);
|
|
||||||
})
|
|
||||||
.toList();
|
|
||||||
CompletableFuture.allOf(textFutures.toArray(new CompletableFuture[0])).join();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -4,17 +4,13 @@ import groovy.transform.EqualsAndHashCode
|
|||||||
import groovy.transform.TupleConstructor
|
import groovy.transform.TupleConstructor
|
||||||
import org.jetbrains.annotations.Nullable
|
import org.jetbrains.annotations.Nullable
|
||||||
|
|
||||||
|
@TupleConstructor
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
final class Diagnostic {
|
final class Diagnostic {
|
||||||
|
|
||||||
final String message
|
final String message
|
||||||
final @Nullable Exception exception
|
final @Nullable Exception exception
|
||||||
|
|
||||||
Diagnostic(String message, Exception exception) {
|
|
||||||
this.message = message
|
|
||||||
this.exception = exception
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String toString() {
|
String toString() {
|
||||||
if (this.exception != null) {
|
if (this.exception != null) {
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
package com.jessebrault.ssg.view
|
package com.jessebrault.ssg.view
|
||||||
|
|
||||||
import com.jessebrault.fp.either.Either
|
|
||||||
import com.jessebrault.ssg.util.Diagnostic
|
import com.jessebrault.ssg.util.Diagnostic
|
||||||
|
import groovy.transform.TupleConstructor
|
||||||
|
import com.jessebrault.fp.either.Either
|
||||||
import groowt.view.component.ComponentTemplate
|
import groowt.view.component.ComponentTemplate
|
||||||
import groowt.view.component.ViewComponent
|
import groowt.view.component.ViewComponent
|
||||||
import groowt.view.component.compiler.ComponentTemplateClassFactory
|
import groowt.view.component.compiler.ComponentTemplateClassFactory
|
||||||
import groowt.view.component.compiler.source.ComponentTemplateSource
|
import groowt.view.component.compiler.source.ComponentTemplateSource
|
||||||
import groowt.view.component.web.compiler.DefaultWebViewComponentTemplateCompileUnit
|
import groowt.view.component.web.compiler.DefaultWebViewComponentTemplateCompileUnit
|
||||||
import jakarta.inject.Inject
|
|
||||||
|
|
||||||
|
@TupleConstructor
|
||||||
class WvcCompiler {
|
class WvcCompiler {
|
||||||
|
|
||||||
private static class SsgWvcTemplateCompileUnit extends DefaultWebViewComponentTemplateCompileUnit {
|
private static class SsgWvcTemplateCompileUnit extends DefaultWebViewComponentTemplateCompileUnit {
|
||||||
@ -29,12 +30,6 @@ class WvcCompiler {
|
|||||||
final GroovyClassLoader groovyClassLoader
|
final GroovyClassLoader groovyClassLoader
|
||||||
final ComponentTemplateClassFactory templateClassFactory
|
final ComponentTemplateClassFactory templateClassFactory
|
||||||
|
|
||||||
@Inject
|
|
||||||
WvcCompiler(GroovyClassLoader groovyClassLoader, ComponentTemplateClassFactory templateClassFactory) {
|
|
||||||
this.groovyClassLoader = groovyClassLoader
|
|
||||||
this.templateClassFactory = templateClassFactory
|
|
||||||
}
|
|
||||||
|
|
||||||
Either<Diagnostic, ComponentTemplate> compileTemplate(
|
Either<Diagnostic, ComponentTemplate> compileTemplate(
|
||||||
Class<? extends ViewComponent> componentClass,
|
Class<? extends ViewComponent> componentClass,
|
||||||
String resourceName
|
String resourceName
|
||||||
@ -42,8 +37,7 @@ class WvcCompiler {
|
|||||||
def templateUrl = componentClass.getResource(resourceName)
|
def templateUrl = componentClass.getResource(resourceName)
|
||||||
if (templateUrl == null) {
|
if (templateUrl == null) {
|
||||||
return Either.left(new Diagnostic(
|
return Either.left(new Diagnostic(
|
||||||
"Could not find templateResource: $resourceName",
|
"Could not find templateResource: $resourceName"
|
||||||
null
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
def source = ComponentTemplateSource.of(templateUrl)
|
def source = ComponentTemplateSource.of(templateUrl)
|
||||||
|
|||||||
@ -4,7 +4,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group 'com.jessebrault.ssg'
|
group 'com.jessebrault.ssg'
|
||||||
version '0.7.0-SNAPSHOT'
|
version '0.6.3'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@ -36,7 +36,7 @@ dependencies {
|
|||||||
|
|
||||||
java {
|
java {
|
||||||
toolchain {
|
toolchain {
|
||||||
languageVersion = JavaLanguageVersion.of(21)
|
languageVersion = JavaLanguageVersion.of(25)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,24 +1,8 @@
|
|||||||
package com.jessebrault.ssg
|
package com.jessebrault.ssg
|
||||||
|
|
||||||
import com.jessebrault.di.DefaultRegistryObjectFactory
|
|
||||||
import com.jessebrault.di.ObjectFactory
|
|
||||||
import com.jessebrault.di.RegistryObjectFactory
|
|
||||||
import com.jessebrault.ssg.buildscript.BuildScriptFactory
|
|
||||||
import com.jessebrault.ssg.buildscript.BuildSpecFactory
|
|
||||||
import com.jessebrault.ssg.buildscript.DefaultBuildScriptFactory
|
|
||||||
import com.jessebrault.ssg.buildscript.DefaultBuildSpecFactory
|
|
||||||
import com.jessebrault.ssg.buildscript.delegates.BuildDelegateConfigurator
|
|
||||||
import com.jessebrault.ssg.buildscript.delegates.BuildDelegateConverter
|
|
||||||
import com.jessebrault.ssg.buildscript.delegates.DefaultBuildDelegateConfigurator
|
|
||||||
import com.jessebrault.ssg.buildscript.delegates.DefaultBuildDelegateConverter
|
|
||||||
import com.jessebrault.ssg.gradle.SsgBuildModel
|
import com.jessebrault.ssg.gradle.SsgBuildModel
|
||||||
import com.jessebrault.ssg.text.MarkdownTextConverter
|
|
||||||
import com.jessebrault.ssg.text.TextsDirMarkdownTextSupplier
|
|
||||||
import com.jessebrault.ssg.util.Diagnostic
|
import com.jessebrault.ssg.util.Diagnostic
|
||||||
import com.jessebrault.ssg.util.URLUtil
|
import com.jessebrault.ssg.util.URLUtil
|
||||||
import com.jessebrault.ssg.view.WvcCompiler
|
|
||||||
import groowt.view.component.compiler.ComponentTemplateClassFactory
|
|
||||||
import groowt.view.component.compiler.SimpleComponentTemplateClassFactory
|
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import org.apache.logging.log4j.Logger
|
import org.apache.logging.log4j.Logger
|
||||||
import org.gradle.tooling.GradleConnector
|
import org.gradle.tooling.GradleConnector
|
||||||
@ -26,10 +10,6 @@ import picocli.CommandLine
|
|||||||
|
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.util.concurrent.ExecutorService
|
|
||||||
import java.util.concurrent.Executors
|
|
||||||
|
|
||||||
import static com.jessebrault.di.BindingUtil.*
|
|
||||||
|
|
||||||
abstract class AbstractBuildCommand extends AbstractSubCommand {
|
abstract class AbstractBuildCommand extends AbstractSubCommand {
|
||||||
|
|
||||||
@ -94,50 +74,8 @@ abstract class AbstractBuildCommand extends AbstractSubCommand {
|
|||||||
)
|
)
|
||||||
boolean profile
|
boolean profile
|
||||||
|
|
||||||
@CommandLine.Option(
|
|
||||||
names = ['-t', '--threads'],
|
|
||||||
description = 'The number of threads to use.',
|
|
||||||
defaultValue = '8'
|
|
||||||
)
|
|
||||||
Integer threads
|
|
||||||
|
|
||||||
protected RegistryObjectFactory objectFactory = null
|
|
||||||
protected StaticSiteGenerator staticSiteGenerator = null
|
protected StaticSiteGenerator staticSiteGenerator = null
|
||||||
|
|
||||||
protected RegistryObjectFactory getApiObjectFactory(
|
|
||||||
GroovyClassLoader groovyClassLoader,
|
|
||||||
ExecutorService executorService,
|
|
||||||
PageWriter pageWriter,
|
|
||||||
List<URL> scriptBaseUrls,
|
|
||||||
File projectDir
|
|
||||||
) {
|
|
||||||
RegistryObjectFactory objectFactory = DefaultRegistryObjectFactory.Builder.withDefaults().build()
|
|
||||||
objectFactory.tap {
|
|
||||||
configureRegistry {
|
|
||||||
bind(BuildSpecFactory, toClass(DefaultBuildSpecFactory))
|
|
||||||
bind(ObjectFactoryConfigurator, toClass(DefaultObjectFactoryConfigurator))
|
|
||||||
bind(GroovyClassLoader, toSingleton(groovyClassLoader))
|
|
||||||
bind(ExecutorService, toSingleton(executorService))
|
|
||||||
bind(PageScanner, toClass(DefaultPageScanner))
|
|
||||||
bind(ComponentClassScanner, toClass(DefaultComponentClassScanner))
|
|
||||||
bind(PageRenderer, toClass(DefaultPageRenderer))
|
|
||||||
bind(PageWriter, toSingleton(pageWriter))
|
|
||||||
bind(BuildScriptFactory, toClass(DefaultBuildScriptFactory))
|
|
||||||
bind(BuildDelegateConfigurator, toClass(DefaultBuildDelegateConfigurator))
|
|
||||||
bind(BuildDelegateConverter, toClass(DefaultBuildDelegateConverter))
|
|
||||||
bind(named('scriptBaseUrls', List), toSingleton(scriptBaseUrls))
|
|
||||||
bind(named('projectDir', File), toSingleton(projectDir))
|
|
||||||
bind(TextsGetter, toClass(DefaultTextsGetter))
|
|
||||||
bind(WvcCompilerFactory, toClass(DefaultWvcCompilerFactory))
|
|
||||||
bind(ComponentTemplateClassFactory, toClass(SimpleComponentTemplateClassFactory))
|
|
||||||
bind(TextsDirMarkdownTextSupplier, toSelf())
|
|
||||||
bind(MarkdownTextConverter, toSelf())
|
|
||||||
bind(PageContextFactory, toClass(DefaultPageContextFactory))
|
|
||||||
bind(ObjectFactory, toSingleton(objectFactory))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final Integer doSingleBuild(String buildName) {
|
protected final Integer doSingleBuild(String buildName) {
|
||||||
logger.traceEntry('buildName: {}', buildName)
|
logger.traceEntry('buildName: {}', buildName)
|
||||||
|
|
||||||
@ -188,21 +126,23 @@ abstract class AbstractBuildCommand extends AbstractSubCommand {
|
|||||||
def buildScriptDirUrls = this.buildScriptDirs.collect {
|
def buildScriptDirUrls = this.buildScriptDirs.collect {
|
||||||
def withProjectDir = new File(this.commonCliOptions.projectDir, it.toString())
|
def withProjectDir = new File(this.commonCliOptions.projectDir, it.toString())
|
||||||
withProjectDir.toURI().toURL()
|
withProjectDir.toURI().toURL()
|
||||||
}
|
} as URL[]
|
||||||
|
|
||||||
this.objectFactory = this.getApiObjectFactory(
|
this.staticSiteGenerator = new DefaultStaticSiteGenerator(
|
||||||
groovyClassLoader,
|
groovyClassLoader,
|
||||||
Executors.newFixedThreadPool(this.threads),
|
|
||||||
!this.dryRun ? new FilePageWriter() : new ConsolePageWriter(),
|
|
||||||
buildScriptDirUrls,
|
buildScriptDirUrls,
|
||||||
new File('.')
|
this.dryRun
|
||||||
)
|
)
|
||||||
this.staticSiteGenerator = objectFactory.createInstance(JDefaultStaticSiteGenerator)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def buildStartTime = System.currentTimeMillis()
|
def buildStartTime = System.currentTimeMillis()
|
||||||
|
|
||||||
final Collection<Diagnostic> diagnostics = this.staticSiteGenerator.doBuild(buildName, this.scriptArgs ?: [:])
|
final Collection<Diagnostic> diagnostics = this.staticSiteGenerator.doBuild(
|
||||||
|
this.commonCliOptions.projectDir,
|
||||||
|
buildName,
|
||||||
|
buildName,
|
||||||
|
this.scriptArgs ?: [:]
|
||||||
|
)
|
||||||
|
|
||||||
def buildElapsedTime = System.currentTimeMillis() - buildStartTime
|
def buildElapsedTime = System.currentTimeMillis() - buildStartTime
|
||||||
if (this.profile) {
|
if (this.profile) {
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import picocli.CommandLine
|
|||||||
@CommandLine.Command(
|
@CommandLine.Command(
|
||||||
name = 'ssg',
|
name = 'ssg',
|
||||||
mixinStandardHelpOptions = true,
|
mixinStandardHelpOptions = true,
|
||||||
version = '0.7.0-SNAPSHOT',
|
version = '0.6.3',
|
||||||
description = 'A static site generator which can interface with Gradle for high extensibility.',
|
description = 'A static site generator which can interface with Gradle for high extensibility.',
|
||||||
subcommands = [SsgInit, SsgBuild, SsgWatch]
|
subcommands = [SsgInit, SsgBuild, SsgWatch]
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
[versions]
|
[versions]
|
||||||
classgraph = '4.8.184'
|
classgraph = '4.8.184'
|
||||||
commonmark = '0.27.0'
|
commonmark = '0.27.0'
|
||||||
di = '0.2.0-SNAPSHOT'
|
di = '0.1.0'
|
||||||
fp = '0.1.0'
|
fp = '0.1.0'
|
||||||
groovy = '4.0.27'
|
groovy = '4.0.27'
|
||||||
groowt = '0.1.4'
|
groowt = '0.1.4'
|
||||||
jetbrains-annotations = '26.0.2'
|
jetbrains-annotations = '26.0.2'
|
||||||
jsoup = '1.21.2'
|
jsoup = '1.21.2'
|
||||||
junit = '5.14.1'
|
junit = '5.14.0'
|
||||||
log4j2 = '2.25.3'
|
log4j2 = '2.25.2'
|
||||||
mockito = '5.21.0'
|
mockito = '5.20.0'
|
||||||
picocli = '4.7.7'
|
picocli = '4.7.7'
|
||||||
slf4j = '2.0.17'
|
slf4j = '2.0.17'
|
||||||
|
|
||||||
@ -25,8 +25,6 @@ groowt-v = { module = 'groowt:views', version.ref = 'groowt' }
|
|||||||
groowt-vc = { module = 'groowt:view-components', version.ref = 'groowt' }
|
groowt-vc = { module = 'groowt:view-components', version.ref = 'groowt' }
|
||||||
groowt-wvc= { module = 'groowt:web-view-components', version.ref = 'groowt' }
|
groowt-wvc= { module = 'groowt:web-view-components', version.ref = 'groowt' }
|
||||||
groowt-wvcc = { module = 'groowt:web-view-components-compiler', version.ref = 'groowt' }
|
groowt-wvcc = { module = 'groowt:web-view-components-compiler', version.ref = 'groowt' }
|
||||||
groowt-fp = { module = 'groowt:util-fp', version.ref = 'groowt' }
|
|
||||||
groowt-di = { module = 'groowt:util-di', version.ref = 'groowt' }
|
|
||||||
jetbrains-anontations = { module = 'org.jetbrains:annotations', version.ref = 'jetbrains-annotations' }
|
jetbrains-anontations = { module = 'org.jetbrains:annotations', version.ref = 'jetbrains-annotations' }
|
||||||
jsoup = { module = 'org.jsoup:jsoup', version.ref = 'jsoup' }
|
jsoup = { module = 'org.jsoup:jsoup', version.ref = 'jsoup' }
|
||||||
junit-jupiter-api = { module = 'org.junit.jupiter:junit-jupiter-api', version.ref = 'junit' }
|
junit-jupiter-api = { module = 'org.junit.jupiter:junit-jupiter-api', version.ref = 'junit' }
|
||||||
|
|||||||
@ -162,8 +162,8 @@ public class SsgGradlePlugin implements Plugin<Project> {
|
|||||||
Configuration ssgApiConfiguration,
|
Configuration ssgApiConfiguration,
|
||||||
Configuration ssgCliConfiguration
|
Configuration ssgCliConfiguration
|
||||||
) {
|
) {
|
||||||
final Dependency ssgApi = project.getDependencies().create("com.jessebrault.ssg:api:0.7.0-SNAPSHOT");
|
final Dependency ssgApi = project.getDependencies().create("com.jessebrault.ssg:api:0.6.3");
|
||||||
final Dependency ssgCli = project.getDependencies().create("com.jessebrault.ssg:cli:0.7.0-SNAPSHOT");
|
final Dependency ssgCli = project.getDependencies().create("com.jessebrault.ssg:cli:0.6.3");
|
||||||
ssgApiConfiguration.getDependencies().add(ssgApi);
|
ssgApiConfiguration.getDependencies().add(ssgApi);
|
||||||
ssgCliConfiguration.getDependencies().add(ssgCli);
|
ssgCliConfiguration.getDependencies().add(ssgCli);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user