Refactoring of all file providers; all paths now include extension.

This commit is contained in:
Jesse Brault 2023-02-14 15:33:15 +01:00
parent 99836856d7
commit 076bc9bc52
11 changed files with 128 additions and 149 deletions

View File

@ -32,10 +32,10 @@ abstract class AbstractBuildCommand extends AbstractSubCommand {
def gspPart = new PartType(['.gsp'], new GspPartRenderer()) def gspPart = new PartType(['.gsp'], new GspPartRenderer())
def gspSpecialPage = new SpecialPageType(['.gsp'], new GspSpecialPageRenderer()) def gspSpecialPage = new SpecialPageType(['.gsp'], new GspSpecialPageRenderer())
def defaultTextsProvider = new TextFileTextsProvider([markdownText], new File('texts')) def defaultTextsProvider = new TextFileTextsProvider(new File('texts'), [markdownText])
def defaultTemplatesProvider = new TemplateFileTemplatesProvider([gspTemplate], new File('templates')) def defaultTemplatesProvider = new TemplateFileTemplatesProvider(new File('templates'), [gspTemplate])
def defaultPartsProvider = new PartFilePartsProvider([gspPart], new File('parts')) def defaultPartsProvider = new PartFilePartsProvider(new File('parts'), [gspPart])
def defaultSpecialPagesProvider = new SpecialPageFileSpecialPagesProvider([gspSpecialPage], new File('specialPages')) def defaultSpecialPagesProvider = new SpecialPageFileSpecialPagesProvider(new File('specialPages'), [gspSpecialPage])
def defaultConfig = new Config( def defaultConfig = new Config(
textProviders: [defaultTextsProvider], textProviders: [defaultTextsProvider],

View File

@ -1,55 +1,38 @@
package com.jessebrault.ssg.part package com.jessebrault.ssg.part
import com.jessebrault.ssg.provider.WithWatchableDir import com.jessebrault.ssg.provider.AbstractFileCollectionProvider
import groovy.io.FileType
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck import groovy.transform.NullCheck
import org.jetbrains.annotations.Nullable
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import static com.jessebrault.ssg.util.ExtensionsUtil.getExtension
@NullCheck @NullCheck
@EqualsAndHashCode(includeFields = true) @EqualsAndHashCode(includeFields = true)
class PartFilePartsProvider implements PartsProvider, WithWatchableDir { class PartFilePartsProvider extends AbstractFileCollectionProvider<Part> implements PartsProvider {
private static final Logger logger = LoggerFactory.getLogger(PartFilePartsProvider) private static final Logger logger = LoggerFactory.getLogger(PartFilePartsProvider)
private final Collection<PartType> partTypes private final Collection<PartType> partTypes
private final File partsDir
PartFilePartsProvider(Collection<PartType> partTypes, File partsDir) { PartFilePartsProvider(File partsDir, Collection<PartType> partTypes) {
this.partTypes = partTypes super(partsDir)
this.partsDir = partsDir this.partTypes = Objects.requireNonNull(partTypes)
this.watchableDir = this.partsDir
} }
private PartType getPartType(File file) { private @Nullable PartType getPartType(String extension) {
def path = file.path
this.partTypes.find { this.partTypes.find {
it.ids.contains(getExtension(path)) it.ids.contains(extension)
} }
} }
@Override @Override
Collection<Part> provide() { protected @Nullable Part transformFileToT(File file, String relativePath, String extension) {
if (!partsDir.isDirectory()) { def partType = getPartType(extension)
logger.warn('partsDir {} does not exist or is not a directory; skipping and providing no Parts', this.partsDir) if (!partType) {
[] logger.warn('there is no PartType for {}, ignoring', relativePath)
} else {
def parts = []
this.partsDir.eachFileRecurse(FileType.FILES) {
def type = this.getPartType(it)
if (type != null) {
def relativePath = this.partsDir.relativePath(it)
logger.debug('found part {}', relativePath)
parts << new Part(relativePath, type, it.text)
} else {
logger.warn('ignoring {} since there is no partType for it', it)
}
}
parts
} }
partType ? new Part(relativePath, partType, file.text) : null
} }
@Override @Override
@ -59,7 +42,7 @@ class PartFilePartsProvider implements PartsProvider, WithWatchableDir {
@Override @Override
String toString() { String toString() {
"PartFilePartsProvider(partsDir: ${ this.partsDir }, partTypes: ${ this.partTypes })" "PartFilePartsProvider(partsDir: ${ this.dir }, partTypes: ${ this.partTypes })"
} }
} }

View File

@ -0,0 +1,40 @@
package com.jessebrault.ssg.provider
import groovy.io.FileType
import org.jetbrains.annotations.Nullable
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import static com.jessebrault.ssg.util.ExtensionsUtil.getExtension
abstract class AbstractFileCollectionProvider<T> implements Provider<Collection<T>>, WithWatchableDir {
private static final Logger logger = LoggerFactory.getLogger(AbstractFileCollectionProvider)
protected final File dir
AbstractFileCollectionProvider(File dir) {
this.dir = Objects.requireNonNull(dir)
this.watchableDir = dir
}
protected abstract @Nullable T transformFileToT(File file, String relativePath, String extension)
@Override
Collection<T> provide() {
if (!this.dir.isDirectory()) {
logger.warn('{} does not exist or is not a directory; skipping', this.dir)
[]
} else {
def ts = []
this.dir.eachFileRecurse(FileType.FILES) {
def t = transformFileToT(it, this.dir.relativePath(it), getExtension(it.path))
if (t) {
ts << t
}
}
ts
}
}
}

View File

@ -1,57 +1,39 @@
package com.jessebrault.ssg.specialpage package com.jessebrault.ssg.specialpage
import com.jessebrault.ssg.provider.WithWatchableDir import com.jessebrault.ssg.provider.AbstractFileCollectionProvider
import groovy.io.FileType
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck import groovy.transform.NullCheck
import org.jetbrains.annotations.Nullable
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import static com.jessebrault.ssg.util.ExtensionsUtil.getExtension
import static com.jessebrault.ssg.util.ExtensionsUtil.stripExtension
@NullCheck @NullCheck
@EqualsAndHashCode(includeFields = true) @EqualsAndHashCode(includeFields = true)
class SpecialPageFileSpecialPagesProvider implements SpecialPagesProvider, WithWatchableDir { class SpecialPageFileSpecialPagesProvider extends AbstractFileCollectionProvider<SpecialPage>
implements SpecialPagesProvider {
private static final Logger logger = LoggerFactory.getLogger(SpecialPageFileSpecialPagesProvider) private static final Logger logger = LoggerFactory.getLogger(SpecialPageFileSpecialPagesProvider)
private final Collection<SpecialPageType> specialPageTypes private final Collection<SpecialPageType> specialPageTypes
private final File specialPagesDir
SpecialPageFileSpecialPagesProvider(Collection<SpecialPageType> specialPageTypes, File specialPagesDir) { SpecialPageFileSpecialPagesProvider(File specialPagesDir, Collection<SpecialPageType> specialPageTypes) {
this.specialPageTypes = specialPageTypes super(specialPagesDir)
this.specialPagesDir = specialPagesDir this.specialPageTypes = Objects.requireNonNull(specialPageTypes)
this.watchableDir = this.specialPagesDir
} }
private SpecialPageType getSpecialPageType(File file) { private @Nullable SpecialPageType getSpecialPageType(String extension) {
def path = file.path
this.specialPageTypes.find { this.specialPageTypes.find {
it.ids.contains(getExtension(path)) it.ids.contains(extension)
} }
} }
@Override @Override
Collection<SpecialPage> provide() { protected @Nullable SpecialPage transformFileToT(File file, String relativePath, String extension) {
if (!this.specialPagesDir.isDirectory()) { def specialPageType = getSpecialPageType(extension)
logger.warn('specialPagesDir {} does not exist or is not a directory; skipping and providing no SpecialPages', this.specialPagesDir) if (!specialPageType) {
[] logger.warn('there is no SpecialPageType for {}, ignoring', relativePath)
} else {
def specialPages = []
this.specialPagesDir.eachFileRecurse(FileType.FILES) {
def type = this.getSpecialPageType(it)
if (type != null) {
def relativePath = this.specialPagesDir.relativePath(it)
def path = stripExtension(relativePath)
logger.info('found specialPage {} with type {}', path, type)
specialPages << new SpecialPage(it.text, path, type)
} else {
logger.warn('ignoring {} since there is no specialPageType for it', it)
}
}
specialPages
} }
specialPageType ? new SpecialPage(file.text, relativePath, specialPageType) : null
} }
@Override @Override
@ -61,7 +43,8 @@ class SpecialPageFileSpecialPagesProvider implements SpecialPagesProvider, WithW
@Override @Override
String toString() { String toString() {
"SpecialPageFileSpecialPagesProvider(specialPagesDir: ${ this.specialPagesDir }, specialPageTypes: ${ this.specialPageTypes })" "SpecialPageFileSpecialPagesProvider(specialPagesDir: ${ this.dir }, " +
"specialPageTypes: ${ this.specialPageTypes })"
} }
} }

View File

@ -1,55 +1,38 @@
package com.jessebrault.ssg.template package com.jessebrault.ssg.template
import com.jessebrault.ssg.provider.WithWatchableDir import com.jessebrault.ssg.provider.AbstractFileCollectionProvider
import groovy.io.FileType
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck import groovy.transform.NullCheck
import org.jetbrains.annotations.Nullable
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import static com.jessebrault.ssg.util.ExtensionsUtil.getExtension
@NullCheck @NullCheck
@EqualsAndHashCode(includeFields = true) @EqualsAndHashCode(includeFields = true)
class TemplateFileTemplatesProvider implements TemplatesProvider, WithWatchableDir { class TemplateFileTemplatesProvider extends AbstractFileCollectionProvider<Template> implements TemplatesProvider {
private static final Logger logger = LoggerFactory.getLogger(TemplateFileTemplatesProvider) private static final Logger logger = LoggerFactory.getLogger(TemplateFileTemplatesProvider)
private final Collection<TemplateType> templateTypes private final Collection<TemplateType> templateTypes
private final File templatesDir
TemplateFileTemplatesProvider(Collection<TemplateType> templateTypes, File templatesDir) { TemplateFileTemplatesProvider(File templatesDir, Collection<TemplateType> templateTypes) {
this.templateTypes = templateTypes super(templatesDir)
this.templatesDir = templatesDir this.templateTypes = Objects.requireNonNull(templateTypes)
this.watchableDir = this.templatesDir
} }
private TemplateType getType(File file) { private @Nullable TemplateType getType(String extension) {
def path = file.path
this.templateTypes.find { this.templateTypes.find {
it.ids.contains(getExtension(path)) it.ids.contains(extension)
} }
} }
@Override @Override
Collection<Template> provide() { protected Template transformFileToT(File file, String relativePath, String extension) {
if (!this.templatesDir.isDirectory()) { def templateType = getType(extension)
logger.warn('templatesDir {} does not exist or is not a directory; skipping and providing no Templates', this.templatesDir) if (templateType == null) {
[] logger.warn('there is no TemplateType for template {}, ignoring', relativePath)
} else {
def templates = []
this.templatesDir.eachFileRecurse(FileType.FILES) {
def type = this.getType(it)
if (type != null) {
def relativePath = this.templatesDir.relativePath(it)
logger.debug('found template {}', relativePath)
templates << new Template(it.text, relativePath, type)
} else {
logger.warn('ignoring {} because there is no templateType for it', it)
}
}
templates
} }
templateType ? new Template(file.text, relativePath, templateType) : null
} }
@Override @Override
@ -59,7 +42,7 @@ class TemplateFileTemplatesProvider implements TemplatesProvider, WithWatchableD
@Override @Override
String toString() { String toString() {
"TemplateFileTemplatesProvider(templatesDir: ${ this.templatesDir }, templateTypes: ${ this.templateTypes })" "TemplateFileTemplatesProvider(templatesDir: ${ this.dir }, templateTypes: ${ this.templateTypes })"
} }
} }

View File

@ -1,57 +1,38 @@
package com.jessebrault.ssg.text package com.jessebrault.ssg.text
import com.jessebrault.ssg.provider.WithWatchableDir import com.jessebrault.ssg.provider.AbstractFileCollectionProvider
import groovy.io.FileType
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck import groovy.transform.NullCheck
import org.jetbrains.annotations.Nullable
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import static com.jessebrault.ssg.util.ExtensionsUtil.getExtension
import static com.jessebrault.ssg.util.ExtensionsUtil.stripExtension
@NullCheck @NullCheck
@EqualsAndHashCode(includeFields = true) @EqualsAndHashCode(includeFields = true)
class TextFileTextsProvider implements TextsProvider, WithWatchableDir { class TextFileTextsProvider extends AbstractFileCollectionProvider<Text> implements TextsProvider {
private static final Logger logger = LoggerFactory.getLogger(TextFileTextsProvider) private static final Logger logger = LoggerFactory.getLogger(TextFileTextsProvider)
private final Collection<TextType> textTypes private final Collection<TextType> textTypes
private final File textsDir
TextFileTextsProvider(Collection<TextType> textTypes, File textsDir) { TextFileTextsProvider(File textsDir, Collection<TextType> textTypes) {
this.textTypes = textTypes super(textsDir)
this.textsDir = textsDir this.textTypes = Objects.requireNonNull(textTypes)
this.watchableDir = this.textsDir
} }
private TextType getTextType(File file) { private TextType getTextType(String extension) {
def path = file.path
this.textTypes.find { this.textTypes.find {
it.ids.contains(getExtension(path)) it.ids.contains(extension)
} }
} }
@Override @Override
Collection<Text> provide() { protected @Nullable Text transformFileToT(File file, String relativePath, String extension) {
if (!this.textsDir.isDirectory()) { def textType = getTextType(extension)
logger.warn('textsDir {} does not exist or is not a directory; skipping and providing no Texts', this.textsDir) if (!textType) {
[] logger.warn('no TextType for text {}, ignoring', file.path)
} else {
def textFiles = []
this.textsDir.eachFileRecurse(FileType.FILES) {
def type = this.getTextType(it)
if (type != null) {
def relativePath = this.textsDir.relativePath(it)
def path = stripExtension(relativePath)
logger.debug('found textFile {} with type {}', path, type)
textFiles << new Text(it.text, path, type)
} else {
logger.warn('ignoring {} because there is no textType for it', it)
}
}
textFiles
} }
textType ? new Text(file.text, relativePath, textType) : null
} }
@Override @Override
@ -61,7 +42,7 @@ class TextFileTextsProvider implements TextsProvider, WithWatchableDir {
@Override @Override
String toString() { String toString() {
"TextFileTextsProvider(textsDir: ${ this.textsDir }, textTypes: ${ this.textTypes })" "TextFileTextsProvider(textsDir: ${ this.dir }, textTypes: ${ this.textTypes })"
} }
} }

View File

@ -41,10 +41,10 @@ class SimpleStaticSiteGeneratorIntegrationTests {
def gspPartType = new PartType(['.gsp'], new GspPartRenderer()) def gspPartType = new PartType(['.gsp'], new GspPartRenderer())
def gspSpecialPageType = new SpecialPageType(['.gsp'], new GspSpecialPageRenderer()) def gspSpecialPageType = new SpecialPageType(['.gsp'], new GspSpecialPageRenderer())
def textsProvider = new TextFileTextsProvider([markdownTextType], this.textsDir) def textsProvider = new TextFileTextsProvider(this.textsDir, [markdownTextType])
def templatesProvider = new TemplateFileTemplatesProvider([gspTemplateType], this.templatesDir) def templatesProvider = new TemplateFileTemplatesProvider(this.templatesDir, [gspTemplateType])
def partsProvider = new PartFilePartsProvider([gspPartType], this.partsDir) def partsProvider = new PartFilePartsProvider(this.partsDir, [gspPartType])
def specialPagesProvider = new SpecialPageFileSpecialPagesProvider([gspSpecialPageType], this.specialPagesDir) def specialPagesProvider = new SpecialPageFileSpecialPagesProvider(this.specialPagesDir, [gspSpecialPageType])
def config = new Config( def config = new Config(
textProviders: [textsProvider], textProviders: [textsProvider],

View File

@ -4,10 +4,11 @@ import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import static org.junit.jupiter.api.Assertions.assertEquals import static org.junit.jupiter.api.Assertions.assertEquals
import static org.mockito.Mockito.mock
class PartFilePartsProviderTests { class PartFilePartsProviderTests {
private static final PartType gspPartType = new PartType(['.gsp'], null) private static final PartType gspPartType = new PartType(['.gsp'], mock(PartRenderer))
private File partsDir private File partsDir
private PartsProvider partsProvider private PartsProvider partsProvider
@ -15,7 +16,7 @@ class PartFilePartsProviderTests {
@BeforeEach @BeforeEach
void beforeEach() { void beforeEach() {
this.partsDir = File.createTempDir() this.partsDir = File.createTempDir()
partsProvider = new PartFilePartsProvider([gspPartType], this.partsDir) partsProvider = new PartFilePartsProvider(this.partsDir, [gspPartType])
} }
@Test @Test

View File

@ -4,10 +4,11 @@ import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import static org.junit.jupiter.api.Assertions.assertEquals import static org.junit.jupiter.api.Assertions.assertEquals
import static org.mockito.Mockito.mock
class SpecialPageFileSpecialPagesProviderTests { class SpecialPageFileSpecialPagesProviderTests {
private static final SpecialPageType gspType = new SpecialPageType(['.gsp'], null) private static final SpecialPageType gspType = new SpecialPageType(['.gsp'], mock(SpecialPageRenderer))
private File specialPagesDir private File specialPagesDir
private SpecialPagesProvider specialPagesProvider private SpecialPagesProvider specialPagesProvider
@ -15,7 +16,7 @@ class SpecialPageFileSpecialPagesProviderTests {
@BeforeEach @BeforeEach
void beforeEach() { void beforeEach() {
this.specialPagesDir = File.createTempDir() this.specialPagesDir = File.createTempDir()
this.specialPagesProvider = new SpecialPageFileSpecialPagesProvider([gspType], this.specialPagesDir) this.specialPagesProvider = new SpecialPageFileSpecialPagesProvider(this.specialPagesDir, [gspType])
} }
@Test @Test
@ -26,7 +27,7 @@ class SpecialPageFileSpecialPagesProviderTests {
def r = this.specialPagesProvider.provide() def r = this.specialPagesProvider.provide()
assertEquals(1, r.size()) assertEquals(1, r.size())
def f0 = r[0] def f0 = r[0]
assertEquals('test', f0.path) assertEquals('test.gsp', f0.path)
assertEquals('<%= "Hello, World!" %>', f0.text) assertEquals('<%= "Hello, World!" %>', f0.text)
assertEquals(gspType, f0.type) assertEquals(gspType, f0.type)
} }
@ -40,7 +41,7 @@ class SpecialPageFileSpecialPagesProviderTests {
def r = this.specialPagesProvider.provide() def r = this.specialPagesProvider.provide()
assertEquals(1, r.size()) assertEquals(1, r.size())
def f0 = r[0] def f0 = r[0]
assertEquals('nested/nested', f0.path) assertEquals('nested/nested.gsp', f0.path)
assertEquals('<%= "Hello, World!" %>', f0.text) assertEquals('<%= "Hello, World!" %>', f0.text)
assertEquals(gspType, f0.type) assertEquals(gspType, f0.type)
} }

View File

@ -4,10 +4,11 @@ import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import static org.junit.jupiter.api.Assertions.assertEquals import static org.junit.jupiter.api.Assertions.assertEquals
import static org.mockito.Mockito.mock
class PageTemplatesProviderTests { class TemplateFileTemplatesProviderTests {
private static final TemplateType gspType = new TemplateType(['.gsp'], null) private static final TemplateType gspType = new TemplateType(['.gsp'], mock(TemplateRenderer))
private File templatesDir private File templatesDir
private TemplatesProvider templatesProvider private TemplatesProvider templatesProvider
@ -15,7 +16,7 @@ class PageTemplatesProviderTests {
@BeforeEach @BeforeEach
void beforeEach() { void beforeEach() {
this.templatesDir = File.createTempDir() this.templatesDir = File.createTempDir()
this.templatesProvider = new TemplateFileTemplatesProvider([gspType], this.templatesDir) this.templatesProvider = new TemplateFileTemplatesProvider(this.templatesDir, [gspType])
} }
@Test @Test

View File

@ -4,10 +4,16 @@ import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import static org.junit.jupiter.api.Assertions.assertEquals import static org.junit.jupiter.api.Assertions.assertEquals
import static org.mockito.Mockito.mock
class TextFileTextsProviderTests { class TextFileTextsProviderTests {
private static final TextType markdownType = new TextType(['.md'], null, null, null) private static final TextType markdownType = new TextType(
['.md'],
mock(TextRenderer),
mock(FrontMatterGetter),
mock(ExcerptGetter)
)
private File textsDir private File textsDir
private TextsProvider textsProvider private TextsProvider textsProvider
@ -15,7 +21,7 @@ class TextFileTextsProviderTests {
@BeforeEach @BeforeEach
void beforeEach() { void beforeEach() {
this.textsDir = File.createTempDir() this.textsDir = File.createTempDir()
this.textsProvider = new TextFileTextsProvider([markdownType], this.textsDir) this.textsProvider = new TextFileTextsProvider(this.textsDir, [markdownType])
} }
@Test @Test
@ -25,7 +31,7 @@ class TextFileTextsProviderTests {
def r = this.textsProvider.provide() def r = this.textsProvider.provide()
assertEquals(1, r.size()) assertEquals(1, r.size())
def f0 = r[0] def f0 = r[0]
assertEquals('test', f0.path) assertEquals('test.md', f0.path)
assertEquals('**Hello, World!**', f0.text) assertEquals('**Hello, World!**', f0.text)
assertEquals(markdownType, f0.type) assertEquals(markdownType, f0.type)
} }
@ -39,7 +45,7 @@ class TextFileTextsProviderTests {
def r = this.textsProvider.provide() def r = this.textsProvider.provide()
assertEquals(1, r.size()) assertEquals(1, r.size())
def f0 = r[0] def f0 = r[0]
assertEquals('nested/nested', f0.path) assertEquals('nested/nested.md', f0.path)
assertEquals('**Hello!**', f0.text) assertEquals('**Hello!**', f0.text)
assertEquals(markdownType, f0.type) assertEquals(markdownType, f0.type)
} }