Massive amount of work: 1. html specs, 2. classloaders.
This commit is contained in:
parent
b741765b24
commit
f44f2df797
@ -8,7 +8,7 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
// https://archiva.jessebrault.com/#artifact/com.jessebrault.gst/lib
|
||||
implementation 'com.jessebrault.gst:lib:0.0.3'
|
||||
implementation 'com.jessebrault.gst:lib:0.0.5'
|
||||
|
||||
// https://mvnrepository.com/artifact/org.apache.groovy/groovy-templates
|
||||
implementation 'org.apache.groovy:groovy-templates:4.0.12'
|
||||
|
@ -2,7 +2,7 @@ package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.buildscript.Build
|
||||
import com.jessebrault.ssg.buildscript.BuildScriptConfiguratorFactory
|
||||
import com.jessebrault.ssg.buildscript.BuildScripts
|
||||
import com.jessebrault.ssg.buildscript.BuildScriptRunner
|
||||
import com.jessebrault.ssg.util.Diagnostic
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.slf4j.Logger
|
||||
@ -18,45 +18,50 @@ final class BuildScriptBasedStaticSiteGenerator implements StaticSiteGenerator {
|
||||
private static final Marker enter = MarkerFactory.getMarker('enter')
|
||||
private static final Marker exit = MarkerFactory.getMarker('exit')
|
||||
|
||||
private final GroovyScriptEngine engine
|
||||
private final Collection<BuildScriptConfiguratorFactory> configuratorFactories
|
||||
private final @Nullable File buildScript
|
||||
private final Map<String, Object> scriptArgs
|
||||
private final Collection<Build> builds = []
|
||||
|
||||
private boolean ranBuildScript = false
|
||||
private GroovyClassLoader buildScriptClassLoader
|
||||
|
||||
/**
|
||||
* @param buildScriptClassLoaderUrls the urls to pass to the buildScriptRunner's GroovyClassLoader.
|
||||
* These should include the URL needed to find the given buildScript file, if present, as
|
||||
* well as any script dependencies (such as the buildSrc dir).
|
||||
* @param buildScript The buildScript File, may be <code>null</code>.
|
||||
*/
|
||||
BuildScriptBasedStaticSiteGenerator(
|
||||
GroovyScriptEngine engine,
|
||||
Collection<BuildScriptConfiguratorFactory> configuratorFactories = [],
|
||||
@Nullable File buildScript = null,
|
||||
Map<String, Object> scriptArgs = [:]
|
||||
Collection<URL> buildScriptClassLoaderUrls,
|
||||
@Nullable File buildScript = null
|
||||
) {
|
||||
this.engine = engine
|
||||
this.configuratorFactories = configuratorFactories
|
||||
this.buildScript = buildScript
|
||||
this.scriptArgs = scriptArgs
|
||||
}
|
||||
|
||||
private void runBuildScript() {
|
||||
logger.trace(enter, '')
|
||||
private void runBuildScript(
|
||||
Collection<BuildScriptConfiguratorFactory> configuratorFactories,
|
||||
Map<String, Object> buildScriptArgs
|
||||
) {
|
||||
logger.trace(enter, 'configuratorFactories: {}, buildScriptArgs: {}', configuratorFactories, buildScriptArgs)
|
||||
|
||||
if (this.buildScript == null) {
|
||||
logger.info('no specified build script; using defaults')
|
||||
def result = BuildScripts.runBuildScript { base ->
|
||||
this.configuratorFactories.each {
|
||||
def result = BuildScriptRunner.runClosureScript { base ->
|
||||
configuratorFactories.each {
|
||||
it.get().accept(base)
|
||||
}
|
||||
}
|
||||
this.builds.addAll(result)
|
||||
} else if (this.buildScript.exists() && this.buildScript.isFile()) {
|
||||
logger.info('running buildScript: {}', this.buildScript)
|
||||
def result = BuildScripts.runBuildScript(
|
||||
def buildScriptRunner = new BuildScriptRunner([
|
||||
this.buildScript.parentFile.toURI().toURL()
|
||||
])
|
||||
this.buildScriptClassLoader = buildScriptRunner.getBuildScriptClassLoader()
|
||||
def result = buildScriptRunner.runBuildScript(
|
||||
this.buildScript.name,
|
||||
this.engine,
|
||||
[args: this.scriptArgs]
|
||||
[args: buildScriptArgs]
|
||||
) { base ->
|
||||
this.configuratorFactories.each { it.get().accept(base) }
|
||||
configuratorFactories.each { it.get().accept(base) }
|
||||
}
|
||||
this.builds.addAll(result)
|
||||
} else {
|
||||
@ -67,12 +72,27 @@ final class BuildScriptBasedStaticSiteGenerator implements StaticSiteGenerator {
|
||||
logger.trace(exit, '')
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The classLoader used to load the buildScript.
|
||||
* @throws NullPointerException if the buildScriptRunner was not initialized yet (make sure to call
|
||||
* {@link #doBuild} first).
|
||||
*/
|
||||
GroovyClassLoader getBuildScriptClassLoader() {
|
||||
Objects.requireNonNull(this.buildScriptClassLoader)
|
||||
}
|
||||
|
||||
// TODO: cache
|
||||
@Override
|
||||
boolean doBuild(String buildName, Consumer<Collection<Diagnostic>> diagnosticsConsumer = { }) {
|
||||
boolean doBuild(
|
||||
String buildName,
|
||||
Collection<BuildScriptConfiguratorFactory> configuratorFactories,
|
||||
Map<String, Object> buildScriptArgs,
|
||||
Consumer<Collection<Diagnostic>> diagnosticsConsumer
|
||||
) {
|
||||
logger.trace(enter, 'buildName: {}, diagnosticsConsumer: {}', buildName, diagnosticsConsumer)
|
||||
|
||||
if (!this.ranBuildScript) {
|
||||
this.runBuildScript()
|
||||
this.runBuildScript(configuratorFactories, buildScriptArgs)
|
||||
}
|
||||
|
||||
def build = this.builds.find { it.name == buildName }
|
||||
|
@ -1,9 +1,15 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.buildscript.BuildScriptConfiguratorFactory
|
||||
import com.jessebrault.ssg.util.Diagnostic
|
||||
|
||||
import java.util.function.Consumer
|
||||
|
||||
interface StaticSiteGenerator {
|
||||
boolean doBuild(String buildName, Consumer<Collection<Diagnostic>> diagnosticsConsumer)
|
||||
boolean doBuild(
|
||||
String buildName,
|
||||
Collection<BuildScriptConfiguratorFactory> configuratorFactories,
|
||||
Map<String, Object> buildScriptArgs,
|
||||
Consumer<Collection<Diagnostic>> diagnosticsConsumer
|
||||
)
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package com.jessebrault.ssg.buildscript
|
||||
|
||||
import com.jessebrault.ssg.util.ExtensionUtil
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.stc.ClosureParams
|
||||
import groovy.transform.stc.SimpleType
|
||||
import org.codehaus.groovy.control.CompilerConfiguration
|
||||
|
||||
import java.util.function.Consumer
|
||||
|
||||
@NullCheck
|
||||
final class BuildScriptRunner {
|
||||
|
||||
private static Collection<Build> runBase(BuildScriptBase base) {
|
||||
base.run()
|
||||
BuildSpecUtil.getBuilds(base.getBuildSpecs())
|
||||
}
|
||||
|
||||
static Collection<Build> runClosureScript(
|
||||
@DelegatesTo(value = BuildScriptBase, strategy = Closure.DELEGATE_FIRST)
|
||||
@ClosureParams(value = SimpleType, options = 'com.jessebrault.ssg.buildscript.BuildScriptBase')
|
||||
Closure<?> scriptBody
|
||||
) {
|
||||
def base = new BuildScriptBase() {
|
||||
|
||||
@Override
|
||||
Object run() {
|
||||
scriptBody.delegate = this
|
||||
scriptBody.resolveStrategy = Closure.DELEGATE_FIRST
|
||||
scriptBody.call(this)
|
||||
}
|
||||
|
||||
}
|
||||
runBase(base)
|
||||
}
|
||||
|
||||
private final GroovyClassLoader buildScriptClassLoader
|
||||
|
||||
BuildScriptRunner(Collection<URL> classLoaderUrls) {
|
||||
this.buildScriptClassLoader = new GroovyClassLoader(
|
||||
Thread.currentThread().contextClassLoader,
|
||||
new CompilerConfiguration().tap {
|
||||
scriptBaseClass = BuildScriptBase.name
|
||||
}
|
||||
)
|
||||
classLoaderUrls.each(this.buildScriptClassLoader::addURL)
|
||||
}
|
||||
|
||||
GroovyClassLoader getBuildScriptClassLoader() {
|
||||
this.buildScriptClassLoader
|
||||
}
|
||||
|
||||
Collection<Build> runBuildScript(
|
||||
String scriptName,
|
||||
Map<String, Object> binding,
|
||||
Consumer<BuildScriptBase> configureBuildScript
|
||||
) {
|
||||
Class<?> scriptClass = this.buildScriptClassLoader.loadClass(
|
||||
ExtensionUtil.stripExtension(scriptName),
|
||||
true,
|
||||
false,
|
||||
false
|
||||
)
|
||||
def scriptObject = scriptClass.getConstructor().newInstance()
|
||||
assert scriptObject instanceof BuildScriptBase
|
||||
scriptObject.setBinding(new Binding(binding))
|
||||
configureBuildScript.accept(scriptObject)
|
||||
runBase(scriptObject)
|
||||
}
|
||||
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
package com.jessebrault.ssg.buildscript
|
||||
|
||||
import groovy.transform.stc.ClosureParams
|
||||
import groovy.transform.stc.SimpleType
|
||||
import org.codehaus.groovy.control.CompilerConfiguration
|
||||
|
||||
import java.util.function.Consumer
|
||||
|
||||
final class BuildScripts {
|
||||
|
||||
private static Collection<Build> runBase(BuildScriptBase base) {
|
||||
base.run()
|
||||
BuildSpecUtil.getBuilds(base.getBuildSpecs())
|
||||
}
|
||||
|
||||
static Collection<Build> runBuildScript(
|
||||
@DelegatesTo(value = BuildScriptBase, strategy = Closure.DELEGATE_FIRST)
|
||||
@ClosureParams(value = SimpleType, options = 'com.jessebrault.ssg.buildscript.BuildScriptBase')
|
||||
Closure<?> scriptBody
|
||||
) {
|
||||
def base = new BuildScriptBase() {
|
||||
|
||||
@Override
|
||||
Object run() {
|
||||
scriptBody.delegate = this
|
||||
scriptBody.resolveStrategy = Closure.DELEGATE_FIRST
|
||||
scriptBody.call(this)
|
||||
}
|
||||
|
||||
}
|
||||
runBase(base)
|
||||
}
|
||||
|
||||
static Collection<Build> runBuildScript(
|
||||
String scriptName,
|
||||
GroovyScriptEngine engine,
|
||||
Map<String, Object> binding = [:],
|
||||
Consumer<BuildScriptBase> configureBuildScript = { }
|
||||
) {
|
||||
engine.config = new CompilerConfiguration().tap {
|
||||
scriptBaseClass = 'com.jessebrault.ssg.buildscript.BuildScriptBase'
|
||||
}
|
||||
|
||||
def base = engine.createScript(scriptName, new Binding(binding))
|
||||
assert base instanceof BuildScriptBase
|
||||
configureBuildScript.accept(base)
|
||||
runBase(base)
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
static Collection<Build> runBuildScript(
|
||||
String scriptName,
|
||||
URL scriptBaseDirUrl,
|
||||
Collection<URL> otherUrls,
|
||||
Map<String, Object> binding,
|
||||
Consumer<BuildScriptBase> configureBuildScript
|
||||
) {
|
||||
def engine = new GroovyScriptEngine([scriptBaseDirUrl, *otherUrls] as URL[])
|
||||
|
||||
engine.config = new CompilerConfiguration().tap {
|
||||
scriptBaseClass = 'com.jessebrault.ssg.buildscript.BuildScriptBase'
|
||||
}
|
||||
|
||||
def base = engine.createScript(scriptName, new Binding(binding))
|
||||
assert base instanceof BuildScriptBase
|
||||
configureBuildScript.accept(base)
|
||||
runBase(base)
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
static Collection<Build> runBuildScript(
|
||||
String scriptName,
|
||||
URL scriptBaseDirUrl,
|
||||
Collection<URL> otherUrls,
|
||||
Map<String, Object> binding
|
||||
) {
|
||||
runBuildScript(scriptName, scriptBaseDirUrl, otherUrls, binding) { }
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
static Collection<Build> runBuildScript(
|
||||
String scriptName,
|
||||
URL scriptBaseDirUrl,
|
||||
Collection<URL> otherUrls
|
||||
) {
|
||||
runBuildScript(scriptName, scriptBaseDirUrl, otherUrls, [:]) { }
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
static Collection<Build> runBuildScript(
|
||||
String scriptName,
|
||||
URL scriptBaseDirUrl
|
||||
) {
|
||||
runBuildScript(scriptName, scriptBaseDirUrl, [], [:]) { }
|
||||
}
|
||||
|
||||
private BuildScripts() {}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.jessebrault.ssg.buildscript
|
||||
|
||||
import com.jessebrault.ssg.html.PageToHtmlSpecProviders
|
||||
import com.jessebrault.ssg.html.PageToHtmlTaskFactory
|
||||
import com.jessebrault.ssg.html.TextToHtmlSpecProviders
|
||||
import com.jessebrault.ssg.html.TextToHtmlTaskFactory
|
||||
@ -16,6 +17,7 @@ import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
import java.util.function.Consumer
|
||||
import java.util.function.Supplier
|
||||
|
||||
@TupleConstructor(includeFields = true, defaults = false)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@ -23,8 +25,7 @@ import java.util.function.Consumer
|
||||
final class DefaultBuildScriptConfiguratorFactory implements BuildScriptConfiguratorFactory {
|
||||
|
||||
private final File baseDir
|
||||
private final File tmpDir
|
||||
private final GroovyScriptEngine engine
|
||||
private final Supplier<ClassLoader> classLoaderSupplier
|
||||
|
||||
@Override
|
||||
Consumer<BuildScriptBase> get() {
|
||||
@ -36,9 +37,9 @@ final class DefaultBuildScriptConfiguratorFactory implements BuildScriptConfigur
|
||||
|
||||
types {
|
||||
textTypes << TextTypes.MARKDOWN
|
||||
pageTypes << PageTypes.getGsp(['.gsp', '.ssg.gst'], this.tmpDir, this.engine)
|
||||
templateTypes << TemplateTypes.getGsp(['.gsp', '.ssg.gst'], this.tmpDir, this.engine)
|
||||
partTypes << PartTypes.getGsp(['.gsp', '.ssg.gst'], this.tmpDir, this.engine)
|
||||
pageTypes << PageTypes.getGsp(['.gsp', '.ssg.gst'], this.classLoaderSupplier.get())
|
||||
templateTypes << TemplateTypes.getGsp(['.gsp', '.ssg.gst'], this.classLoaderSupplier.get())
|
||||
partTypes << PartTypes.getGsp(['.gsp', '.ssg.gst'], this.classLoaderSupplier.get())
|
||||
}
|
||||
|
||||
sources { base, types ->
|
||||
@ -50,14 +51,14 @@ final class DefaultBuildScriptConfiguratorFactory implements BuildScriptConfigur
|
||||
|
||||
taskFactories { base, sources ->
|
||||
register('textToHtml', TextToHtmlTaskFactory::new) {
|
||||
it.specProvider += TextToHtmlSpecProviders.from(sources)
|
||||
it.specsProvider += TextToHtmlSpecProviders.from(sources)
|
||||
it.allTextsProvider += sources.textsProvider
|
||||
it.allPartsProvider += sources.partsProvider
|
||||
it.allModelsProvider += sources.modelsProvider
|
||||
}
|
||||
|
||||
register('pageToHtml', PageToHtmlTaskFactory::new) {
|
||||
it.pagesProvider += sources.pagesProvider
|
||||
it.specsProvider += PageToHtmlSpecProviders.from(sources.pagesProvider)
|
||||
it.allTextsProvider += sources.textsProvider
|
||||
it.allPartsProvider += sources.partsProvider
|
||||
it.allModelsProvider += sources.modelsProvider
|
||||
|
@ -13,8 +13,7 @@ import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
final class SourceProviders {
|
||||
|
||||
@ -26,22 +25,24 @@ final class SourceProviders {
|
||||
sp0.modelsProvider + sp1.modelsProvider,
|
||||
sp0.pagesProvider + sp1.pagesProvider,
|
||||
sp0.templatesProvider + sp1.templatesProvider,
|
||||
sp0.partsProvider + sp1.partsProvider
|
||||
sp0.partsProvider + sp1.partsProvider,
|
||||
sp0.custom + sp1.custom
|
||||
)
|
||||
}
|
||||
|
||||
static SourceProviders get(Map<String, Object> args) {
|
||||
new SourceProviders(
|
||||
args?.textsProvider as CollectionProvider<Text>
|
||||
args.textsProvider as CollectionProvider<Text>
|
||||
?: CollectionProviders.getEmpty() as CollectionProvider<Text>,
|
||||
args?.modelsProvider as CollectionProvider<Model<Object>>
|
||||
args.modelsProvider as CollectionProvider<Model<Object>>
|
||||
?: CollectionProviders.getEmpty() as CollectionProvider<Model<Object>>,
|
||||
args?.pagesProvider as CollectionProvider<Page>
|
||||
args.pagesProvider as CollectionProvider<Page>
|
||||
?: CollectionProviders.getEmpty() as CollectionProvider<Page>,
|
||||
args?.templatesProvider as CollectionProvider<Template>
|
||||
args.templatesProvider as CollectionProvider<Template>
|
||||
?: CollectionProviders.getEmpty() as CollectionProvider<Template>,
|
||||
args?.partsProvider as CollectionProvider<Part>
|
||||
?: CollectionProviders.getEmpty() as CollectionProvider<Part>
|
||||
args.partsProvider as CollectionProvider<Part>
|
||||
?: CollectionProviders.getEmpty() as CollectionProvider<Part>,
|
||||
args.custom as Map<String, CollectionProvider<?>> ?: [:]
|
||||
)
|
||||
}
|
||||
|
||||
@ -51,7 +52,8 @@ final class SourceProviders {
|
||||
CollectionProviders.getEmpty(),
|
||||
CollectionProviders.getEmpty(),
|
||||
CollectionProviders.getEmpty(),
|
||||
CollectionProviders.getEmpty()
|
||||
CollectionProviders.getEmpty(),
|
||||
[:]
|
||||
)
|
||||
}
|
||||
|
||||
@ -61,10 +63,40 @@ final class SourceProviders {
|
||||
final CollectionProvider<Template> templatesProvider
|
||||
final CollectionProvider<Part> partsProvider
|
||||
|
||||
private final Map<String, CollectionProvider<Object>> custom
|
||||
|
||||
SourceProviders(
|
||||
CollectionProvider<Text> textsProvider,
|
||||
CollectionProvider<Model<Object>> modelsProvider,
|
||||
CollectionProvider<Page> pagesProvider,
|
||||
CollectionProvider<Template> templatesProvider,
|
||||
CollectionProvider<Part> partsProvider,
|
||||
Map<String, CollectionProvider<Object>> custom
|
||||
) {
|
||||
this.textsProvider = textsProvider
|
||||
this.modelsProvider = modelsProvider
|
||||
this.pagesProvider = pagesProvider
|
||||
this.templatesProvider = templatesProvider
|
||||
this.partsProvider = partsProvider
|
||||
this.custom = custom
|
||||
}
|
||||
|
||||
SourceProviders plus(SourceProviders other) {
|
||||
concat(this, other)
|
||||
}
|
||||
|
||||
def <T> CollectionProvider<T> getCustom(String name, Class<T> tClass) {
|
||||
this.custom.get(name) as CollectionProvider<T>
|
||||
}
|
||||
|
||||
void putCustom(String name, CollectionProvider<?> customProvider) {
|
||||
this.custom.put(name, customProvider as CollectionProvider<Object>)
|
||||
}
|
||||
|
||||
Map<String, CollectionProvider<Object>> getAllCustom() {
|
||||
this.custom
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"SourceProviders(textsProvider: ${ this.textsProvider }, modelsProvider: ${ this.modelsProvider }, " +
|
||||
|
@ -21,6 +21,8 @@ final class SourceProvidersDelegate {
|
||||
private CollectionProvider<Template> templatesProvider = CollectionProviders.getEmpty()
|
||||
private CollectionProvider<Part> partsProvider = CollectionProviders.getEmpty()
|
||||
|
||||
private final Map<String, CollectionProvider<Object>> custom = [:]
|
||||
|
||||
void texts(CollectionProvider<Text> textsProvider) {
|
||||
this.textsProvider += textsProvider
|
||||
}
|
||||
@ -41,13 +43,18 @@ final class SourceProvidersDelegate {
|
||||
this.partsProvider += partsProvider
|
||||
}
|
||||
|
||||
void custom(String name, CollectionProvider<?> customProvider) {
|
||||
this.custom.put(name, customProvider as CollectionProvider<Object>)
|
||||
}
|
||||
|
||||
SourceProviders getResult() {
|
||||
new SourceProviders(
|
||||
this.textsProvider,
|
||||
this.modelsProvider,
|
||||
this.pagesProvider,
|
||||
this.templatesProvider,
|
||||
this.partsProvider
|
||||
this.partsProvider,
|
||||
this.custom
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,17 @@
|
||||
package com.jessebrault.ssg.html
|
||||
|
||||
import com.jessebrault.ssg.page.Page
|
||||
import com.jessebrault.ssg.task.TaskSpec
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
import java.util.function.Function
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@EqualsAndHashCode
|
||||
final class PageToHtmlSpec {
|
||||
final Page page
|
||||
final Function<TaskSpec, String> toRelativeHtmlPath
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.jessebrault.ssg.html
|
||||
|
||||
import com.jessebrault.ssg.page.Page
|
||||
import com.jessebrault.ssg.provider.CollectionProvider
|
||||
import com.jessebrault.ssg.provider.CollectionProviders
|
||||
import com.jessebrault.ssg.task.TaskSpec
|
||||
import com.jessebrault.ssg.util.ExtensionUtil
|
||||
|
||||
import java.util.function.Function
|
||||
|
||||
final class PageToHtmlSpecProviders {
|
||||
|
||||
static CollectionProvider<PageToHtmlSpec> from(CollectionProvider<Page> pagesProvider) {
|
||||
CollectionProviders.fromCollection(pagesProvider.provide().collect { Page page ->
|
||||
new PageToHtmlSpec(page, { TaskSpec taskSpec ->
|
||||
ExtensionUtil.stripExtension(page.path) + '.html'
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
static CollectionProvider<PageToHtmlSpec> from(
|
||||
CollectionProvider<Page> pagesProvider,
|
||||
Function<Page, Function<TaskSpec, String>> toRelativeHtmlPath
|
||||
) {
|
||||
CollectionProviders.fromCollection(pagesProvider.provide().collect {
|
||||
new PageToHtmlSpec(it, toRelativeHtmlPath.apply(it))
|
||||
})
|
||||
}
|
||||
|
||||
private PageToHtmlSpecProviders() {}
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package com.jessebrault.ssg.html
|
||||
|
||||
import com.jessebrault.ssg.page.Page
|
||||
|
||||
import com.jessebrault.ssg.provider.CollectionProvider
|
||||
import com.jessebrault.ssg.provider.CollectionProviders
|
||||
import com.jessebrault.ssg.task.AbstractRenderTaskFactory
|
||||
@ -8,28 +8,27 @@ import com.jessebrault.ssg.task.Task
|
||||
import com.jessebrault.ssg.task.TaskSpec
|
||||
import com.jessebrault.ssg.util.Result
|
||||
|
||||
import static com.jessebrault.ssg.util.ExtensionUtil.stripExtension
|
||||
import static java.util.Objects.requireNonNull
|
||||
|
||||
final class PageToHtmlTaskFactory extends AbstractRenderTaskFactory {
|
||||
|
||||
CollectionProvider<Page> pagesProvider = CollectionProviders.getEmpty()
|
||||
CollectionProvider<PageToHtmlSpec> specsProvider = CollectionProviders.getEmpty()
|
||||
|
||||
@Override
|
||||
Result<Collection<Task>> getTasks(TaskSpec taskSpec) {
|
||||
super.checkProviders()
|
||||
requireNonNull(this.pagesProvider)
|
||||
this.checkProviders()
|
||||
requireNonNull(this.specsProvider)
|
||||
|
||||
def allTexts = this.allTextsProvider.provide()
|
||||
def allModels = this.allModelsProvider.provide()
|
||||
def allParts = this.allPartsProvider.provide()
|
||||
|
||||
final Collection<Task> tasks = this.pagesProvider.provide()
|
||||
final Collection<Task> tasks = this.specsProvider.provide()
|
||||
.collect {
|
||||
new PageToHtmlTask(
|
||||
stripExtension(it.path) + '.html',
|
||||
it.toRelativeHtmlPath.apply(taskSpec),
|
||||
taskSpec,
|
||||
it,
|
||||
it.page,
|
||||
allTexts,
|
||||
allModels,
|
||||
allParts
|
||||
|
@ -1,16 +1,19 @@
|
||||
package com.jessebrault.ssg.html
|
||||
|
||||
import com.jessebrault.ssg.task.TaskSpec
|
||||
import com.jessebrault.ssg.template.Template
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
import java.util.function.Function
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@EqualsAndHashCode
|
||||
final class TextToHtmlSpec {
|
||||
final Text text
|
||||
final Template template
|
||||
final String path
|
||||
final Function<TaskSpec, String> toRelativeHtmlPath
|
||||
}
|
||||
|
@ -3,15 +3,39 @@ package com.jessebrault.ssg.html
|
||||
import com.jessebrault.ssg.buildscript.SourceProviders
|
||||
import com.jessebrault.ssg.provider.CollectionProvider
|
||||
import com.jessebrault.ssg.provider.CollectionProviders
|
||||
import com.jessebrault.ssg.task.TaskSpec
|
||||
import com.jessebrault.ssg.template.Template
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import com.jessebrault.ssg.util.ExtensionUtil
|
||||
import com.jessebrault.ssg.util.Result
|
||||
|
||||
import java.util.function.Function
|
||||
|
||||
final class TextToHtmlSpecProviders {
|
||||
|
||||
static CollectionProvider<Result<TextToHtmlSpec>> from(SourceProviders sources) {
|
||||
from(sources) { text ->
|
||||
return { TaskSpec taskSpec ->
|
||||
ExtensionUtil.stripExtension(text.path) + '.html'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static CollectionProvider<Result<TextToHtmlSpec>> from(
|
||||
SourceProviders sources,
|
||||
Function<Text, Function<TaskSpec, String>> toRelativeHtmlPath
|
||||
) {
|
||||
from(sources.textsProvider, sources.templatesProvider, toRelativeHtmlPath)
|
||||
}
|
||||
|
||||
static CollectionProvider<Result<TextToHtmlSpec>> from(
|
||||
CollectionProvider<Text> textsProvider,
|
||||
CollectionProvider<Template> templatesProvider,
|
||||
Function<Text, Function<TaskSpec, String>> toRelativeHtmlPath
|
||||
) {
|
||||
CollectionProviders.fromSupplier {
|
||||
def templates = sources.templatesProvider.provide()
|
||||
sources.textsProvider.provide().findResults {
|
||||
def templates = templatesProvider.provide()
|
||||
textsProvider.provide().findResults {
|
||||
def frontMatterResult = it.type.frontMatterGetter.get(it)
|
||||
if (frontMatterResult.hasDiagnostics()) {
|
||||
return Result.ofDiagnostics(frontMatterResult.diagnostics) as Result<TextToHtmlSpec>
|
||||
@ -22,7 +46,7 @@ final class TextToHtmlSpecProviders {
|
||||
return Result.of(new TextToHtmlSpec(
|
||||
it,
|
||||
template,
|
||||
ExtensionUtil.stripExtension(it.path) + '.html'
|
||||
toRelativeHtmlPath.apply(it)
|
||||
))
|
||||
} else {
|
||||
return null
|
||||
|
@ -12,12 +12,12 @@ import static java.util.Objects.requireNonNull
|
||||
|
||||
final class TextToHtmlTaskFactory extends AbstractRenderTaskFactory {
|
||||
|
||||
CollectionProvider<Result<TextToHtmlSpec>> specProvider = CollectionProviders.getEmpty()
|
||||
CollectionProvider<Result<TextToHtmlSpec>> specsProvider = CollectionProviders.getEmpty()
|
||||
|
||||
@Override
|
||||
Result<Collection<Task>> getTasks(TaskSpec taskSpec) {
|
||||
super.checkProviders()
|
||||
requireNonNull(this.specProvider)
|
||||
requireNonNull(this.specsProvider)
|
||||
|
||||
def allTexts = this.allTextsProvider.provide()
|
||||
def allModels = this.allModelsProvider.provide()
|
||||
@ -25,23 +25,22 @@ final class TextToHtmlTaskFactory extends AbstractRenderTaskFactory {
|
||||
|
||||
Collection<Diagnostic> diagnostics = []
|
||||
|
||||
final Collection<Task> tasks = this.specProvider.provide()
|
||||
.findResults {
|
||||
if (it.hasDiagnostics()) {
|
||||
diagnostics.addAll(it.diagnostics)
|
||||
} else {
|
||||
def spec = it.get()
|
||||
new TextToHtmlTask(
|
||||
spec.path,
|
||||
taskSpec,
|
||||
spec.text,
|
||||
spec.template,
|
||||
allTexts,
|
||||
allModels,
|
||||
allParts
|
||||
)
|
||||
}
|
||||
}
|
||||
final Collection<Task> tasks = this.specsProvider.provide().findResults {
|
||||
if (it.hasDiagnostics()) {
|
||||
diagnostics.addAll(it.diagnostics)
|
||||
} else {
|
||||
def spec = it.get()
|
||||
new TextToHtmlTask(
|
||||
spec.toRelativeHtmlPath.apply(taskSpec),
|
||||
taskSpec,
|
||||
spec.text,
|
||||
spec.template,
|
||||
allTexts,
|
||||
allModels,
|
||||
allParts
|
||||
)
|
||||
}
|
||||
}
|
||||
Result.of(diagnostics, tasks)
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package com.jessebrault.ssg.page
|
||||
|
||||
import com.jessebrault.ssg.render.RenderContext
|
||||
import com.jessebrault.ssg.render.StandardGspRenderer
|
||||
import com.jessebrault.ssg.util.Diagnostic
|
||||
import com.jessebrault.ssg.util.Result
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
@ -13,8 +12,8 @@ final class GspPageRenderer implements PageRenderer {
|
||||
|
||||
private final StandardGspRenderer gspRenderer
|
||||
|
||||
GspPageRenderer(File tmpDir, GroovyScriptEngine engine) {
|
||||
this.gspRenderer = new StandardGspRenderer(tmpDir, engine)
|
||||
GspPageRenderer(ClassLoader parentClassLoader) {
|
||||
this.gspRenderer = new StandardGspRenderer(parentClassLoader)
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,9 +1,12 @@
|
||||
package com.jessebrault.ssg.page
|
||||
|
||||
import groovy.transform.NullCheck
|
||||
|
||||
@NullCheck
|
||||
final class PageTypes {
|
||||
|
||||
static PageType getGsp(Collection<String> extensions, File tmpDir, GroovyScriptEngine engine) {
|
||||
new PageType(extensions, new GspPageRenderer(tmpDir, engine))
|
||||
static PageType getGsp(Collection<String> extensions, ClassLoader parentClassLoader) {
|
||||
new PageType(extensions, new GspPageRenderer(parentClassLoader))
|
||||
}
|
||||
|
||||
private PageTypes() {}
|
||||
|
@ -6,23 +6,34 @@ import com.jessebrault.ssg.util.ExtensionUtil
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import java.util.function.BiPredicate
|
||||
import java.util.function.Predicate
|
||||
|
||||
final class PagesProviders {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PagesProviders)
|
||||
|
||||
static CollectionProvider<Page> from(File pagesDirectory, Collection<PageType> pageTypes) {
|
||||
from(pagesDirectory, pageTypes) { file, path -> true }
|
||||
}
|
||||
|
||||
static CollectionProvider<Page> from(File pagesDirectory, Collection<PageType> pageTypes, BiPredicate<File, String> filter) {
|
||||
CollectionProviders.fromDirectory(pagesDirectory) { file, relativePath ->
|
||||
def extension = ExtensionUtil.getExtension(relativePath)
|
||||
if (extension) {
|
||||
def pageType = pageTypes.find { it.ids.contains(extension) }
|
||||
if (!pageType) {
|
||||
logger.debug('there is no PageType for file {}; skipping', file)
|
||||
return null
|
||||
if (filter.test(file, relativePath)) {
|
||||
def extension = ExtensionUtil.getExtension(relativePath)
|
||||
if (extension) {
|
||||
def pageType = pageTypes.find { it.ids.contains(extension) }
|
||||
if (!pageType) {
|
||||
logger.debug('there is no PageType for file {}; skipping', file)
|
||||
return null
|
||||
} else {
|
||||
return new Page(relativePath, pageType, file.getText())
|
||||
}
|
||||
} else {
|
||||
return new Page(relativePath, pageType, file.getText())
|
||||
logger.debug('there is no extension for file {}; skipping', file)
|
||||
return null
|
||||
}
|
||||
} else {
|
||||
logger.debug('there is no extension for file {}; skipping', file)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package com.jessebrault.ssg.part
|
||||
import com.jessebrault.ssg.render.RenderContext
|
||||
import com.jessebrault.ssg.render.StandardGspRenderer
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import com.jessebrault.ssg.util.Diagnostic
|
||||
import com.jessebrault.ssg.util.Result
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import org.jetbrains.annotations.Nullable
|
||||
@ -15,8 +14,8 @@ final class GspPartRenderer implements PartRenderer {
|
||||
|
||||
private final StandardGspRenderer gspRenderer
|
||||
|
||||
GspPartRenderer(File tmpDir, GroovyScriptEngine engine) {
|
||||
this.gspRenderer = new StandardGspRenderer(tmpDir, engine)
|
||||
GspPartRenderer(ClassLoader parentClassLoader) {
|
||||
this.gspRenderer = new StandardGspRenderer(parentClassLoader)
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,9 +1,12 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import groovy.transform.NullCheck
|
||||
|
||||
@NullCheck
|
||||
final class PartTypes {
|
||||
|
||||
static PartType getGsp(Collection<String> extensions, File tmpDir, GroovyScriptEngine engine) {
|
||||
new PartType(extensions, new GspPartRenderer(tmpDir, engine))
|
||||
static PartType getGsp(Collection<String> extensions, ClassLoader parentClassLoader) {
|
||||
new PartType(extensions, new GspPartRenderer(parentClassLoader))
|
||||
}
|
||||
|
||||
private PartTypes() {}
|
||||
|
@ -13,8 +13,8 @@ final class StandardGspRenderer {
|
||||
|
||||
private final TemplateCreator templateCreator
|
||||
|
||||
StandardGspRenderer(File tmpDir, GroovyScriptEngine engine) {
|
||||
this.templateCreator = new GroovyTemplateCreator(ExtendedGstParser::new, tmpDir, engine, true)
|
||||
StandardGspRenderer(ClassLoader parentClassLoader) {
|
||||
this.templateCreator = new GroovyTemplateCreator(ExtendedGstParser::new, parentClassLoader, true)
|
||||
}
|
||||
|
||||
Result<String> render(
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.jessebrault.ssg.template
|
||||
|
||||
import com.jessebrault.ssg.render.StandardGspRenderer
|
||||
import com.jessebrault.ssg.util.Diagnostic
|
||||
import com.jessebrault.ssg.render.RenderContext
|
||||
import com.jessebrault.ssg.util.Result
|
||||
import com.jessebrault.ssg.text.Text
|
||||
@ -14,8 +13,8 @@ final class GspTemplateRenderer implements TemplateRenderer {
|
||||
|
||||
private final StandardGspRenderer gspRenderer
|
||||
|
||||
GspTemplateRenderer(File tmpDir, GroovyScriptEngine engine) {
|
||||
this.gspRenderer = new StandardGspRenderer(tmpDir, engine)
|
||||
GspTemplateRenderer(ClassLoader parentClassLoader) {
|
||||
this.gspRenderer = new StandardGspRenderer(parentClassLoader)
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,9 +1,12 @@
|
||||
package com.jessebrault.ssg.template
|
||||
|
||||
import groovy.transform.NullCheck
|
||||
|
||||
@NullCheck
|
||||
final class TemplateTypes {
|
||||
|
||||
static TemplateType getGsp(Collection<String> extensions, File tmpDir, GroovyScriptEngine engine) {
|
||||
new TemplateType(extensions, new GspTemplateRenderer(tmpDir, engine))
|
||||
static TemplateType getGsp(Collection<String> extensions, ClassLoader parentClassLoader) {
|
||||
new TemplateType(extensions, new GspTemplateRenderer(parentClassLoader))
|
||||
}
|
||||
|
||||
private TemplateTypes() {}
|
||||
|
@ -1,14 +1,10 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.buildscript.BuildScriptBase
|
||||
import com.jessebrault.ssg.buildscript.BuildScriptConfiguratorFactory
|
||||
import com.jessebrault.ssg.util.ResourceUtil
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import java.util.function.Consumer
|
||||
|
||||
import static com.jessebrault.ssg.util.FileAssertions.assertFileStructureAndContents
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue
|
||||
|
||||
@ -32,19 +28,17 @@ final class BuildScriptBasedStaticSiteGeneratorTests {
|
||||
}
|
||||
}
|
||||
|
||||
def tmpDir = File.createTempDir()
|
||||
def engine = new GroovyScriptEngine([sourceDir.toURI().toURL(), tmpDir.toURI().toURL()] as URL[])
|
||||
def ssg = new BuildScriptBasedStaticSiteGenerator(engine, [new BuildScriptConfiguratorFactory() {
|
||||
def ssg = new BuildScriptBasedStaticSiteGenerator([sourceDir.toURI().toURL()], buildScript)
|
||||
|
||||
@Override
|
||||
Consumer<BuildScriptBase> get() {
|
||||
return { }
|
||||
}
|
||||
|
||||
}], buildScript, [sourceDir: sourceDir, tmpDir: tmpDir, engine: engine])
|
||||
assertTrue(ssg.doBuild('test') {
|
||||
it.each { logger.error(it.toString()) }
|
||||
})
|
||||
assertTrue(
|
||||
ssg.doBuild(
|
||||
'test',
|
||||
[],
|
||||
[sourceDir: sourceDir, gclSupplier: ssg::getBuildScriptClassLoader]
|
||||
) {
|
||||
it.each { logger.error(it.toString()) }
|
||||
}
|
||||
)
|
||||
|
||||
def expectedBase = File.createTempDir()
|
||||
new File(expectedBase, 'hello.html').tap {
|
||||
|
@ -10,189 +10,179 @@ import org.mockito.junit.jupiter.MockitoExtension
|
||||
import java.util.function.Consumer
|
||||
import java.util.function.Function
|
||||
|
||||
import static com.jessebrault.ssg.buildscript.BuildScripts.runBuildScript
|
||||
import static BuildScriptRunner.runClosureScript
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
import static org.mockito.Mockito.verify
|
||||
|
||||
@NullCheck
|
||||
@ExtendWith(MockitoExtension)
|
||||
final class BuildScriptsTests {
|
||||
|
||||
@NullCheck
|
||||
@ExtendWith(MockitoExtension)
|
||||
static final class ScriptFileTests {
|
||||
|
||||
/**
|
||||
* Must be non-static, otherwise Groovy gets confused inside the Closures.
|
||||
*
|
||||
* TODO: use the FileUtil.copyResourceToWriter method
|
||||
*/
|
||||
@SuppressWarnings('GrMethodMayBeStatic')
|
||||
private void copyLocalResourceToWriter(String name, Writer target) {
|
||||
BuildScriptsTests.getResourceAsStream(name).withReader {
|
||||
it.transferTo(target)
|
||||
}
|
||||
/**
|
||||
* Must be non-static, otherwise Groovy gets confused inside the Closures.
|
||||
*
|
||||
* TODO: use the FileUtil.copyResourceToWriter method
|
||||
*/
|
||||
@SuppressWarnings('GrMethodMayBeStatic')
|
||||
private void copyLocalResourceToWriter(String name, Writer target) {
|
||||
BuildScriptsTests.getResourceAsStream(name).withReader {
|
||||
it.transferTo(target)
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be non-static, otherwise Groovy gets confused inside the Closures.
|
||||
*/
|
||||
@SuppressWarnings('GrMethodMayBeStatic')
|
||||
private File setupScripts(Collection<String> resourceNames) {
|
||||
def tempDir = File.createTempDir()
|
||||
new FileTreeBuilder(tempDir).tap {
|
||||
resourceNames.each { String resourceName ->
|
||||
file(resourceName).withWriter {
|
||||
this.copyLocalResourceToWriter(resourceName, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
tempDir
|
||||
}
|
||||
|
||||
private static Collection<Build> getBuilds(
|
||||
String scriptName,
|
||||
Collection<URL> urls,
|
||||
Map<String, Object> binding = [:],
|
||||
Consumer<BuildScriptBase> configureBase = { }
|
||||
) {
|
||||
runBuildScript(scriptName, new GroovyScriptEngine(urls as URL[]), binding, configureBase)
|
||||
}
|
||||
|
||||
@Test
|
||||
void simpleScript() {
|
||||
def baseDir = this.setupScripts(['simple.groovy'])
|
||||
def builds = getBuilds('simple.groovy', [baseDir.toURI().toURL()])
|
||||
assertEquals(1, builds.size())
|
||||
assertEquals('test', builds[0].name)
|
||||
}
|
||||
|
||||
@Test
|
||||
void testImport() {
|
||||
def baseDir = this.setupScripts(['testImport.groovy', 'TestHtmlTask.groovy'])
|
||||
def builds = getBuilds('testImport.groovy', [baseDir.toURI().toURL()])
|
||||
assertEquals(1, builds.size())
|
||||
assertEquals('test', builds[0].name)
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildSrcTest() {
|
||||
def baseDir = File.createTempDir()
|
||||
new FileTreeBuilder(baseDir).tap {
|
||||
file('buildSrcTest.groovy').withWriter {
|
||||
this.copyLocalResourceToWriter('buildSrcTest.groovy', it)
|
||||
}
|
||||
dir('buildSrc') {
|
||||
file('AnotherTask.groovy').withWriter {
|
||||
this.copyLocalResourceToWriter('buildSrc/AnotherTask.groovy', it)
|
||||
}
|
||||
}
|
||||
}
|
||||
def builds = getBuilds(
|
||||
'buildSrcTest.groovy',
|
||||
[
|
||||
baseDir.toURI().toURL(),
|
||||
new File(baseDir, 'buildSrc').toURI().toURL()
|
||||
]
|
||||
)
|
||||
assertEquals(1, builds.size())
|
||||
assertEquals('test', builds[0].name)
|
||||
}
|
||||
|
||||
@Test
|
||||
void withBinding(@Mock Consumer<String> stringConsumer) {
|
||||
def baseDir = this.setupScripts(['withBinding.groovy'])
|
||||
def engine = new GroovyScriptEngine([baseDir.toURI().toURL()] as URL[])
|
||||
runBuildScript('withBinding.groovy', engine, [stringConsumer: stringConsumer])
|
||||
verify(stringConsumer).accept('test')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ExtendWith(MockitoExtension)
|
||||
static final class ClosureScriptTests {
|
||||
|
||||
@Test
|
||||
void simple() {
|
||||
def result = runBuildScript {
|
||||
build(name: 'test') { }
|
||||
}
|
||||
assertEquals(1, result.size())
|
||||
assertEquals('test', result[0].name)
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneBuildOutputDirWithFunction(@Mock Function<Build, OutputDir> mockOutputDirFunction) {
|
||||
def r = runBuildScript {
|
||||
build(name: 'test') {
|
||||
outputDirFunction = mockOutputDirFunction
|
||||
/**
|
||||
* Must be non-static, otherwise Groovy gets confused inside the Closures.
|
||||
*/
|
||||
@SuppressWarnings('GrMethodMayBeStatic')
|
||||
private File setupScripts(Collection<String> resourceNames) {
|
||||
def tempDir = File.createTempDir()
|
||||
new FileTreeBuilder(tempDir).tap {
|
||||
resourceNames.each { String resourceName ->
|
||||
file(resourceName).withWriter {
|
||||
this.copyLocalResourceToWriter(resourceName, it)
|
||||
}
|
||||
}
|
||||
assertEquals(1, r.size())
|
||||
def b0 = r[0]
|
||||
assertEquals(mockOutputDirFunction, b0.outputDirFunction)
|
||||
}
|
||||
tempDir
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneBuildOutputDirWithFile() {
|
||||
def f = new File('test')
|
||||
def r = runBuildScript {
|
||||
build(name: 'test') {
|
||||
outputDir = f
|
||||
private static Collection<Build> getBuilds(
|
||||
String scriptName,
|
||||
Collection<URL> urls,
|
||||
Map<String, Object> binding = [:],
|
||||
Consumer<BuildScriptBase> configureBase = { }
|
||||
) {
|
||||
new BuildScriptRunner(urls).runBuildScript(scriptName, binding, configureBase)
|
||||
}
|
||||
|
||||
@Test
|
||||
void simpleScript() {
|
||||
def baseDir = this.setupScripts(['simple.groovy'])
|
||||
def builds = getBuilds('simple.groovy', [baseDir.toURI().toURL()])
|
||||
assertEquals(1, builds.size())
|
||||
assertEquals('test', builds[0].name)
|
||||
}
|
||||
|
||||
@Test
|
||||
void testImport() {
|
||||
def baseDir = this.setupScripts(['testImport.groovy', 'TestHtmlTask.groovy'])
|
||||
def builds = getBuilds('testImport.groovy', [baseDir.toURI().toURL()])
|
||||
assertEquals(1, builds.size())
|
||||
assertEquals('test', builds[0].name)
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildSrcTest() {
|
||||
def baseDir = File.createTempDir()
|
||||
new FileTreeBuilder(baseDir).tap {
|
||||
file('buildSrcTest.groovy').withWriter {
|
||||
this.copyLocalResourceToWriter('buildSrcTest.groovy', it)
|
||||
}
|
||||
dir('buildSrc') {
|
||||
file('AnotherTask.groovy').withWriter {
|
||||
this.copyLocalResourceToWriter('buildSrc/AnotherTask.groovy', it)
|
||||
}
|
||||
}
|
||||
assertEquals(1, r.size())
|
||||
def b0 = r[0]
|
||||
assertEquals(f, b0.outputDirFunction.apply(b0) as File)
|
||||
}
|
||||
def builds = getBuilds(
|
||||
'buildSrcTest.groovy',
|
||||
[
|
||||
baseDir.toURI().toURL(),
|
||||
new File(baseDir, 'buildSrc').toURI().toURL()
|
||||
]
|
||||
)
|
||||
assertEquals(1, builds.size())
|
||||
assertEquals('test', builds[0].name)
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneBuildOutputDirWithString() {
|
||||
def r = runBuildScript {
|
||||
build(name: 'test') {
|
||||
outputDir = 'test'
|
||||
@Test
|
||||
void withBinding(@Mock Consumer<String> stringConsumer) {
|
||||
def baseDir = this.setupScripts(['withBinding.groovy'])
|
||||
getBuilds('withBinding.groovy', [baseDir.toURI().toURL()], [stringConsumer: stringConsumer])
|
||||
verify(stringConsumer).accept('test')
|
||||
}
|
||||
|
||||
@Test
|
||||
void simple() {
|
||||
def result = runClosureScript {
|
||||
build(name: 'test') { }
|
||||
}
|
||||
assertEquals(1, result.size())
|
||||
assertEquals('test', result[0].name)
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneBuildOutputDirWithFunction(@Mock Function<Build, OutputDir> mockOutputDirFunction) {
|
||||
def r = runClosureScript {
|
||||
build(name: 'test') {
|
||||
outputDirFunction = mockOutputDirFunction
|
||||
}
|
||||
}
|
||||
assertEquals(1, r.size())
|
||||
def b0 = r[0]
|
||||
assertEquals(mockOutputDirFunction, b0.outputDirFunction)
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneBuildOutputDirWithFile() {
|
||||
def f = new File('test')
|
||||
def r = runClosureScript {
|
||||
build(name: 'test') {
|
||||
outputDir = f
|
||||
}
|
||||
}
|
||||
assertEquals(1, r.size())
|
||||
def b0 = r[0]
|
||||
assertEquals(f, b0.outputDirFunction.apply(b0) as File)
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneBuildOutputDirWithString() {
|
||||
def r = runClosureScript {
|
||||
build(name: 'test') {
|
||||
outputDir = 'test'
|
||||
}
|
||||
}
|
||||
assertEquals(1, r.size())
|
||||
def b0 = r[0]
|
||||
assertEquals('test', b0.outputDirFunction.apply(b0) as String)
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneBuildSiteSpec() {
|
||||
def r = runClosureScript {
|
||||
build(name: 'test') {
|
||||
siteSpec {
|
||||
name = 'testSite'
|
||||
baseUrl = 'https://testsite.com'
|
||||
}
|
||||
}
|
||||
assertEquals(1, r.size())
|
||||
def b0 = r[0]
|
||||
assertEquals('test', b0.outputDirFunction.apply(b0) as String)
|
||||
}
|
||||
assertEquals(1, r.size())
|
||||
def b0 = r[0]
|
||||
assertEquals(new SiteSpec('testSite', 'https://testsite.com'), b0.siteSpec)
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneBuildSiteSpec() {
|
||||
def r = runBuildScript {
|
||||
build(name: 'test') {
|
||||
siteSpec {
|
||||
name = 'testSite'
|
||||
baseUrl = 'https://testsite.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
assertEquals(1, r.size())
|
||||
def b0 = r[0]
|
||||
assertEquals(new SiteSpec('testSite', 'https://testsite.com'), b0.siteSpec)
|
||||
}
|
||||
|
||||
@Test
|
||||
void oneBuildWithAbstractParent() {
|
||||
def r = runBuildScript {
|
||||
abstractBuild(name: 'parent') {
|
||||
siteSpec {
|
||||
name = 'Test Site'
|
||||
baseUrl = 'https://test.com'
|
||||
}
|
||||
}
|
||||
|
||||
build(name: 'child', extending: 'parent') {
|
||||
siteSpec { base ->
|
||||
baseUrl = base.baseUrl + '/child'
|
||||
}
|
||||
@Test
|
||||
void oneBuildWithAbstractParent() {
|
||||
def r = runClosureScript {
|
||||
abstractBuild(name: 'parent') {
|
||||
siteSpec {
|
||||
name = 'Test Site'
|
||||
baseUrl = 'https://test.com'
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(1, r.size())
|
||||
def b0 = r[0]
|
||||
assertEquals(new SiteSpec('Test Site', 'https://test.com/child'), b0.siteSpec)
|
||||
build(name: 'child', extending: 'parent') {
|
||||
siteSpec { base ->
|
||||
baseUrl = base.baseUrl + '/child'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(1, r.size())
|
||||
def b0 = r[0]
|
||||
assertEquals(new SiteSpec('Test Site', 'https://test.com/child'), b0.siteSpec)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,17 +7,14 @@ import com.jessebrault.ssg.util.Result
|
||||
final class GspPageRendererTests implements StandardDslConsumerTests {
|
||||
|
||||
private static GspPageRenderer getRenderer(
|
||||
ClassLoader classLoader,
|
||||
Collection<URL> urls
|
||||
ClassLoader parentClassLoader = GspPageRendererTests.classLoader
|
||||
) {
|
||||
def tmpDir = File.createTempDir()
|
||||
def engine = new GroovyScriptEngine([tmpDir.toURI().toURL(), *urls] as URL[], classLoader)
|
||||
new GspPageRenderer(tmpDir, engine)
|
||||
new GspPageRenderer(parentClassLoader)
|
||||
}
|
||||
|
||||
@Override
|
||||
Result<String> render(String scriptlet, RenderContext context, ClassLoader classLoader, Collection<URL> urls) {
|
||||
def renderer = getRenderer(classLoader, urls)
|
||||
Result<String> render(String scriptlet, RenderContext context, ClassLoader classLoader) {
|
||||
def renderer = getRenderer(classLoader)
|
||||
renderer.render(
|
||||
new Page('', new PageType([], renderer), scriptlet),
|
||||
context
|
||||
|
@ -14,13 +14,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue
|
||||
|
||||
final class GspPartRendererTests implements StandardDslConsumerTests {
|
||||
|
||||
private static GspPartRenderer getRenderer(
|
||||
ClassLoader parentClassLoader = GspPartRendererTests.classLoader,
|
||||
Collection<URL> urls = []
|
||||
) {
|
||||
def tmpDir = File.createTempDir()
|
||||
def engine = new GroovyScriptEngine([tmpDir.toURI().toURL(), *urls] as URL[], parentClassLoader)
|
||||
new GspPartRenderer(tmpDir, engine)
|
||||
private static GspPartRenderer getRenderer(ClassLoader parentClassLoader = GspPartRendererTests.classLoader) {
|
||||
new GspPartRenderer(parentClassLoader)
|
||||
}
|
||||
|
||||
private static Result<String> doRender(
|
||||
@ -28,10 +23,9 @@ final class GspPartRendererTests implements StandardDslConsumerTests {
|
||||
RenderContext context,
|
||||
Map binding = [:],
|
||||
@Nullable Text text = null,
|
||||
ClassLoader classLoader = GspPartRendererTests.classLoader,
|
||||
Collection<URL> urls = []
|
||||
ClassLoader classLoader = GspPartRendererTests.classLoader
|
||||
) {
|
||||
def renderer = getRenderer(classLoader, urls)
|
||||
def renderer = getRenderer(classLoader)
|
||||
renderer.render(
|
||||
new Part('', new PartType([], renderer), scriptlet),
|
||||
binding,
|
||||
@ -41,8 +35,8 @@ final class GspPartRendererTests implements StandardDslConsumerTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
Result<String> render(String scriptlet, RenderContext context, ClassLoader classLoader, Collection<URL> urls) {
|
||||
doRender(scriptlet, context, [:], null, classLoader, urls)
|
||||
Result<String> render(String scriptlet, RenderContext context, ClassLoader classLoader) {
|
||||
doRender(scriptlet, context, [:], null, classLoader)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -13,29 +13,23 @@ import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
|
||||
final class GspTemplateRendererTests implements StandardDslConsumerTests {
|
||||
|
||||
private static TemplateRenderer getRenderer(
|
||||
ClassLoader parentLoader = GspTemplateRendererTests.class.classLoader,
|
||||
Collection<URL> urls = []
|
||||
) {
|
||||
def tmpDir = File.createTempDir()
|
||||
def engine = new GroovyScriptEngine([tmpDir.toURI().toURL(), *urls] as URL[], parentLoader)
|
||||
new GspTemplateRenderer(tmpDir, engine)
|
||||
private static TemplateRenderer getRenderer(ClassLoader parentClassLoader = GspTemplateRendererTests.classLoader) {
|
||||
new GspTemplateRenderer(parentClassLoader)
|
||||
}
|
||||
|
||||
private static Result<String> doRender(
|
||||
String scriptlet,
|
||||
Text text,
|
||||
RenderContext context,
|
||||
ClassLoader classLoader,
|
||||
Collection<URL> urls
|
||||
ClassLoader classLoader
|
||||
) {
|
||||
def renderer = getRenderer(classLoader, urls)
|
||||
def renderer = getRenderer(classLoader)
|
||||
renderer.render(new Template('', new TemplateType([], renderer), scriptlet), text, context)
|
||||
}
|
||||
|
||||
@Override
|
||||
Result<String> render(String scriptlet, RenderContext context, ClassLoader classLoader, Collection<URL> urls) {
|
||||
doRender(scriptlet, blankText(), context, classLoader, urls)
|
||||
Result<String> render(String scriptlet, RenderContext context, ClassLoader classLoader) {
|
||||
doRender(scriptlet, blankText(), context, classLoader)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -9,13 +9,14 @@ import com.jessebrault.ssg.text.TextTypes
|
||||
import com.jessebrault.ssg.text.TextsProviders
|
||||
import groovy.transform.BaseScript
|
||||
|
||||
import java.util.function.Supplier
|
||||
|
||||
@BaseScript
|
||||
BuildScriptBase b
|
||||
|
||||
final class Args {
|
||||
File sourceDir
|
||||
File tmpDir
|
||||
GroovyScriptEngine engine
|
||||
Supplier<GroovyClassLoader> gclSupplier
|
||||
}
|
||||
|
||||
def args = args as Args
|
||||
@ -25,7 +26,7 @@ build(name: 'test') {
|
||||
|
||||
types {
|
||||
textTypes << TextTypes.MARKDOWN
|
||||
templateTypes << TemplateTypes.getGsp(['.gsp'], args.tmpDir, args.engine)
|
||||
templateTypes << TemplateTypes.getGsp(['.gsp'], args.gclSupplier.get())
|
||||
}
|
||||
|
||||
sources { base, types ->
|
||||
@ -35,7 +36,7 @@ build(name: 'test') {
|
||||
|
||||
taskFactories { base, sources ->
|
||||
register('textToHtml', TextToHtmlTaskFactory::new) {
|
||||
it.specProvider += TextToHtmlSpecProviders.from(sources)
|
||||
it.specsProvider += TextToHtmlSpecProviders.from(sources)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ import static org.mockito.Mockito.*
|
||||
@ExtendWith(MockitoExtension)
|
||||
interface StandardDslConsumerTests {
|
||||
|
||||
Result<String> render(String scriptlet, RenderContext context, ClassLoader classLoader, Collection<URL> urls)
|
||||
Result<String> render(String scriptlet, RenderContext context, ClassLoader classLoader)
|
||||
|
||||
default void checkResult(String expected, Result<String> result) {
|
||||
assertEmptyDiagnostics(result)
|
||||
@ -44,21 +44,19 @@ interface StandardDslConsumerTests {
|
||||
String expected,
|
||||
String scriptlet,
|
||||
RenderContext context = new RenderContext(),
|
||||
ClassLoader classLoader = this.class.classLoader,
|
||||
Collection<URL> urls = []
|
||||
ClassLoader classLoader = this.class.classLoader
|
||||
) {
|
||||
this.checkResult(expected, this.render(scriptlet, context, classLoader, urls))
|
||||
this.checkResult(expected, this.render(scriptlet, context, classLoader))
|
||||
}
|
||||
|
||||
default void doDslAssertionTest(
|
||||
String scriptlet,
|
||||
RenderContext context = new RenderContext(),
|
||||
ClassLoader classLoader = this.class.classLoader,
|
||||
Collection<URL> urls = []
|
||||
ClassLoader classLoader = this.class.classLoader
|
||||
) {
|
||||
Result<String> result = null
|
||||
try {
|
||||
result = this.render(scriptlet, context, classLoader, urls)
|
||||
result = this.render(scriptlet, context, classLoader)
|
||||
} catch (Throwable e) {
|
||||
fail(e)
|
||||
}
|
||||
@ -279,12 +277,13 @@ interface StandardDslConsumerTests {
|
||||
['com', 'jessebrault', 'ssg', 'tmp'],
|
||||
greeterText
|
||||
)
|
||||
def configuredClassLoader = new GroovyClassLoader(this.class.classLoader)
|
||||
configuredClassLoader.addURL(greeterBaseUrl)
|
||||
this.doDslRenderTest(
|
||||
"Hello, World!",
|
||||
"<%@ import com.jessebrault.ssg.tmp.TmpGreeter %><%= new TmpGreeter().greet() %>",
|
||||
new RenderContext(),
|
||||
parentClassLoader,
|
||||
[greeterBaseUrl]
|
||||
configuredClassLoader
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.buildscript.BuildScriptConfiguratorFactory
|
||||
import com.jessebrault.ssg.util.Diagnostic
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.Logger
|
||||
@ -37,23 +38,32 @@ abstract class AbstractBuildCommand extends AbstractSubCommand {
|
||||
)
|
||||
Collection<String> requestedBuilds = ['default']
|
||||
|
||||
protected StaticSiteGenerator staticSiteGenerator = null
|
||||
protected CliBasedStaticSiteGenerator staticSiteGenerator = null
|
||||
|
||||
protected final Integer doSingleBuild(String requestedBuild, File tmpDir, GroovyScriptEngine engine) {
|
||||
protected final Integer doSingleBuild(
|
||||
String requestedBuild,
|
||||
Collection<BuildScriptConfiguratorFactory> configuratorFactories,
|
||||
Map<String, Object> buildScriptBinding
|
||||
) {
|
||||
logger.traceEntry('requestedBuild: {}', requestedBuild)
|
||||
|
||||
if (this.staticSiteGenerator == null) {
|
||||
this.staticSiteGenerator = new CliBasedStaticSiteGenerator(
|
||||
new File('.'),
|
||||
this.buildScript,
|
||||
tmpDir,
|
||||
engine,
|
||||
this.scriptArgs
|
||||
[
|
||||
this.buildScript.parentFile.toURI().toURL(),
|
||||
*this.buildSrcDirs.collect { it.toURI().toURL() }
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
final Collection<Diagnostic> diagnostics = []
|
||||
if (!this.staticSiteGenerator.doBuild(requestedBuild, diagnostics.&addAll)) {
|
||||
if (!this.staticSiteGenerator.doBuild(
|
||||
requestedBuild,
|
||||
configuratorFactories,
|
||||
buildScriptBinding,
|
||||
diagnostics.&addAll
|
||||
)) {
|
||||
diagnostics.each { logger.warn(it) }
|
||||
logger.traceExit(1)
|
||||
} else {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.buildscript.DefaultBuildScriptConfiguratorFactory
|
||||
import com.jessebrault.ssg.buildscript.BuildScriptConfiguratorFactory
|
||||
import com.jessebrault.ssg.util.Diagnostic
|
||||
import groovy.transform.PackageScope
|
||||
|
||||
@ -9,40 +9,43 @@ import java.util.function.Consumer
|
||||
@PackageScope
|
||||
final class CliBasedStaticSiteGenerator implements StaticSiteGenerator {
|
||||
|
||||
private final File baseDir
|
||||
private final File buildScript
|
||||
private final File tmpDir
|
||||
private final Map<String, String> scriptArgs
|
||||
private final GroovyScriptEngine engine
|
||||
private final Collection<URL> buildScriptClassLoaderUrls
|
||||
|
||||
private StaticSiteGenerator staticSiteGenerator
|
||||
private BuildScriptBasedStaticSiteGenerator delegate
|
||||
|
||||
/**
|
||||
* @param buildScript The buildScript File.
|
||||
* @param buildScriptClassLoaderUrls all the necessary urls to needed to run the given buildScript.
|
||||
* Likely includes the parent directory of the buildScript, as well as buildSrc dir(s).
|
||||
*/
|
||||
CliBasedStaticSiteGenerator(
|
||||
File baseDir,
|
||||
File buildScript,
|
||||
File tmpDir,
|
||||
GroovyScriptEngine engine,
|
||||
Map<String, String> scriptArgs
|
||||
Collection<URL> buildScriptClassLoaderUrls
|
||||
) {
|
||||
this.baseDir = baseDir
|
||||
this.buildScript = buildScript
|
||||
this.tmpDir = tmpDir
|
||||
this.scriptArgs = scriptArgs
|
||||
this.engine = engine
|
||||
this.buildScriptClassLoaderUrls = buildScriptClassLoaderUrls
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean doBuild(String buildName, Consumer<Collection<Diagnostic>> diagnosticsConsumer) {
|
||||
if (this.staticSiteGenerator == null) {
|
||||
this.staticSiteGenerator = new BuildScriptBasedStaticSiteGenerator(
|
||||
this.engine,
|
||||
[new DefaultBuildScriptConfiguratorFactory(this.baseDir, this.tmpDir, this.engine)],
|
||||
this.buildScript,
|
||||
this.scriptArgs
|
||||
boolean doBuild(
|
||||
String buildName,
|
||||
Collection<BuildScriptConfiguratorFactory> configuratorFactories,
|
||||
Map<String, Object> buildScriptArgs,
|
||||
Consumer<Collection<Diagnostic>> diagnosticsConsumer
|
||||
) {
|
||||
if (this.delegate == null) {
|
||||
this.delegate = new BuildScriptBasedStaticSiteGenerator(
|
||||
this.buildScriptClassLoaderUrls,
|
||||
this.buildScript
|
||||
)
|
||||
}
|
||||
|
||||
this.staticSiteGenerator.doBuild(buildName, diagnosticsConsumer)
|
||||
this.delegate.doBuild(buildName, configuratorFactories, buildScriptArgs, diagnosticsConsumer)
|
||||
}
|
||||
|
||||
GroovyClassLoader getBuildScriptClassLoader() {
|
||||
this.delegate.buildScriptClassLoader
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.buildscript.DefaultBuildScriptConfiguratorFactory
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.Logger
|
||||
import picocli.CommandLine
|
||||
@ -17,13 +18,15 @@ final class SsgBuild extends AbstractBuildCommand {
|
||||
protected Integer doSubCommand() {
|
||||
logger.traceEntry()
|
||||
def result = 0
|
||||
def tmpDir = File.createTempDir()
|
||||
def urls = [tmpDir, *this.buildSrcDirs, new File('.')].collect {
|
||||
it.toURI().toURL()
|
||||
} as URL[]
|
||||
def engine = new GroovyScriptEngine(urls)
|
||||
this.requestedBuilds.each {
|
||||
def buildResult = this.doSingleBuild(it, tmpDir, engine)
|
||||
def buildResult = this.doSingleBuild(
|
||||
it,
|
||||
[new DefaultBuildScriptConfiguratorFactory(
|
||||
new File('.'),
|
||||
this.staticSiteGenerator::getBuildScriptClassLoader
|
||||
)],
|
||||
this.scriptArgs
|
||||
)
|
||||
if (buildResult == 1) {
|
||||
result = 1
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.buildscript.DefaultBuildScriptConfiguratorFactory
|
||||
import com.jessebrault.ssg.util.Diagnostic
|
||||
import com.jessebrault.ssg.util.ResourceUtil
|
||||
import org.junit.jupiter.api.Test
|
||||
@ -14,20 +15,17 @@ final class CliBasedStaticSiteGeneratorTests {
|
||||
def baseDir = File.createTempDir()
|
||||
SsgInit.init(baseDir, true)
|
||||
|
||||
def tmpDir = File.createTempDir()
|
||||
def engine = new GroovyScriptEngine([
|
||||
new File(baseDir, 'buildSrc').toURI().toURL(),
|
||||
tmpDir.toURI().toURL()
|
||||
] as URL[])
|
||||
def ssg = new CliBasedStaticSiteGenerator(
|
||||
baseDir,
|
||||
new File(baseDir, 'ssgBuilds.groovy'),
|
||||
tmpDir,
|
||||
engine,
|
||||
[:]
|
||||
)
|
||||
def groovyClassLoader = new GroovyClassLoader()
|
||||
[baseDir.toURI().toURL(), new File(baseDir, 'buildSrc').toURI().toURL()]
|
||||
.each(groovyClassLoader::addURL)
|
||||
|
||||
def ssg = new CliBasedStaticSiteGenerator(new File(baseDir, 'ssgBuilds.groovy'), [])
|
||||
def configuratorFactories = [
|
||||
new DefaultBuildScriptConfiguratorFactory(baseDir, ssg::getBuildScriptClassLoader)
|
||||
]
|
||||
|
||||
def diagnostics = [] as Collection<Diagnostic>
|
||||
assertTrue(ssg.doBuild('production', diagnostics.&addAll), {
|
||||
assertTrue(ssg.doBuild('production', configuratorFactories, [:], diagnostics.&addAll), {
|
||||
diagnostics.inject('') { acc, diagnostic ->
|
||||
acc + '\n' + diagnostic.message
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user