Files
sbt/main/Defaults.scala
T
Mark Harrah 042128a673 Put default conflict warnings at the debug level. Fixes #709.
This is at debug instead of disabled so as to be a minimal change
during a point release.  It is dropped to debug because the conflict warnings
don't work correctly, especially for the artifacts they were designed for,
sbt and Scala.  This is due to the overrides and excludes present in 0.12.x.

The other possible use of conflictWarning is for general libraries, but
in 0.13 that is better served by using a strict conflict manager.  Therefore,
0.13 should drop the warnings based on the evicted modules completely.
2013-03-14 16:48:42 -04:00

1392 lines
73 KiB
Scala
Executable File

/* sbt -- Simple Build Tool
* Copyright 2011 Mark Harrah
*/
package sbt
import Build.data
import Scope.{fillTaskAxis, GlobalScope, ThisScope}
import xsbt.api.Discovery
import xsbti.compile.CompileOrder
import Project.{inConfig, Initialize, inScope, inTask, ScopedKey, Setting, SettingsDefinition}
import Load.LoadedBuild
import Artifact.{DocClassifier, SourceClassifier}
import Configurations.{Compile, CompilerPlugin, IntegrationTest, names, Provided, Runtime, Test}
import CrossVersion.{binarySbtVersion, binaryScalaVersion}
import complete._
import std.TaskExtra._
import inc.{FileValueCache, Locate}
import org.scalatools.testing.{Framework, AnnotatedFingerprint, SubclassFingerprint}
import sys.error
import scala.xml.NodeSeq
import org.apache.ivy.core.module.{descriptor, id}
import descriptor.ModuleDescriptor, id.ModuleRevisionId
import java.io.File
import java.net.{URI,URL}
import java.util.concurrent.Callable
import sbinary.DefaultProtocol.StringFormat
import Cache.seqFormat
import Types._
import Path._
import Keys._
object Defaults extends BuildCommon
{
final val CacheDirectoryName = "cache"
def configSrcSub(key: SettingKey[File]): Initialize[File] = (key in ThisScope.copy(config = Global), configuration) { (src, conf) => src / nameForSrc(conf.name) }
def nameForSrc(config: String) = if(config == "compile") "main" else config
def prefix(config: String) = if(config == "compile") "" else config + "-"
def lock(app: xsbti.AppConfiguration): xsbti.GlobalLock = app.provider.scalaProvider.launcher.globalLock
def extractAnalysis[T](a: Attributed[T]): (T, inc.Analysis) =
(a.data, a.metadata get Keys.analysis getOrElse inc.Analysis.Empty)
def analysisMap[T](cp: Seq[Attributed[T]]): T => Option[inc.Analysis] =
{
val m = (for(a <- cp; an <- a.metadata get Keys.analysis) yield (a.data, an) ).toMap
m.get _
}
def buildCore: Seq[Setting[_]] = thisBuildCore ++ globalCore
def thisBuildCore: Seq[Setting[_]] = inScope(GlobalScope.copy(project = Select(ThisBuild)))(Seq(
managedDirectory <<= baseDirectory(_ / "lib_managed")
))
def globalCore: Seq[Setting[_]] = inScope(GlobalScope)(defaultTestTasks(test) ++ defaultTestTasks(testOnly) ++ defaultTestTasks(testQuick) ++ Seq(
compilerCache <<= state map { _ get Keys.stateCompilerCache getOrElse compiler.CompilerCache.fresh },
crossVersion :== CrossVersion.Disabled,
scalaOrganization :== ScalaArtifacts.Organization,
buildDependencies <<= buildDependencies or Classpaths.constructBuildDependencies,
taskTemporaryDirectory := { val dir = IO.createTemporaryDirectory; dir.deleteOnExit(); dir },
onComplete <<= taskTemporaryDirectory { dir => () => IO.delete(dir); IO.createDirectory(dir) },
concurrentRestrictions <<= concurrentRestrictions or defaultRestrictions,
parallelExecution :== true,
sbtVersion <<= appConfiguration { _.provider.id.version },
sbtBinaryVersion <<= sbtVersion apply binarySbtVersion,
sbtResolver <<= sbtVersion { sbtV => if(sbtV endsWith "-SNAPSHOT") Classpaths.typesafeSnapshots else Classpaths.typesafeReleases },
pollInterval :== 500,
logBuffered :== false,
connectInput :== false,
cancelable :== false,
sourcesInBase :== true,
autoScalaLibrary :== true,
onLoad <<= onLoad ?? idFun[State],
onUnload <<= (onUnload ?? idFun[State]),
onUnload <<= (onUnload, taskTemporaryDirectory) { (f, dir) => s => { try f(s) finally IO.delete(dir) } },
watchingMessage <<= watchingMessage ?? Watched.defaultWatchingMessage,
triggeredMessage <<= triggeredMessage ?? Watched.defaultTriggeredMessage,
definesClass :== FileValueCache(Locate.definesClass _ ).get,
trapExit :== false,
trapExit in run :== true,
traceLevel in run :== 0,
traceLevel in runMain :== 0,
traceLevel in console :== Int.MaxValue,
traceLevel in consoleProject :== Int.MaxValue,
autoCompilerPlugins :== true,
internalConfigurationMap :== Configurations.internalMap _,
initialize :== (),
credentials :== Nil,
scalaHome :== None,
javaHome :== None,
extraLoggers :== { _ => Nil },
skip :== false,
watchSources :== Nil,
version :== "0.1-SNAPSHOT",
outputStrategy :== None,
exportJars :== false,
fork :== false,
javaOptions :== Nil,
sbtPlugin :== false,
crossPaths :== true,
classpathTypes :== Set("jar", "bundle") ++ CustomPomParser.JarPackagings,
aggregate :== true,
maxErrors :== 100,
showTiming :== true,
timingFormat :== Aggregation.defaultFormat,
showSuccess :== true,
commands :== Nil,
retrieveManaged :== false,
buildStructure <<= state map Project.structure,
settings <<= buildStructure map ( _.data ),
artifactClassifier :== None,
artifactClassifier in packageSrc :== Some(SourceClassifier),
artifactClassifier in packageDoc :== Some(DocClassifier),
checksums <<= appConfiguration(Classpaths.bootChecksums),
pomExtra :== NodeSeq.Empty,
pomPostProcess :== idFun,
pomAllRepositories :== false,
includeFilter :== NothingFilter,
includeFilter in unmanagedSources :== "*.java" | "*.scala",
includeFilter in unmanagedJars :== "*.jar" | "*.so" | "*.dll" | "*.jnilib",
includeFilter in unmanagedResources :== AllPassFilter,
excludeFilter :== (".*" - ".") || HiddenFileFilter,
pomIncludeRepository :== Classpaths.defaultRepositoryFilter
))
def defaultTestTasks(key: Scoped): Seq[Setting[_]] = inTask(key)(Seq(
tags := Seq(Tags.Test -> 1),
logBuffered := true
))
def projectCore: Seq[Setting[_]] = Seq(
name <<= thisProject(_.id),
logManager <<= extraLoggers(extra => LogManager.defaults(extra, StandardMain.console)),
onLoadMessage <<= onLoadMessage or (name, thisProjectRef)("Set current project to " + _ + " (in build " + _.build +")"),
runnerTask
)
def paths = Seq(
baseDirectory <<= thisProject(_.base),
target <<= baseDirectory / "target",
historyPath <<= historyPath or target(t => Some(t / ".history")),
sourceDirectory <<= baseDirectory / "src",
sourceManaged <<= crossTarget / "src_managed",
resourceManaged <<= crossTarget / "resource_managed",
cacheDirectory <<= (crossTarget, thisProject)(_ / CacheDirectoryName / _.id / "global")
)
lazy val configPaths = sourceConfigPaths ++ resourceConfigPaths ++ outputConfigPaths
lazy val sourceConfigPaths = Seq(
sourceDirectory <<= configSrcSub(sourceDirectory),
sourceManaged <<= configSrcSub(sourceManaged),
scalaSource <<= sourceDirectory / "scala",
javaSource <<= sourceDirectory / "java",
unmanagedSourceDirectories <<= Seq(scalaSource, javaSource).join,
// remove when sourceFilter, defaultExcludes are removed
includeFilter in unmanagedSources <<= (sourceFilter in unmanagedSources) or (includeFilter in unmanagedSources),
excludeFilter in unmanagedSources <<= (defaultExcludes in unmanagedSources) or (excludeFilter in unmanagedSources),
unmanagedSources <<= collectFiles(unmanagedSourceDirectories, includeFilter in unmanagedSources, excludeFilter in unmanagedSources),
watchSources in ConfigGlobal <++= unmanagedSources,
managedSourceDirectories <<= Seq(sourceManaged).join,
managedSources <<= generate(sourceGenerators),
sourceGenerators :== Nil,
sourceDirectories <<= Classpaths.concatSettings(unmanagedSourceDirectories, managedSourceDirectories),
sources <<= Classpaths.concat(unmanagedSources, managedSources)
)
lazy val resourceConfigPaths = Seq(
resourceDirectory <<= sourceDirectory / "resources",
resourceManaged <<= configSrcSub(resourceManaged),
unmanagedResourceDirectories <<= Seq(resourceDirectory).join,
managedResourceDirectories <<= Seq(resourceManaged).join,
resourceDirectories <<= Classpaths.concatSettings(unmanagedResourceDirectories, managedResourceDirectories),
// remove when defaultExcludes are removed
excludeFilter in unmanagedResources <<= (defaultExcludes in unmanagedResources) or (excludeFilter in unmanagedResources),
unmanagedResources <<= collectFiles(unmanagedResourceDirectories, includeFilter in unmanagedResources, excludeFilter in unmanagedResources),
watchSources in ConfigGlobal <++= unmanagedResources,
resourceGenerators :== Nil,
resourceGenerators <+= (definedSbtPlugins, resourceManaged) map writePluginsDescriptor,
managedResources <<= generate(resourceGenerators),
resources <<= Classpaths.concat(managedResources, unmanagedResources)
)
lazy val outputConfigPaths = Seq(
cacheDirectory <<= (crossTarget, thisProject, configuration) { _ / CacheDirectoryName / _.id / _.name },
classDirectory <<= (crossTarget, configuration) { (outDir, conf) => outDir / (prefix(conf.name) + "classes") },
docDirectory <<= (crossTarget, configuration) { (outDir, conf) => outDir / (prefix(conf.name) + "api") }
)
def addBaseSources = Seq(
unmanagedSources <<= (unmanagedSources, baseDirectory, includeFilter in unmanagedSources, excludeFilter in unmanagedSources, sourcesInBase) map {
(srcs,b,f,excl,enable) => if(enable) (srcs +++ b * (f -- excl)).get else srcs
}
)
def compileBase = inTask(console)(compilersSetting :: Nil) ++ Seq(
classpathOptions in GlobalScope :== ClasspathOptions.boot,
classpathOptions in GlobalScope in console :== ClasspathOptions.repl,
compileOrder in GlobalScope :== CompileOrder.Mixed,
compilersSetting,
javacOptions in GlobalScope :== Nil,
scalacOptions in GlobalScope :== Nil,
scalaInstance <<= scalaInstanceSetting,
scalaVersion in GlobalScope <<= appConfiguration( _.provider.scalaProvider.version),
scalaBinaryVersion in GlobalScope <<= scalaVersion apply binaryScalaVersion,
crossVersion <<= (crossPaths) { enabled => if(enabled) CrossVersion.binary else CrossVersion.Disabled },
crossScalaVersions in GlobalScope <<= Seq(scalaVersion).join,
crossTarget <<= (target, scalaBinaryVersion, sbtBinaryVersion, sbtPlugin, crossPaths)(makeCrossTarget)
)
def makeCrossTarget(t: File, sv: String, sbtv: String, plugin: Boolean, cross: Boolean): File =
{
val scalaBase = if(cross) t / ("scala-" + sv) else t
if(plugin) scalaBase / ("sbt-" + sbtv) else scalaBase
}
def compilersSetting = compilers <<= (scalaInstance, appConfiguration, streams, classpathOptions, javaHome) map { (si, app, s, co, jh) => Compiler.compilers(si, co, jh)(app, s.log) }
lazy val configTasks = docTaskSettings(doc) ++ compileTaskSettings ++ compileInputsSettings ++ Seq(
initialCommands in GlobalScope :== "",
cleanupCommands in GlobalScope :== "",
compile <<= compileTask tag(Tags.Compile, Tags.CPU),
printWarnings <<= printWarningsTask,
compileIncSetup <<= compileIncSetupTask,
console <<= consoleTask,
consoleQuick <<= consoleQuickTask,
discoveredMainClasses <<= compile map discoverMainClasses storeAs discoveredMainClasses triggeredBy compile,
definedSbtPlugins <<= discoverPlugins,
inTask(run)(runnerTask :: Nil).head,
selectMainClass <<= (discoveredMainClasses, mainClass) map { (classes, explicit) => explicit orElse selectRunMain(classes) },
mainClass in run <<= selectMainClass in run,
mainClass <<= discoveredMainClasses map selectPackageMain,
run <<= runTask(fullClasspath, mainClass in run, runner in run),
runMain <<= runMainTask(fullClasspath, runner in run),
copyResources <<= copyResourcesTask
)
lazy val projectTasks: Seq[Setting[_]] = Seq(
cleanFiles <<= Seq(managedDirectory, target).join,
cleanKeepFiles <<= historyPath(_.toList),
clean <<= (cleanFiles, cleanKeepFiles) map doClean,
consoleProject <<= consoleProjectTask,
watchTransitiveSources <<= watchTransitiveSourcesTask,
watch <<= watchSetting
)
def generate(generators: SettingKey[Seq[Task[Seq[File]]]]): Initialize[Task[Seq[File]]] = generators {_.join.map(_.flatten) }
def inAllConfigurations[T](key: TaskKey[T]): Initialize[Task[Seq[T]]] = (state, thisProjectRef) flatMap { (state, ref) =>
val structure = Project structure state
val configurations = Project.getProject(ref, structure).toList.flatMap(_.configurations)
configurations.flatMap { conf =>
key in (ref, conf) get structure.data
} join
}
def watchTransitiveSourcesTask: Initialize[Task[Seq[File]]] =
inDependencies[Task[Seq[File]]](watchSources.task, const(std.TaskExtra.constant(Nil)), aggregate = true, includeRoot = true) apply { _.join.map(_.flatten) }
def transitiveUpdateTask: Initialize[Task[Seq[UpdateReport]]] =
forDependencies(ref => (update.task in ref).?, aggregate = false, includeRoot = false) apply( _.flatten.join)
def watchSetting: Initialize[Watched] = (pollInterval, thisProjectRef, watchingMessage, triggeredMessage) { (interval, base, msg, trigMsg) =>
new Watched {
val scoped = watchTransitiveSources in base
val key = ScopedKey(scoped.scope, scoped.key)
override def pollInterval = interval
override def watchingMessage(s: WatchState) = msg(s)
override def triggeredMessage(s: WatchState) = trigMsg(s)
override def watchPaths(s: State) = EvaluateTask.evaluateTask(Project structure s, key, s, base) match {
case Some(Value(ps)) => ps
case Some(Inc(i)) => throw i
case None => error("key not found: " + Project.displayFull(key))
}
}
}
def scalaInstanceSetting = (appConfiguration, scalaOrganization, scalaVersion, scalaHome) map { (app, org, version, home) =>
val launcher = app.provider.scalaProvider.launcher
home match {
case None => ScalaInstance(org, version, launcher)
case Some(h) => ScalaInstance(h, launcher)
}
}
lazy val testTasks: Seq[Setting[_]] = testTaskOptions(test) ++ testTaskOptions(testOnly) ++ testTaskOptions(testQuick) ++ Seq(
testLoader <<= (fullClasspath, scalaInstance, taskTemporaryDirectory) map { (cp, si, temp) => TestFramework.createTestLoader(data(cp), si, IO.createUniqueDirectory(temp)) },
testFrameworks in GlobalScope :== {
import sbt.TestFrameworks._
Seq(ScalaCheck, Specs2, Specs, ScalaTest, JUnit)
},
loadedTestFrameworks <<= (testFrameworks, streams, testLoader) map { (frameworks, s, loader) =>
frameworks.flatMap(f => f.create(loader, s.log).map( x => (f,x)).toIterable).toMap
},
definedTests <<= detectTests,
definedTestNames <<= definedTests map ( _.map(_.name).distinct) storeAs definedTestNames triggeredBy compile,
testListeners in GlobalScope :== Nil,
testOptions in GlobalScope :== Nil,
testFilter in testOnly :== (selectedFilter _),
testFilter in testQuick <<= testQuickFilter,
executeTests <<= (streams in test, loadedTestFrameworks, testLoader, testGrouping in test, testExecution in test, fullClasspath in test, javaHome in test) flatMap allTestGroupsTask,
test <<= (executeTests, streams, resolvedScoped, state) map {
(results, s, scoped, st) =>
implicit val display = Project.showContextKey(st)
Tests.showResults(s.log, results, noTestsMessage(scoped))
},
testOnly <<= inputTests(testOnly),
testQuick <<= inputTests(testQuick)
)
private[this] def noTestsMessage(scoped: ScopedKey[_])(implicit display: Show[ScopedKey[_]]): String =
"No tests to run for " + display(scoped)
lazy val TaskGlobal: Scope = ThisScope.copy(task = Global)
lazy val ConfigGlobal: Scope = ThisScope.copy(config = Global)
def testTaskOptions(key: Scoped): Seq[Setting[_]] = inTask(key)( Seq(
testListeners <<= (streams, resolvedScoped, streamsManager, logBuffered, cacheDirectory in test, testListeners in TaskGlobal) map { (s, sco, sm, buff, dir, ls) =>
TestLogger(s.log, testLogger(sm, test in sco.scope), buff) +: new TestStatusReporter(succeededFile(dir)) +: ls
},
testOptions <<= (testOptions in TaskGlobal, testListeners) map { (options, ls) => Tests.Listeners(ls) +: options },
testExecution <<= testExecutionTask(key),
testGrouping <<= testGrouping or singleTestGroup(key)
) )
def testLogger(manager: Streams, baseKey: Scoped)(tdef: TestDefinition): Logger =
{
val scope = baseKey.scope
val extra = scope.extra match { case Select(x) => x; case _ => AttributeMap.empty }
val key = ScopedKey(scope.copy(extra = Select(testExtra(extra, tdef))), baseKey.key)
manager(key).log
}
def buffered(log: Logger): Logger = new BufferedLogger(FullLogger(log))
def testExtra(extra: AttributeMap, tdef: TestDefinition): AttributeMap =
{
val mod = tdef.fingerprint match { case f: SubclassFingerprint => f.isModule; case f: AnnotatedFingerprint => f.isModule; case _ => false }
extra.put(name.key, tdef.name).put(isModule, mod)
}
def singleTestGroup(key: Scoped): Initialize[Task[Seq[Tests.Group]]] =
((definedTests in key, fork in key, javaOptions in key) map {
(tests, fork, javaOpts) => Seq(new Tests.Group("<default>", tests, if (fork) Tests.SubProcess(javaOpts) else Tests.InProcess))
})
def testExecutionTask(task: Scoped): Initialize[Task[Tests.Execution]] =
(testOptions in task, parallelExecution in task, tags in task) map {
(opts, par, ts) =>
new Tests.Execution(opts, par, ts)
}
def testQuickFilter: Initialize[Task[Seq[String] => String => Boolean]] =
(fullClasspath in test, cacheDirectory) map {
(cp, dir) =>
val ans = cp.flatMap(_.metadata get Keys.analysis)
val succeeded = TestStatus.read(succeededFile(dir))
val stamps = collection.mutable.Map.empty[File, Long]
def stamp(dep: String): Long = {
val stamps = for (a <- ans; f <- a.relations.definesClass(dep)) yield intlStamp(f, a, Set.empty)
if (stamps.isEmpty) Long.MinValue else stamps.max
}
def intlStamp(f: File, analysis: inc.Analysis, s: Set[File]): Long = {
if (s contains f) Long.MinValue else
stamps.getOrElseUpdate(f, {
import analysis.{relations => rel, apis}
rel.internalSrcDeps(f).map(intlStamp(_, analysis, s + f)) ++
rel.externalDeps(f).map(stamp) +
apis.internal(f).compilation.startTime
}.max)
}
args => test => selectedFilter(args)(test) && {
succeeded.get(test) match {
case None => true
case Some(ts) => stamp(test) > ts
}
}
}
def succeededFile(dir: File) = dir / "succeeded_tests"
def inputTests(key: InputKey[_]): Initialize[InputTask[Unit]] =
InputTask( loadForParser(definedTestNames)( (s, i) => testOnlyParser(s, i getOrElse Nil) ) ) { result =>
(streams, loadedTestFrameworks, testFilter in key, testGrouping in key, testExecution in key, testLoader, resolvedScoped, result, fullClasspath in key, javaHome in key, state) flatMap {
case (s, frameworks, filter, groups, config, loader, scoped, (selected, frameworkOptions), cp, javaHome, st) =>
implicit val display = Project.showContextKey(st)
val modifiedOpts = Tests.Filter(filter(selected)) +: Tests.Argument(frameworkOptions : _*) +: config.options
val newConfig = config.copy(options = modifiedOpts)
allTestGroupsTask(s, frameworks, loader, groups, newConfig, cp, javaHome) map (Tests.showResults(s.log, _, noTestsMessage(scoped)))
}
}
def allTestGroupsTask(s: TaskStreams, frameworks: Map[TestFramework,Framework], loader: ClassLoader, groups: Seq[Tests.Group], config: Tests.Execution, cp: Classpath, javaHome: Option[File]): Task[Tests.Output] = {
val groupTasks = groups map {
case Tests.Group(name, tests, runPolicy) =>
runPolicy match {
case Tests.SubProcess(javaOpts) =>
ForkTests(frameworks.keys.toSeq, tests.toList, config, cp.files, javaHome, javaOpts, s.log) tag Tags.ForkedTestGroup
case Tests.InProcess =>
Tests(frameworks, loader, tests, config, s.log)
}
}
Tests.foldTasks(groupTasks, config.parallel)
}
def selectedFilter(args: Seq[String]): String => Boolean =
{
val filters = args map GlobFilter.apply
s => filters.isEmpty || filters.exists { _ accept s }
}
def detectTests: Initialize[Task[Seq[TestDefinition]]] = (loadedTestFrameworks, compile, streams) map { (frameworkMap, analysis, s) =>
Tests.discover(frameworkMap.values.toSeq, analysis, s.log)._1
}
def defaultRestrictions: Initialize[Seq[Tags.Rule]] = parallelExecution { par =>
val max = EvaluateTask.SystemProcessors
Tags.limitAll(if(par) max else 1) :: Tags.limit(Tags.ForkedTestGroup, 1) :: Nil
}
lazy val packageBase: Seq[Setting[_]] = Seq(
artifact <<= moduleName(n => Artifact(n)),
packageOptions in GlobalScope :== Nil,
artifactName in GlobalScope :== ( Artifact.artifactName _ )
)
lazy val packageConfig: Seq[Setting[_]] =
inTask(packageBin)(Seq(
packageOptions <<= (name, version, homepage, organization, organizationName, mainClass, packageOptions) map { (name, ver, h, org, orgName, main, p) => Package.addSpecManifestAttributes(name, ver, orgName) +: Package.addImplManifestAttributes(name, ver, h, org, orgName) +: main.map(Package.MainClass.apply) ++: p })) ++
inTask(packageSrc)(Seq(
packageOptions <<= (name, version, organizationName, packageOptions) map { Package.addSpecManifestAttributes(_, _, _) +: _ })) ++
packageTaskSettings(packageBin, packageBinMappings) ++
packageTaskSettings(packageSrc, packageSrcMappings) ++
packageTaskSettings(packageDoc, packageDocMappings) ++
Seq(`package` <<= packageBin)
def packageBinMappings = products map { _ flatMap Path.allSubpaths }
def packageDocMappings = doc map { Path.allSubpaths(_).toSeq }
def packageSrcMappings = concatMappings(resourceMappings, sourceMappings)
@deprecated("Use `packageBinMappings` instead", "0.12.0")
def packageBinTask = packageBinMappings
@deprecated("Use `packageDocMappings` instead", "0.12.0")
def packageDocTask = packageDocMappings
@deprecated("Use `packageSrcMappings` instead", "0.12.0")
def packageSrcTask = packageSrcMappings
private type Mappings = Initialize[Task[Seq[(File, String)]]]
def concatMappings(as: Mappings, bs: Mappings) = (as zipWith bs)( (a,b) => (a :^: b :^: KNil) map { case a :+: b :+: HNil => a ++ b } )
// drop base directories, since there are no valid mappings for these
def sourceMappings = (unmanagedSources, unmanagedSourceDirectories, baseDirectory) map { (srcs, sdirs, base) =>
( (srcs --- sdirs --- base) pair (relativeTo(sdirs)|relativeTo(base)|flat)) toSeq
}
def resourceMappings = relativeMappings(unmanagedResources, unmanagedResourceDirectories)
def relativeMappings(files: ScopedTaskable[Seq[File]], dirs: ScopedTaskable[Seq[File]]): Initialize[Task[Seq[(File, String)]]] =
(files, dirs) map { (rs, rdirs) =>
(rs --- rdirs) pair (relativeTo(rdirs)|flat) toSeq
}
def collectFiles(dirs: ScopedTaskable[Seq[File]], filter: ScopedTaskable[FileFilter], excludes: ScopedTaskable[FileFilter]): Initialize[Task[Seq[File]]] =
(dirs, filter, excludes) map { (d,f,excl) => d.descendantsExcept(f,excl).get }
def artifactPathSetting(art: SettingKey[Artifact]) = (crossTarget, projectID, art, scalaVersion in artifactName, scalaBinaryVersion in artifactName, artifactName) {
(t, module, a, sv, sbv, toString) =>
t / toString(ScalaVersion(sv, sbv), module, a) asFile
}
def artifactSetting = ((artifact, artifactClassifier).identity zipWith configuration.?) { case ((a,classifier),cOpt) =>
val cPart = cOpt flatMap { c => if(c == Compile) None else Some(c.name) }
val combined = cPart.toList ++ classifier.toList
if(combined.isEmpty) a.copy(classifier = None, configurations = cOpt.toList) else {
val classifierString = combined mkString "-"
val confs = cOpt.toList flatMap { c => artifactConfigurations(a, c, classifier) }
a.copy(classifier = Some(classifierString), `type` = Artifact.classifierType(classifierString), configurations = confs)
}
}
def artifactConfigurations(base: Artifact, scope: Configuration, classifier: Option[String]): Iterable[Configuration] =
if(base.configurations.isEmpty)
classifier match {
case Some(c) => Artifact.classifierConf(c) :: Nil
case None => scope :: Nil
}
else
base.configurations
@deprecated("Use `Util.pairID` instead", "0.12.0")
def pairID = Util.pairID
def perTaskCache(key: TaskKey[_]): Setting[File] =
cacheDirectory ~= { _ / ("for_" + key.key.label) }
@deprecated("Use `packageTaskSettings` instead", "0.12.0")
def packageTasks(key: TaskKey[File], mappingsTask: Initialize[Task[Seq[(File,String)]]]) = packageTaskSettings(key, mappingsTask)
def packageTaskSettings(key: TaskKey[File], mappingsTask: Initialize[Task[Seq[(File,String)]]]) =
inTask(key)( Seq(
key in TaskGlobal <<= packageTask,
packageConfiguration <<= packageConfigurationTask,
mappings <<= mappingsTask,
packagedArtifact <<= (artifact, key) map Util.pairID,
artifact <<= artifactSetting,
perTaskCache(key),
artifactPath <<= artifactPathSetting(artifact)
))
def packageTask: Initialize[Task[File]] =
(packageConfiguration, cacheDirectory, streams) map { (config, cacheDir, s) =>
Package(config, cacheDir, s.log)
config.jar
}
def packageConfigurationTask: Initialize[Task[Package.Configuration]] =
(mappings, artifactPath, packageOptions) map { (srcs, path, options) =>
new Package.Configuration(srcs, path, options)
}
def selectRunMain(classes: Seq[String]): Option[String] =
sbt.SelectMainClass(Some(SimpleReader readLine _), classes)
def selectPackageMain(classes: Seq[String]): Option[String] =
sbt.SelectMainClass(None, classes)
def doClean(clean: Seq[File], preserve: Seq[File]): Unit =
IO.withTemporaryDirectory { temp =>
val (dirs, files) = preserve.filter(_.exists).flatMap(_.***.get).partition(_.isDirectory)
val mappings = files.zipWithIndex map { case (f, i) => (f, new File(temp, i.toHexString)) }
IO.move(mappings)
IO.delete(clean)
IO.createDirectories(dirs) // recreate empty directories
IO.move(mappings.map(_.swap))
}
def runMainTask(classpath: TaskKey[Classpath], scalaRun: TaskKey[ScalaRun]): Initialize[InputTask[Unit]] =
{
import DefaultParsers._
InputTask( loadForParser(discoveredMainClasses)( (s, names) => runMainParser(s, names getOrElse Nil) ) ) { result =>
(classpath, scalaRun, streams, result) map { case (cp, runner, s, (mainClass, args)) =>
toError(runner.run(mainClass, data(cp), args, s.log))
}
}
}
def runTask(classpath: TaskKey[Classpath], mainClassTask: TaskKey[Option[String]], scalaRun: TaskKey[ScalaRun]): Initialize[InputTask[Unit]] =
inputTask { result =>
(classpath, mainClassTask, scalaRun, streams, result) map { (cp, main, runner, s, args) =>
val mainClass = main getOrElse error("No main class detected.")
toError(runner.run(mainClass, data(cp), args, s.log))
}
}
def runnerTask = runner <<= runnerInit
def runnerInit: Initialize[Task[ScalaRun]] =
(taskTemporaryDirectory, scalaInstance, baseDirectory, javaOptions, outputStrategy, fork, javaHome, trapExit, connectInput) map {
(tmp, si, base, options, strategy, forkRun, javaHomeDir, trap, connectIn) =>
if(forkRun) {
new ForkRun( ForkOptions(scalaJars = si.jars, javaHome = javaHomeDir, connectInput = connectIn, outputStrategy = strategy, runJVMOptions = options, workingDirectory = Some(base)) )
} else
new Run(si, trap, tmp)
}
@deprecated("Use `docTaskSettings` instead", "0.12.0")
def docSetting(key: TaskKey[File]) = docTaskSettings(key)
def docTaskSettings(key: TaskKey[File] = doc): Seq[Setting[_]] = inTask(key)(compileInputsSettings ++ Seq(
perTaskCache(key),
target <<= docDirectory, // deprecate docDirectory in favor of 'target in doc'; remove when docDirectory is removed
scalacOptions <<= scaladocOptions or scalacOptions, // deprecate scaladocOptions in favor of 'scalacOptions in doc'; remove when scaladocOptions is removed
key in TaskGlobal <<= (cacheDirectory, compileInputs, target, configuration, streams) map { (cache, in, out, config, s) =>
val srcs = in.config.sources
val hasScala = srcs.exists(_.name.endsWith(".scala"))
val hasJava = srcs.exists(_.name.endsWith(".java"))
val cp = in.config.classpath.toList - in.config.classesDirectory
if(hasScala)
Doc(in.config.maxErrors, in.compilers.scalac).cached(cache / "scala", nameForSrc(config.name), srcs, cp, out, in.config.options, s.log)
else if(hasJava)
Doc(in.config.maxErrors, in.compilers.javac).cached(cache / "java", nameForSrc(config.name), srcs, cp, out, in.config.javacOptions, s.log)
out
}
))
def mainRunTask = run <<= runTask(fullClasspath in Runtime, mainClass in run, runner in run)
def mainRunMainTask = runMain <<= runMainTask(fullClasspath in Runtime, runner in run)
def discoverMainClasses(analysis: inc.Analysis): Seq[String] =
Discovery.applications(Tests.allDefs(analysis)) collect { case (definition, discovered) if(discovered.hasMain) => definition.name }
def consoleProjectTask = (state, streams, initialCommands in consoleProject) map { (state, s, extra) => ConsoleProject(state, extra)(s.log); println() }
def consoleTask: Initialize[Task[Unit]] = consoleTask(fullClasspath, console)
def consoleQuickTask = consoleTask(externalDependencyClasspath, consoleQuick)
def consoleTask(classpath: TaskKey[Classpath], task: TaskKey[_]): Initialize[Task[Unit]] =
(compilers in task, classpath in task, scalacOptions in task, initialCommands in task, cleanupCommands in task, taskTemporaryDirectory in task, scalaInstance in task, streams) map {
(cs, cp, options, initCommands, cleanup, temp, si, s) =>
val loader = sbt.classpath.ClasspathUtilities.makeLoader(data(cp), si.loader, si, IO.createUniqueDirectory(temp))
(new Console(cs.scalac))(data(cp), options, loader, initCommands, cleanup)()(s.log).foreach(msg => error(msg))
println()
}
def compileTaskSettings: Seq[Setting[_]] = inTask(compile)(compileInputsSettings)
def compileTask = (compileInputs in compile, streams) map { (i,s) => Compiler(i,s.log) }
def compileIncSetupTask =
(dependencyClasspath, cacheDirectory, skip in compile, definesClass, compilerCache) map { (cp, cacheDir, skip, definesC, cache) =>
Compiler.IncSetup(analysisMap(cp), definesC, skip, cacheDir / "inc_compile", cache)
}
def compileInputsSettings: Seq[Setting[_]] = {
val optionsPair = TaskKey.local[(Seq[String], Seq[String])]
Seq(optionsPair <<= (scalacOptions, javacOptions) map Util.pairID,
compileInputs <<= (dependencyClasspath, sources, compilers, optionsPair, classDirectory, compileOrder, compileIncSetup, maxErrors, streams) map {
(cp, srcs, cs, optsPair, classes, order, incSetup, maxErr, s) =>
Compiler.inputs(classes +: data(cp), srcs, classes, optsPair._1, optsPair._2, maxErr, order)(cs, incSetup, s.log)
})
}
def printWarningsTask: Initialize[Task[Unit]] =
(streams, compile, maxErrors) map { (s, analysis, max) =>
val problems = analysis.infos.allInfos.values.flatMap(i => i.reportedProblems++ i.unreportedProblems)
val reporter = new LoggerReporter(max, s.log)
problems foreach { p => reporter.display(p.position, p.message, p.severity) }
}
def sbtPluginExtra(m: ModuleID, sbtV: String, scalaV: String): ModuleID =
m.extra(CustomPomParser.SbtVersionKey -> sbtV, CustomPomParser.ScalaVersionKey -> scalaV).copy(crossVersion = CrossVersion.Disabled)
def writePluginsDescriptor(plugins: Set[String], dir: File): Seq[File] =
{
val descriptor: File = dir / "sbt" / "sbt.plugins"
if(plugins.isEmpty)
{
IO.delete(descriptor)
Nil
}
else
{
IO.writeLines(descriptor, plugins.toSeq.sorted)
descriptor :: Nil
}
}
def discoverPlugins: Initialize[Task[Set[String]]] = (compile, sbtPlugin, streams) map { (analysis, isPlugin, s) => if(isPlugin) discoverSbtPlugins(analysis, s.log) else Set.empty }
def discoverSbtPlugins(analysis: inc.Analysis, log: Logger): Set[String] =
{
val pluginClass = classOf[Plugin].getName
val discovery = Discovery(Set(pluginClass), Set.empty)( Tests allDefs analysis )
discovery collect { case (df, disc) if (disc.baseClasses contains pluginClass) && disc.isModule => df.name } toSet;
}
def copyResourcesTask =
(classDirectory, cacheDirectory, resources, resourceDirectories, streams) map { (target, cache, resrcs, dirs, s) =>
val cacheFile = cache / "copy-resources"
val mappings = (resrcs --- dirs) pair (rebase(dirs, target) | flat(target))
s.log.debug("Copy resource mappings: " + mappings.mkString("\n\t","\n\t",""))
Sync(cacheFile)( mappings )
mappings
}
def runMainParser: (State, Seq[String]) => Parser[(String, Seq[String])] =
{
import DefaultParsers._
(state, mainClasses) => Space ~> token(NotSpace examples mainClasses.toSet) ~ spaceDelimited("<arg>")
}
def testOnlyParser: (State, Seq[String]) => Parser[(Seq[String],Seq[String])] =
{ (state, tests) =>
import DefaultParsers._
val selectTests = distinctParser(tests.toSet, true)
val options = (token(Space) ~> token("--") ~> spaceDelimited("<option>")) ?? Nil
selectTests ~ options
}
def distinctParser(exs: Set[String], raw: Boolean): Parser[Seq[String]] =
{
import DefaultParsers._
val base = token(Space) ~> token(NotSpace - "--" examples exs)
val recurse = base flatMap { ex =>
val (matching, notMatching) = exs.partition( GlobFilter(ex).accept _ )
distinctParser(notMatching, raw) map { result => if(raw) ex +: result else matching.toSeq ++ result }
}
recurse ?? Nil
}
def inDependencies[T](key: SettingKey[T], default: ProjectRef => T, includeRoot: Boolean = true, classpath: Boolean = true, aggregate: Boolean = false): Initialize[Seq[T]] =
forDependencies[T,T](ref => (key in ref) ?? default(ref), includeRoot, classpath, aggregate)
def forDependencies[T,V](init: ProjectRef => Initialize[V], includeRoot: Boolean = true, classpath: Boolean = true, aggregate: Boolean = false): Initialize[Seq[V]] =
Project.bind( (loadedBuild, thisProjectRef).identity ) { case (lb, base) =>
transitiveDependencies(base, lb, includeRoot, classpath, aggregate) map init join ;
}
def transitiveDependencies(base: ProjectRef, structure: LoadedBuild, includeRoot: Boolean, classpath: Boolean = true, aggregate: Boolean = false): Seq[ProjectRef] =
{
def tdeps(enabled: Boolean, f: ProjectRef => Seq[ProjectRef]): Seq[ProjectRef] =
{
val full = if(enabled) Dag.topologicalSort(base)(f) else Nil
if(includeRoot) full else full dropRight 1
}
def fullCp = tdeps(classpath, getDependencies(structure, classpath=true, aggregate=false))
def fullAgg = tdeps(aggregate, getDependencies(structure, classpath=false, aggregate=true))
(classpath, aggregate) match {
case (true, true) => (fullCp ++ fullAgg).distinct
case (true, false) => fullCp
case _ => fullAgg
}
}
def getDependencies(structure: LoadedBuild, classpath: Boolean = true, aggregate: Boolean = false): ProjectRef => Seq[ProjectRef] =
ref => Project.getProject(ref, structure).toList flatMap { p =>
(if(classpath) p.dependencies.map(_.project) else Nil) ++
(if(aggregate) p.aggregate else Nil)
}
val CompletionsID = "completions"
def noAggregation: Seq[Scoped] = Seq(run, runMain, console, consoleQuick, consoleProject)
lazy val disableAggregation = noAggregation map disableAggregate
def disableAggregate(k: Scoped) =
aggregate in Scope.GlobalScope.copy(task = Select(k.key)) :== false
lazy val baseTasks: Seq[Setting[_]] = projectTasks ++ packageBase
lazy val baseClasspaths: Seq[Setting[_]] = Classpaths.publishSettings ++ Classpaths.baseSettings
lazy val configSettings: Seq[Setting[_]] = Classpaths.configSettings ++ configTasks ++ configPaths ++ packageConfig ++ Classpaths.compilerPluginConfig
lazy val compileSettings: Seq[Setting[_]] = configSettings ++ (mainRunMainTask +: mainRunTask +: addBaseSources)
lazy val testSettings: Seq[Setting[_]] = configSettings ++ testTasks
lazy val itSettings: Seq[Setting[_]] = inConfig(IntegrationTest)(testSettings)
lazy val defaultConfigs: Seq[Setting[_]] = inConfig(Compile)(compileSettings) ++ inConfig(Test)(testSettings) ++ inConfig(Runtime)(Classpaths.configSettings)
// settings that are not specific to a configuration
lazy val projectBaseSettings: Seq[Setting[_]] = projectCore ++ paths ++ baseClasspaths ++ baseTasks ++ compileBase ++ disableAggregation
lazy val defaultSettings: Seq[Setting[_]] = projectBaseSettings ++ defaultConfigs
}
object Classpaths
{
import Path._
import Keys._
import Scope.ThisScope
import Defaults._
import Attributed.{blank, blankSeq}
def concatDistinct[T](a: ScopedTaskable[Seq[T]], b: ScopedTaskable[Seq[T]]): Initialize[Task[Seq[T]]] = (a,b) map { (x,y) => (x ++ y).distinct }
def concat[T](a: ScopedTaskable[Seq[T]], b: ScopedTaskable[Seq[T]]): Initialize[Task[Seq[T]]] = (a,b) map ( _ ++ _)
def concatSettings[T](a: SettingKey[Seq[T]], b: SettingKey[Seq[T]]): Initialize[Seq[T]] = (a,b)(_ ++ _)
lazy val configSettings: Seq[Setting[_]] = Seq(
externalDependencyClasspath <<= concat(unmanagedClasspath, managedClasspath),
dependencyClasspath <<= concat(internalDependencyClasspath, externalDependencyClasspath),
fullClasspath <<= concatDistinct(exportedProducts, dependencyClasspath),
internalDependencyClasspath <<= internalDependencies,
unmanagedClasspath <<= unmanagedDependencies,
products <<= makeProducts,
productDirectories <<= compileInputs map (_.config.classesDirectory :: Nil),
exportedProducts <<= exportProductsTask,
classpathConfiguration <<= (internalConfigurationMap, configuration, classpathConfiguration.?, update.task) apply findClasspathConfig,
managedClasspath <<= (classpathConfiguration, classpathTypes, update) map managedJars,
// remove when defaultExcludes and classpathFilter are removed
excludeFilter in unmanagedJars <<= (defaultExcludes in unmanagedJars) or (excludeFilter in unmanagedJars),
includeFilter in unmanagedJars <<= classpathFilter or (includeFilter in unmanagedJars),
unmanagedJars <<= (configuration, unmanagedBase, includeFilter in unmanagedJars, excludeFilter in unmanagedJars) map { (config, base, filter, excl) =>
(base * (filter -- excl) +++ (base / config.name).descendantsExcept(filter, excl)).classpath
}
)
def defaultPackageKeys = Seq(packageBin, packageSrc, packageDoc)
lazy val defaultPackages: Seq[TaskKey[File]] =
for(task <- defaultPackageKeys; conf <- Seq(Compile, Test)) yield (task in conf)
lazy val defaultArtifactTasks: Seq[TaskKey[File]] = makePom +: defaultPackages
def findClasspathConfig(map: Configuration => Configuration, thisConfig: Configuration, delegate: Task[Option[Configuration]], up: Task[UpdateReport]): Task[Configuration] =
(delegate :^: up :^: KNil) map { case delegated :+: report :+: HNil =>
val defined = report.allConfigurations.toSet
val search = map(thisConfig) +: (delegated.toList ++ Seq(Compile, Configurations.Default))
def notFound = error("Configuration to use for managed classpath must be explicitly defined when default configurations are not present.")
search find { defined contains _.name } getOrElse notFound
}
def packaged(pkgTasks: Seq[TaskKey[File]]): Initialize[Task[Map[Artifact, File]]] =
enabledOnly(packagedArtifact.task, pkgTasks) apply (_.join.map(_.toMap))
def artifactDefs(pkgTasks: Seq[TaskKey[File]]): Initialize[Seq[Artifact]] =
enabledOnly(artifact, pkgTasks)
def enabledOnly[T](key: SettingKey[T], pkgTasks: Seq[TaskKey[File]]): Initialize[Seq[T]] =
( forallIn(key, pkgTasks) zipWith forallIn(publishArtifact, pkgTasks) ) ( _ zip _ collect { case (a, true) => a } )
def forallIn[T](key: SettingKey[T], pkgTasks: Seq[TaskKey[_]]): Initialize[Seq[T]] =
pkgTasks.map( pkg => key in pkg.scope in pkg ).join
val publishSettings: Seq[Setting[_]] = Seq(
publishMavenStyle in GlobalScope :== true,
publishArtifact in GlobalScope :== true,
publishArtifact in GlobalScope in Test:== false,
artifacts <<= artifactDefs(defaultArtifactTasks),
packagedArtifacts <<= packaged(defaultArtifactTasks),
makePom <<= (ivyModule, makePomConfiguration, streams) map { (module, config, s) => IvyActions.makePom(module, config, s.log); config.file },
packagedArtifact in makePom <<= (artifact in makePom, makePom) map Util.pairID,
deliver <<= deliverTask(deliverConfiguration),
deliverLocal <<= deliverTask(deliverLocalConfiguration),
publish <<= publishTask(publishConfiguration, deliver),
publishLocal <<= publishTask(publishLocalConfiguration, deliverLocal)
)
val baseSettings: Seq[Setting[_]] = sbtClassifiersTasks ++ Seq(
conflictWarning in GlobalScope :== ConflictWarning.default("global").copy(level = Level.Debug),
conflictWarning <<= (thisProjectRef, conflictWarning) { (ref, cw) => cw.copy(label = Project.display(ref)) },
unmanagedBase <<= baseDirectory / "lib",
normalizedName <<= name(StringUtilities.normalize),
isSnapshot <<= isSnapshot or version(_ endsWith "-SNAPSHOT"),
description <<= description or name,
homepage in GlobalScope :== None,
startYear in GlobalScope :== None,
licenses in GlobalScope :== Nil,
organization <<= organization or normalizedName,
organizationName <<= organizationName or organization,
organizationHomepage <<= organizationHomepage or homepage,
scmInfo in GlobalScope :== None,
projectInfo <<= (name, description, homepage, startYear, licenses, organizationName, organizationHomepage, scmInfo) apply ModuleInfo,
overrideBuildResolvers <<= appConfiguration(isOverrideRepositories),
externalResolvers <<= (externalResolvers.task.?, resolvers) {
case (Some(delegated), Seq()) => delegated
case (_, rs) => task { Resolver.withDefaultResolvers(rs) }
},
bootResolvers <<= appConfiguration map bootRepositories,
fullResolvers <<= (projectResolver,externalResolvers,sbtPlugin,sbtResolver,bootResolvers,overrideBuildResolvers) map { (proj,rs,isPlugin,sbtr, boot, overrideFlag) =>
boot match {
case Some(repos) if overrideFlag => proj +: repos
case _ =>
val base = if(isPlugin) sbtr +: sbtPluginReleases +: rs else rs
proj +: base
}
},
offline in GlobalScope :== false,
moduleName <<= normalizedName,
defaultConfiguration in GlobalScope :== Some(Configurations.Compile),
defaultConfigurationMapping in GlobalScope <<= defaultConfiguration{ case Some(d) => "*->" + d.name; case None => "*->*" },
ivyPaths <<= (baseDirectory, appConfiguration) { (base, app) => new IvyPaths(base, bootIvyHome(app)) },
otherResolvers <<= publishTo(_.toList),
projectResolver <<= projectResolverTask,
projectDependencies <<= projectDependenciesTask,
dependencyOverrides in GlobalScope :== Set.empty,
libraryDependencies in GlobalScope :== Nil,
libraryDependencies <++= (autoScalaLibrary, sbtPlugin, scalaVersion) apply autoLibraryDependency,
allDependencies <<= (projectDependencies,libraryDependencies,sbtPlugin,sbtDependency) map { (projDeps, libDeps, isPlugin, sbtDep) =>
val base = projDeps ++ libDeps
if(isPlugin) sbtDep.copy(configurations = Some(Provided.name)) +: base else base
},
ivyLoggingLevel in GlobalScope :== UpdateLogging.DownloadOnly,
ivyXML in GlobalScope :== NodeSeq.Empty,
ivyValidate in GlobalScope :== false,
ivyScala <<= ivyScala or (scalaHome, scalaVersion in update, scalaBinaryVersion in update) { (sh,fv,bv) =>
Some(new IvyScala(fv, bv, Nil, filterImplicit = true, checkExplicit = true, overrideScalaVersion = sh.isEmpty))
},
moduleConfigurations in GlobalScope :== Nil,
publishTo in GlobalScope :== None,
artifactPath in makePom <<= artifactPathSetting(artifact in makePom),
publishArtifact in makePom <<= (publishMavenStyle, publishArtifact).apply(_ && _) ,
artifact in makePom <<= moduleName(Artifact.pom),
projectID <<= (organization,moduleName,version,artifacts,crossVersion in projectID){ (org,module,version,as,cross) =>
ModuleID(org, module, version).cross(cross).artifacts(as : _*)
},
projectID <<= pluginProjectID,
resolvers in GlobalScope :== Nil,
projectDescriptors <<= depMap,
retrievePattern in GlobalScope :== Resolver.defaultRetrievePattern,
updateConfiguration <<= (retrieveConfiguration, ivyLoggingLevel)((conf,level) => new UpdateConfiguration(conf, false, level) ),
retrieveConfiguration <<= (managedDirectory, retrievePattern, retrieveManaged) { (libm, pattern, enabled) => if(enabled) Some(new RetrieveConfiguration(libm, pattern)) else None },
ivyConfiguration <<= mkIvyConfiguration,
ivyConfigurations <<= (autoCompilerPlugins, internalConfigurationMap, thisProject) { (auto, internalMap, project) =>
(project.configurations ++ project.configurations.map(internalMap) ++ (if(auto) CompilerPlugin :: Nil else Nil)).distinct
},
ivyConfigurations ++= Configurations.auxiliary,
moduleSettings <<= moduleSettings0,
makePomConfiguration <<= (artifactPath in makePom, projectInfo, pomExtra, pomPostProcess, pomIncludeRepository, pomAllRepositories) {
(file, minfo, extra, process, include, all) => new MakePomConfiguration(file, minfo, None, extra, process, include, all)
},
deliverLocalConfiguration <<= (crossTarget, isSnapshot, ivyLoggingLevel) map { (outDir, snapshot, level) => deliverConfig( outDir, status = if (snapshot) "integration" else "release", logging = level ) },
deliverConfiguration <<= deliverLocalConfiguration,
publishConfiguration <<= (packagedArtifacts, publishTo, publishMavenStyle, deliver, checksums in publish, ivyLoggingLevel) map { (arts, publishTo, mavenStyle, ivyFile, checks, level) =>
publishConfig(arts, if(mavenStyle) None else Some(ivyFile), resolverName = getPublishTo(publishTo).name, checksums = checks, logging = level)
},
publishLocalConfiguration <<= (packagedArtifacts, deliverLocal, checksums in publishLocal, ivyLoggingLevel) map {
(arts, ivyFile, checks, level) => publishConfig(arts, Some(ivyFile), checks, logging = level )
},
ivySbt <<= ivySbt0,
ivyModule <<= (ivySbt, moduleSettings) map { (ivySbt, settings) => new ivySbt.Module(settings) },
transitiveUpdate <<= transitiveUpdateTask,
update <<= (ivyModule, thisProjectRef, updateConfiguration, cacheDirectory, scalaInstance, transitiveUpdate, executionRoots, resolvedScoped, skip in update, streams) map {
(module, ref, config, cacheDirectory, si, reports, roots, resolved, skip, s) =>
val depsUpdated = reports.exists(!_.stats.cached)
val isRoot = roots contains resolved
cachedUpdate(cacheDirectory / "update", Project.display(ref), module, config, Some(si), skip = skip, force = isRoot, depsUpdated = depsUpdated, log = s.log)
} tag(Tags.Update, Tags.Network),
update <<= (conflictWarning, update, streams) map { (config, report, s) => ConflictWarning(config, report, s.log); report },
transitiveClassifiers in GlobalScope :== Seq(SourceClassifier, DocClassifier),
classifiersModule in updateClassifiers <<= (projectID, update, transitiveClassifiers in updateClassifiers, ivyConfigurations in updateClassifiers) map { ( pid, up, classifiers, confs) =>
GetClassifiersModule(pid, up.allModules, confs, classifiers)
},
updateClassifiers <<= (ivySbt, classifiersModule in updateClassifiers, updateConfiguration, ivyScala, appConfiguration, streams) map { (is, mod, c, ivyScala, app, s) =>
val out = is.withIvy(s.log)(_.getSettings.getDefaultIvyUserDir)
withExcludes(out, mod.classifiers, lock(app)) { excludes =>
IvyActions.updateClassifiers(is, GetClassifiersConfiguration(mod, excludes, c, ivyScala), s.log)
}
} tag(Tags.Update, Tags.Network),
sbtDependency in GlobalScope <<= appConfiguration { app =>
val id = app.provider.id
val scalaVersion = app.provider.scalaProvider.version
val binVersion = binaryScalaVersion(scalaVersion)
val cross = if(id.crossVersioned) CrossVersion.binary else CrossVersion.Disabled
val base = ModuleID(id.groupID, id.name, id.version, crossVersion = cross)
CrossVersion(scalaVersion, binVersion)(base).copy(crossVersion = CrossVersion.Disabled)
}
)
def warnResolversConflict(ress: Seq[Resolver], log: Logger) {
val resset = ress.toSet
for ((name, r) <- resset groupBy (_.name) if r.size > 1) {
log.warn("Multiple resolvers having different access mechanism configured with same name '" + name + "'. To avoid conflict, Remove duplicate project resolvers (`resolvers`) or rename publishing resolver (`publishTo`).")
}
}
def pluginProjectID: Initialize[ModuleID] = (sbtBinaryVersion in update, scalaBinaryVersion in update, projectID, sbtPlugin) {
(sbtBV, scalaBV, pid, isPlugin) =>
if(isPlugin) sbtPluginExtra(pid, sbtBV, scalaBV) else pid
}
def ivySbt0: Initialize[Task[IvySbt]] =
(ivyConfiguration, credentials, streams) map { (conf, creds, s) =>
Credentials.register(creds, s.log)
new IvySbt(conf)
}
def moduleSettings0: Initialize[Task[ModuleSettings]] =
(projectID, allDependencies, dependencyOverrides, ivyXML, ivyConfigurations, defaultConfiguration, ivyScala, ivyValidate, projectInfo) map {
(pid, deps, over, ivyXML, confs, defaultConf, ivyS, validate, pinfo) => new InlineConfiguration(pid, pinfo, deps, over, ivyXML, confs, defaultConf, ivyS, validate)
}
def sbtClassifiersTasks = inTask(updateSbtClassifiers)(Seq(
transitiveClassifiers in GlobalScope in updateSbtClassifiers ~= ( _.filter(_ != DocClassifier) ),
externalResolvers <<= (externalResolvers, appConfiguration, buildStructure, thisProjectRef) map { (defaultRs, ac, struct, ref) =>
val explicit = struct.units(ref.build).unit.plugins.pluginData.resolvers
explicit orElse bootRepositories(ac) getOrElse defaultRs
},
ivyConfiguration <<= (externalResolvers, ivyPaths, offline, checksums, appConfiguration, target, streams) map { (rs, paths, off, check, app, t, s) =>
val resCacheDir = t / "resolution-cache"
new InlineIvyConfiguration(paths, rs, Nil, Nil, off, Option(lock(app)), check, Some(resCacheDir), s.log)
},
ivySbt <<= ivySbt0,
classifiersModule <<= (projectID, sbtDependency, transitiveClassifiers, loadedBuild, thisProjectRef) map { ( pid, sbtDep, classifiers, lb, ref) =>
val pluginIDs: Seq[ModuleID] = lb.units(ref.build).unit.plugins.fullClasspath.flatMap(_ get moduleID.key)
GetClassifiersModule(pid, sbtDep +: pluginIDs, Configurations.Default :: Nil, classifiers)
},
updateSbtClassifiers in TaskGlobal <<= (ivySbt, classifiersModule, updateConfiguration, ivyScala, appConfiguration, streams) map {
(is, mod, c, ivyScala, app, s) =>
val out = is.withIvy(s.log)(_.getSettings.getDefaultIvyUserDir)
withExcludes(out, mod.classifiers, lock(app)) { excludes =>
val noExplicitCheck = ivyScala.map(_.copy(checkExplicit=false))
IvyActions.transitiveScratch(is, "sbt", GetClassifiersConfiguration(mod, excludes, c, noExplicitCheck), s.log)
}
} tag(Tags.Update, Tags.Network)
))
def deliverTask(config: TaskKey[DeliverConfiguration]): Initialize[Task[File]] =
(ivyModule, config, update, streams) map { (module, config, _, s) => IvyActions.deliver(module, config, s.log) }
def publishTask(config: TaskKey[PublishConfiguration], deliverKey: TaskKey[_]): Initialize[Task[Unit]] =
(ivyModule, config, streams) map { (module, config, s) =>
IvyActions.publish(module, config, s.log)
} tag(Tags.Publish, Tags.Network)
import Cache._
import CacheIvy.{classpathFormat, /*publishIC,*/ updateIC, updateReportFormat, excludeMap}
def withExcludes(out: File, classifiers: Seq[String], lock: xsbti.GlobalLock)(f: Map[ModuleID, Set[String]] => UpdateReport): UpdateReport =
{
val exclName = "exclude_classifiers"
val file = out / exclName
lock(out / (exclName + ".lock"), new Callable[UpdateReport] { def call = {
val excludes = CacheIO.fromFile[Map[ModuleID, Set[String]]](excludeMap, Map.empty[ModuleID, Set[String]])(file)
val report = f(excludes)
val allExcludes = excludes ++ IvyActions.extractExcludes(report)
CacheIO.toFile(excludeMap)(allExcludes)(file)
IvyActions.addExcluded(report, classifiers, allExcludes)
}})
}
def cachedUpdate(cacheFile: File, label: String, module: IvySbt#Module, config: UpdateConfiguration, scalaInstance: Option[ScalaInstance], skip: Boolean, force: Boolean, depsUpdated: Boolean, log: Logger): UpdateReport =
{
implicit val updateCache = updateIC
implicit val updateReport = updateReportFormat
type In = IvyConfiguration :+: ModuleSettings :+: UpdateConfiguration :+: HNil
def work = (_: In) match { case conf :+: settings :+: config :+: HNil =>
log.info("Updating " + label + "...")
val r = IvyActions.update(module, config, log)
log.info("Done updating.")
scalaInstance match { case Some(si) => substituteScalaFiles(si, r); case None => r }
}
def uptodate(inChanged: Boolean, out: UpdateReport): Boolean =
!force &&
!depsUpdated &&
!inChanged &&
out.allFiles.forall(f => fileUptodate(f,out.stamps)) &&
fileUptodate(out.cachedDescriptor, out.stamps)
val outCacheFile = cacheFile / "output"
def skipWork: In => UpdateReport =
Tracked.lastOutput[In, UpdateReport](outCacheFile) {
case (_, Some(out)) => out
case _ => error("Skipping update requested, but update has not previously run successfully.")
}
def doWork: In => UpdateReport =
Tracked.inputChanged(cacheFile / "inputs") { (inChanged: Boolean, in: In) =>
val outCache = Tracked.lastOutput[In, UpdateReport](outCacheFile) {
case (_, Some(out)) if uptodate(inChanged, out) => out
case _ => work(in)
}
outCache(in)
}
val f = if(skip && !force) skipWork else doWork
f(module.owner.configuration :+: module.moduleSettings :+: config :+: HNil)
}
private[this] def fileUptodate(file: File, stamps: Map[File, Long]): Boolean =
stamps.get(file).forall(_ == file.lastModified)
/*
// can't cache deliver/publish easily since files involved are hidden behind patterns. publish will be difficult to verify target-side anyway
def cachedPublish(cacheFile: File)(g: (IvySbt#Module, PublishConfiguration) => Unit, module: IvySbt#Module, config: PublishConfiguration) => Unit =
{ case module :+: config :+: HNil =>
/* implicit val publishCache = publishIC
val f = cached(cacheFile) { (conf: IvyConfiguration, settings: ModuleSettings, config: PublishConfiguration) =>*/
g(module, config)
/*}
f(module.owner.configuration :+: module.moduleSettings :+: config :+: HNil)*/
}*/
def defaultRepositoryFilter = (repo: MavenRepository) => !repo.root.startsWith("file:")
def getPublishTo(repo: Option[Resolver]): Resolver = repo getOrElse error("Repository for publishing is not specified.")
def deliverConfig(outputDirectory: File, status: String = "release", logging: UpdateLogging.Value = UpdateLogging.DownloadOnly) =
new DeliverConfiguration(deliverPattern(outputDirectory), status, None, logging)
def publishConfig(artifacts: Map[Artifact, File], ivyFile: Option[File], checksums: Seq[String], resolverName: String = "local", logging: UpdateLogging.Value = UpdateLogging.DownloadOnly) =
new PublishConfiguration(ivyFile, resolverName, artifacts, checksums, logging)
def deliverPattern(outputPath: File): String = (outputPath / "[artifact]-[revision](-[classifier]).[ext]").absolutePath
def projectDependenciesTask: Initialize[Task[Seq[ModuleID]]] =
(thisProjectRef, settings, buildDependencies) map { (ref, data, deps) =>
deps.classpath(ref) flatMap { dep => (projectID in dep.project) get data map {
_.copy(configurations = dep.configuration, explicitArtifacts = Nil) }
}
}
def depMap: Initialize[Task[Map[ModuleRevisionId, ModuleDescriptor]]] =
(thisProjectRef, settings, buildDependencies, streams) flatMap { (root, data, deps, s) =>
depMap(deps classpathTransitiveRefs root, data, s.log)
}
def depMap(projects: Seq[ProjectRef], data: Settings[Scope], log: Logger): Task[Map[ModuleRevisionId, ModuleDescriptor]] =
projects.flatMap( ivyModule in _ get data).join.map { mod =>
mod map { _.dependencyMapping(log) } toMap ;
}
def projectResolverTask: Initialize[Task[Resolver]] =
projectDescriptors map { m =>
new RawRepository(new ProjectResolver("inter-project", m))
}
def analyzed[T](data: T, analysis: inc.Analysis) = Attributed.blank(data).put(Keys.analysis, analysis)
def makeProducts: Initialize[Task[Seq[File]]] =
(compile, compileInputs, copyResources) map { (_, i, _) => i.config.classesDirectory :: Nil }
def exportProductsTask: Initialize[Task[Classpath]] =
(products.task, packageBin.task, exportJars, compile) flatMap { (psTask, pkgTask, useJars, analysis) =>
(if(useJars) Seq(pkgTask).join else psTask) map { _ map { f => analyzed(f, analysis) } }
}
def constructBuildDependencies: Initialize[BuildDependencies] =
loadedBuild { lb =>
import collection.mutable.HashMap
val agg = new HashMap[ProjectRef, Seq[ProjectRef]]
val cp = new HashMap[ProjectRef, Seq[ClasspathDep[ProjectRef]]]
for(lbu <- lb.units.values; rp <- lbu.defined.values)
{
val ref = ProjectRef(lbu.unit.uri, rp.id)
cp(ref) = rp.dependencies
agg(ref) = rp.aggregate
}
BuildDependencies(cp.toMap, agg.toMap)
}
def internalDependencies: Initialize[Task[Classpath]] =
(thisProjectRef, classpathConfiguration, configuration, settings, buildDependencies) flatMap internalDependencies0
def unmanagedDependencies: Initialize[Task[Classpath]] =
(thisProjectRef, configuration, settings, buildDependencies) flatMap unmanagedDependencies0
def mkIvyConfiguration: Initialize[Task[IvyConfiguration]] =
(fullResolvers, ivyPaths, otherResolvers, moduleConfigurations, offline, checksums in update, appConfiguration, target, streams) map { (rs, paths, other, moduleConfs, off, check, app, t, s) =>
warnResolversConflict(rs ++: other, s.log)
val resCacheDir = t / "resolution-cache"
new InlineIvyConfiguration(paths, rs, other, moduleConfs, off, Some(lock(app)), check, Some(resCacheDir), s.log)
}
import java.util.LinkedHashSet
import collection.JavaConversions.asScalaSet
def interSort(projectRef: ProjectRef, conf: Configuration, data: Settings[Scope], deps: BuildDependencies): Seq[(ProjectRef,String)] =
{
val visited = asScalaSet(new LinkedHashSet[(ProjectRef,String)])
def visit(p: ProjectRef, c: Configuration)
{
val applicableConfigs = allConfigs(c)
for(ac <- applicableConfigs) // add all configurations in this project
visited add (p, ac.name)
val masterConfs = names(getConfigurations(projectRef, data))
for( ResolvedClasspathDependency(dep, confMapping) <- deps.classpath(p))
{
val configurations = getConfigurations(dep, data)
val mapping = mapped(confMapping, masterConfs, names(configurations), "compile", "*->compile")
// map master configuration 'c' and all extended configurations to the appropriate dependency configuration
for(ac <- applicableConfigs; depConfName <- mapping(ac.name))
{
for(depConf <- confOpt(configurations, depConfName) )
if( ! visited( (dep, depConfName) ) )
visit(dep, depConf)
}
}
}
visit(projectRef, conf)
visited.toSeq
}
def unmanagedDependencies0(projectRef: ProjectRef, conf: Configuration, data: Settings[Scope], deps: BuildDependencies): Task[Classpath] =
interDependencies(projectRef, deps, conf, conf, data, true, unmanagedLibs)
def internalDependencies0(projectRef: ProjectRef, conf: Configuration, self: Configuration, data: Settings[Scope], deps: BuildDependencies): Task[Classpath] =
interDependencies(projectRef, deps, conf, self, data, false, productsTask)
def interDependencies(projectRef: ProjectRef, deps: BuildDependencies, conf: Configuration, self: Configuration, data: Settings[Scope], includeSelf: Boolean,
f: (ProjectRef, String, Settings[Scope]) => Task[Classpath]): Task[Classpath] =
{
val visited = interSort(projectRef, conf, data, deps)
val tasks = asScalaSet(new LinkedHashSet[Task[Classpath]])
for( (dep, c) <- visited )
if(includeSelf || (dep != projectRef) || (conf.name != c && self.name != c))
tasks += f(dep, c, data)
(tasks.toSeq.join).map(_.flatten.distinct)
}
def mapped(confString: Option[String], masterConfs: Seq[String], depConfs: Seq[String], default: String, defaultMapping: String): String => Seq[String] =
{
lazy val defaultMap = parseMapping(defaultMapping, masterConfs, depConfs, _ :: Nil)
parseMapping(confString getOrElse default, masterConfs, depConfs, defaultMap)
}
def parseMapping(confString: String, masterConfs: Seq[String], depConfs: Seq[String], default: String => Seq[String]): String => Seq[String] =
union(confString.split(";") map parseSingleMapping(masterConfs, depConfs, default))
def parseSingleMapping( masterConfs: Seq[String], depConfs: Seq[String], default: String => Seq[String])(confString: String): String => Seq[String] =
{
val ms: Seq[(String,Seq[String])] =
trim(confString.split("->",2)) match {
case x :: Nil => for(a <- parseList(x, masterConfs)) yield (a,default(a))
case x :: y :: Nil => val target = parseList(y, depConfs); for(a <- parseList(x, masterConfs)) yield (a,target)
case _ => error("Invalid configuration '" + confString + "'") // shouldn't get here
}
val m = ms.toMap
s => m.getOrElse(s, Nil)
}
def union[A,B](maps: Seq[A => Seq[B]]): A => Seq[B] =
a => (Seq[B]() /: maps) { _ ++ _(a) } distinct;
def parseList(s: String, allConfs: Seq[String]): Seq[String] = (trim(s split ",") flatMap replaceWildcard(allConfs)).distinct
def replaceWildcard(allConfs: Seq[String])(conf: String): Seq[String] =
if(conf == "") Nil else if(conf == "*") allConfs else conf :: Nil
private def trim(a: Array[String]): List[String] = a.toList.map(_.trim)
def missingConfiguration(in: String, conf: String) =
error("Configuration '" + conf + "' not defined in '" + in + "'")
def allConfigs(conf: Configuration): Seq[Configuration] =
Dag.topologicalSort(conf)(_.extendsConfigs)
def getConfigurations(p: ResolvedReference, data: Settings[Scope]): Seq[Configuration] =
ivyConfigurations in p get data getOrElse Nil
def confOpt(configurations: Seq[Configuration], conf: String): Option[Configuration] =
configurations.find(_.name == conf)
def productsTask(dep: ResolvedReference, conf: String, data: Settings[Scope]): Task[Classpath] =
getClasspath(exportedProducts, dep, conf, data)
def unmanagedLibs(dep: ResolvedReference, conf: String, data: Settings[Scope]): Task[Classpath] =
getClasspath(unmanagedJars, dep, conf, data)
def getClasspath(key: TaskKey[Classpath], dep: ResolvedReference, conf: String, data: Settings[Scope]): Task[Classpath] =
( key in (dep, ConfigKey(conf)) ) get data getOrElse constant(Nil)
def defaultConfigurationTask(p: ResolvedReference, data: Settings[Scope]): Configuration =
flatten(defaultConfiguration in p get data) getOrElse Configurations.Default
def flatten[T](o: Option[Option[T]]): Option[T] = o flatMap idFun
lazy val typesafeReleases = Resolver.typesafeIvyRepo("releases")
lazy val typesafeSnapshots = Resolver.typesafeIvyRepo("snapshots")
@deprecated("Use `typesafeReleases` instead", "0.12.0")
lazy val typesafeResolver = typesafeReleases
@deprecated("Use `Resolver.typesafeIvyRepo` instead", "0.12.0")
def typesafeRepo(status: String) = Resolver.typesafeIvyRepo(status)
lazy val sbtPluginReleases = Resolver.sbtPluginRepo("releases")
lazy val sbtPluginSnapshots = Resolver.sbtPluginRepo("snapshots")
def modifyForPlugin(plugin: Boolean, dep: ModuleID): ModuleID =
if(plugin) dep.copy(configurations = Some(Provided.name)) else dep
def autoLibraryDependency(auto: Boolean, plugin: Boolean, version: String): Seq[ModuleID] =
if(auto)
modifyForPlugin(plugin, ScalaArtifacts.libraryDependency(version)) :: Nil
else
Nil
import DependencyFilter._
def managedJars(config: Configuration, jarTypes: Set[String], up: UpdateReport): Classpath =
up.filter( configurationFilter(config.name) && artifactFilter(`type` = jarTypes) ).toSeq.map { case (conf, module, art, file) =>
Attributed(file)(AttributeMap.empty.put(artifact.key, art).put(moduleID.key, module).put(configuration.key, config))
} distinct;
def autoPlugins(report: UpdateReport): Seq[String] =
{
val pluginClasspath = report matching configurationFilter(CompilerPlugin.name)
classpath.ClasspathUtilities.compilerPlugins(pluginClasspath).map("-Xplugin:" + _.getAbsolutePath).toSeq
}
lazy val compilerPluginConfig = Seq(
scalacOptions <<= (scalacOptions, autoCompilerPlugins, update) map { (options, auto, report) =>
if(auto) options ++ autoPlugins(report) else options
}
)
def substituteScalaFiles(scalaInstance: ScalaInstance, report: UpdateReport): UpdateReport =
report.substitute { (configuration, module, arts) =>
import ScalaArtifacts._
(module.organization, module.name) match
{
case (Organization, LibraryID) => (Artifact(LibraryID), scalaInstance.libraryJar) :: Nil
case (Organization, CompilerID) => (Artifact(CompilerID), scalaInstance.compilerJar) :: Nil
case _ => arts
}
}
// try/catch for supporting earlier launchers
def bootIvyHome(app: xsbti.AppConfiguration): Option[File] =
try { Option(app.provider.scalaProvider.launcher.ivyHome) }
catch { case _: NoSuchMethodError => None }
def bootChecksums(app: xsbti.AppConfiguration): Seq[String] =
try { app.provider.scalaProvider.launcher.checksums.toSeq }
catch { case _: NoSuchMethodError => IvySbt.DefaultChecksums }
def isOverrideRepositories(app: xsbti.AppConfiguration): Boolean =
try app.provider.scalaProvider.launcher.isOverrideRepositories
catch { case _: NoSuchMethodError => false }
def bootRepositories(app: xsbti.AppConfiguration): Option[Seq[Resolver]] =
try { Some(app.provider.scalaProvider.launcher.ivyRepositories.toSeq map bootRepository) }
catch { case _: NoSuchMethodError => None }
private[this] def mavenCompatible(ivyRepo: xsbti.IvyRepository): Boolean =
try { ivyRepo.mavenCompatible }
catch { case _: NoSuchMethodError => false }
private[this] def bootRepository(repo: xsbti.Repository): Resolver =
{
import xsbti.Predefined
repo match
{
case m: xsbti.MavenRepository => MavenRepository(m.id, m.url.toString)
case i: xsbti.IvyRepository => Resolver.url(i.id, i.url)(Patterns(i.ivyPattern :: Nil, i.artifactPattern :: Nil, mavenCompatible(i)))
case p: xsbti.PredefinedRepository => p.id match {
case Predefined.Local => Resolver.defaultLocal
case Predefined.MavenLocal => Resolver.mavenLocal
case Predefined.MavenCentral => DefaultMavenRepository
case Predefined.ScalaToolsReleases => ScalaToolsReleases
case Predefined.ScalaToolsSnapshots => ScalaToolsSnapshots
}
}
}
}
trait BuildExtra extends BuildCommon
{
import Defaults._
/** Defines an alias given by `name` that expands to `value`.
* This alias is defined globally after projects are loaded.
* The alias is undefined when projects are unloaded.
* Names are restricted to be either alphanumeric or completely symbolic.
* As an exception, '-' and '_' are allowed within an alphanumeric name.*/
def addCommandAlias(name: String, value: String): Seq[Setting[State => State]] =
{
val add = (s: State) => BasicCommands.addAlias(s, name, value)
val remove = (s: State) => BasicCommands.removeAlias(s, name)
def compose(setting: SettingKey[State => State], f: State => State) = setting in Global ~= (_ compose f)
Seq( compose(onLoad, add), compose(onUnload, remove) )
}
def addSbtPlugin(dependency: ModuleID, sbtVersion: String, scalaVersion: String): Setting[Seq[ModuleID]] =
libraryDependencies += sbtPluginExtra(dependency, sbtVersion, scalaVersion)
def addSbtPlugin(dependency: ModuleID, sbtVersion: String): Setting[Seq[ModuleID]] =
libraryDependencies <+= (scalaBinaryVersion in update) { scalaV => sbtPluginExtra(dependency, sbtVersion, scalaV) }
def addSbtPlugin(dependency: ModuleID): Setting[Seq[ModuleID]] =
libraryDependencies <+= (sbtBinaryVersion in update,scalaBinaryVersion in update) { (sbtV, scalaV) => sbtPluginExtra(dependency, sbtV, scalaV) }
def compilerPlugin(dependency: ModuleID): ModuleID =
dependency.copy(configurations = Some("plugin->default(compile)"))
def addCompilerPlugin(dependency: ModuleID): Setting[Seq[ModuleID]] =
libraryDependencies += compilerPlugin(dependency)
def addArtifact(a: Artifact, taskDef: TaskKey[File]): SettingsDefinition =
{
val pkgd = packagedArtifacts <<= (packagedArtifacts, taskDef) map ( (pas,file) => pas updated (a, file) )
seq( artifacts += a, pkgd )
}
def addArtifact(artifact: Initialize[Artifact], taskDef: Initialize[Task[File]]): SettingsDefinition =
{
val artLocal = SettingKey.local[Artifact]
val taskLocal = TaskKey.local[File]
val art = artifacts <<= (artLocal, artifacts)( _ +: _ )
val pkgd = packagedArtifacts <<= (packagedArtifacts, artLocal, taskLocal) map ( (pas,a,file) => pas updated (a, file))
seq( artLocal <<= artifact, taskLocal <<= taskDef, art, pkgd )
}
def seq(settings: Setting[_]*): SettingsDefinition = new Project.SettingList(settings)
def externalIvySettings(file: Initialize[File] = baseDirectory / "ivysettings.xml", addMultiResolver: Boolean = true): Setting[Task[IvyConfiguration]] =
externalIvySettingsURI(file(_.toURI), addMultiResolver)
def externalIvySettingsURL(url: URL, addMultiResolver: Boolean = true): Setting[Task[IvyConfiguration]] =
externalIvySettingsURI(Project.value(url.toURI), addMultiResolver)
def externalIvySettingsURI(uri: Initialize[URI], addMultiResolver: Boolean = true): Setting[Task[IvyConfiguration]] =
{
val other = (baseDirectory, appConfiguration, projectResolver, streams).identityMap
ivyConfiguration <<= (uri zipWith other) { case (u, otherTask) =>
otherTask map { case (base, app, pr, s) =>
val extraResolvers = if(addMultiResolver) pr :: Nil else Nil
new ExternalIvyConfiguration(base, u, Some(lock(app)), extraResolvers, s.log) }
}
}
def externalIvyFile(file: Initialize[File] = baseDirectory / "ivy.xml", iScala: Initialize[Option[IvyScala]] = ivyScala): Setting[Task[ModuleSettings]] =
external(file, iScala)( (f, is, v) => new IvyFileConfiguration(f, is, v) )
def externalPom(file: Initialize[File] = baseDirectory / "pom.xml", iScala: Initialize[Option[IvyScala]] = ivyScala): Setting[Task[ModuleSettings]] =
external(file, iScala)( (f, is, v) => new PomConfiguration(f, is, v) )
private[this] def external(file: Initialize[File], iScala: Initialize[Option[IvyScala]])(make: (File, Option[IvyScala], Boolean) => ModuleSettings): Setting[Task[ModuleSettings]] =
moduleSettings <<= ((file zip iScala) zipWith ivyValidate) { case ((f, is), v) => task { make(f, is, v) } }
def runInputTask(config: Configuration, mainClass: String, baseArguments: String*): Initialize[InputTask[Unit]] =
inputTask { result =>
(fullClasspath in config, runner in (config, run), streams, result) map { (cp, r, s, args) =>
toError(r.run(mainClass, data(cp), baseArguments ++ args, s.log))
}
}
def runTask(config: Configuration, mainClass: String, arguments: String*): Initialize[Task[Unit]] =
(fullClasspath in config, runner in (config, run), streams) map { (cp, r, s) =>
toError(r.run(mainClass, data(cp), arguments, s.log))
}
def fullRunInputTask(scoped: InputKey[Unit], config: Configuration, mainClass: String, baseArguments: String*): Setting[InputTask[Unit]] =
scoped <<= inputTask { result =>
( initScoped(scoped.scopedKey, runnerInit) zipWith (fullClasspath in config, streams, result).identityMap) { (rTask, t) =>
(t :^: rTask :^: KNil) map { case (cp, s, args) :+: r :+: HNil =>
toError(r.run(mainClass, data(cp), baseArguments ++ args, s.log))
}
}
}
def fullRunTask(scoped: TaskKey[Unit], config: Configuration, mainClass: String, arguments: String*): Setting[Task[Unit]] =
scoped <<= ( initScoped(scoped.scopedKey, runnerInit) zipWith (fullClasspath in config, streams).identityMap ) { case (rTask, t) =>
(t :^: rTask :^: KNil) map { case (cp, s) :+: r :+: HNil =>
toError(r.run(mainClass, data(cp), arguments, s.log))
}
}
def initScoped[T](sk: ScopedKey[_], i: Initialize[T]): Initialize[T] = initScope(fillTaskAxis(sk.scope, sk.key), i)
def initScope[T](s: Scope, i: Initialize[T]): Initialize[T] = i mapReferenced Project.mapScope(Scope.replaceThis(s))
/** Disables post-compilation hook for determining tests for tab-completion (such as for 'test-only').
* This is useful for reducing test:compile time when not running test. */
def noTestCompletion(config: Configuration = Test): Setting[_] = inConfig(config)( Seq(definedTests <<= detectTests) ).head
def filterKeys(ss: Seq[Setting[_]], transitive: Boolean = false)(f: ScopedKey[_] => Boolean): Seq[Setting[_]] =
ss filter ( s => f(s.key) && (!transitive || s.dependencies.forall(f)) )
}
trait BuildCommon
{
def inputTask[T](f: TaskKey[Seq[String]] => Initialize[Task[T]]): Initialize[InputTask[T]] = InputTask(_ => complete.Parsers.spaceDelimited("<arg>"))(f)
implicit def globFilter(expression: String): NameFilter = GlobFilter(expression)
implicit def richAttributed(s: Seq[Attributed[File]]): RichAttributed = new RichAttributed(s)
implicit def richFiles(s: Seq[File]): RichFiles = new RichFiles(s)
implicit def richPathFinder(s: PathFinder): RichPathFinder = new RichPathFinder(s)
final class RichPathFinder private[sbt](s: PathFinder)
{
def classpath: Classpath = Attributed blankSeq s.get
}
final class RichAttributed private[sbt](s: Seq[Attributed[File]])
{
def files: Seq[File] = Build data s
}
final class RichFiles private[sbt](s: Seq[File])
{
def classpath: Classpath = Attributed blankSeq s
}
def toError(o: Option[String]): Unit = o foreach error
def overrideConfigs(cs: Configuration*)(configurations: Seq[Configuration]): Seq[Configuration] =
{
val existingName = configurations.map(_.name).toSet
val newByName = cs.map(c => (c.name, c)).toMap
val overridden = configurations map { conf => newByName.getOrElse(conf.name, conf) }
val newConfigs = cs filter { c => !existingName(c.name) }
overridden ++ newConfigs
}
// these are intended for use in input tasks for creating parsers
def getFromContext[T](task: TaskKey[T], context: ScopedKey[_], s: State): Option[T] =
SessionVar.get(SessionVar.resolveContext(task.scopedKey, context.scope, s), s)
def loadFromContext[T](task: TaskKey[T], context: ScopedKey[_], s: State)(implicit f: sbinary.Format[T]): Option[T] =
SessionVar.load(SessionVar.resolveContext(task.scopedKey, context.scope, s), s)
// intended for use in constructing InputTasks
def loadForParser[P,T](task: TaskKey[T])(f: (State, Option[T]) => Parser[P])(implicit format: sbinary.Format[T]): Initialize[State => Parser[P]] =
loadForParserI(task)(Project value f)(format)
def loadForParserI[P,T](task: TaskKey[T])(init: Initialize[(State, Option[T]) => Parser[P]])(implicit format: sbinary.Format[T]): Initialize[State => Parser[P]] =
(resolvedScoped, init)( (ctx, f) => (s: State) => f( s, loadFromContext(task, ctx, s)(format)) )
def getForParser[P,T](task: TaskKey[T])(init: (State, Option[T]) => Parser[P]): Initialize[State => Parser[P]] =
getForParserI(task)(Project value init)
def getForParserI[P,T](task: TaskKey[T])(init: Initialize[(State, Option[T]) => Parser[P]]): Initialize[State => Parser[P]] =
(resolvedScoped, init)( (ctx, f) => (s: State) => f(s, getFromContext(task, ctx, s)) )
// these are for use for constructing Tasks
def loadPrevious[T](task: TaskKey[T])(implicit f: sbinary.Format[T]): Initialize[Task[Option[T]]] =
(state, resolvedScoped) map { (s, ctx) => loadFromContext(task, ctx, s)(f) }
def getPrevious[T](task: TaskKey[T]): Initialize[Task[Option[T]]] =
(state, resolvedScoped) map { (s, ctx) => getFromContext(task, ctx, s) }
}