mirror of https://github.com/sbt/sbt.git
generalized build loaders
This commit is contained in:
parent
794f87d0b9
commit
b6fc7ba0a7
|
|
@ -19,7 +19,7 @@ trait Build
|
||||||
def projectDefinitions(baseDirectory: File): Seq[Project] = projects
|
def projectDefinitions(baseDirectory: File): Seq[Project] = projects
|
||||||
def projects: Seq[Project] = ReflectUtilities.allVals[Project](this).values.toSeq
|
def projects: Seq[Project] = ReflectUtilities.allVals[Project](this).values.toSeq
|
||||||
def settings: Seq[Setting[_]] = Defaults.buildCore
|
def settings: Seq[Setting[_]] = Defaults.buildCore
|
||||||
def buildResolvers: Seq[BuildLoader.BuildResolver] = Nil
|
def buildLoaders: Seq[BuildLoader.Components] = Nil
|
||||||
}
|
}
|
||||||
trait Plugin
|
trait Plugin
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,45 +7,121 @@ package sbt
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import Load.{BuildUnit, LoadBuildConfiguration}
|
import Load.{BuildUnit, LoadBuildConfiguration}
|
||||||
import BuildLoader._
|
import BuildLoader._
|
||||||
|
import Alternatives._
|
||||||
|
import Types.{const,idFun}
|
||||||
|
|
||||||
final class ResolveInfo(val build: URI, val staging: File)
|
final class MultiHandler[S,T](builtIn: S=>Option[T], root: Option[S => Option[T]], nonRoots: List[(URI, S => Option[T])], getURI: S => URI, log: S => Logger)
|
||||||
final class BuildLoader(val load: (URI, File) => BuildUnit, val builtIn: BuildResolver, val root: Option[BuildResolver], val nonRoots: List[(URI, BuildResolver)], val fail: URI => Nothing, val config: LoadBuildConfiguration)
|
|
||||||
{
|
{
|
||||||
import Alternatives._
|
def applyFun: S => Option[T] = apply _
|
||||||
import config.{log, stagingDirectory => dir}
|
def apply(info: S): Option[T] =
|
||||||
|
|
||||||
def apply(uri: URI): BuildUnit = load(uri, resolve(new ResolveInfo(uri, dir)))
|
|
||||||
def resolve(info: ResolveInfo): File =
|
|
||||||
(baseLoader(info), applyNonRoots(info)) match
|
(baseLoader(info), applyNonRoots(info)) match
|
||||||
{
|
{
|
||||||
case (None, Nil) => fail(info.build)
|
case (None, Nil) => None
|
||||||
case (None, xs @ (_, nr) :: ignored ) =>
|
case (None, xs @ (_, nr) :: ignored ) =>
|
||||||
if(!ignored.isEmpty) warn("Using first of multiple matching non-root build resolver for " + info.build, log, xs)
|
if(!ignored.isEmpty) warn("Using first of multiple matching non-root build resolvers for " + getURI(info), log(info), xs)
|
||||||
nr()
|
Some(nr)
|
||||||
case (Some(b), xs) =>
|
case (Some(b), xs) =>
|
||||||
if(!xs.isEmpty) warn("Ignoring shadowed non-root build resolver(s) for " + info.build, log, xs)
|
if(!xs.isEmpty) warn("Ignoring shadowed non-root build resolver(s) for " + getURI(info), log(info), xs)
|
||||||
b()
|
Some(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
def baseLoader: BuildResolver = root match { case Some(rl) => rl | builtIn; case None => builtIn }
|
def baseLoader: S => Option[T] = root match { case Some(rl) => rl | builtIn; case None => builtIn }
|
||||||
|
|
||||||
def addNonRoot(uri: URI, loader: BuildResolver) = new BuildLoader(load, builtIn, root, (uri, loader) :: nonRoots, fail, config)
|
def addNonRoot(uri: URI, loader: S => Option[T]) = new MultiHandler(builtIn, root, (uri, loader) :: nonRoots, getURI, log)
|
||||||
def setRoot(resolver: BuildResolver) = new BuildLoader(load, builtIn, Some(resolver), nonRoots, fail, config)
|
def setRoot(resolver: S => Option[T]) = new MultiHandler(builtIn, Some(resolver), nonRoots, getURI, log)
|
||||||
def applyNonRoots(info: ResolveInfo): List[(URI, () => File)] =
|
def applyNonRoots(info: S): List[(URI, T)] =
|
||||||
nonRoots flatMap { case (definingURI, loader) => loader(info) map { unit => (definingURI, unit) } }
|
nonRoots flatMap { case (definingURI, loader) => loader(info) map { unit => (definingURI, unit) } }
|
||||||
|
|
||||||
private[this] def warn(baseMessage: String, log: Logger, matching: Seq[(URI, () => File)])
|
private[this] def warn(baseMessage: String, log: Logger, matching: Seq[(URI, T)])
|
||||||
{
|
{
|
||||||
log.warn(baseMessage)
|
log.warn(baseMessage)
|
||||||
log.debug("Non-root build resolvers defined in:")
|
log.debug("Non-root build resolvers defined in:")
|
||||||
log.debug(matching.map(_._1).mkString("\n\t"))
|
log.debug(matching.map(_._1).mkString("\n\t"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object BuildLoader
|
object BuildLoader
|
||||||
{
|
{
|
||||||
/** in: Build URI and staging directory
|
/** in: Build URI and staging directory
|
||||||
* out: None if unhandled or Some containing the retrieve function, which returns the directory retrieved to (can be the same as the staging directory) */
|
* out: None if unhandled or Some containing the retrieve function, which returns the directory retrieved to (can be the same as the staging directory) */
|
||||||
type BuildResolver = ResolveInfo => Option[() => File]
|
type Resolver = ResolveInfo => Option[() => File]
|
||||||
def apply(load: (URI, File) => BuildUnit, builtIn: BuildResolver, fail: URI => Nothing, config: LoadBuildConfiguration): BuildLoader =
|
type Builder = BuildInfo => Option[File => BuildUnit]
|
||||||
new BuildLoader(load, builtIn, None, Nil, fail, config)
|
type Transformer = TransformInfo => BuildUnit
|
||||||
|
type Loader = LoadInfo => Option[() => BuildUnit]
|
||||||
|
|
||||||
|
final class Components(val resolver: Resolver, val builder: Builder, val transformer: Transformer, val full: Loader) {
|
||||||
|
def | (cs: Components): Components = new Components(resolver | cs.resolver, builder | cs.builder, seq(transformer, cs.transformer), full | cs.full)
|
||||||
|
}
|
||||||
|
def transform(t: Transformer): Components = components(transformer = t)
|
||||||
|
def resolve(r: Resolver): Components = components(resolver = r)
|
||||||
|
def build(b: Builder): Components = components(builder = b)
|
||||||
|
def full(f: Loader): Components = components(full = f)
|
||||||
|
def components(resolver: Resolver = const(None), builder: Builder = const(None), transformer: Transformer = _.unit, full: Loader = const(None)) =
|
||||||
|
new Components(resolver, builder, transformer, full)
|
||||||
|
|
||||||
|
def seq(a: Transformer, b: Transformer): Transformer = info => b(info.setUnit(a(info)))
|
||||||
|
|
||||||
|
sealed trait Info {
|
||||||
|
def uri: URI
|
||||||
|
def config: LoadBuildConfiguration
|
||||||
|
def state: State
|
||||||
|
}
|
||||||
|
final class ResolveInfo(val uri: URI, val staging: File, val config: LoadBuildConfiguration, val state: State) extends Info
|
||||||
|
final class BuildInfo(val uri: URI, val config: LoadBuildConfiguration, val state: State) extends Info
|
||||||
|
final class TransformInfo(val uri: URI, val base: File, val unit: BuildUnit, val config: LoadBuildConfiguration, val state: State) extends Info {
|
||||||
|
def setUnit(newUnit: BuildUnit): TransformInfo = new TransformInfo(uri, base, newUnit, config, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
final class LoadInfo(val uri: URI, val staging: File, val config: LoadBuildConfiguration, val state: State, val components: Components) extends Info
|
||||||
|
|
||||||
|
def apply(base: Components, fail: URI => Nothing, s: State, config: LoadBuildConfiguration): BuildLoader =
|
||||||
|
{
|
||||||
|
def makeMulti[S <: Info, T](base: S => Option[T]) = new MultiHandler[S,T](base, None, Nil, _.uri, _.config.log)
|
||||||
|
new BuildLoader(fail, s, config, makeMulti(base.resolver), makeMulti(base.builder), base.transformer, makeMulti(base.full))
|
||||||
|
}
|
||||||
|
|
||||||
|
def componentLoader: Loader = (info: LoadInfo) => {
|
||||||
|
import info.{components, config, staging, state, uri}
|
||||||
|
val cs = info.components
|
||||||
|
for {
|
||||||
|
resolve <- cs.resolver(new ResolveInfo(uri, staging, config, state))
|
||||||
|
build <- cs.builder(new BuildInfo(uri, config, state))
|
||||||
|
} yield () => {
|
||||||
|
val base = resolve()
|
||||||
|
val unit = build(base)
|
||||||
|
cs.transformer(new TransformInfo(uri, base, unit, config, state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class BuildLoader(
|
||||||
|
val fail: URI => Nothing,
|
||||||
|
val state: State,
|
||||||
|
val config: LoadBuildConfiguration,
|
||||||
|
val resolvers: MultiHandler[ResolveInfo, ()=>File],
|
||||||
|
val builders: MultiHandler[BuildInfo, File=>BuildUnit],
|
||||||
|
val transformer: Transformer,
|
||||||
|
val full: MultiHandler[LoadInfo, ()=>BuildUnit])
|
||||||
|
{
|
||||||
|
def addNonRoot(uri: URI, loaders: Components): BuildLoader =
|
||||||
|
new BuildLoader(fail, state, config,
|
||||||
|
resolvers.addNonRoot(uri, loaders.resolver),
|
||||||
|
builders.addNonRoot(uri, loaders.builder),
|
||||||
|
seq(transformer, loaders.transformer),
|
||||||
|
full.addNonRoot(uri, loaders.full)
|
||||||
|
)
|
||||||
|
def setRoot(loaders: Components): BuildLoader =
|
||||||
|
new BuildLoader(fail, state, config,
|
||||||
|
resolvers.setRoot(loaders.resolver),
|
||||||
|
builders.setRoot(loaders.builder),
|
||||||
|
seq(loaders.transformer, transformer),
|
||||||
|
full.setRoot(loaders.full)
|
||||||
|
)
|
||||||
|
def components = new Components(resolvers.applyFun, builders.applyFun, transformer, full.applyFun)
|
||||||
|
def apply(uri: URI): BuildUnit =
|
||||||
|
{
|
||||||
|
val info = new LoadInfo(uri, config.stagingDirectory, config, state, components)
|
||||||
|
val load = full(info) getOrElse fail(uri)
|
||||||
|
load()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -226,9 +226,11 @@ object Load
|
||||||
|
|
||||||
def load(file: File, s: State, config: LoadBuildConfiguration): PartBuild =
|
def load(file: File, s: State, config: LoadBuildConfiguration): PartBuild =
|
||||||
{
|
{
|
||||||
val loader = (uri: URI, local: File) => loadUnit(uri, local, s, config)
|
|
||||||
val fail = (uri: URI) => error("Invalid build URI: " + uri)
|
val fail = (uri: URI) => error("Invalid build URI: " + uri)
|
||||||
val builtinLoader = BuildLoader(loader, info => RetrieveUnit(info.staging, info.build), fail, config)
|
val resolver = (info: BuildLoader.ResolveInfo) => RetrieveUnit(info.staging, info.uri)
|
||||||
|
val build = (info: BuildLoader.BuildInfo) => Some((base: File) => loadUnit(info.uri, base, info.state, info.config))
|
||||||
|
val components = BuildLoader.components(resolver, build, full = BuildLoader.componentLoader)
|
||||||
|
val builtinLoader = BuildLoader(components, fail, s, config)
|
||||||
load(file, builtinLoader)
|
load(file, builtinLoader)
|
||||||
}
|
}
|
||||||
def load(file: File, loaders: BuildLoader): PartBuild = loadURI(IO.directoryURI(file), loaders)
|
def load(file: File, loaders: BuildLoader): PartBuild = loadURI(IO.directoryURI(file), loaders)
|
||||||
|
|
@ -240,7 +242,7 @@ object Load
|
||||||
new PartBuild(uri, map)
|
new PartBuild(uri, map)
|
||||||
}
|
}
|
||||||
def addResolvers(unit: BuildUnit, isRoot: Boolean, loaders: BuildLoader): BuildLoader =
|
def addResolvers(unit: BuildUnit, isRoot: Boolean, loaders: BuildLoader): BuildLoader =
|
||||||
unit.definitions.builds.flatMap(_.buildResolvers) match
|
unit.definitions.builds.flatMap(_.buildLoaders) match
|
||||||
{
|
{
|
||||||
case Nil => loaders
|
case Nil => loaders
|
||||||
case x :: xs =>
|
case x :: xs =>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue