Major refactoring and introduction of Task model.
This commit is contained in:
parent
107f394b82
commit
92c810870c
@ -8,6 +8,7 @@ import com.jessebrault.ssg.part.PartType
|
|||||||
import com.jessebrault.ssg.specialpage.GspSpecialPageRenderer
|
import com.jessebrault.ssg.specialpage.GspSpecialPageRenderer
|
||||||
import com.jessebrault.ssg.specialpage.SpecialPageFileSpecialPagesProvider
|
import com.jessebrault.ssg.specialpage.SpecialPageFileSpecialPagesProvider
|
||||||
import com.jessebrault.ssg.specialpage.SpecialPageType
|
import com.jessebrault.ssg.specialpage.SpecialPageType
|
||||||
|
import com.jessebrault.ssg.task.TaskExecutorContext
|
||||||
import com.jessebrault.ssg.template.GspTemplateRenderer
|
import com.jessebrault.ssg.template.GspTemplateRenderer
|
||||||
import com.jessebrault.ssg.template.TemplateFileTemplatesProvider
|
import com.jessebrault.ssg.template.TemplateFileTemplatesProvider
|
||||||
import com.jessebrault.ssg.template.TemplateType
|
import com.jessebrault.ssg.template.TemplateType
|
||||||
@ -80,16 +81,28 @@ abstract class AbstractBuildCommand extends AbstractSubCommand {
|
|||||||
// Do each build
|
// Do each build
|
||||||
this.builds.each {
|
this.builds.each {
|
||||||
def result = this.ssg.generate(it)
|
def result = this.ssg.generate(it)
|
||||||
if (result.v1.size() > 0) {
|
if (result.hasDiagnostics()) {
|
||||||
hadDiagnostics = true
|
hadDiagnostics = true
|
||||||
result.v1.each {
|
result.diagnostics.each {
|
||||||
logger.error(it.message)
|
logger.error(it.message)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.v2.each { Output output ->
|
def tasks = result.get()
|
||||||
def target = new File(it.outDir, output.meta.targetPath)
|
Collection<Diagnostic> executionDiagnostics = []
|
||||||
target.createParentDirectories()
|
def context = new TaskExecutorContext(
|
||||||
target.write(output.content)
|
it,
|
||||||
|
tasks,
|
||||||
|
null,
|
||||||
|
{ Collection<Diagnostic> diagnostics ->
|
||||||
|
executionDiagnostics.addAll(diagnostics)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
result.get().each { it.execute(context) }
|
||||||
|
if (!executionDiagnostics.isEmpty()) {
|
||||||
|
hadDiagnostics = true
|
||||||
|
executionDiagnostics.each {
|
||||||
|
logger.error(it.message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
lib/src/main/groovy/com/jessebrault/ssg/Result.groovy
Normal file
28
lib/src/main/groovy/com/jessebrault/ssg/Result.groovy
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package com.jessebrault.ssg
|
||||||
|
|
||||||
|
import groovy.transform.EqualsAndHashCode
|
||||||
|
import groovy.transform.NullCheck
|
||||||
|
import groovy.transform.TupleConstructor
|
||||||
|
|
||||||
|
@TupleConstructor(defaults = false, includeFields = true)
|
||||||
|
@NullCheck(includeGenerated = true)
|
||||||
|
@EqualsAndHashCode
|
||||||
|
final class Result<T> {
|
||||||
|
|
||||||
|
final Collection<Diagnostic> diagnostics
|
||||||
|
private final T t
|
||||||
|
|
||||||
|
boolean hasDiagnostics() {
|
||||||
|
!this.diagnostics.isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
T get() {
|
||||||
|
this.t
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String toString() {
|
||||||
|
"Result(diagnostics: ${ this.diagnostics }, t: ${ this.t })"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,25 +1,15 @@
|
|||||||
package com.jessebrault.ssg
|
package com.jessebrault.ssg
|
||||||
|
|
||||||
import com.jessebrault.ssg.renderer.RenderContext
|
import com.jessebrault.ssg.task.SpecialPageToHtmlFileTaskFactory
|
||||||
import com.jessebrault.ssg.specialpage.SpecialPage
|
import com.jessebrault.ssg.task.TaskContainer
|
||||||
import com.jessebrault.ssg.task.Output
|
import com.jessebrault.ssg.task.TextToHtmlFileTaskFactory
|
||||||
import com.jessebrault.ssg.task.OutputMeta
|
|
||||||
import com.jessebrault.ssg.task.OutputMetaMap
|
|
||||||
import com.jessebrault.ssg.text.FrontMatter
|
|
||||||
import com.jessebrault.ssg.text.Text
|
|
||||||
import groovy.transform.EqualsAndHashCode
|
|
||||||
import groovy.transform.NullCheck
|
import groovy.transform.NullCheck
|
||||||
import groovy.transform.TupleConstructor
|
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.slf4j.Marker
|
import org.slf4j.Marker
|
||||||
import org.slf4j.MarkerFactory
|
import org.slf4j.MarkerFactory
|
||||||
|
|
||||||
import static com.jessebrault.ssg.util.ExtensionsUtil.stripExtension
|
|
||||||
|
|
||||||
@TupleConstructor(includeFields = true)
|
|
||||||
@NullCheck
|
@NullCheck
|
||||||
@EqualsAndHashCode(includeFields = true)
|
|
||||||
class SimpleStaticSiteGenerator implements StaticSiteGenerator {
|
class SimpleStaticSiteGenerator implements StaticSiteGenerator {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(SimpleStaticSiteGenerator)
|
private static final Logger logger = LoggerFactory.getLogger(SimpleStaticSiteGenerator)
|
||||||
@ -27,128 +17,25 @@ class SimpleStaticSiteGenerator implements StaticSiteGenerator {
|
|||||||
private static final Marker exit = MarkerFactory.getMarker('EXIT')
|
private static final Marker exit = MarkerFactory.getMarker('EXIT')
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Tuple2<Collection<Diagnostic>, Collection<Output>> generate(Build build) {
|
Result<TaskContainer> generate(Build build) {
|
||||||
logger.trace(enter, 'build: {}', build)
|
logger.trace(enter, 'build: {}', build)
|
||||||
logger.info('processing build with name: {}', build.name)
|
logger.info('processing build with name: {}', build.name)
|
||||||
|
|
||||||
def config = build.config
|
def tasks = new TaskContainer()
|
||||||
def siteSpec = build.siteSpec
|
def diagnostics = []
|
||||||
|
|
||||||
// Get all texts, templates, parts, and specialPages
|
def textToHtmlFactory = new TextToHtmlFileTaskFactory()
|
||||||
def texts = config.textProviders.collectMany { it.provide() }
|
def textsResult = textToHtmlFactory.getTasks(build)
|
||||||
def templates = config.templatesProviders.collectMany { it.provide() }
|
tasks.addAll(textsResult.get())
|
||||||
def parts = config.partsProviders.collectMany { it.provide() }
|
diagnostics.addAll(textsResult.diagnostics)
|
||||||
def specialPages = config.specialPagesProviders.collectMany { it.provide() }
|
|
||||||
|
|
||||||
logger.debug('\n\ttexts: {}\n\ttemplates: {}\n\tparts: {}\n\tspecialPages: {}', texts, templates, parts, specialPages)
|
def specialPageToHtmlFactory = new SpecialPageToHtmlFileTaskFactory()
|
||||||
|
def specialPagesResult = specialPageToHtmlFactory.getTasks(build)
|
||||||
|
tasks.addAll(specialPagesResult.get())
|
||||||
|
diagnostics.addAll(specialPagesResult.diagnostics)
|
||||||
|
|
||||||
def globals = build.globals
|
logger.trace(exit, '\n\tdiagnostics: {}\n\ttasks: {}', diagnostics, tasks)
|
||||||
Collection<Diagnostic> diagnostics = []
|
new Result<>(diagnostics, tasks)
|
||||||
Collection<Output> generatedPages = []
|
|
||||||
|
|
||||||
Map<Text, OutputMeta> textOutputTasks = texts.collectEntries {
|
|
||||||
[(it): new OutputMeta(it.path, stripExtension(it.path) + '.html')]
|
|
||||||
}
|
|
||||||
Map<SpecialPage, OutputMeta> specialPageOutputTasks = specialPages.collectEntries {
|
|
||||||
[(it): new OutputMeta(it.path, stripExtension(it.path) + '.html')]
|
|
||||||
}
|
|
||||||
|
|
||||||
def textOutputMetas = textOutputTasks.values() as ArrayList
|
|
||||||
def specialPageOutputMetas = specialPageOutputTasks.values() as ArrayList
|
|
||||||
def outputMetaMap = new OutputMetaMap([*textOutputMetas, *specialPageOutputMetas])
|
|
||||||
|
|
||||||
// Generate pages from each text, but only those that have a 'template' frontMatter field with a valid value
|
|
||||||
textOutputTasks.each { text, outputMeta ->
|
|
||||||
logger.trace(enter, 'text: {}, outputMeta: {}', text, outputMeta)
|
|
||||||
logger.info('processing text: {}', text.path)
|
|
||||||
|
|
||||||
// Extract frontMatter from text
|
|
||||||
def frontMatterResult = text.type.frontMatterGetter.get(text)
|
|
||||||
FrontMatter frontMatter
|
|
||||||
if (frontMatterResult.v1.size() > 0) {
|
|
||||||
logger.debug('diagnostics for getting frontMatter for {}: {}', text.path, frontMatterResult.v1)
|
|
||||||
diagnostics.addAll(frontMatterResult.v1)
|
|
||||||
logger.trace(exit, '')
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
frontMatter = frontMatterResult.v2
|
|
||||||
logger.debug('frontMatter: {}', frontMatter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the appropriate template from the frontMatter
|
|
||||||
def desiredTemplate = frontMatter.find('template')
|
|
||||||
if (desiredTemplate.isEmpty()) {
|
|
||||||
logger.info('{} has no \'template\' key in its frontMatter; skipping generation', text)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
def template = templates.find { it.path == desiredTemplate.get() }
|
|
||||||
if (template == null) {
|
|
||||||
diagnostics << new Diagnostic('in textFile' + text.path + ' frontMatter.template references an unknown template: ' + desiredTemplate, null)
|
|
||||||
logger.trace(exit, '')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logger.debug('found template: {}', template)
|
|
||||||
|
|
||||||
// Render the template using the result of rendering the text earlier
|
|
||||||
def templateRenderResult = template.type.renderer.render(
|
|
||||||
template,
|
|
||||||
text,
|
|
||||||
new RenderContext(
|
|
||||||
config,
|
|
||||||
siteSpec,
|
|
||||||
globals,
|
|
||||||
texts,
|
|
||||||
parts,
|
|
||||||
outputMeta.sourcePath,
|
|
||||||
outputMeta.targetPath
|
|
||||||
)
|
|
||||||
)
|
|
||||||
String renderedTemplate
|
|
||||||
if (templateRenderResult.v1.size() > 0) {
|
|
||||||
diagnostics.addAll(templateRenderResult.v1)
|
|
||||||
logger.trace(exit, '')
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
renderedTemplate = templateRenderResult.v2
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a GeneratedPage
|
|
||||||
generatedPages << new Output(outputMeta, renderedTemplate)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate special pages
|
|
||||||
specialPageOutputTasks.each { specialPage, outputMeta ->
|
|
||||||
logger.info('processing specialPage: {}', specialPage.path)
|
|
||||||
|
|
||||||
def specialPageRenderResult = specialPage.type.renderer.render(
|
|
||||||
specialPage,
|
|
||||||
new RenderContext(
|
|
||||||
config,
|
|
||||||
siteSpec,
|
|
||||||
globals,
|
|
||||||
texts,
|
|
||||||
parts,
|
|
||||||
outputMeta.sourcePath,
|
|
||||||
outputMeta.targetPath
|
|
||||||
)
|
|
||||||
)
|
|
||||||
String renderedSpecialPage
|
|
||||||
if (specialPageRenderResult.v1.size() > 0) {
|
|
||||||
diagnostics.addAll(specialPageRenderResult.v1)
|
|
||||||
logger.trace(exit, '')
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
renderedSpecialPage = specialPageRenderResult.v2
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a GeneratedPage
|
|
||||||
generatedPages << new Output(outputMeta, renderedSpecialPage)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.trace(exit, '\n\tdiagnostics: {}\n\tgeneratedPages: {}', diagnostics, generatedPages)
|
|
||||||
new Tuple2<>(diagnostics, generatedPages)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.jessebrault.ssg
|
package com.jessebrault.ssg
|
||||||
|
|
||||||
import com.jessebrault.ssg.task.Output
|
import com.jessebrault.ssg.task.TaskContainer
|
||||||
|
|
||||||
interface StaticSiteGenerator {
|
interface StaticSiteGenerator {
|
||||||
Tuple2<Collection<Diagnostic>, Collection<Output>> generate(Build build)
|
Result<TaskContainer> generate(Build build)
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ final class StandardDslMap {
|
|||||||
it.siteSpec = context.siteSpec
|
it.siteSpec = context.siteSpec
|
||||||
it.sourcePath = context.sourcePath
|
it.sourcePath = context.sourcePath
|
||||||
it.targetPath = context.targetPath
|
it.targetPath = context.targetPath
|
||||||
|
it.tasks = context.tasks
|
||||||
it.text = b.text ? new EmbeddableText(
|
it.text = b.text ? new EmbeddableText(
|
||||||
b.text,
|
b.text,
|
||||||
context.globals,
|
context.globals,
|
||||||
|
@ -3,6 +3,8 @@ package com.jessebrault.ssg.renderer
|
|||||||
import com.jessebrault.ssg.Config
|
import com.jessebrault.ssg.Config
|
||||||
import com.jessebrault.ssg.SiteSpec
|
import com.jessebrault.ssg.SiteSpec
|
||||||
import com.jessebrault.ssg.part.Part
|
import com.jessebrault.ssg.part.Part
|
||||||
|
import com.jessebrault.ssg.task.Task
|
||||||
|
import com.jessebrault.ssg.task.TaskContainer
|
||||||
import com.jessebrault.ssg.text.Text
|
import com.jessebrault.ssg.text.Text
|
||||||
import groovy.transform.EqualsAndHashCode
|
import groovy.transform.EqualsAndHashCode
|
||||||
import groovy.transform.NullCheck
|
import groovy.transform.NullCheck
|
||||||
@ -19,4 +21,6 @@ final class RenderContext {
|
|||||||
final Collection<Part> parts
|
final Collection<Part> parts
|
||||||
final String sourcePath
|
final String sourcePath
|
||||||
final String targetPath
|
final String targetPath
|
||||||
|
final TaskContainer tasks
|
||||||
|
final Set<Class<? extends Task>> taskTypes
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
package com.jessebrault.ssg.specialpage
|
package com.jessebrault.ssg.specialpage
|
||||||
|
|
||||||
import com.jessebrault.ssg.task.Input
|
|
||||||
import groovy.transform.EqualsAndHashCode
|
import groovy.transform.EqualsAndHashCode
|
||||||
import groovy.transform.NullCheck
|
import groovy.transform.NullCheck
|
||||||
import groovy.transform.TupleConstructor
|
import groovy.transform.TupleConstructor
|
||||||
|
|
||||||
@TupleConstructor(defaults = false)
|
@TupleConstructor(defaults = false)
|
||||||
@NullCheck
|
@NullCheck(includeGenerated = true)
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
class SpecialPage implements Input {
|
final class SpecialPage {
|
||||||
|
|
||||||
String text
|
final String text
|
||||||
String path
|
final String path
|
||||||
SpecialPageType type
|
final SpecialPageType type
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String toString() {
|
String toString() {
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
import groovy.transform.EqualsAndHashCode
|
||||||
|
import groovy.transform.NullCheck
|
||||||
|
|
||||||
|
@NullCheck
|
||||||
|
@EqualsAndHashCode
|
||||||
|
abstract class AbstractTask<T extends Task> implements Task {
|
||||||
|
|
||||||
|
final TaskType<T> type
|
||||||
|
final String name
|
||||||
|
|
||||||
|
AbstractTask(TaskType<T> type, String name) {
|
||||||
|
this.type = type
|
||||||
|
this.name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract T getThis()
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void execute(TaskExecutorContext context) {
|
||||||
|
// I am guessing that if we put this.getThis(), it will think the runtime type is AbstractTask? Not sure.
|
||||||
|
this.type.executor.execute(getThis(), context)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String toString() {
|
||||||
|
"AbstractTask(name: ${ this.name }, type: ${ this.type })"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
interface FileInput extends Input {
|
||||||
|
File getFile()
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
interface FileOutput extends Output {
|
||||||
|
File getFile()
|
||||||
|
String getContent()
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
import groovy.transform.EqualsAndHashCode
|
||||||
|
import groovy.transform.NullCheck
|
||||||
|
import groovy.transform.TupleConstructor
|
||||||
|
|
||||||
|
@TupleConstructor(defaults = false, includeFields = true)
|
||||||
|
@NullCheck(includeGenerated = true)
|
||||||
|
@EqualsAndHashCode
|
||||||
|
final class HtmlFileOutput {
|
||||||
|
|
||||||
|
final File file
|
||||||
|
final String htmlPath
|
||||||
|
|
||||||
|
private final Closure<String> contentClosure
|
||||||
|
|
||||||
|
String getContent(TaskContainer tasks, TaskTypeContainer taskTypes, Closure onDiagnostics) {
|
||||||
|
this.contentClosure(tasks, taskTypes, onDiagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String toString() {
|
||||||
|
"HtmlFileOutput(file: ${ this.file }, htmlPath: ${ this.htmlPath })"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
package com.jessebrault.ssg.task
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
interface Input {
|
interface Input {
|
||||||
String getPath()
|
String getName()
|
||||||
}
|
}
|
@ -1,20 +1,5 @@
|
|||||||
package com.jessebrault.ssg.task
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
import groovy.transform.EqualsAndHashCode
|
interface Output {
|
||||||
import groovy.transform.NullCheck
|
String getName()
|
||||||
import groovy.transform.TupleConstructor
|
|
||||||
|
|
||||||
@TupleConstructor(defaults = false)
|
|
||||||
@NullCheck
|
|
||||||
@EqualsAndHashCode
|
|
||||||
final class Output {
|
|
||||||
|
|
||||||
final OutputMeta meta
|
|
||||||
final String content
|
|
||||||
|
|
||||||
@Override
|
|
||||||
String toString() {
|
|
||||||
"Output(meta: ${ this.meta })"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
package com.jessebrault.ssg.task
|
|
||||||
|
|
||||||
final class OutputMetaMap {
|
|
||||||
|
|
||||||
@Delegate
|
|
||||||
private final Map<String, OutputMeta> map = [:]
|
|
||||||
|
|
||||||
OutputMetaMap(Collection<OutputMeta> outputMetas) {
|
|
||||||
outputMetas.each {
|
|
||||||
this.put(it.sourcePath, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
String toString() {
|
|
||||||
"OutputMetaMap(map: ${ this.map })"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
import com.jessebrault.ssg.specialpage.SpecialPage
|
||||||
|
import groovy.transform.EqualsAndHashCode
|
||||||
|
import groovy.transform.NullCheck
|
||||||
|
|
||||||
|
@NullCheck
|
||||||
|
@EqualsAndHashCode
|
||||||
|
final class SpecialPageToHtmlFileTask extends AbstractTask<SpecialPageToHtmlFileTask> {
|
||||||
|
|
||||||
|
private static final class SpecialPageToHtmlFileTaskExecutor implements TaskExecutor<SpecialPageToHtmlFileTask> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void execute(SpecialPageToHtmlFileTask task, TaskExecutorContext context) {
|
||||||
|
task.output.file.write(task.output.getContent(
|
||||||
|
context.allTasks, context.allTypes, context.onDiagnostics
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String toString() {
|
||||||
|
'SpecialPageToHtmlFileTaskExecutor()'
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final TaskType<SpecialPageToHtmlFileTask> type = new TaskType<>(
|
||||||
|
'specialPageToHtmlFile', new SpecialPageToHtmlFileTaskExecutor()
|
||||||
|
)
|
||||||
|
|
||||||
|
final SpecialPage input
|
||||||
|
final HtmlFileOutput output
|
||||||
|
|
||||||
|
SpecialPageToHtmlFileTask(String name, SpecialPage input, HtmlFileOutput output) {
|
||||||
|
super(type, name)
|
||||||
|
this.input = input
|
||||||
|
this.output = output
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SpecialPageToHtmlFileTask getThis() {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String toString() {
|
||||||
|
"SpecialPageToHtmlFileTask(input: ${ this.input }, output: ${ this.output }, super: ${ super })"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
import com.jessebrault.ssg.Build
|
||||||
|
import com.jessebrault.ssg.Result
|
||||||
|
import com.jessebrault.ssg.renderer.RenderContext
|
||||||
|
import com.jessebrault.ssg.util.ExtensionsUtil
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.slf4j.Marker
|
||||||
|
import org.slf4j.MarkerFactory
|
||||||
|
|
||||||
|
final class SpecialPageToHtmlFileTaskFactory implements TaskFactory<SpecialPageToHtmlFileTask> {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(SpecialPageToHtmlFileTaskFactory)
|
||||||
|
private static final Marker enter = MarkerFactory.getMarker('ENTER')
|
||||||
|
private static final Marker exit = MarkerFactory.getMarker('EXIT')
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Result<TaskCollection<SpecialPageToHtmlFileTask>> getTasks(Build build) {
|
||||||
|
logger.trace(enter, 'build: {}', build)
|
||||||
|
logger.info('processing build with name {} for SpecialPageToHtmlFileTasks', build.name)
|
||||||
|
|
||||||
|
def config = build.config
|
||||||
|
def siteSpec = build.siteSpec
|
||||||
|
def globals = build.globals
|
||||||
|
|
||||||
|
def specialPages = config.specialPagesProviders.collectMany { it.provide() }
|
||||||
|
def templates = config.templatesProviders.collectMany { it.provide() }
|
||||||
|
def parts = config.partsProviders.collectMany { it.provide() }
|
||||||
|
def texts = config.textProviders.collectMany { it.provide() }
|
||||||
|
|
||||||
|
logger.debug('\n\tspecialPages: {}\n\ttemplates: {}\n\tparts: {}', specialPages, templates, parts)
|
||||||
|
|
||||||
|
def tasks = new TaskCollection<SpecialPageToHtmlFileTask>(specialPages.findResults {
|
||||||
|
logger.trace(enter, 'specialPage: {}', it)
|
||||||
|
logger.info('processing specialPage with path: {}', it.path)
|
||||||
|
|
||||||
|
def htmlPath = ExtensionsUtil.stripExtension(it.path) + '.html'
|
||||||
|
|
||||||
|
def renderSpecialPage = { TaskContainer tasks, TaskTypeContainer taskTypes, Closure<Void> onDiagnostics ->
|
||||||
|
def renderResult = it.type.renderer.render(
|
||||||
|
it,
|
||||||
|
new RenderContext(
|
||||||
|
config,
|
||||||
|
siteSpec,
|
||||||
|
globals,
|
||||||
|
texts,
|
||||||
|
parts,
|
||||||
|
it.path,
|
||||||
|
htmlPath,
|
||||||
|
tasks,
|
||||||
|
taskTypes
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!renderResult.v1.isEmpty()) {
|
||||||
|
onDiagnostics(renderResult.v1)
|
||||||
|
''
|
||||||
|
} else {
|
||||||
|
renderResult.v2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def result = new SpecialPageToHtmlFileTask(
|
||||||
|
"specialPageToHtmlFileTask:${ it.path }:${ htmlPath }",
|
||||||
|
it,
|
||||||
|
new HtmlFileOutput(
|
||||||
|
new File(build.outDir, htmlPath),
|
||||||
|
htmlPath,
|
||||||
|
renderSpecialPage
|
||||||
|
)
|
||||||
|
)
|
||||||
|
logger.trace(exit, 'result: {}', result)
|
||||||
|
result
|
||||||
|
})
|
||||||
|
|
||||||
|
def result = new Result<>([], tasks)
|
||||||
|
logger.trace(exit, 'result: {}', result)
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package com.jessebrault.ssg.task
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
interface Task {
|
interface Task {
|
||||||
Output getOutput()
|
String getName()
|
||||||
OutputMeta getOutputMeta()
|
void execute(TaskExecutorContext context)
|
||||||
}
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull
|
||||||
|
|
||||||
|
class TaskCollection<T extends Task> {
|
||||||
|
|
||||||
|
@Delegate
|
||||||
|
private final Collection<T> tasks = new ArrayList<T>()
|
||||||
|
|
||||||
|
TaskCollection(Collection<? extends T> tasks = null) {
|
||||||
|
if (tasks != null) {
|
||||||
|
this.tasks.addAll(requireNonNull(tasks))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def <U extends T> TaskCollection<U> findAllByType(
|
||||||
|
Class<U> taskClass
|
||||||
|
) {
|
||||||
|
new TaskCollection<>(this.tasks.findResults {
|
||||||
|
taskClass.isAssignableFrom(it.class) ? taskClass.cast(it) : null
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
final class TaskContainer extends TaskCollection<Task> {
|
||||||
|
|
||||||
|
TaskContainer(Collection<? extends Task> tasks = null) {
|
||||||
|
super(tasks)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,21 +0,0 @@
|
|||||||
package com.jessebrault.ssg.task
|
|
||||||
|
|
||||||
import com.jessebrault.ssg.Config
|
|
||||||
import com.jessebrault.ssg.SiteSpec
|
|
||||||
import groovy.transform.TupleConstructor
|
|
||||||
import groovy.transform.builder.Builder
|
|
||||||
|
|
||||||
@Builder
|
|
||||||
@TupleConstructor(defaults = false)
|
|
||||||
final class TaskContext {
|
|
||||||
|
|
||||||
final Config config
|
|
||||||
final SiteSpec siteSpec
|
|
||||||
final Collection<OutputMeta> outputMetas
|
|
||||||
|
|
||||||
@Override
|
|
||||||
String toString() {
|
|
||||||
"TaskContext(config: ${ this.config }, siteSpec: ${ this.siteSpec }, outputMetas: ${ this.outputMetas })"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
interface TaskExecutor<T extends Task> {
|
||||||
|
void execute(T task, TaskExecutorContext context)
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
import com.jessebrault.ssg.Build
|
||||||
|
import groovy.transform.EqualsAndHashCode
|
||||||
|
import groovy.transform.NullCheck
|
||||||
|
import groovy.transform.TupleConstructor
|
||||||
|
|
||||||
|
@TupleConstructor(defaults = false)
|
||||||
|
@NullCheck(includeGenerated = true)
|
||||||
|
@EqualsAndHashCode
|
||||||
|
final class TaskExecutorContext {
|
||||||
|
|
||||||
|
final Build build
|
||||||
|
final TaskContainer allTasks
|
||||||
|
final TaskTypeContainer allTypes
|
||||||
|
final Closure onDiagnostics
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String toString() {
|
||||||
|
"TaskExecutorContext(build: ${ this.build }, allTasks: ${ this.allTasks }, allTypes: ${ this.allTypes })"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
package com.jessebrault.ssg.task
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable
|
import com.jessebrault.ssg.Build
|
||||||
|
import com.jessebrault.ssg.Result
|
||||||
|
|
||||||
interface TaskFactory {
|
interface TaskFactory<T extends Task> {
|
||||||
@Nullable Task getTask(Input input, TaskContext context)
|
Result<TaskCollection<T>> getTasks(Build build)
|
||||||
}
|
}
|
@ -5,16 +5,16 @@ import groovy.transform.NullCheck
|
|||||||
import groovy.transform.TupleConstructor
|
import groovy.transform.TupleConstructor
|
||||||
|
|
||||||
@TupleConstructor(defaults = false)
|
@TupleConstructor(defaults = false)
|
||||||
@NullCheck
|
@NullCheck(includeGenerated = true)
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
final class OutputMeta {
|
final class TaskType<T extends Task> {
|
||||||
|
|
||||||
final String sourcePath
|
final String name
|
||||||
final String targetPath
|
final TaskExecutor<T> executor
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String toString() {
|
String toString() {
|
||||||
"OutputMeta(sourcePath: ${ sourcePath }, targetPath: ${ targetPath })"
|
"TaskType(${ this.name }, ${ this.executor })"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
final class TaskTypeContainer {
|
||||||
|
|
||||||
|
private static final Pattern taskTypeNamePattern = ~/(.*)Task/
|
||||||
|
|
||||||
|
@Delegate
|
||||||
|
private final Set<Class<? extends Task>> taskTypes = []
|
||||||
|
|
||||||
|
TaskTypeContainer(Collection<Class<? extends Task>> taskTypes = null) {
|
||||||
|
if (taskTypes) {
|
||||||
|
this.taskTypes.addAll(taskTypes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Class<? extends Task> getProperty(String propertyName) {
|
||||||
|
def result = this.taskTypes.find {
|
||||||
|
def m = taskTypeNamePattern.matcher(it.simpleName)
|
||||||
|
if (m.matches()) {
|
||||||
|
def withoutTaskEnd = m.group(1)
|
||||||
|
def uncapitalized = withoutTaskEnd.uncapitalize()
|
||||||
|
return propertyName == uncapitalized
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("invalid task type name: ${ it.simpleName }")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!result) {
|
||||||
|
throw new IllegalStateException("no such taskType: ${ propertyName }")
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
import com.jessebrault.ssg.text.Text
|
||||||
|
import groovy.transform.EqualsAndHashCode
|
||||||
|
import groovy.transform.NullCheck
|
||||||
|
import groovy.transform.TupleConstructor
|
||||||
|
|
||||||
|
@TupleConstructor(defaults = false)
|
||||||
|
@NullCheck(includeGenerated = true)
|
||||||
|
@EqualsAndHashCode
|
||||||
|
final class TextInput implements Input {
|
||||||
|
final String name
|
||||||
|
final Text text
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
import com.jessebrault.ssg.text.Text
|
||||||
|
import groovy.transform.EqualsAndHashCode
|
||||||
|
import groovy.transform.NullCheck
|
||||||
|
|
||||||
|
@NullCheck
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
final class TextToHtmlFileTask extends AbstractTask<TextToHtmlFileTask> {
|
||||||
|
|
||||||
|
private static final class TextToHtmlFileTaskExecutor implements TaskExecutor<TextToHtmlFileTask> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void execute(TextToHtmlFileTask task, TaskExecutorContext context) {
|
||||||
|
task.output.file.write(task.output.getContent(
|
||||||
|
context.allTasks, context.allTypes, context.onDiagnostics
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String toString() {
|
||||||
|
'TextToHtmlFileTaskExecutor()'
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final TaskType<TextToHtmlFileTask> type = new TaskType<>(
|
||||||
|
'textToHtmlFile', new TextToHtmlFileTaskExecutor()
|
||||||
|
)
|
||||||
|
|
||||||
|
final Text input
|
||||||
|
final HtmlFileOutput output
|
||||||
|
|
||||||
|
TextToHtmlFileTask(String name, Text input, HtmlFileOutput output) {
|
||||||
|
super(type, name)
|
||||||
|
this.input = input
|
||||||
|
this.output = output
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TextToHtmlFileTask getThis() {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String toString() {
|
||||||
|
"TextToHtmlFileTask(input: ${ this.input }, output: ${ this.output }, super: ${ super })"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,112 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
import com.jessebrault.ssg.Build
|
||||||
|
import com.jessebrault.ssg.Diagnostic
|
||||||
|
import com.jessebrault.ssg.Result
|
||||||
|
import com.jessebrault.ssg.renderer.RenderContext
|
||||||
|
import com.jessebrault.ssg.text.FrontMatter
|
||||||
|
import com.jessebrault.ssg.util.ExtensionsUtil
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.slf4j.Marker
|
||||||
|
import org.slf4j.MarkerFactory
|
||||||
|
|
||||||
|
final class TextToHtmlFileTaskFactory implements TaskFactory<TextToHtmlFileTask> {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(TextToHtmlFileTaskFactory)
|
||||||
|
private static final Marker enter = MarkerFactory.getMarker('ENTER')
|
||||||
|
private static final Marker exit = MarkerFactory.getMarker('EXIT')
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Result<TaskCollection<TextToHtmlFileTask>> getTasks(Build build) {
|
||||||
|
logger.trace(enter, 'build: {}', build)
|
||||||
|
logger.info('getting TextToHtmlFileTasks for build with name: {}', build.name)
|
||||||
|
|
||||||
|
def config = build.config
|
||||||
|
def siteSpec = build.siteSpec
|
||||||
|
def globals = build.globals
|
||||||
|
def diagnostics = []
|
||||||
|
|
||||||
|
// Get all texts, templates, parts, and specialPages
|
||||||
|
def texts = config.textProviders.collectMany { it.provide() }
|
||||||
|
def templates = config.templatesProviders.collectMany { it.provide() }
|
||||||
|
def parts = config.partsProviders.collectMany { it.provide() }
|
||||||
|
|
||||||
|
logger.debug('\n\ttexts: {}\n\ttemplates: {}\n\tparts: {}', texts, templates, parts)
|
||||||
|
|
||||||
|
def tasks = new TaskCollection<TextToHtmlFileTask>(texts.findResults {
|
||||||
|
logger.trace(enter, 'text: {}', it)
|
||||||
|
logger.info('processing text with path: {}', it.path)
|
||||||
|
|
||||||
|
def frontMatterResult = it.type.frontMatterGetter.get(it)
|
||||||
|
FrontMatter frontMatter
|
||||||
|
if (!frontMatterResult.v1.isEmpty()) {
|
||||||
|
diagnostics.addAll(frontMatterResult.v1)
|
||||||
|
logger.trace(exit, 'result: {}', null)
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
|
frontMatter = frontMatterResult.v2
|
||||||
|
logger.debug('frontMatter: {}', frontMatter)
|
||||||
|
}
|
||||||
|
|
||||||
|
def desiredTemplate = frontMatter.find('template')
|
||||||
|
if (desiredTemplate.isEmpty()) {
|
||||||
|
logger.info('text with path {} has no \'template\' key in its frontMatter; skipping', it.path)
|
||||||
|
logger.trace(exit, 'result: {}', null)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
def template = templates.find { it.path == desiredTemplate.get() }
|
||||||
|
if (template == null) {
|
||||||
|
diagnostics << new Diagnostic("in text with path ${ it.path }, frontMatter.template refers to an unknown template: ${ desiredTemplate.get() }")
|
||||||
|
logger.trace(exit, 'result: {}', null)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
logger.debug('found template: {}', template)
|
||||||
|
|
||||||
|
def htmlPath = ExtensionsUtil.stripExtension(it.path) + '.html'
|
||||||
|
|
||||||
|
def renderTemplate = { TaskContainer tasks, TaskTypeContainer taskTypes, Closure<Void> onDiagnostics ->
|
||||||
|
def templateRenderResult = template.type.renderer.render(
|
||||||
|
template,
|
||||||
|
it,
|
||||||
|
new RenderContext(
|
||||||
|
config,
|
||||||
|
siteSpec,
|
||||||
|
globals,
|
||||||
|
texts,
|
||||||
|
parts,
|
||||||
|
it.path,
|
||||||
|
htmlPath,
|
||||||
|
tasks,
|
||||||
|
taskTypes
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!templateRenderResult.v1.isEmpty()) {
|
||||||
|
onDiagnostics(templateRenderResult.v1)
|
||||||
|
''
|
||||||
|
} else {
|
||||||
|
templateRenderResult.v2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def result = new TextToHtmlFileTask(
|
||||||
|
"textToHtmlFileTask:${ it.path }:${ htmlPath }",
|
||||||
|
it,
|
||||||
|
new HtmlFileOutput(
|
||||||
|
new File(build.outDir, htmlPath),
|
||||||
|
htmlPath,
|
||||||
|
renderTemplate
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.trace(exit, 'result: {}', result)
|
||||||
|
result
|
||||||
|
})
|
||||||
|
|
||||||
|
def result = new Result<>(diagnostics, tasks)
|
||||||
|
logger.trace(exit, 'result: {}', result)
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
interface WithInput<I extends Input> {
|
||||||
|
I getInput()
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
interface WithOutput<O extends Output> {
|
||||||
|
O getOutput()
|
||||||
|
}
|
@ -1,18 +1,17 @@
|
|||||||
package com.jessebrault.ssg.text
|
package com.jessebrault.ssg.text
|
||||||
|
|
||||||
import com.jessebrault.ssg.task.Input
|
|
||||||
import groovy.transform.EqualsAndHashCode
|
import groovy.transform.EqualsAndHashCode
|
||||||
import groovy.transform.NullCheck
|
import groovy.transform.NullCheck
|
||||||
import groovy.transform.TupleConstructor
|
import groovy.transform.TupleConstructor
|
||||||
|
|
||||||
@TupleConstructor(defaults = false)
|
@TupleConstructor(defaults = false)
|
||||||
@NullCheck
|
@NullCheck(includeGenerated = true)
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
class Text implements Input {
|
final class Text {
|
||||||
|
|
||||||
String text
|
final String text
|
||||||
String path
|
final String path
|
||||||
TextType type
|
final TextType type
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String toString() {
|
String toString() {
|
||||||
|
@ -6,6 +6,10 @@ import com.jessebrault.ssg.part.PartType
|
|||||||
import com.jessebrault.ssg.specialpage.GspSpecialPageRenderer
|
import com.jessebrault.ssg.specialpage.GspSpecialPageRenderer
|
||||||
import com.jessebrault.ssg.specialpage.SpecialPageFileSpecialPagesProvider
|
import com.jessebrault.ssg.specialpage.SpecialPageFileSpecialPagesProvider
|
||||||
import com.jessebrault.ssg.specialpage.SpecialPageType
|
import com.jessebrault.ssg.specialpage.SpecialPageType
|
||||||
|
import com.jessebrault.ssg.task.SpecialPageToHtmlFileTask
|
||||||
|
import com.jessebrault.ssg.task.Task
|
||||||
|
import com.jessebrault.ssg.task.TaskTypeContainer
|
||||||
|
import com.jessebrault.ssg.task.TextToHtmlFileTask
|
||||||
import com.jessebrault.ssg.template.GspTemplateRenderer
|
import com.jessebrault.ssg.template.GspTemplateRenderer
|
||||||
import com.jessebrault.ssg.template.TemplateFileTemplatesProvider
|
import com.jessebrault.ssg.template.TemplateFileTemplatesProvider
|
||||||
import com.jessebrault.ssg.template.TemplateType
|
import com.jessebrault.ssg.template.TemplateType
|
||||||
@ -18,6 +22,7 @@ import org.junit.jupiter.api.BeforeEach
|
|||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.assertEmptyDiagnostics
|
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.assertEmptyDiagnostics
|
||||||
|
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.getDiagnosticsMessageSupplier
|
||||||
import static org.junit.jupiter.api.Assertions.*
|
import static org.junit.jupiter.api.Assertions.*
|
||||||
|
|
||||||
class SimpleStaticSiteGeneratorIntegrationTests {
|
class SimpleStaticSiteGeneratorIntegrationTests {
|
||||||
@ -68,11 +73,15 @@ class SimpleStaticSiteGeneratorIntegrationTests {
|
|||||||
def result = this.ssg.generate(this.build)
|
def result = this.ssg.generate(this.build)
|
||||||
|
|
||||||
assertEmptyDiagnostics(result)
|
assertEmptyDiagnostics(result)
|
||||||
assertTrue(result.v2.size() == 1)
|
def tasks = result.get()
|
||||||
|
assertTrue(tasks.size() == 1)
|
||||||
|
|
||||||
def p0 = result.v2[0]
|
def t0 = tasks.findAllByType(TextToHtmlFileTask)[0]
|
||||||
assertEquals('test.html', p0.meta.targetPath)
|
assertEquals('test.html', t0.output.htmlPath)
|
||||||
assertEquals('<p><strong>Hello, World!</strong></p>\n', p0.content)
|
def contentResult = t0.output.getContent(tasks, new TaskTypeContainer([TextToHtmlFileTask])) { Collection<Diagnostic> diagnostics ->
|
||||||
|
fail(getDiagnosticsMessageSupplier(diagnostics))
|
||||||
|
}
|
||||||
|
assertEquals('<p><strong>Hello, World!</strong></p>\n', contentResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -88,11 +97,18 @@ class SimpleStaticSiteGeneratorIntegrationTests {
|
|||||||
def result = this.ssg.generate(this.build)
|
def result = this.ssg.generate(this.build)
|
||||||
|
|
||||||
assertEmptyDiagnostics(result)
|
assertEmptyDiagnostics(result)
|
||||||
assertTrue(result.v2.size() == 1)
|
def tasks = result.get()
|
||||||
|
assertTrue(tasks.size() == 1)
|
||||||
|
|
||||||
def p0 = result.v2[0]
|
def t0 = tasks.findAllByType(TextToHtmlFileTask)[0]
|
||||||
assertEquals('nested/nested.html', p0.meta.targetPath)
|
assertEquals('nested/nested.html', t0.output.htmlPath)
|
||||||
assertEquals('<p><strong>Hello, World!</strong></p>\n', p0.content)
|
def contentResult = t0.output.getContent(
|
||||||
|
tasks,
|
||||||
|
new TaskTypeContainer([TextToHtmlFileTask])
|
||||||
|
) { Collection<Diagnostic> diagnostics ->
|
||||||
|
fail(getDiagnosticsMessageSupplier(diagnostics))
|
||||||
|
}
|
||||||
|
assertEquals('<p><strong>Hello, World!</strong></p>\n', contentResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -105,15 +121,28 @@ class SimpleStaticSiteGeneratorIntegrationTests {
|
|||||||
def result = this.ssg.generate(this.build)
|
def result = this.ssg.generate(this.build)
|
||||||
|
|
||||||
assertEmptyDiagnostics(result)
|
assertEmptyDiagnostics(result)
|
||||||
assertEquals(2, result.v2.size())
|
def tasks = result.get()
|
||||||
|
assertEquals(2, tasks.size())
|
||||||
|
|
||||||
def testPage = result.v2.find { it.meta.targetPath == 'test.html' }
|
def taskTypes = new TaskTypeContainer([TextToHtmlFileTask, SpecialPageToHtmlFileTask])
|
||||||
assertNotNull(testPage)
|
|
||||||
assertEquals('2', testPage.content)
|
|
||||||
|
|
||||||
def specialPage = result.v2.find { it.meta.targetPath == 'special.html' }
|
def testPageTask = tasks.findAllByType(TextToHtmlFileTask).find {
|
||||||
assertNotNull(specialPage)
|
it.output.htmlPath == 'test.html'
|
||||||
assertEquals('<p>Hello, World!</p>\n', specialPage.content)
|
}
|
||||||
|
assertNotNull(testPageTask)
|
||||||
|
def testPageContent = testPageTask.output.getContent(tasks, taskTypes) { Collection<Diagnostic> diagnostics ->
|
||||||
|
fail(getDiagnosticsMessageSupplier(diagnostics))
|
||||||
|
}
|
||||||
|
assertEquals('2', testPageContent)
|
||||||
|
|
||||||
|
def specialPageTask = tasks.findAllByType(SpecialPageToHtmlFileTask).find {
|
||||||
|
it.output.htmlPath == 'special.html'
|
||||||
|
}
|
||||||
|
assertNotNull(specialPageTask)
|
||||||
|
def specialPageContent = specialPageTask.output.getContent(tasks, taskTypes) { Collection<Diagnostic> diagnostics ->
|
||||||
|
fail(getDiagnosticsMessageSupplier(diagnostics))
|
||||||
|
}
|
||||||
|
assertEquals('<p>Hello, World!</p>\n', specialPageContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -121,7 +150,7 @@ class SimpleStaticSiteGeneratorIntegrationTests {
|
|||||||
new File(this.textsDir, 'test.md').write('Hello, World!')
|
new File(this.textsDir, 'test.md').write('Hello, World!')
|
||||||
def result = this.ssg.generate(this.build)
|
def result = this.ssg.generate(this.build)
|
||||||
assertEmptyDiagnostics(result)
|
assertEmptyDiagnostics(result)
|
||||||
assertEquals(0, result.v2.size())
|
assertEquals(0, result.get().size())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package com.jessebrault.ssg.text
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
import static com.jessebrault.ssg.text.TextMocks.renderableText
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
|
||||||
class ExcerptGetterTests {
|
class ExcerptGetterTests {
|
||||||
@ -10,7 +11,7 @@ class ExcerptGetterTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void takesAllIfTextLessThanLimit() {
|
void takesAllIfTextLessThanLimit() {
|
||||||
def text = new Text('One Two Three Four Five', null, null)
|
def text = renderableText('One Two Three Four Five')
|
||||||
def result = this.excerptGetter.getExcerpt(text, 10)
|
def result = this.excerptGetter.getExcerpt(text, 10)
|
||||||
assertEquals(0, result.v1.size())
|
assertEquals(0, result.v1.size())
|
||||||
assertEquals('One Two Three Four Five', result.v2)
|
assertEquals('One Two Three Four Five', result.v2)
|
||||||
@ -18,7 +19,7 @@ class ExcerptGetterTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void takesTheLimit() {
|
void takesTheLimit() {
|
||||||
def text = new Text('One Two Three Four Five', null, null)
|
def text = renderableText('One Two Three Four Five')
|
||||||
def result = this.excerptGetter.getExcerpt(text, 2)
|
def result = this.excerptGetter.getExcerpt(text, 2)
|
||||||
assertEquals(0, result.v1.size())
|
assertEquals(0, result.v1.size())
|
||||||
assertEquals('One Two', result.v2)
|
assertEquals('One Two', result.v2)
|
||||||
@ -26,7 +27,7 @@ class ExcerptGetterTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void worksWithHeading() {
|
void worksWithHeading() {
|
||||||
def text = new Text('# Heading\nOne Two Three', null, null)
|
def text = renderableText('# Heading\nOne Two Three')
|
||||||
def result = this.excerptGetter.getExcerpt(text, 1)
|
def result = this.excerptGetter.getExcerpt(text, 1)
|
||||||
assertEquals(0, result.v1.size())
|
assertEquals(0, result.v1.size())
|
||||||
assertEquals('Heading', result.v2)
|
assertEquals('Heading', result.v2)
|
||||||
@ -34,7 +35,7 @@ class ExcerptGetterTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void worksWithFrontMatter() {
|
void worksWithFrontMatter() {
|
||||||
def text = new Text('---\ntest: hello\n---\nOne Two Three', null, null)
|
def text = renderableText('---\ntest: hello\n---\nOne Two Three')
|
||||||
def result = this.excerptGetter.getExcerpt(text, 1)
|
def result = this.excerptGetter.getExcerpt(text, 1)
|
||||||
assertEquals(0, result.v1.size())
|
assertEquals(0, result.v1.size())
|
||||||
assertEquals('One', result.v2)
|
assertEquals('One', result.v2)
|
||||||
|
@ -8,6 +8,10 @@ import com.jessebrault.ssg.part.PartRenderer
|
|||||||
import com.jessebrault.ssg.part.PartType
|
import com.jessebrault.ssg.part.PartType
|
||||||
import com.jessebrault.ssg.renderer.RenderContext
|
import com.jessebrault.ssg.renderer.RenderContext
|
||||||
import com.jessebrault.ssg.tagbuilder.TagBuilder
|
import com.jessebrault.ssg.tagbuilder.TagBuilder
|
||||||
|
import com.jessebrault.ssg.task.HtmlFileOutput
|
||||||
|
import com.jessebrault.ssg.task.TaskContainer
|
||||||
|
import com.jessebrault.ssg.task.TaskTypeContainer
|
||||||
|
import com.jessebrault.ssg.task.TextToHtmlFileTask
|
||||||
import com.jessebrault.ssg.text.EmbeddableTextsCollection
|
import com.jessebrault.ssg.text.EmbeddableTextsCollection
|
||||||
import com.jessebrault.ssg.url.UrlBuilder
|
import com.jessebrault.ssg.url.UrlBuilder
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
@ -18,8 +22,11 @@ import org.mockito.junit.jupiter.MockitoExtension
|
|||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
|
import static com.jessebrault.ssg.task.SpecialPageToHtmlFileTaskMocks.blankSpecialPageToHtmlFileTask
|
||||||
|
import static com.jessebrault.ssg.task.TextToHtmlFileTaskMocks.blankTextToHtmlFileTask
|
||||||
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.assertEmptyDiagnostics
|
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.assertEmptyDiagnostics
|
||||||
import static com.jessebrault.ssg.testutil.RenderContextUtil.getRenderContext
|
import static com.jessebrault.ssg.testutil.RenderContextUtil.getRenderContext
|
||||||
|
import static com.jessebrault.ssg.text.TextMocks.blankText
|
||||||
import static com.jessebrault.ssg.text.TextMocks.renderableTextWithPath
|
import static com.jessebrault.ssg.text.TextMocks.renderableTextWithPath
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||||
import static org.junit.jupiter.api.Assertions.fail
|
import static org.junit.jupiter.api.Assertions.fail
|
||||||
@ -146,6 +153,48 @@ interface StandardDslConsumerTests {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
default void tasksAvailable() {
|
||||||
|
this.doDslAssertionTest("<% assert tasks != null && tasks instanceof ${ TaskContainer.name } %>")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
default void tasksFind() {
|
||||||
|
def task = new TextToHtmlFileTask(
|
||||||
|
'testTask',
|
||||||
|
blankText(),
|
||||||
|
new HtmlFileOutput(
|
||||||
|
new File('test.html'),
|
||||||
|
'test.html',
|
||||||
|
{ '' }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
this.doDslRenderTest(
|
||||||
|
'test.html',
|
||||||
|
'<%= tasks.find { it.name == "testTask" }.output.htmlPath %>',
|
||||||
|
getRenderContext(tasks: new TaskContainer([task]))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
default void taskTypesAvailable() {
|
||||||
|
this.doDslAssertionTest(
|
||||||
|
"<% assert taskTypes != null && taskTypes instanceof ${ TaskTypeContainer.name } %>"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
default void taskFindAllByType() {
|
||||||
|
def t0 = blankTextToHtmlFileTask()
|
||||||
|
def t1 = blankSpecialPageToHtmlFileTask()
|
||||||
|
this.doDslAssertionTest(
|
||||||
|
'<% assert tasks.size() == 2 && ' +
|
||||||
|
'tasks.findAllByType(taskTypes.textToHtmlFile).size() == 1 &&' +
|
||||||
|
'tasks.findAllByType(taskTypes.specialPageToHtmlFile).size() == 1 %>',
|
||||||
|
getRenderContext(tasks: new TaskContainer([t0, t1]))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
default void textsAvailable() {
|
default void textsAvailable() {
|
||||||
this.doDslAssertionTest(
|
this.doDslAssertionTest(
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.jessebrault.ssg.specialpage
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock
|
||||||
|
|
||||||
|
final class SpecialPageMocks {
|
||||||
|
|
||||||
|
static SpecialPage blankSpecialPage() {
|
||||||
|
def renderer = mock(SpecialPageRenderer)
|
||||||
|
new SpecialPage(
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
new SpecialPageType([], renderer)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
import static com.jessebrault.ssg.specialpage.SpecialPageMocks.blankSpecialPage
|
||||||
|
|
||||||
|
final class SpecialPageToHtmlFileTaskMocks {
|
||||||
|
|
||||||
|
static SpecialPageToHtmlFileTask blankSpecialPageToHtmlFileTask() {
|
||||||
|
new SpecialPageToHtmlFileTask(
|
||||||
|
'',
|
||||||
|
blankSpecialPage(),
|
||||||
|
new HtmlFileOutput(
|
||||||
|
new File(''),
|
||||||
|
'',
|
||||||
|
{ '' }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.jessebrault.ssg.task
|
||||||
|
|
||||||
|
import static com.jessebrault.ssg.text.TextMocks.blankText
|
||||||
|
|
||||||
|
final class TextToHtmlFileTaskMocks {
|
||||||
|
|
||||||
|
static TextToHtmlFileTask blankTextToHtmlFileTask() {
|
||||||
|
new TextToHtmlFileTask(
|
||||||
|
'',
|
||||||
|
blankText(),
|
||||||
|
new HtmlFileOutput(
|
||||||
|
new File(''),
|
||||||
|
'',
|
||||||
|
{ '' }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package com.jessebrault.ssg.testutil
|
package com.jessebrault.ssg.testutil
|
||||||
|
|
||||||
import com.jessebrault.ssg.Diagnostic
|
import com.jessebrault.ssg.Diagnostic
|
||||||
|
import com.jessebrault.ssg.Result
|
||||||
import com.jessebrault.ssg.text.ExcerptGetter
|
import com.jessebrault.ssg.text.ExcerptGetter
|
||||||
import groovy.transform.stc.ClosureParams
|
import groovy.transform.stc.ClosureParams
|
||||||
import groovy.transform.stc.FirstParam
|
import groovy.transform.stc.FirstParam
|
||||||
@ -25,6 +26,10 @@ class DiagnosticsUtil {
|
|||||||
assertTrue(result.v1.isEmpty(), getDiagnosticsMessageSupplier(result.v1))
|
assertTrue(result.v1.isEmpty(), getDiagnosticsMessageSupplier(result.v1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void assertEmptyDiagnostics(Result<?> result) {
|
||||||
|
assertTrue(!result.hasDiagnostics(), getDiagnosticsMessageSupplier(result.diagnostics))
|
||||||
|
}
|
||||||
|
|
||||||
static <E extends Exception> void assertDiagnosticException(
|
static <E extends Exception> void assertDiagnosticException(
|
||||||
Class<E> expectedException,
|
Class<E> expectedException,
|
||||||
Diagnostic diagnostic,
|
Diagnostic diagnostic,
|
||||||
|
@ -3,6 +3,8 @@ package com.jessebrault.ssg.testutil
|
|||||||
import com.jessebrault.ssg.Config
|
import com.jessebrault.ssg.Config
|
||||||
import com.jessebrault.ssg.SiteSpec
|
import com.jessebrault.ssg.SiteSpec
|
||||||
import com.jessebrault.ssg.renderer.RenderContext
|
import com.jessebrault.ssg.renderer.RenderContext
|
||||||
|
import com.jessebrault.ssg.task.Task
|
||||||
|
import com.jessebrault.ssg.task.TaskContainer
|
||||||
|
|
||||||
class RenderContextUtil {
|
class RenderContextUtil {
|
||||||
|
|
||||||
@ -14,7 +16,9 @@ class RenderContextUtil {
|
|||||||
args?.texts as Collection ?: [],
|
args?.texts as Collection ?: [],
|
||||||
args?.parts as Collection ?: [],
|
args?.parts as Collection ?: [],
|
||||||
args?.sourcePath as String ?: '',
|
args?.sourcePath as String ?: '',
|
||||||
args?.targetPath as String ?: ''
|
args?.targetPath as String ?: '',
|
||||||
|
args?.tasks as TaskContainer ?: new TaskContainer(),
|
||||||
|
args?.taskTypes as Set<Class<? extends Task>> ?: [] as Set<Class<? extends Task>>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ class TextMocks {
|
|||||||
when(textRenderer.render(any(), any())).thenReturn(new Tuple2<>([], text))
|
when(textRenderer.render(any(), any())).thenReturn(new Tuple2<>([], text))
|
||||||
def frontMatterGetter = mock(FrontMatterGetter)
|
def frontMatterGetter = mock(FrontMatterGetter)
|
||||||
def excerptGetter = mock(ExcerptGetter)
|
def excerptGetter = mock(ExcerptGetter)
|
||||||
new Text('', '', new TextType([], textRenderer, frontMatterGetter, excerptGetter))
|
new Text(text, '', new TextType([], textRenderer, frontMatterGetter, excerptGetter))
|
||||||
}
|
}
|
||||||
|
|
||||||
static Text textWithPath(String path) {
|
static Text textWithPath(String path) {
|
||||||
@ -33,7 +33,7 @@ class TextMocks {
|
|||||||
when(textRenderer.render(any(), any())).thenReturn(new Tuple2<>([], text))
|
when(textRenderer.render(any(), any())).thenReturn(new Tuple2<>([], text))
|
||||||
def frontMatterGetter = mock(FrontMatterGetter)
|
def frontMatterGetter = mock(FrontMatterGetter)
|
||||||
def excerptGetter = mock(ExcerptGetter)
|
def excerptGetter = mock(ExcerptGetter)
|
||||||
new Text('', path, new TextType([], textRenderer, frontMatterGetter, excerptGetter))
|
new Text(text, path, new TextType([], textRenderer, frontMatterGetter, excerptGetter))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user