Added multiple inheritance for builds.

This commit is contained in:
JesseBrault0709 2023-06-16 14:02:54 +02:00
parent f3c6f1ef3c
commit c7ba01380e
15 changed files with 487 additions and 586 deletions

View File

@ -1,57 +0,0 @@
package com.jessebrault.ssg.buildscript
import groovy.transform.NullCheck
import groovy.transform.PackageScope
@PackageScope
@NullCheck
final class BuildExtension {
static BuildExtension getEmpty() {
new BuildExtension()
}
static BuildExtension get(String buildName) {
new BuildExtension(buildName)
}
private final String buildName
private BuildExtension(String buildName) {
this.buildName = buildName
}
private BuildExtension() {
this.buildName = null
}
boolean isPresent() {
this.buildName != null
}
boolean isEmpty() {
!this.present
}
String getBuildName() {
Objects.requireNonNull(this.buildName)
}
@Override
String toString() {
this.present ? "BuildExtension(extending: ${ this.buildName })" : "BuildExtension(empty)"
}
@Override
int hashCode() {
Objects.hash(this.buildName)
}
@Override
boolean equals(Object obj) {
obj.is(this)
|| (obj instanceof BuildExtension && obj.present && obj.buildName == this.buildName)
|| (obj instanceof BuildExtension && !obj.present && !this.present)
}
}

View File

@ -0,0 +1,73 @@
package com.jessebrault.ssg.buildscript;
import com.jessebrault.ssg.util.Monoid;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.DirectedAcyclicGraph;
import java.util.Collection;
import java.util.List;
import java.util.function.BiFunction;
public final class BuildGraph {
private static void addAncestorEdges(
Graph<BuildSpec, DefaultEdge> graph,
BuildSpec buildSpec,
Collection<BuildSpec> allBuildSpecs
) {
if (!graph.containsVertex(buildSpec)) {
throw new IllegalStateException("Given buildSpec " + buildSpec.getName() + " is not in the given graph.");
}
for (final var extendingName : buildSpec.getExtending()) {
final var ancestor = allBuildSpecs.stream()
.filter(bs -> extendingName.equals(bs.getName()))
.findAny()
.orElseThrow(() -> new IllegalStateException(
"Could not find ancestor " + extendingName + " for buildSpec " + buildSpec.getName() + "."
));
graph.addEdge(ancestor, buildSpec);
addAncestorEdges(graph, ancestor, allBuildSpecs);
}
}
private final Graph<BuildSpec, DefaultEdge> graph;
public BuildGraph(Collection<BuildSpec> buildSpecs) {
this.graph = new DirectedAcyclicGraph<>(DefaultEdge.class);
for (final var buildSpec : buildSpecs) {
if (!this.graph.containsVertex(buildSpec)) {
this.graph.addVertex(buildSpec);
}
addAncestorEdges(this.graph, buildSpec, buildSpecs);
}
}
public List<BuildSpec> getParents(BuildSpec start) {
return this.graph.incomingEdgesOf(start).stream()
.map(this.graph::getEdgeSource)
.toList();
}
@Deprecated(forRemoval = true)
public BuildIntermediate toIntermediate(
BuildSpec rootSpec,
Monoid<BuildIntermediate> buildIntermediateMonoid,
BiFunction<BuildIntermediate, BuildSpec, BuildIntermediate> parentAndSpecToIntermediate
) {
final List<BuildSpec> parents = this.getParents(rootSpec);
if (parents.size() == 0) {
return parentAndSpecToIntermediate.apply(buildIntermediateMonoid.getZero(), rootSpec);
} else {
final List<BuildIntermediate> parentIntermediates = parents.stream()
.map(parent -> this.toIntermediate(parent, buildIntermediateMonoid, parentAndSpecToIntermediate))
.toList();
final BuildIntermediate parentsReduced = parentIntermediates.stream()
.reduce(buildIntermediateMonoid.getZero(), (bi0, bi1) ->
buildIntermediateMonoid.getConcat().apply(bi0, bi1)
);
return parentAndSpecToIntermediate.apply(parentsReduced, rootSpec);
}
}
}

View File

@ -1,79 +0,0 @@
package com.jessebrault.ssg.buildscript
import groovy.transform.PackageScope
import org.jgrapht.Graph
import org.jgrapht.graph.DefaultEdge
import org.jgrapht.graph.DirectedAcyclicGraph
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.slf4j.Marker
import org.slf4j.MarkerFactory
@PackageScope
final class BuildGraphUtil {
private static final Logger logger = LoggerFactory.getLogger(BuildGraphUtil)
private static final Marker enter = MarkerFactory.getMarker('ENTER')
private static final Marker exit = MarkerFactory.getMarker('EXIT')
private static void addParentEdges(
Graph<BuildSpec, DefaultEdge> graph,
BuildSpec spec,
Collection<BuildSpec> allBuildSpecs
) {
logger.trace(enter, 'graph: {}, spec: {}', graph, spec)
if (!graph.containsVertex(spec)) {
throw new IllegalStateException("given spec is not in the graph")
}
if (spec.extending.present) {
def parent = allBuildSpecs.find { it.name == spec.extending.buildName }
if (parent == null) {
throw new IllegalStateException("no such parent/extends from build: ${ spec.extending.buildName }")
}
if (!graph.containsVertex(parent)) {
graph.addVertex(parent)
}
graph.addEdge(parent, spec)
addParentEdges(graph, parent, allBuildSpecs)
}
logger.trace(exit, '')
}
static Graph<BuildSpec, DefaultEdge> getDependencyGraph(Collection<BuildSpec> buildSpecs) {
logger.trace(enter, '')
final Graph<BuildSpec, DefaultEdge> graph = new DirectedAcyclicGraph<>(DefaultEdge)
buildSpecs.each {
if (!graph.containsVertex(it)) {
graph.addVertex(it)
}
addParentEdges(graph, it, buildSpecs)
}
logger.trace(exit, 'graph: {}', graph)
graph
}
static Collection<BuildSpec> getAncestors(BuildSpec child, Graph<BuildSpec, DefaultEdge> graph) {
logger.trace(enter, 'child: {}, graph: {}', child, graph)
if (child.extending.isEmpty()) {
def r = [] as Collection<BuildSpec>
logger.trace(exit, 'r: {}', r)
r
} else {
// use incoming to get edges pointing to child
def incomingEdges = graph.incomingEdgesOf(child)
if (incomingEdges.size() == 0) {
throw new IllegalArgumentException("child does not have an edge to its parent")
}
if (incomingEdges.size() > 1) {
throw new IllegalArgumentException("child has more than one parent")
}
def parent = graph.getEdgeSource(incomingEdges[0])
def r = getAncestors(parent, graph) + [parent] // needs to be 'oldest' -> 'youngest'
logger.trace(exit, 'r: {}', r)
r
}
}
private BuildGraphUtil() {}
}

View File

@ -0,0 +1,20 @@
package com.jessebrault.ssg.buildscript;
import com.jessebrault.ssg.SiteSpec;
import com.jessebrault.ssg.task.TaskFactory;
import com.jessebrault.ssg.task.TaskFactorySpec;
import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
public interface BuildIntermediate {
BuildSpec getBuildSpec();
Function<Build, OutputDir> getOutputDirFunction();
SiteSpec getSiteSpec();
Map<String, Object> getGlobals();
TypesContainer getTypes();
SourceProviders getSources();
Collection<TaskFactorySpec<TaskFactory>> getTaskFactorySpecs();
Collection<String> getIncludedBuilds();
}

View File

@ -0,0 +1,48 @@
package com.jessebrault.ssg.buildscript
import com.jessebrault.ssg.SiteSpec
import com.jessebrault.ssg.task.TaskFactory
import com.jessebrault.ssg.task.TaskFactorySpec
import com.jessebrault.ssg.util.Monoid
import com.jessebrault.ssg.util.Monoids
import java.util.function.Function
final class BuildMonoids {
static final Monoid<Function<Build, OutputDir>> outputDirFunctionMonoid = OutputDirFunctions.DEFAULT_MONOID
static final Monoid<SiteSpec> siteSpecMonoid = SiteSpec.DEFAULT_MONOID
static final Monoid<Map<String, Object>> globalsMonoid = Monoids.getMapMonoid()
static final Monoid<TypesContainer> typesMonoid = TypesContainer.DEFAULT_MONOID
static final Monoid<SourceProviders> sourcesMonoid = SourceProviders.DEFAULT_MONOID
static final Monoid<Collection<TaskFactorySpec<TaskFactory>>> taskFactoriesMonoid =
Monoids.getMergeCollectionMonoid(
TaskFactorySpec.SAME_NAME_AND_SUPPLIER_EQ,
TaskFactorySpec.DEFAULT_SEMIGROUP
)
static final Monoid<Collection<String>> includedBuildsMonoid = Monoids.getCollectionMonoid()
static Monoid<BuildIntermediate> buildIntermediateMonoid = Monoids.of(SyntheticBuildIntermediate.getEmpty())
{ bi0, bi1 ->
new SyntheticBuildIntermediate(
BuildSpec.get(
name: "SyntheticBuildSpec(${ bi0.buildSpec.name }, ${ bi1.buildSpec.name })",
isAbstract: true,
extending: [],
buildClosure: { }
),
outputDirFunctionMonoid.concat.apply(bi0.outputDirFunction, bi1.outputDirFunction),
siteSpecMonoid.concat.apply(bi0.siteSpec, bi1.siteSpec),
globalsMonoid.concat.apply(bi0.globals, bi1.globals),
typesMonoid.concat.apply(bi0.types, bi1.types),
sourcesMonoid.concat.apply(bi0.sources, bi1.sources),
taskFactoriesMonoid.concat.apply(bi0.taskFactorySpecs, bi1.taskFactorySpecs),
includedBuildsMonoid.concat.apply(bi0.includedBuilds, bi1.includedBuilds)
)
}
private BuildMonoids() {}
}

View File

@ -15,10 +15,19 @@ abstract class BuildScriptBase extends Script {
protected static final Marker enter = MarkerFactory.getMarker('ENTER') protected static final Marker enter = MarkerFactory.getMarker('ENTER')
protected static final Marker exit = MarkerFactory.getMarker('EXIT') protected static final Marker exit = MarkerFactory.getMarker('EXIT')
private static Collection<String> convertExtendingArg(Object arg) {
arg instanceof Collection<String> ? arg as Collection<String>
: arg instanceof String ? [arg] as Collection<String> : []
}
protected final Collection<BuildSpec> buildSpecs = [] protected final Collection<BuildSpec> buildSpecs = []
/** /**
* args keys: name (required), extending (optional) * args keys and values:
* <ul>
* <li><code>name: String<code></li>
* <li><code>extending?: String | Collection&lt;String&gt;</code></li>
* </ul>
* *
* @param args * @param args
* @param buildClosure * @param buildClosure
@ -28,16 +37,21 @@ abstract class BuildScriptBase extends Script {
@DelegatesTo(value = BuildDelegate, strategy = Closure.DELEGATE_FIRST) @DelegatesTo(value = BuildDelegate, strategy = Closure.DELEGATE_FIRST)
Closure<?> buildClosure Closure<?> buildClosure
) { ) {
this.buildSpecs << new BuildSpec( final Collection<String> extending = convertExtendingArg(args.extending)
requireNonNull(args.name as String), this.buildSpecs << BuildSpec.get(
true, name: requireNonNull(args.name as String),
args.extending != null ? BuildExtension.get(args.extending as String) : BuildExtension.getEmpty(), isAbstract: true,
buildClosure extending: extending,
buildClosure: buildClosure
) )
} }
/** /**
* args keys: name (required), extending (optional) * args keys and values:
* <ul>
* <li><code>name: String<code></li>
* <li><code>extending?: String | Collection&lt;String&gt;</code></li>
* </ul>
* *
* @param args * @param args
* @param buildClosure * @param buildClosure
@ -47,11 +61,12 @@ abstract class BuildScriptBase extends Script {
@DelegatesTo(value = BuildDelegate, strategy = Closure.DELEGATE_FIRST) @DelegatesTo(value = BuildDelegate, strategy = Closure.DELEGATE_FIRST)
Closure<?> buildClosure Closure<?> buildClosure
) { ) {
this.buildSpecs << new BuildSpec( final Collection<String> extending = convertExtendingArg(args.extending)
requireNonNull(args.name as String), this.buildSpecs << BuildSpec.get(
false, name: requireNonNull(args.name as String),
args.extending != null ? BuildExtension.get(args.extending as String) : BuildExtension.getEmpty(), isAbstract: false,
buildClosure extending: extending,
buildClosure: buildClosure
) )
} }

View File

@ -3,36 +3,43 @@ package com.jessebrault.ssg.buildscript
import com.jessebrault.ssg.buildscript.delegates.BuildDelegate import com.jessebrault.ssg.buildscript.delegates.BuildDelegate
import groovy.transform.EqualsAndHashCode import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck import groovy.transform.NullCheck
import groovy.transform.PackageScope
import groovy.transform.TupleConstructor
@PackageScope @NullCheck
@NullCheck()
@EqualsAndHashCode(excludes = 'buildClosure') @EqualsAndHashCode(excludes = 'buildClosure')
final class BuildSpec { final class BuildSpec {
static BuildSpec getEmpty() { static BuildSpec getEmpty() {
new BuildSpec('', false, BuildExtension.getEmpty(), { }) new BuildSpec('', false, [], { })
} }
static BuildSpec get(Map<String, Object> args) { static BuildSpec get(Map<String, Object> args) {
new BuildSpec( new BuildSpec(
args.name as String ?: '', args.name as String ?: '',
args.isAbstract as boolean ?: false, args.isAbstract as boolean ?: false,
args.extending as BuildExtension ?: BuildExtension.getEmpty(), args.extending as Collection<String> ?: [],
args.buildClosure as Closure<?> ?: { } args.buildClosure as Closure<?> ?: { }
) )
} }
final String name static BuildSpec get(
final boolean isAbstract
final BuildExtension extending
final Closure<?> buildClosure
BuildSpec(
String name, String name,
boolean isAbstract, boolean isAbstract,
BuildExtension extending, Collection<String> extending,
@DelegatesTo(value = BuildDelegate, strategy = Closure.DELEGATE_FIRST)
Closure<?> buildClosure
) {
new BuildSpec(name, isAbstract, extending, buildClosure)
}
final String name
final boolean isAbstract
final Collection<String> extending
final Closure<?> buildClosure
private BuildSpec(
String name,
boolean isAbstract,
Collection<String> extending,
@DelegatesTo(value = BuildDelegate, strategy = Closure.DELEGATE_FIRST) @DelegatesTo(value = BuildDelegate, strategy = Closure.DELEGATE_FIRST)
Closure<?> buildClosure Closure<?> buildClosure
) { ) {

View File

@ -1,13 +1,8 @@
package com.jessebrault.ssg.buildscript package com.jessebrault.ssg.buildscript
import com.jessebrault.ssg.SiteSpec
import com.jessebrault.ssg.buildscript.delegates.BuildDelegate import com.jessebrault.ssg.buildscript.delegates.BuildDelegate
import com.jessebrault.ssg.task.TaskFactory
import com.jessebrault.ssg.task.TaskFactorySpec
import com.jessebrault.ssg.util.Monoid import com.jessebrault.ssg.util.Monoid
import com.jessebrault.ssg.util.Monoids import groovy.transform.NullCheck
import com.jessebrault.ssg.util.Zero
import org.jgrapht.traverse.DepthFirstIterator
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.slf4j.Marker import org.slf4j.Marker
@ -15,98 +10,79 @@ import org.slf4j.MarkerFactory
import java.util.function.BiFunction import java.util.function.BiFunction
@NullCheck
final class BuildSpecUtil { final class BuildSpecUtil {
private static final Logger logger = LoggerFactory.getLogger(BuildSpecUtil) private static final Logger logger = LoggerFactory.getLogger(BuildSpecUtil)
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 static final Monoid<Map<String, Object>> globalsMonoid = Monoids.of([:]) { m0, m1 -> private static Build intermediateToBuild(BuildIntermediate intermediate) {
m0 + m1
}
private static final Monoid<Collection<String>> includedBuildsMonoid = Monoids.of([]) { c0, c1 ->
c0 + c1
}
private static final Monoid<Collection<TaskFactorySpec<TaskFactory>>> taskFactoriesMonoid =
Monoids.getMergeCollectionMonoid(TaskFactorySpec.SAME_NAME_AND_SUPPLIER_EQ, TaskFactorySpec.DEFAULT_SEMIGROUP)
private static <T> T reduceResults(
Collection<BuildDelegate.Results> resultsCollection,
Zero<T> tZero,
BiFunction<T, BuildDelegate.Results, T> resultsToT
) {
resultsCollection.inject(tZero.zero) { acc, r ->
resultsToT.apply(acc, r)
}
}
private static Collection<BuildDelegate.Results> mapBuildSpecsToResults(Collection<BuildSpec> buildSpecs) {
buildSpecs.collect {
def delegate = new BuildDelegate()
it.buildClosure.delegate = delegate
//noinspection UnnecessaryQualifiedReference
it.buildClosure.resolveStrategy = Closure.DELEGATE_FIRST
it.buildClosure()
new BuildDelegate.Results(delegate)
}
}
private static Build toBuild(
Collection<BuildSpec> specs
) {
if (specs.empty) {
throw new IllegalArgumentException('specs must contain at least one BuildSpec')
}
def allResults = mapBuildSpecsToResults(specs)
def outputDirFunctionResult = reduceResults(allResults, OutputDirFunctions.DEFAULT_MONOID) { acc, r ->
r.getOutputDirFunctionResult(acc, { acc })
}
def siteSpecResult = reduceResults(allResults, SiteSpec.DEFAULT_MONOID) { acc, r ->
r.getSiteSpecResult(acc, true, SiteSpec.DEFAULT_MONOID)
}
def globalsResult = reduceResults(allResults, globalsMonoid) { acc, r ->
r.getGlobalsResult(acc, true, globalsMonoid)
}
def typesResult = reduceResults(allResults, TypesContainer.DEFAULT_MONOID) { acc, r ->
r.getTypesResult(acc, true, TypesContainer.DEFAULT_MONOID)
}
def sourcesResult = reduceResults(allResults, SourceProviders.DEFAULT_MONOID) { acc, r ->
r.getSourcesResult(acc, true, SourceProviders.DEFAULT_MONOID, typesResult)
}
def taskFactoriesResult = reduceResults(allResults, taskFactoriesMonoid) { acc, r ->
r.getTaskFactoriesResult(acc, true, taskFactoriesMonoid, sourcesResult)
}
def includedBuildsResult = reduceResults(allResults, includedBuildsMonoid) { acc, r ->
r.getIncludedBuildsResult(acc, true, includedBuildsMonoid)
}
Build.get( Build.get(
name: specs.last().name, name: intermediate.buildSpec.name,
outputDirFunction: outputDirFunctionResult, outputDirFunction: intermediate.outputDirFunction,
siteSpec: siteSpecResult, siteSpec: intermediate.siteSpec,
globals: globalsResult, globals: intermediate.globals,
taskFactorySpecs: taskFactoriesResult, taskFactorySpecs: intermediate.taskFactorySpecs,
includedBuilds: includedBuildsResult includedBuilds: intermediate.includedBuilds
) )
} }
static Collection<Build> getBuilds(Collection<BuildSpec> buildSpecs) { private static BuildIntermediate specToIntermediate(BuildSpec buildSpec, BuildIntermediate parent) {
logger.trace(enter, '') def d = new BuildDelegate()
def graph = BuildGraphUtil.getDependencyGraph(buildSpecs) buildSpec.buildClosure.delegate = d
def r = new DepthFirstIterator<>(graph).findResults { buildSpec.buildClosure.resolveStrategy = Closure.DELEGATE_FIRST
if (it.isAbstract) { buildSpec.buildClosure()
return null new BuildDelegate.BuildDelegateBuildIntermediate(
buildSpec,
d,
parent,
BuildMonoids.siteSpecMonoid,
BuildMonoids.globalsMonoid,
BuildMonoids.typesMonoid,
BuildMonoids.sourcesMonoid,
BuildMonoids.taskFactoriesMonoid,
BuildMonoids.includedBuildsMonoid
)
}
private static BuildIntermediate reduceWithParents(
BuildSpec rootSpec,
BuildGraph buildGraph,
Monoid<BuildIntermediate> buildIntermediateMonoid,
BiFunction<BuildIntermediate, BuildSpec, BuildIntermediate> parentAndSpecToIntermediate
) {
final List<BuildSpec> parents = buildGraph.getParents(rootSpec)
if (parents.size() == 0) {
parentAndSpecToIntermediate.apply(buildIntermediateMonoid.zero, rootSpec)
} else {
final List<BuildIntermediate> parentIntermediates = parents.collect {
reduceWithParents(it, buildGraph, buildIntermediateMonoid, parentAndSpecToIntermediate)
} }
def ancestors = BuildGraphUtil.getAncestors(it, graph) final BuildIntermediate parentsReduced = parentIntermediates.inject(buildIntermediateMonoid.zero)
logger.debug('ancestors of {}: {}', it, ancestors) { acc, bi ->
toBuild([*ancestors, it]) buildIntermediateMonoid.concat.apply(acc, bi)
}
parentAndSpecToIntermediate.apply(parentsReduced, rootSpec)
} }
logger.trace(exit, 'r: {}', r) }
r
static Collection<Build> getBuilds(Collection<BuildSpec> buildSpecs) {
logger.trace(enter, 'buildSpecs: {}', buildSpecs)
def graph = new BuildGraph(buildSpecs)
def intermediates = buildSpecs.findResults {
if (it.isAbstract) {
null
} else {
reduceWithParents(it, graph, BuildMonoids.buildIntermediateMonoid)
{ parent, spec ->
specToIntermediate(spec, parent)
}
}
}
def builds = intermediates.collect { intermediateToBuild(it) }
logger.trace(exit, 'builds: {}', builds)
builds
} }
private BuildSpecUtil() {} private BuildSpecUtil() {}

View File

@ -0,0 +1,74 @@
package com.jessebrault.ssg.buildscript
import com.jessebrault.ssg.SiteSpec
import com.jessebrault.ssg.task.TaskFactory
import com.jessebrault.ssg.task.TaskFactorySpec
import groovy.transform.EqualsAndHashCode
import groovy.transform.NullCheck
import groovy.transform.TupleConstructor
import java.util.function.Function
@TupleConstructor(defaults = false)
@NullCheck(includeGenerated = true)
@EqualsAndHashCode
final class SyntheticBuildIntermediate implements BuildIntermediate {
static BuildIntermediate getEmpty() {
new SyntheticBuildIntermediate(
BuildSpec.getEmpty(),
OutputDirFunctions.DEFAULT,
SiteSpec.getBlank(),
[:],
TypesContainer.getEmpty(),
SourceProviders.getEmpty(),
[],
[]
)
}
static BuildIntermediate get(Map<String, Object> args) {
new SyntheticBuildIntermediate(
args.buildSpec as BuildSpec ?: BuildSpec.getEmpty(),
args.outputDirFunction as Function<Build, OutputDir> ?: OutputDirFunctions.DEFAULT,
args.siteSpec as SiteSpec ?: SiteSpec.getBlank(),
args.globals as Map<String, Object> ?: [:],
args.types as TypesContainer ?: TypesContainer.getEmpty(),
args.sources as SourceProviders ?: SourceProviders.getEmpty(),
args.taskFactorySpecs as Collection<TaskFactorySpec<TaskFactory>> ?: [],
args.includedBuilds as Collection<String> ?: []
)
}
static BuildIntermediate get(
BuildSpec buildSpec,
Function<Build, OutputDir> outputDirFunction,
SiteSpec siteSpec,
Map<String, Object> globals,
TypesContainer types,
SourceProviders sources,
Collection<TaskFactorySpec<TaskFactory>> taskFactorySpecs,
Collection<String> includedBuilds
) {
new SyntheticBuildIntermediate(
buildSpec,
outputDirFunction,
siteSpec,
globals,
types,
sources,
taskFactorySpecs,
includedBuilds
)
}
final BuildSpec buildSpec
final Function<Build, OutputDir> outputDirFunction
final SiteSpec siteSpec
final Map<String, Object> globals
final TypesContainer types
final SourceProviders sources
final Collection<TaskFactorySpec<TaskFactory>> taskFactorySpecs
final Collection<String> includedBuilds
}

View File

@ -1,10 +1,7 @@
package com.jessebrault.ssg.buildscript.delegates package com.jessebrault.ssg.buildscript.delegates
import com.jessebrault.ssg.SiteSpec import com.jessebrault.ssg.SiteSpec
import com.jessebrault.ssg.buildscript.Build import com.jessebrault.ssg.buildscript.*
import com.jessebrault.ssg.buildscript.OutputDir
import com.jessebrault.ssg.buildscript.SourceProviders
import com.jessebrault.ssg.buildscript.TypesContainer
import com.jessebrault.ssg.mutable.Mutable import com.jessebrault.ssg.mutable.Mutable
import com.jessebrault.ssg.mutable.Mutables import com.jessebrault.ssg.mutable.Mutables
import com.jessebrault.ssg.task.TaskFactory import com.jessebrault.ssg.task.TaskFactory
@ -18,7 +15,6 @@ import groovy.transform.stc.FromString
import groovy.transform.stc.SimpleType import groovy.transform.stc.SimpleType
import java.util.function.Function import java.util.function.Function
import java.util.function.Supplier
import java.util.function.UnaryOperator import java.util.function.UnaryOperator
@NullCheck(includeGenerated = true) @NullCheck(includeGenerated = true)
@ -28,133 +24,107 @@ final class BuildDelegate {
@TupleConstructor(includeFields = true, defaults = false) @TupleConstructor(includeFields = true, defaults = false)
@NullCheck(includeGenerated = true) @NullCheck(includeGenerated = true)
@EqualsAndHashCode(includeFields = true) @EqualsAndHashCode(includeFields = true)
static final class Results { static final class BuildDelegateBuildIntermediate implements BuildIntermediate {
private final BuildSpec buildSpec
private final BuildDelegate delegate private final BuildDelegate delegate
private final BuildIntermediate parent
Function<Build, OutputDir> getOutputDirFunctionResult( private final Monoid<SiteSpec> siteSpecMonoid
Function<Build, OutputDir> base, private final Monoid<Map<String, Object>> globalsMonoid
Supplier<Function<Build, OutputDir>> onEmpty private final Monoid<TypesContainer> typesMonoid
) { private final Monoid<SourceProviders> sourcesMonoid
private final Monoid<Collection<TaskFactorySpec<TaskFactory>>> taskFactoriesMonoid
private final Monoid<Collection<String>> includedBuildsMonoid
@Override
BuildSpec getBuildSpec() {
this.buildSpec
}
@Override
Function<Build, OutputDir> getOutputDirFunction() {
this.delegate.outputDirFunction.getOrElse { this.delegate.outputDirFunction.getOrElse {
this.delegate.outputDirFunctionMapper.match(onEmpty) { this.delegate.outputDirFunctionMapper.match({ parent.outputDirFunction }) {
it.apply(base) it.apply(this.parent.outputDirFunction)
} }
} }
} }
SiteSpec getSiteSpecResult( @Override
SiteSpec base, SiteSpec getSiteSpec() {
boolean onConcatWithBaseEmpty, def siteSpecClosure = this.delegate.siteSpecClosure.getOrElse { return { } }
Monoid<SiteSpec> siteSpecMonoid def d = new SiteSpecDelegate(this.siteSpecMonoid)
) { siteSpecClosure.delegate = d
def concatWithBase = this.delegate.siteSpecConcatBase.isPresent() siteSpecClosure.resolveStrategy = Closure.DELEGATE_FIRST
? this.delegate.siteSpecConcatBase.get() siteSpecClosure(this.parent.siteSpec)
: onConcatWithBaseEmpty if (this.delegate.siteSpecConcatBase.getOrElse { true }) {
def onEmpty = { concatWithBase ? base : siteSpecMonoid.zero } this.siteSpecMonoid.concat.apply(this.parent.siteSpec, d.result)
this.delegate.siteSpecClosure.match(onEmpty) { } else {
def d = new SiteSpecDelegate(siteSpecMonoid) d.result
it.delegate = d
//noinspection UnnecessaryQualifiedReference
it.resolveStrategy = Closure.DELEGATE_FIRST
it(base)
def r = d.getResult()
concatWithBase ? siteSpecMonoid.concat.apply(base, r) : r
} }
} }
Map<String, Object> getGlobalsResult( @Override
Map<String, Object> base, Map<String, Object> getGlobals() {
boolean onConcatWithBaseEmpty, def globalsClosure = this.delegate.globalsClosure.getOrElse { return { } }
Monoid<Map<String, Object>> globalsMonoid def d = new GlobalsDelegate()
) { globalsClosure.delegate = d
def concatWithBase = this.delegate.globalsConcatBase.isPresent() globalsClosure.resolveStrategy = Closure.DELEGATE_FIRST
? this.delegate.globalsConcatBase.get() globalsClosure(this.parent.globals)
: onConcatWithBaseEmpty if (this.delegate.globalsConcatBase.getOrElse { true }) {
def onEmpty = { concatWithBase ? base : globalsMonoid.zero } this.globalsMonoid.concat.apply(this.parent.globals, d.getResult())
this.delegate.globalsClosure.match(onEmpty) { } else {
def d = new GlobalsDelegate() d.getResult()
it.delegate = d
//noinspection UnnecessaryQualifiedReference
it.resolveStrategy = Closure.DELEGATE_FIRST
it(base)
def r = d.getResult()
concatWithBase ? globalsMonoid.concat.apply(base, r) : r
} }
} }
TypesContainer getTypesResult( @Override
TypesContainer base, TypesContainer getTypes() {
boolean onConcatWithBaseEmpty, def typesClosure = this.delegate.typesClosure.getOrElse { return { } }
Monoid<TypesContainer> typesContainerMonoid def d = new TypesDelegate()
) { typesClosure.delegate = d
def concatWithBase = this.delegate.typesConcatBase.isPresent() typesClosure.resolveStrategy = Closure.DELEGATE_FIRST
? this.delegate.typesConcatBase.get() typesClosure(this.parent.types)
: onConcatWithBaseEmpty if (this.delegate.typesConcatBase.getOrElse { true }) {
def onEmpty = { concatWithBase ? base : typesContainerMonoid.zero } this.typesMonoid.concat.apply(this.parent.types, d.result)
this.delegate.typesClosure.match(onEmpty) { } else {
def d = new TypesDelegate() d.result
it.delegate = d
//noinspection UnnecessaryQualifiedReference
it.resolveStrategy = Closure.DELEGATE_FIRST
it(base)
def r = d.getResult()
concatWithBase ? typesContainerMonoid.concat.apply(base, r) : r
} }
} }
SourceProviders getSourcesResult( @Override
SourceProviders base, SourceProviders getSources() {
boolean onConcatWithBaseEmpty, def sourcesClosure = this.delegate.sourcesClosure.getOrElse { return { base, types -> } }
Monoid<SourceProviders> sourceProvidersMonoid, def d = new SourceProvidersDelegate()
TypesContainer types sourcesClosure.delegate = d
) { sourcesClosure.resolveStrategy = Closure.DELEGATE_FIRST
def concatWithBase = this.delegate.sourcesConcatBase.isPresent() sourcesClosure(this.parent.sources, this.types)
? this.delegate.sourcesConcatBase.get() if (this.delegate.sourcesConcatBase.getOrElse { true }) {
: onConcatWithBaseEmpty this.sourcesMonoid.concat.apply(this.parent.sources, d.result)
def onEmpty = { concatWithBase ? base : sourceProvidersMonoid.zero } } else {
this.delegate.sourcesClosure.match(onEmpty) { d.result
def d = new SourceProvidersDelegate()
it.delegate = d
//noinspection UnnecessaryQualifiedReference
it.resolveStrategy = Closure.DELEGATE_FIRST
it(base, types)
def r = d.getResult()
concatWithBase ? sourceProvidersMonoid.concat.apply(base, r) : r
} }
} }
Collection<TaskFactorySpec<TaskFactory>> getTaskFactoriesResult( @Override
Collection<TaskFactorySpec<TaskFactory>> base, Collection<TaskFactorySpec<TaskFactory>> getTaskFactorySpecs() {
boolean onConcatWithBaseEmpty, def taskFactoriesClosure = this.delegate.taskFactoriesClosure.getOrElse { return { base, sources -> } }
Monoid<Collection<TaskFactorySpec<TaskFactory>>> taskFactorySpecsMonoid, def d = new TaskFactoriesDelegate()
SourceProviders sources taskFactoriesClosure.delegate = d
) { taskFactoriesClosure.resolveStrategy = Closure.DELEGATE_FIRST
def concatWithBase = this.delegate.taskFactoriesConcatBase.isPresent() taskFactoriesClosure(this.parent.taskFactorySpecs, this.sources)
? this.delegate.taskFactoriesConcatBase.get() if (this.delegate.taskFactoriesConcatBase.getOrElse { true }) {
: onConcatWithBaseEmpty this.taskFactoriesMonoid.concat.apply(this.parent.taskFactorySpecs, d.result)
def onEmpty = { concatWithBase ? base : taskFactorySpecsMonoid.zero } } else {
this.delegate.taskFactoriesClosure.match(onEmpty) { d.result
def d = new TaskFactoriesDelegate()
it.delegate = d
//noinspection UnnecessaryQualifiedReference
it.resolveStrategy = Closure.DELEGATE_FIRST
it(base, sources)
def r = d.getResult()
concatWithBase ? taskFactorySpecsMonoid.concat.apply(base, r) : r
} }
} }
Collection<String> getIncludedBuildsResult( @Override
Collection<String> base, Collection<String> getIncludedBuilds() {
boolean onConcatWithBaseEmpty, if (this.delegate.includedBuildsConcatBase.getOrElse { true }) {
Monoid<Collection<String>> includedBuildsMonoid this.includedBuildsMonoid.concat.apply(this.parent.includedBuilds, this.delegate.includedBuilds)
) {
def concatWithBase = this.delegate.includedBuildsConcatBase.isPresent()
? this.delegate.includedBuildsConcatBase.get()
: onConcatWithBaseEmpty
if (concatWithBase) {
includedBuildsMonoid.concat.apply(base, this.delegate.includedBuilds)
} else { } else {
this.delegate.includedBuilds this.delegate.includedBuilds
} }

View File

@ -28,6 +28,14 @@ final class Monoids {
}) })
} }
static <T> Monoid<Collection<T>> getCollectionMonoid() {
of([], { c0, c1 -> c0 + c1 })
}
static <T, U> Monoid<Map<T, U>> getMapMonoid() {
of([:], { m0, m1 -> m0 + m1 })
}
private Monoids() {} private Monoids() {}
} }

View File

@ -1,98 +0,0 @@
package com.jessebrault.ssg.buildscript
import groovy.transform.PackageScope
import org.junit.jupiter.api.Test
import static com.jessebrault.ssg.buildscript.BuildGraphUtil.getAncestors
import static com.jessebrault.ssg.buildscript.BuildGraphUtil.getDependencyGraph
import static org.junit.jupiter.api.Assertions.*
@PackageScope
final class BuildGraphUtilTests {
@Test
void oneBuildGraph() {
def spec = BuildSpec.getEmpty()
def graph = getDependencyGraph([spec])
assertTrue(graph.containsVertex(spec))
assertEquals(0, graph.edgesOf(spec).size())
}
@Test
void twoBuildsNotConnectedGraph() {
def spec0 = BuildSpec.getEmpty()
def spec1 = BuildSpec.getEmpty()
def graph = getDependencyGraph([spec0, spec1])
[spec0, spec1].each {
assertTrue(graph.containsVertex(it))
assertEquals(0, graph.edgesOf(it).size())
}
}
@Test
void twoBuildsParentAndChildGraph() {
def child = BuildSpec.get(name: 'child', extending: BuildExtension.get('parent'))
def parent = BuildSpec.get(name: 'parent')
def graph = getDependencyGraph([child, parent])
[child, parent].each {
assertTrue(graph.containsVertex(it))
}
assertEquals(1, graph.edgeSet().size())
assertTrue(graph.containsEdge(parent, child))
}
@Test
void threeBuildPyramidGraph() {
def left = BuildSpec.get(name: 'left', extending: BuildExtension.get('parent'))
def right = BuildSpec.get(name: 'right', extending: BuildExtension.get('parent'))
def parent = BuildSpec.get(name: 'parent')
def graph = getDependencyGraph([left, right, parent])
[left, right, parent].each {
assertTrue(graph.containsVertex(it))
}
assertEquals(2, graph.edgeSet().size())
assertTrue(graph.containsEdge(parent, left))
assertTrue(graph.containsEdge(parent, right))
}
@Test
void noAncestors() {
def spec = BuildSpec.getEmpty()
def graph = getDependencyGraph([spec])
def ancestors = getAncestors(spec, graph)
assertEquals(0, ancestors.size())
}
@Test
void oneAncestor() {
def child = BuildSpec.get(name: 'child', extending: BuildExtension.get('parent'))
def parent = BuildSpec.get(name: 'parent')
def graph = getDependencyGraph([child, parent])
def ancestors = getAncestors(child, graph)
assertEquals(1, ancestors.size())
assertIterableEquals([parent], ancestors)
}
@Test
void pyramidNotConfusedBySibling() {
def child = BuildSpec.get(name: 'child', extending: BuildExtension.get('parent'))
def sibling = BuildSpec.get(name: 'sibling', extending: BuildExtension.get('parent'))
def parent = BuildSpec.get(name: 'parent')
def graph = getDependencyGraph([child, sibling, parent])
def ancestorsOfChild = getAncestors(child, graph)
assertEquals(1, ancestorsOfChild.size())
assertIterableEquals([parent], ancestorsOfChild)
}
@Test
void threeGenerationAncestors() {
def child = BuildSpec.get(name: 'child', extending: BuildExtension.get('parent'))
def parent = BuildSpec.get(name: 'parent', extending: BuildExtension.get('grandparent'))
def grandparent = BuildSpec.get(name: 'grandparent')
def graph = getDependencyGraph([child, parent, grandparent])
def ancestorsOfChild = getAncestors(child, graph)
assertEquals(2, ancestorsOfChild.size())
assertIterableEquals([grandparent, parent], ancestorsOfChild)
}
}

View File

@ -77,7 +77,7 @@ final class BuildScriptBaseTests {
assertEquals(2, r.size()) assertEquals(2, r.size())
assertEquals( assertEquals(
[ [
BuildSpec.get(name: 'child', extending: BuildExtension.get('parent')), BuildSpec.get(name: 'child', extending: ['parent']),
BuildSpec.get(name: 'parent') BuildSpec.get(name: 'parent')
], ],
r r
@ -94,8 +94,8 @@ final class BuildScriptBaseTests {
assertEquals(3, r.size()) assertEquals(3, r.size())
assertEquals( assertEquals(
[ [
BuildSpec.get(name: 'child', extending: BuildExtension.get('parent')), BuildSpec.get(name: 'child', extending: ['parent']),
BuildSpec.get(name: 'parent', extending: BuildExtension.get('grandparent')), BuildSpec.get(name: 'parent', extending: ['grandparent']),
BuildSpec.get(name: 'grandparent') BuildSpec.get(name: 'grandparent')
], ],
r r
@ -112,8 +112,8 @@ final class BuildScriptBaseTests {
assertEquals(3, r.size()) assertEquals(3, r.size())
assertEquals( assertEquals(
[ [
BuildSpec.get(name: 'child0', extending: BuildExtension.get('parent')), BuildSpec.get(name: 'child0', extending: ['parent']),
BuildSpec.get(name: 'child1', extending: BuildExtension.get('parent')), BuildSpec.get(name: 'child1', extending: ['parent']),
BuildSpec.get(name: 'parent') BuildSpec.get(name: 'parent')
], ],
r r

View File

@ -14,12 +14,12 @@ final class BuildSpecUtilTests {
@Test @Test
void overwrittenOutputDir(@Mock Function<Build, OutputDir> spec1OutputDirFunction) { void overwrittenOutputDir(@Mock Function<Build, OutputDir> spec1OutputDirFunction) {
def spec0 = new BuildSpec('spec0', true, BuildExtension.getEmpty(), { def spec0 = BuildSpec.get('spec0', true, []) {
outputDirFunction = { } outputDirFunction = { }
}) }
def spec1 = new BuildSpec('spec1', false, BuildExtension.get('spec0'), { def spec1 = BuildSpec.get('spec1', false, ['spec0']) {
outputDirFunction = spec1OutputDirFunction outputDirFunction = spec1OutputDirFunction
}) }
def r = BuildSpecUtil.getBuilds([spec0, spec1]) def r = BuildSpecUtil.getBuilds([spec0, spec1])
assertEquals(1, r.size()) assertEquals(1, r.size())
def b0 = r[0] def b0 = r[0]
@ -29,16 +29,16 @@ final class BuildSpecUtilTests {
@Test @Test
void outputDirManualConcat() { void outputDirManualConcat() {
def spec0 = new BuildSpec('spec0', true, BuildExtension.getEmpty(), { def spec0 = BuildSpec.get('spec0', true, []) {
outputDirFunction = OutputDirFunctions.DEFAULT outputDirFunction = OutputDirFunctions.DEFAULT
}) }
def spec1 = new BuildSpec('spec1', false, BuildExtension.get('spec0'), { def spec1 = BuildSpec.get('spec1', false, ['spec0']) {
outputDirFunction { outputDirFunction {
it.andThen { it.andThen {
new OutputDir(new File(it.asFile(), 'spec1')) new OutputDir(new File(it.asFile(), 'spec1'))
} }
} }
}) }
def r = BuildSpecUtil.getBuilds([spec0, spec1]) def r = BuildSpecUtil.getBuilds([spec0, spec1])
assertEquals(1, r.size()) assertEquals(1, r.size())
def b0 = r[0] def b0 = r[0]

View File

@ -2,8 +2,12 @@ package com.jessebrault.ssg.buildscript.delegates
import com.jessebrault.ssg.SiteSpec import com.jessebrault.ssg.SiteSpec
import com.jessebrault.ssg.buildscript.Build import com.jessebrault.ssg.buildscript.Build
import com.jessebrault.ssg.buildscript.BuildIntermediate
import com.jessebrault.ssg.buildscript.BuildMonoids
import com.jessebrault.ssg.buildscript.BuildSpec
import com.jessebrault.ssg.buildscript.OutputDir import com.jessebrault.ssg.buildscript.OutputDir
import com.jessebrault.ssg.buildscript.SourceProviders import com.jessebrault.ssg.buildscript.SourceProviders
import com.jessebrault.ssg.buildscript.SyntheticBuildIntermediate
import com.jessebrault.ssg.buildscript.TypesContainer import com.jessebrault.ssg.buildscript.TypesContainer
import com.jessebrault.ssg.provider.CollectionProvider import com.jessebrault.ssg.provider.CollectionProvider
import com.jessebrault.ssg.provider.CollectionProviders import com.jessebrault.ssg.provider.CollectionProviders
@ -11,8 +15,6 @@ import com.jessebrault.ssg.task.TaskFactory
import com.jessebrault.ssg.task.TaskFactorySpec import com.jessebrault.ssg.task.TaskFactorySpec
import com.jessebrault.ssg.text.Text import com.jessebrault.ssg.text.Text
import com.jessebrault.ssg.text.TextTypes import com.jessebrault.ssg.text.TextTypes
import com.jessebrault.ssg.util.Monoid
import com.jessebrault.ssg.util.Monoids
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.Mock import org.mockito.Mock
@ -29,55 +31,48 @@ final class BuildDelegateTests {
private final BuildDelegate d = new BuildDelegate() private final BuildDelegate d = new BuildDelegate()
private BuildDelegate.Results getResults() { private BuildIntermediate getResults(BuildIntermediate parent = SyntheticBuildIntermediate.getEmpty()) {
new BuildDelegate.Results(this.d) new BuildDelegate.BuildDelegateBuildIntermediate(
BuildSpec.getEmpty(),
this.d,
parent,
BuildMonoids.siteSpecMonoid,
BuildMonoids.globalsMonoid,
BuildMonoids.typesMonoid,
BuildMonoids.sourcesMonoid,
BuildMonoids.taskFactoriesMonoid,
BuildMonoids.includedBuildsMonoid
)
} }
@Test @Test
void simpleOutputDirFunction( void simpleOutputDirFunction(@Mock Function<Build, OutputDir> expected) {
@Mock Function<Build, OutputDir> expected,
@Mock Function<Build, OutputDir> base,
@Mock Supplier<Function<Build, OutputDir>> onEmpty
) {
this.d.outputDirFunction = expected this.d.outputDirFunction = expected
def r = this.results.getOutputDirFunctionResult(base, onEmpty) def r = this.getResults().outputDirFunction
assertEquals(expected, r) assertEquals(expected, r)
} }
@Test @Test
void mappedOutputDirFunction( void mappedOutputDirFunction() {
@Mock Supplier<Function<Build, OutputDir>> onEmpty
) {
final Function<Build, OutputDir> base = { Build b -> final Function<Build, OutputDir> base = { Build b ->
new OutputDir('test') new OutputDir('test')
} }
this.d.outputDirFunction { this.d.outputDirFunction {
it.andThen { new OutputDir(it.asString() + '/nested') } it.andThen { new OutputDir(it.asString() + '/nested') }
} }
def r = this.results.getOutputDirFunctionResult(base, onEmpty) def r = this.getResults(SyntheticBuildIntermediate.get(outputDirFunction: base))
.outputDirFunction
def outputDir = r.apply(Build.getEmpty()) def outputDir = r.apply(Build.getEmpty())
assertEquals('test/nested', outputDir.asString()) assertEquals('test/nested', outputDir.asString())
} }
@Test
void emptyOutputDirFunction(
@Mock Function<Build, OutputDir> base,
@Mock Function<Build, OutputDir> empty
) {
assertEquals(empty, this.results.getOutputDirFunctionResult(base, { empty }))
}
@Test @Test
void siteSpecNoBase() { void siteSpecNoBase() {
this.d.siteSpec { this.d.siteSpec {
name = 'test' name = 'test'
baseUrl = 'testUrl' baseUrl = 'testUrl'
} }
def r = this.results.getSiteSpecResult( def r = this.getResults().siteSpec
SiteSpec.getBlank(),
true,
SiteSpec.DEFAULT_MONOID
)
assertEquals('test', r.name) assertEquals('test', r.name)
assertEquals('testUrl', r.baseUrl) assertEquals('testUrl', r.baseUrl)
} }
@ -88,11 +83,9 @@ final class BuildDelegateTests {
name = base.name + 'Preview' name = base.name + 'Preview'
baseUrl = base.baseUrl + '/preview' baseUrl = base.baseUrl + '/preview'
} }
def r = this.results.getSiteSpecResult( def r = this.getResults(
new SiteSpec('mySite', 'https://mysite.com'), SyntheticBuildIntermediate.get(siteSpec: new SiteSpec('mySite', 'https://mysite.com'))
true, ).siteSpec
SiteSpec.DEFAULT_MONOID
)
assertEquals('mySitePreview', r.name) assertEquals('mySitePreview', r.name)
assertEquals('https://mysite.com/preview', r.baseUrl) assertEquals('https://mysite.com/preview', r.baseUrl)
} }
@ -102,11 +95,9 @@ final class BuildDelegateTests {
this.d.siteSpec { this.d.siteSpec {
name = '123' name = '123'
} }
def r = this.results.getSiteSpecResult( def r = this.getResults(
new SiteSpec('', '456'), SyntheticBuildIntermediate.get(siteSpec: new SiteSpec('', '456'))
true, ).siteSpec
SiteSpec.DEFAULT_MONOID
)
assertEquals('123', r.name) assertEquals('123', r.name)
assertEquals('456', r.baseUrl) assertEquals('456', r.baseUrl)
} }
@ -116,25 +107,16 @@ final class BuildDelegateTests {
this.d.siteSpec(false) { this.d.siteSpec(false) {
name = '123' name = '123'
} }
def r = this.results.getSiteSpecResult( def r = this.getResults(
new SiteSpec('', '456'), SyntheticBuildIntermediate.get(siteSpec: new SiteSpec('', '456'))
true, ).siteSpec
SiteSpec.DEFAULT_MONOID
)
assertEquals('123', r.name) assertEquals('123', r.name)
assertEquals(SiteSpec.DEFAULT_MONOID.zero.baseUrl, r.baseUrl) assertEquals(SiteSpec.DEFAULT_MONOID.zero.baseUrl, r.baseUrl)
} }
@Test @Test
void emptySiteSpec() { void emptySiteSpec() {
assertEquals( assertEquals(SiteSpec.getBlank(), this.getResults().siteSpec)
SiteSpec.getBlank(),
this.results.getSiteSpecResult(SiteSpec.getBlank(), true, SiteSpec.DEFAULT_MONOID)
)
}
private static Monoid<Map<String, Object>> getGlobalsMonoid() {
Monoids.of([:]) { m0, m1 -> m0 + m1 }
} }
@Test @Test
@ -142,7 +124,7 @@ final class BuildDelegateTests {
this.d.globals { this.d.globals {
test = 'abc' test = 'abc'
} }
def r = this.results.getGlobalsResult([:], true, getGlobalsMonoid()) def r = this.getResults().globals
assertEquals([test: 'abc'], r) assertEquals([test: 'abc'], r)
} }
@ -151,17 +133,13 @@ final class BuildDelegateTests {
this.d.globals { base -> this.d.globals { base ->
test = base.test test = base.test
} }
def r = this.results.getGlobalsResult( def r = this.getResults(SyntheticBuildIntermediate.get(globals: [test: 'abc'])).globals
[test: 'abc'],
true,
getGlobalsMonoid()
)
assertEquals([test: 'abc'], r) assertEquals([test: 'abc'], r)
} }
@Test @Test
void globalsEmpty() { void globalsEmpty() {
assertEquals([:], this.results.getGlobalsResult([:], true, getGlobalsMonoid())) assertEquals([:], this.getResults().globals)
} }
@Test @Test
@ -169,11 +147,7 @@ final class BuildDelegateTests {
this.d.types { this.d.types {
textTypes << TextTypes.MARKDOWN textTypes << TextTypes.MARKDOWN
} }
def r = this.results.getTypesResult( def r = this.getResults().types
TypesContainer.getEmpty(),
true,
TypesContainer.DEFAULT_MONOID
)
assertEquals(TypesContainer.get(textTypes: [TextTypes.MARKDOWN]), r) assertEquals(TypesContainer.get(textTypes: [TextTypes.MARKDOWN]), r)
} }
@ -182,11 +156,9 @@ final class BuildDelegateTests {
this.d.types(false) { base -> this.d.types(false) { base ->
textTypes.addAll(base.textTypes) textTypes.addAll(base.textTypes)
} }
def r = this.results.getTypesResult( def r = this.getResults(
TypesContainer.get(textTypes: [TextTypes.MARKDOWN]), SyntheticBuildIntermediate.get(types: TypesContainer.get(textTypes: [TextTypes.MARKDOWN]))
true, ).types
TypesContainer.DEFAULT_MONOID
)
assertEquals(TypesContainer.get(textTypes: [TextTypes.MARKDOWN]), r) assertEquals(TypesContainer.get(textTypes: [TextTypes.MARKDOWN]), r)
} }
@ -195,12 +167,7 @@ final class BuildDelegateTests {
this.d.sources { base, types -> this.d.sources { base, types ->
texts textsProvider texts textsProvider
} }
def r = this.results.getSourcesResult( def r = this.getResults().sources
SourceProviders.getEmpty(),
true,
SourceProviders.DEFAULT_MONOID,
TypesContainer.getEmpty()
)
assertTrue(textsProvider in r.textsProvider) assertTrue(textsProvider in r.textsProvider)
} }
@ -217,44 +184,27 @@ final class BuildDelegateTests {
this.d.sources { base, types -> this.d.sources { base, types ->
texts base.textsProvider texts base.textsProvider
} }
def r = this.results.getSourcesResult( def r = this.getResults(
SourceProviders.get(textsProvider: textsProvider), SyntheticBuildIntermediate.get(sources: SourceProviders.get(textsProvider: textsProvider))
true, ).sources
SourceProviders.DEFAULT_MONOID,
TypesContainer.getEmpty()
)
assertTrue(textsProvider in r.textsProvider) assertTrue(textsProvider in r.textsProvider)
} }
@Test @Test
void sourceProvidersMergeBase() { void sourceProvidersMergeBase() {
def textsProvider = CollectionProviders.fromCollection([] as Collection<Text>) def textsProvider = CollectionProviders.fromCollection([] as Collection<Text>)
def r = this.results.getSourcesResult( def r = this.getResults(
SourceProviders.get(textsProvider: textsProvider), SyntheticBuildIntermediate.get(sources: SourceProviders.get(textsProvider: textsProvider))
true, ).sources
SourceProviders.DEFAULT_MONOID,
TypesContainer.getEmpty()
)
assertTrue(textsProvider in r.textsProvider) assertTrue(textsProvider in r.textsProvider)
} }
private static Monoid<Collection<TaskFactorySpec<TaskFactory>>> getTaskFactoriesMonoid() {
Monoids.of([] as Collection<TaskFactorySpec<TaskFactory>>) { c0, c1 ->
c0 + c1
}
}
@Test @Test
void taskFactoriesNoBase(@Mock Supplier<TaskFactory> taskFactorySupplier) { void taskFactoriesNoBase(@Mock Supplier<TaskFactory> taskFactorySupplier) {
this.d.taskFactories { base, sources -> this.d.taskFactories { base, sources ->
register('f0', taskFactorySupplier) register('f0', taskFactorySupplier)
} }
def r = this.results.getTaskFactoriesResult( def r = this.getResults().taskFactorySpecs
[],
true,
getTaskFactoriesMonoid(),
SourceProviders.getEmpty()
)
assertEquals(1, r.size()) assertEquals(1, r.size())
def spec0 = r[0] def spec0 = r[0]
assertEquals('f0', spec0.name) assertEquals('f0', spec0.name)
@ -266,12 +216,11 @@ final class BuildDelegateTests {
this.d.taskFactories(false) { base, sources -> this.d.taskFactories(false) { base, sources ->
registerAll(base) registerAll(base)
} }
def r = this.results.getTaskFactoriesResult( def r = this.getResults(
[new TaskFactorySpec<TaskFactory>('spec0', taskFactorySupplier, [])], SyntheticBuildIntermediate.get(
true, taskFactorySpecs: [new TaskFactorySpec<TaskFactory>('spec0', taskFactorySupplier, [])]
getTaskFactoriesMonoid(), )
SourceProviders.getEmpty() ).taskFactorySpecs
)
assertEquals(1, r.size()) assertEquals(1, r.size())
def spec0 = r[0] def spec0 = r[0]
assertEquals('spec0', spec0.name) assertEquals('spec0', spec0.name)
@ -281,12 +230,11 @@ final class BuildDelegateTests {
@Test @Test
void taskFactoriesMergeBase(@Mock Supplier<TaskFactory> taskFactorySupplier) { void taskFactoriesMergeBase(@Mock Supplier<TaskFactory> taskFactorySupplier) {
def r = this.results.getTaskFactoriesResult( def r = this.getResults(
[new TaskFactorySpec<TaskFactory>('spec0', taskFactorySupplier, [])], SyntheticBuildIntermediate.get(
true, taskFactorySpecs: [new TaskFactorySpec<TaskFactory>('spec0', taskFactorySupplier, [])]
getTaskFactoriesMonoid(), )
SourceProviders.getEmpty() ).taskFactorySpecs
)
assertEquals(1, r.size()) assertEquals(1, r.size())
def spec0 = r[0] def spec0 = r[0]
assertEquals('spec0', spec0.name) assertEquals('spec0', spec0.name)
@ -294,17 +242,13 @@ final class BuildDelegateTests {
assertEquals([], spec0.configurators) assertEquals([], spec0.configurators)
} }
private static Monoid<Collection<String>> getIncludedBuildsMonoid() {
Monoids.of([]) { c0, c1 -> c0 + c1 }
}
@Test @Test
void includedBuildsNoBase() { void includedBuildsNoBase() {
this.d.concatIncludedBuildsWithBase = false this.d.concatIncludedBuildsWithBase = false
this.d.includeBuild('included') this.d.includeBuild('included')
def r = this.results.getIncludedBuildsResult( def r = this.getResults(
['notIncluded'], true, getIncludedBuildsMonoid() SyntheticBuildIntermediate.get(includedBuilds: ['notIncluded'])
) ).includedBuilds
assertEquals(1, r.size()) assertEquals(1, r.size())
def includedBuild0 = r[0] def includedBuild0 = r[0]
assertEquals('included', includedBuild0) assertEquals('included', includedBuild0)
@ -313,9 +257,9 @@ final class BuildDelegateTests {
@Test @Test
void includedBuildsWithBase() { void includedBuildsWithBase() {
this.d.concatIncludedBuildsWithBase = true this.d.concatIncludedBuildsWithBase = true
def r = this.results.getIncludedBuildsResult( def r = this.getResults(
['baseIncluded'], true, getIncludedBuildsMonoid() SyntheticBuildIntermediate.get(includedBuilds: ['baseIncluded'])
) ).includedBuilds
assertEquals(1, r.size()) assertEquals(1, r.size())
def includedBuild0 = r[0] def includedBuild0 = r[0]
assertEquals('baseIncluded', includedBuild0) assertEquals('baseIncluded', includedBuild0)