Fixed bugs with gst; now using one GroovyScriptEngine.

This commit is contained in:
JesseBrault0709 2023-06-12 15:53:22 +02:00
parent 2208c9f4c0
commit b741765b24
25 changed files with 153 additions and 103 deletions

View File

@ -8,7 +8,7 @@ repositories {
dependencies { dependencies {
// https://archiva.jessebrault.com/#artifact/com.jessebrault.gst/lib // https://archiva.jessebrault.com/#artifact/com.jessebrault.gst/lib
implementation 'com.jessebrault.gst:lib:0.0.1' implementation 'com.jessebrault.gst:lib:0.0.3'
// https://mvnrepository.com/artifact/org.apache.groovy/groovy-templates // https://mvnrepository.com/artifact/org.apache.groovy/groovy-templates
implementation 'org.apache.groovy:groovy-templates:4.0.12' implementation 'org.apache.groovy:groovy-templates:4.0.12'

View File

@ -18,24 +18,23 @@ final class BuildScriptBasedStaticSiteGenerator implements StaticSiteGenerator {
private static final Marker enter = MarkerFactory.getMarker('enter') private static final Marker enter = MarkerFactory.getMarker('enter')
private static final Marker exit = MarkerFactory.getMarker('exit') private static final Marker exit = MarkerFactory.getMarker('exit')
private final GroovyScriptEngine engine
private final Collection<BuildScriptConfiguratorFactory> configuratorFactories private final Collection<BuildScriptConfiguratorFactory> configuratorFactories
@Nullable private final @Nullable File buildScript
private final File buildScript
private final Collection<File> buildSrcDirs
private final Map<String, Object> scriptArgs private final Map<String, Object> scriptArgs
private final Collection<Build> builds = [] private final Collection<Build> builds = []
private boolean ranBuildScript = false private boolean ranBuildScript = false
BuildScriptBasedStaticSiteGenerator( BuildScriptBasedStaticSiteGenerator(
GroovyScriptEngine engine,
Collection<BuildScriptConfiguratorFactory> configuratorFactories = [], Collection<BuildScriptConfiguratorFactory> configuratorFactories = [],
@Nullable File buildScript = null, @Nullable File buildScript = null,
Collection<File> buildSrcDirs = [],
Map<String, Object> scriptArgs = [:] Map<String, Object> scriptArgs = [:]
) { ) {
this.engine = engine
this.configuratorFactories = configuratorFactories this.configuratorFactories = configuratorFactories
this.buildScript = buildScript this.buildScript = buildScript
this.buildSrcDirs = buildSrcDirs
this.scriptArgs = scriptArgs this.scriptArgs = scriptArgs
} }
@ -54,13 +53,10 @@ final class BuildScriptBasedStaticSiteGenerator implements StaticSiteGenerator {
logger.info('running buildScript: {}', this.buildScript) logger.info('running buildScript: {}', this.buildScript)
def result = BuildScripts.runBuildScript( def result = BuildScripts.runBuildScript(
this.buildScript.name, this.buildScript.name,
this.buildScript.parentFile.toURI().toURL(), this.engine,
this.buildSrcDirs.collect { it.toURI().toURL() },
[args: this.scriptArgs] [args: this.scriptArgs]
) { base -> ) { base ->
this.configuratorFactories.each { this.configuratorFactories.each { it.get().accept(base) }
it.get().accept(base)
}
} }
this.builds.addAll(result) this.builds.addAll(result)
} else { } else {

View File

@ -31,6 +31,23 @@ final class BuildScripts {
runBase(base) 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( static Collection<Build> runBuildScript(
String scriptName, String scriptName,
URL scriptBaseDirUrl, URL scriptBaseDirUrl,
@ -50,6 +67,7 @@ final class BuildScripts {
runBase(base) runBase(base)
} }
@Deprecated
static Collection<Build> runBuildScript( static Collection<Build> runBuildScript(
String scriptName, String scriptName,
URL scriptBaseDirUrl, URL scriptBaseDirUrl,
@ -59,6 +77,7 @@ final class BuildScripts {
runBuildScript(scriptName, scriptBaseDirUrl, otherUrls, binding) { } runBuildScript(scriptName, scriptBaseDirUrl, otherUrls, binding) { }
} }
@Deprecated
static Collection<Build> runBuildScript( static Collection<Build> runBuildScript(
String scriptName, String scriptName,
URL scriptBaseDirUrl, URL scriptBaseDirUrl,
@ -67,6 +86,7 @@ final class BuildScripts {
runBuildScript(scriptName, scriptBaseDirUrl, otherUrls, [:]) { } runBuildScript(scriptName, scriptBaseDirUrl, otherUrls, [:]) { }
} }
@Deprecated
static Collection<Build> runBuildScript( static Collection<Build> runBuildScript(
String scriptName, String scriptName,
URL scriptBaseDirUrl URL scriptBaseDirUrl

View File

@ -23,8 +23,8 @@ import java.util.function.Consumer
final class DefaultBuildScriptConfiguratorFactory implements BuildScriptConfiguratorFactory { final class DefaultBuildScriptConfiguratorFactory implements BuildScriptConfiguratorFactory {
private final File baseDir private final File baseDir
private final ClassLoader classLoader private final File tmpDir
private final Collection<URL> scriptBaseUrls private final GroovyScriptEngine engine
@Override @Override
Consumer<BuildScriptBase> get() { Consumer<BuildScriptBase> get() {
@ -36,9 +36,9 @@ final class DefaultBuildScriptConfiguratorFactory implements BuildScriptConfigur
types { types {
textTypes << TextTypes.MARKDOWN textTypes << TextTypes.MARKDOWN
pageTypes << PageTypes.getGsp(['.gsp', '.ssg.gst'], this.classLoader, this.scriptBaseUrls) pageTypes << PageTypes.getGsp(['.gsp', '.ssg.gst'], this.tmpDir, this.engine)
templateTypes << TemplateTypes.getGsp(['.gsp', '.ssg.gst'], this.classLoader, this.scriptBaseUrls) templateTypes << TemplateTypes.getGsp(['.gsp', '.ssg.gst'], this.tmpDir, this.engine)
partTypes << PartTypes.getGsp(['.gsp', '.ssg.gst'], this.classLoader, this.scriptBaseUrls) partTypes << PartTypes.getGsp(['.gsp', '.ssg.gst'], this.tmpDir, this.engine)
} }
sources { base, types -> sources { base, types ->

View File

@ -13,8 +13,8 @@ final class GspPageRenderer implements PageRenderer {
private final StandardGspRenderer gspRenderer private final StandardGspRenderer gspRenderer
GspPageRenderer(ClassLoader classLoader, Collection<URL> urls) { GspPageRenderer(File tmpDir, GroovyScriptEngine engine) {
this.gspRenderer = new StandardGspRenderer(classLoader, urls) this.gspRenderer = new StandardGspRenderer(tmpDir, engine)
} }
@Override @Override

View File

@ -2,11 +2,8 @@ package com.jessebrault.ssg.page
final class PageTypes { final class PageTypes {
@Deprecated static PageType getGsp(Collection<String> extensions, File tmpDir, GroovyScriptEngine engine) {
static final PageType GSP = new PageType(['.gsp'], new GspPageRenderer(PageTypes.classLoader, [])) new PageType(extensions, new GspPageRenderer(tmpDir, engine))
static PageType getGsp(Collection<String> extensions, ClassLoader classLoader, Collection<URL> urls) {
new PageType(extensions, new GspPageRenderer(classLoader, urls))
} }
private PageTypes() {} private PageTypes() {}

View File

@ -15,8 +15,8 @@ final class GspPartRenderer implements PartRenderer {
private final StandardGspRenderer gspRenderer private final StandardGspRenderer gspRenderer
GspPartRenderer(ClassLoader classLoader, Collection<URL> urls) { GspPartRenderer(File tmpDir, GroovyScriptEngine engine) {
this.gspRenderer = new StandardGspRenderer(classLoader, urls) this.gspRenderer = new StandardGspRenderer(tmpDir, engine)
} }
@Override @Override

View File

@ -2,11 +2,8 @@ package com.jessebrault.ssg.part
final class PartTypes { final class PartTypes {
@Deprecated static PartType getGsp(Collection<String> extensions, File tmpDir, GroovyScriptEngine engine) {
static final PartType GSP = new PartType(['.gsp'], new GspPartRenderer(PartTypes.classLoader, [])) new PartType(extensions, new GspPartRenderer(tmpDir, engine))
static PartType getGsp(Collection<String> extensions, ClassLoader classLoader, Collection<URL> scriptBaseUrls) {
new PartType(extensions, new GspPartRenderer(classLoader, scriptBaseUrls))
} }
private PartTypes() {} private PartTypes() {}

View File

@ -13,8 +13,8 @@ final class StandardGspRenderer {
private final TemplateCreator templateCreator private final TemplateCreator templateCreator
StandardGspRenderer(ClassLoader parentClassLoader, Collection<URL> urls) { StandardGspRenderer(File tmpDir, GroovyScriptEngine engine) {
this.templateCreator = new GroovyTemplateCreator(ExtendedGstParser::new, urls, parentClassLoader, true) this.templateCreator = new GroovyTemplateCreator(ExtendedGstParser::new, tmpDir, engine, true)
} }
Result<String> render( Result<String> render(

View File

@ -14,8 +14,8 @@ final class GspTemplateRenderer implements TemplateRenderer {
private final StandardGspRenderer gspRenderer private final StandardGspRenderer gspRenderer
GspTemplateRenderer(ClassLoader parentClassLoader, Collection<URL> urls) { GspTemplateRenderer(File tmpDir, GroovyScriptEngine engine) {
this.gspRenderer = new StandardGspRenderer(parentClassLoader, urls) this.gspRenderer = new StandardGspRenderer(tmpDir, engine)
} }
@Override @Override

View File

@ -2,15 +2,8 @@ package com.jessebrault.ssg.template
final class TemplateTypes { final class TemplateTypes {
@Deprecated static TemplateType getGsp(Collection<String> extensions, File tmpDir, GroovyScriptEngine engine) {
static final TemplateType GSP = new TemplateType(['.gsp'], new GspTemplateRenderer(TemplateTypes.classLoader, [])) new TemplateType(extensions, new GspTemplateRenderer(tmpDir, engine))
static TemplateType getGsp(
Collection<String> extensions,
ClassLoader classLoader,
Collection<URL> scriptBaseUrls
) {
new TemplateType(extensions, new GspTemplateRenderer(classLoader, scriptBaseUrls))
} }
private TemplateTypes() {} private TemplateTypes() {}

View File

@ -32,19 +32,16 @@ final class BuildScriptBasedStaticSiteGeneratorTests {
} }
} }
def ssg = new BuildScriptBasedStaticSiteGenerator( def tmpDir = File.createTempDir()
[new BuildScriptConfiguratorFactory() { def engine = new GroovyScriptEngine([sourceDir.toURI().toURL(), tmpDir.toURI().toURL()] as URL[])
def ssg = new BuildScriptBasedStaticSiteGenerator(engine, [new BuildScriptConfiguratorFactory() {
@Override @Override
Consumer<BuildScriptBase> get() { Consumer<BuildScriptBase> get() {
return { } return { }
} }
}], }], buildScript, [sourceDir: sourceDir, tmpDir: tmpDir, engine: engine])
buildScript,
[],
[sourceDir: sourceDir]
)
assertTrue(ssg.doBuild('test') { assertTrue(ssg.doBuild('test') {
it.each { logger.error(it.toString()) } it.each { logger.error(it.toString()) }
}) })

View File

@ -48,10 +48,19 @@ final class BuildScriptsTests {
tempDir 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 @Test
void simpleScript() { void simpleScript() {
def baseDir = this.setupScripts(['simple.groovy']) def baseDir = this.setupScripts(['simple.groovy'])
def builds = runBuildScript('simple.groovy', baseDir.toURI().toURL()) def builds = getBuilds('simple.groovy', [baseDir.toURI().toURL()])
assertEquals(1, builds.size()) assertEquals(1, builds.size())
assertEquals('test', builds[0].name) assertEquals('test', builds[0].name)
} }
@ -59,7 +68,7 @@ final class BuildScriptsTests {
@Test @Test
void testImport() { void testImport() {
def baseDir = this.setupScripts(['testImport.groovy', 'TestHtmlTask.groovy']) def baseDir = this.setupScripts(['testImport.groovy', 'TestHtmlTask.groovy'])
def builds = runBuildScript('testImport.groovy', baseDir.toURI().toURL()) def builds = getBuilds('testImport.groovy', [baseDir.toURI().toURL()])
assertEquals(1, builds.size()) assertEquals(1, builds.size())
assertEquals('test', builds[0].name) assertEquals('test', builds[0].name)
} }
@ -77,10 +86,12 @@ final class BuildScriptsTests {
} }
} }
} }
def builds = runBuildScript( def builds = getBuilds(
'buildSrcTest.groovy', 'buildSrcTest.groovy',
baseDir.toURI().toURL(), [
[new File(baseDir, 'buildSrc').toURI().toURL()] baseDir.toURI().toURL(),
new File(baseDir, 'buildSrc').toURI().toURL()
]
) )
assertEquals(1, builds.size()) assertEquals(1, builds.size())
assertEquals('test', builds[0].name) assertEquals('test', builds[0].name)
@ -89,12 +100,8 @@ final class BuildScriptsTests {
@Test @Test
void withBinding(@Mock Consumer<String> stringConsumer) { void withBinding(@Mock Consumer<String> stringConsumer) {
def baseDir = this.setupScripts(['withBinding.groovy']) def baseDir = this.setupScripts(['withBinding.groovy'])
runBuildScript( def engine = new GroovyScriptEngine([baseDir.toURI().toURL()] as URL[])
'withBinding.groovy', runBuildScript('withBinding.groovy', engine, [stringConsumer: stringConsumer])
baseDir.toURI().toURL(),
[],
[stringConsumer: stringConsumer]
)
verify(stringConsumer).accept('test') verify(stringConsumer).accept('test')
} }

View File

@ -6,8 +6,13 @@ import com.jessebrault.ssg.util.Result
final class GspPageRendererTests implements StandardDslConsumerTests { final class GspPageRendererTests implements StandardDslConsumerTests {
private static GspPageRenderer getRenderer(ClassLoader classLoader, Collection<URL> urls) { private static GspPageRenderer getRenderer(
new GspPageRenderer(classLoader, urls) ClassLoader classLoader,
Collection<URL> urls
) {
def tmpDir = File.createTempDir()
def engine = new GroovyScriptEngine([tmpDir.toURI().toURL(), *urls] as URL[], classLoader)
new GspPageRenderer(tmpDir, engine)
} }
@Override @Override

View File

@ -15,10 +15,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue
final class GspPartRendererTests implements StandardDslConsumerTests { final class GspPartRendererTests implements StandardDslConsumerTests {
private static GspPartRenderer getRenderer( private static GspPartRenderer getRenderer(
ClassLoader classLoader = GspPartRendererTests.classLoader, ClassLoader parentClassLoader = GspPartRendererTests.classLoader,
Collection<URL> urls = [] Collection<URL> urls = []
) { ) {
new GspPartRenderer(classLoader, urls) def tmpDir = File.createTempDir()
def engine = new GroovyScriptEngine([tmpDir.toURI().toURL(), *urls] as URL[], parentClassLoader)
new GspPartRenderer(tmpDir, engine)
} }
private static Result<String> doRender( private static Result<String> doRender(

View File

@ -14,10 +14,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals
final class GspTemplateRendererTests implements StandardDslConsumerTests { final class GspTemplateRendererTests implements StandardDslConsumerTests {
private static TemplateRenderer getRenderer( private static TemplateRenderer getRenderer(
ClassLoader classLoader = GspTemplateRendererTests.classLoader, ClassLoader parentLoader = GspTemplateRendererTests.class.classLoader,
Collection<URL> urls = [] Collection<URL> urls = []
) { ) {
new GspTemplateRenderer(classLoader, urls) def tmpDir = File.createTempDir()
def engine = new GroovyScriptEngine([tmpDir.toURI().toURL(), *urls] as URL[], parentLoader)
new GspTemplateRenderer(tmpDir, engine)
} }
private static Result<String> doRender( private static Result<String> doRender(

View File

@ -1,3 +1,4 @@
//file:noinspection
def t = new AnotherTask() def t = new AnotherTask()
build(name: 'test') { } build(name: 'test') { }

View File

@ -14,6 +14,8 @@ BuildScriptBase b
final class Args { final class Args {
File sourceDir File sourceDir
File tmpDir
GroovyScriptEngine engine
} }
def args = args as Args def args = args as Args
@ -23,7 +25,7 @@ build(name: 'test') {
types { types {
textTypes << TextTypes.MARKDOWN textTypes << TextTypes.MARKDOWN
templateTypes << TemplateTypes.GSP templateTypes << TemplateTypes.getGsp(['.gsp'], args.tmpDir, args.engine)
} }
sources { base, types -> sources { base, types ->

View File

@ -39,17 +39,16 @@ abstract class AbstractBuildCommand extends AbstractSubCommand {
protected StaticSiteGenerator staticSiteGenerator = null protected StaticSiteGenerator staticSiteGenerator = null
protected final Integer doSingleBuild(String requestedBuild) { protected final Integer doSingleBuild(String requestedBuild, File tmpDir, GroovyScriptEngine engine) {
logger.traceEntry('requestedBuild: {}', requestedBuild) logger.traceEntry('requestedBuild: {}', requestedBuild)
if (this.staticSiteGenerator == null) { if (this.staticSiteGenerator == null) {
this.staticSiteGenerator = new CliBasedStaticSiteGenerator( this.staticSiteGenerator = new CliBasedStaticSiteGenerator(
new File('.'), new File('.'),
this.buildScript, this.buildScript,
this.buildSrcDirs, tmpDir,
this.scriptArgs, engine,
this.class.classLoader, this.scriptArgs
this.buildSrcDirs.collect { it.toURI().toURL() }
) )
} }

View File

@ -11,38 +11,33 @@ final class CliBasedStaticSiteGenerator implements StaticSiteGenerator {
private final File baseDir private final File baseDir
private final File buildScript private final File buildScript
private final Collection<File> buildSrcDirs private final File tmpDir
private final Map<String, String> scriptArgs private final Map<String, String> scriptArgs
private final ClassLoader classLoader private final GroovyScriptEngine engine
private final Collection<URL> scriptBaseUrls
private StaticSiteGenerator staticSiteGenerator private StaticSiteGenerator staticSiteGenerator
CliBasedStaticSiteGenerator( CliBasedStaticSiteGenerator(
File baseDir, File baseDir,
File buildScript, File buildScript,
Collection<File> buildSrcDirs, File tmpDir,
Map<String, String> scriptArgs, GroovyScriptEngine engine,
ClassLoader classLoader, Map<String, String> scriptArgs
Collection<URL> scriptBaseUrls
) { ) {
this.baseDir = baseDir this.baseDir = baseDir
this.buildScript = buildScript this.buildScript = buildScript
this.buildSrcDirs = buildSrcDirs this.tmpDir = tmpDir
this.scriptArgs = scriptArgs this.scriptArgs = scriptArgs
this.classLoader = classLoader this.engine = engine
this.scriptBaseUrls = scriptBaseUrls
} }
@Override @Override
boolean doBuild(String buildName, Consumer<Collection<Diagnostic>> diagnosticsConsumer) { boolean doBuild(String buildName, Consumer<Collection<Diagnostic>> diagnosticsConsumer) {
if (this.staticSiteGenerator == null) { if (this.staticSiteGenerator == null) {
this.staticSiteGenerator = new BuildScriptBasedStaticSiteGenerator( this.staticSiteGenerator = new BuildScriptBasedStaticSiteGenerator(
[new DefaultBuildScriptConfiguratorFactory(this.baseDir, this.classLoader, this.scriptBaseUrls)], this.engine,
this.buildScript == new File('ssgBuilds.groovy') || this.buildScript.exists() [new DefaultBuildScriptConfiguratorFactory(this.baseDir, this.tmpDir, this.engine)],
? new File(this.baseDir, this.buildScript.path) this.buildScript,
: null,
this.buildSrcDirs.collect { new File(this.baseDir, it.path) },
this.scriptArgs this.scriptArgs
) )
} }

View File

@ -17,8 +17,13 @@ final class SsgBuild extends AbstractBuildCommand {
protected Integer doSubCommand() { protected Integer doSubCommand() {
logger.traceEntry() logger.traceEntry()
def result = 0 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 { this.requestedBuilds.each {
def buildResult = this.doSingleBuild(it) def buildResult = this.doSingleBuild(it, tmpDir, engine)
if (buildResult == 1) { if (buildResult == 1) {
result = 1 result = 1
} }

View File

@ -1,5 +1,6 @@
<html> <html>
<% <%
println "delegate.text: $delegate.text"
out << parts['head.gsp'].render([ out << parts['head.gsp'].render([
title: "${ siteSpec.name }: ${ text.frontMatter.title }" title: "${ siteSpec.name }: ${ text.frontMatter.title }"
]) ])

View File

@ -13,5 +13,8 @@
<Root level="warn"> <Root level="warn">
<AppenderRef ref="standard" /> <AppenderRef ref="standard" />
</Root> </Root>
<Logger name="com.jessebrault.fsm" level="OFF" />
<Logger name="com.jessebrault.gst" level="OFF" />
<Logger name="com.jessebrault.gst.groovy.GroovyTemplateCreator" level="trace" />
</Loggers> </Loggers>
</Configuration> </Configuration>

View File

@ -11,22 +11,30 @@ final class CliBasedStaticSiteGeneratorTests {
@Test @Test
void meatyInitAndBuild() { void meatyInitAndBuild() {
def tempDir = File.createTempDir() def baseDir = File.createTempDir()
SsgInit.init(tempDir, true) 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( def ssg = new CliBasedStaticSiteGenerator(
tempDir, baseDir,
new File('ssgBuilds.groovy'), new File(baseDir, 'ssgBuilds.groovy'),
[new File('buildSrc')], tmpDir,
[:], engine,
this.class.classLoader, [:]
[new File(tempDir, 'buildSrc').toURI().toURL()]
) )
def diagnostics = [] as Collection<Diagnostic> def diagnostics = [] as Collection<Diagnostic>
assertTrue(ssg.doBuild('production', diagnostics.&addAll)) assertTrue(ssg.doBuild('production', diagnostics.&addAll), {
diagnostics.inject('') { acc, diagnostic ->
acc + '\n' + diagnostic.message
}
})
assertTrue(diagnostics.empty) assertTrue(diagnostics.empty)
def buildDir = new File(tempDir, 'production') def buildDir = new File(baseDir, 'production')
assertTrue(buildDir.exists()) assertTrue(buildDir.exists())
assertTrue(buildDir.directory) assertTrue(buildDir.directory)

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Configuration name="ssg" status="WARN">
<Appenders>
<Console name="standard" target="SYSTEM_OUT">
<PatternLayout>
<MarkerPatternSelector defaultPattern="%highlight{%-5level} %logger{1}: %msg%n%ex">
<PatternMatch key="FLOW" pattern="%highlight{%-5level} %logger{1}: %markerSimpleName %msg%n%ex" />
</MarkerPatternSelector>
</PatternLayout>
</Console>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="standard" />
</Root>
<Logger name="com.jessebrault.fsm" level="OFF" />
<Logger name="com.jessebrault.gst" level="OFF" />
<Logger name="com.jessebrault.gst.groovy.GroovyTemplateCreator" level="trace" />
</Loggers>
</Configuration>