sbt/main/Default.scala

603 lines
30 KiB
Scala
Raw Normal View History

2011-02-06 03:40:10 +01:00
/* sbt -- Simple Build Tool
* Copyright 2011 Mark Harrah
*/
package sbt
import java.io.File
import Build.data
2011-02-10 14:16:07 +01:00
import Scope.{GlobalScope,ThisScope}
import Project.{AppConfig, Config, Initialize, ScopedKey, Setting, ThisProject, ThisProjectRef}
import Configurations.{Compile => CompileConf, Test => TestConf}
import Command.{HistoryPath, ShellPrompt}
import EvaluateTask.{resolvedScoped, streams}
import complete._
import inc.Analysis
import std.TaskExtra._
import scala.xml.{Node => XNode,NodeSeq}
import org.apache.ivy.core.module.{descriptor, id}
import descriptor.ModuleDescriptor, id.ModuleRevisionId
import Types._
object Default
{
import Path._
import GlobFilter._
import Keys._
implicit def richFileSetting(s: ScopedSetting[File]): RichFileSetting = new RichFileSetting(s)
implicit def richFilesSetting(s: ScopedSetting[Seq[File]]): RichFilesSetting = new RichFilesSetting(s)
final class RichFileSetting(s: ScopedSetting[File]) extends RichFileBase
{
def /(c: String): Initialize[File] = s { _ / c }
2011-02-06 17:33:29 +01:00
protected[this] def map0(f: PathFinder => PathFinder) = s(file => finder(f)(file :: Nil))
}
final class RichFilesSetting(s: ScopedSetting[Seq[File]]) extends RichFileBase
{
def /(s: String): Initialize[Seq[File]] = map0 { _ / s }
2011-02-06 17:33:29 +01:00
protected[this] def map0(f: PathFinder => PathFinder) = s(finder(f))
}
sealed abstract class RichFileBase
{
def *(filter: FileFilter): Initialize[Seq[File]] = map0 { _ * filter }
def **(filter: FileFilter): Initialize[Seq[File]] = map0 { _ ** filter }
protected[this] def map0(f: PathFinder => PathFinder): Initialize[Seq[File]]
protected[this] def finder(f: PathFinder => PathFinder): Seq[File] => Seq[File] =
in => f(in).getFiles.toSeq
}
def configSrcSub(key: ScopedSetting[File]): Initialize[File] = (key, Config) { (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 toSeq[T](key: ScopedSetting[T]): Initialize[Seq[T]] = key( _ :: Nil)
def extractAnalysis[T](a: Attributed[T]): (T, Analysis) =
(a.data, a.metadata get Command.Analysis getOrElse Analysis.Empty)
def analysisMap[T](cp: Seq[Attributed[T]]): Map[T, Analysis] =
(cp map extractAnalysis).toMap
2011-02-26 00:35:52 +01:00
def core: Seq[Setting[_]] = Seq(
JavaHome in GlobalScope :== None,
OutputStrategy in GlobalScope :== None,
Fork in GlobalScope :== false,
JavaOptions in GlobalScope :== Nil,
CrossPaths :== true,
ShellPrompt in GlobalScope :== (_ => "> "),
Aggregate in GlobalScope :== Aggregation.Enabled,
2011-02-16 00:41:40 +01:00
Name <<= ThisProject(_.id),
Version :== "0.1",
2011-02-10 14:16:07 +01:00
MaxErrors in GlobalScope :== 100,
Project.Commands :== Nil,
Data <<= EvaluateTask.state map { state => Project.structure(state).data }
)
def paths = Seq(
Base <<= ThisProject(_.base),
Target <<= Base / "target",
2011-02-10 14:16:07 +01:00
DefaultExcludes in GlobalScope :== (".*" - ".") || HiddenFileFilter,
HistoryPath <<= Target(t => Some(t / ".history")),
CacheDirectory <<= Target / "cache",
Source <<= Base / "src",
2011-02-10 14:16:07 +01:00
SourceFilter in GlobalScope :== ("*.java" | "*.scala"),
SourceManaged <<= Base / "src_managed"
)
lazy val configPaths = Seq(
Source <<= configSrcSub( Source in Scope(This,Global,This,This) ),
SourceManaged <<= configSrcSub(SourceManaged),
CacheDirectory <<= (CacheDirectory, Config) { _ / _.name },
ClassDirectory <<= (Target, Config) { (target, conf) => target / (prefix(conf.name) + "classes") },
2011-02-06 17:33:29 +01:00
DocDirectory <<= (Target, Config) { (target, conf) => target / (prefix(conf.name) + "api") },
Sources <<= (SourceDirectories, SourceFilter, DefaultExcludes) map { (d,f,excl) => d.descendentsExcept(f,excl).getFiles.toSeq },
ScalaSource <<= Source / "scala",
JavaSource <<= Source / "java",
JavaSourceRoots <<= toSeq(JavaSource),
ResourceDir <<= Source / "resources",
SourceDirectories <<= (ScalaSource, JavaSourceRoots) { _ +: _ },
2011-02-06 19:01:50 +01:00
ResourceDirectories <<= toSeq(ResourceDir),
Resources <<= (ResourceDirectories, DefaultExcludes) map { (dirs, excl) => dirs.descendentsExcept("*",excl).getFiles.toSeq }
)
def addBaseSources = Seq(
Sources <<= (Sources, Base, SourceFilter, DefaultExcludes) map { (srcs,b,f,excl) => (srcs +++ b * (f -- excl)).getFiles.toSeq }
)
def webPaths = Seq(
WebappDir <<= Source / "webapp"
)
def compileBase = Seq(
2011-02-06 17:33:29 +01:00
Compilers <<= (ScalaInstance, AppConfig, streams) map { (si, app, s) => Compile.compilers(si)(app, s.log) },
2011-02-10 14:16:07 +01:00
JavacOptions in GlobalScope :== Nil,
ScalacOptions in GlobalScope :== Nil,
ScalaInstance <<= (AppConfig, ScalaVersion){ (app, version) => sbt.ScalaInstance(version, app.provider.scalaProvider.launcher) },
ScalaVersion <<= AppConfig( _.provider.scalaProvider.version),
Target <<= (Target, ScalaInstance, CrossPaths)( (t,si,cross) => if(cross) t / ("scala-" + si.actualVersion) else t )
2011-02-06 03:40:10 +01:00
)
2011-02-26 00:35:52 +01:00
lazy val configTasks = Seq(
2011-02-10 14:16:07 +01:00
InitialCommands in GlobalScope :== "",
CompileTask <<= compileTask,
2011-02-06 03:40:10 +01:00
CompileInputs <<= compileInputsTask,
ConsoleTask <<= console,
ConsoleQuick <<= consoleQuick,
DiscoveredMainClasses <<= CompileTask map discoverMainClasses,
2011-02-26 00:35:52 +01:00
inTask(RunTask)(runner :: Nil).head,
2011-02-06 03:40:10 +01:00
SelectMainClass <<= DiscoveredMainClasses map selectRunMain,
MainClass in RunTask :== SelectMainClass,
MainClass <<= DiscoveredMainClasses map selectPackageMain,
2011-02-26 00:35:52 +01:00
RunTask <<= runTask(FullClasspath, MainClass in RunTask, Runner in RunTask),
2011-02-06 17:33:29 +01:00
ScaladocOptions <<= ScalacOptions(identity),
2011-02-06 19:01:50 +01:00
DocTask <<= docTask,
CopyResources <<= copyResources
)
2011-02-26 00:35:52 +01:00
lazy val projectTasks: Seq[Setting[_]] = Seq(
2011-02-06 17:33:29 +01:00
CleanFiles <<= (Target, SourceManaged) { _ :: _ :: Nil },
Clean <<= CleanFiles map IO.delete,
ConsoleProject <<= consoleProject
2011-02-06 17:33:29 +01:00
)
lazy val testTasks = Seq(
TestLoader <<= (FullClasspath, ScalaInstance) map { (cp, si) => TestFramework.createTestLoader(data(cp), si) },
2011-02-10 14:16:07 +01:00
TestFrameworks in GlobalScope :== {
2011-02-06 17:33:29 +01:00
import sbt.TestFrameworks._
Seq(ScalaCheck, Specs, ScalaTest, ScalaCheckCompat, ScalaTestCompat, SpecsCompat, JUnit)
},
LoadedTestFrameworks <<= (TestFrameworks, streams, TestLoader) map { (frameworks, s, loader) =>
frameworks.flatMap(f => f.create(loader, s.log).map( x => (f,x)).toIterable).toMap
},
DefinedTests <<= (LoadedTestFrameworks, CompileTask, streams) map { (frameworkMap, analysis, s) =>
2011-02-26 00:35:52 +01:00
val tests = Test.discover(frameworkMap.values.toSeq, analysis, s.log)._1
IO.writeLines(s.text(CompletionsID), tests.map(_.name).distinct)
tests
2011-02-06 17:33:29 +01:00
},
TestListeners <<= (streams in TestTask) map ( s => TestLogger(s.log) :: Nil ),
TestOptions <<= TestListeners map { listeners => Test.Listeners(listeners) :: Nil },
2011-02-26 00:35:52 +01:00
ExecuteTests <<= (streams in TestTask, LoadedTestFrameworks, TestOptions, TestLoader, DefinedTests) flatMap {
(s, frameworkMap, options, loader, discovered) => Test(frameworkMap, loader, discovered, options, s.log)
2011-02-06 17:33:29 +01:00
},
TestTask <<= (ExecuteTests, streams) map { (results, s) => Test.showResults(s.log, results) },
TestOnly <<= testOnly
2011-02-06 03:40:10 +01:00
)
def testOnly =
InputTask(resolvedScoped(testOnlyParser)) ( result =>
2011-02-26 00:35:52 +01:00
(streams, LoadedTestFrameworks, TestOptions, TestLoader, DefinedTests, result) flatMap {
case (s, frameworks, opts, loader, discovered, (tests, frameworkOptions)) =>
val modifiedOpts = Test.Filter(if(tests.isEmpty) _ => true else tests.toSet ) +: Test.Argument(frameworkOptions : _*) +: opts
Test(frameworks, loader, discovered, modifiedOpts, s.log) map { results =>
Test.showResults(s.log, results)
}
}
)
2011-02-10 14:16:07 +01:00
lazy val packageBase = Seq(
jarName,
PackageOptions in GlobalScope :== Nil,
NameToString in GlobalScope :== (ArtifactName.show _)
)
lazy val packageConfig = Seq(
JarName <<= (JarName, Config) { (n,c) => n.copy(config = c.name) },
2011-02-23 04:36:48 +01:00
PackageOptions in Package <<= (PackageOptions, MainClass in Package) map { _ ++ _.map(sbt.Package.MainClass.apply).toList }
2011-02-10 14:16:07 +01:00
) ++
packageTasks(Package, "", packageBin) ++
packageTasks(PackageSrc, "src", packageSrc) ++
packageTasks(PackageDoc, "doc", packageDoc)
private[this] val allSubpaths = (_: File).###.***.xx.toSeq
def packageBin = concat(classMappings, resourceMappings)
2011-02-10 14:16:07 +01:00
def packageDoc = DocTask map allSubpaths
def packageSrc = concat(resourceMappings, sourceMappings)
private type Mappings = Initialize[Task[Seq[(File, String)]]]
def concat(as: Mappings, bs: Mappings) = (as zipWith bs)( (a,b) => (a :^: b :^: KNil) map { case a :+: b :+: HNil => a ++ b } )
def classMappings = (CompileInputs, CompileTask) map { (in, _) => allSubpaths(in.config.classesDirectory) }
// drop base directories, since there are no valid mappings for these
def sourceMappings = (Sources, SourceDirectories, Base) map { (srcs, sdirs, base) =>
( (srcs --- sdirs --- base) x (relativeTo(sdirs)|relativeTo(base))) toSeq
}
def resourceMappings = (Resources, ResourceDirectories) map { (rs, rdirs) =>
(rs --- rdirs) x relativeTo(rdirs) toSeq
2011-02-10 14:16:07 +01:00
}
def jarName = JarName <<= (ModuleName, Version, ScalaVersion, CrossPaths) { (n,v, sv, withCross) =>
ArtifactName(base = n, version = v, config = "", tpe = "", ext = "jar", cross = if(withCross) sv else "")
2011-02-10 14:16:07 +01:00
}
def jarPath = JarPath <<= (Target, JarName, NameToString) { (t, n, toString) => t / toString(n) }
def packageTasks(key: TaskKey[sbt.Package.Configuration], tpeString: String, mappings: Initialize[Task[Seq[(File,String)]]]) =
2011-02-10 14:16:07 +01:00
inTask(key)( Seq(
key in ThisScope.copy(task = Global) <<= packageTask,
Mappings <<= mappings,
JarType :== tpeString,
JarName <<= (JarType,JarName){ (tpe, name) => (name.copy(tpe = tpe)) },
CacheDirectory <<= CacheDirectory / key.key.label,
jarPath
))
def packageTask: Initialize[Task[sbt.Package.Configuration]] =
2011-02-10 14:16:07 +01:00
(JarPath, Mappings, PackageOptions, CacheDirectory, streams) map { (jar, srcs, options, cacheDir, s) =>
val config = new sbt.Package.Configuration(srcs, jar, options)
sbt.Package(config, cacheDir, s.log)
config
}
2011-02-06 03:40:10 +01:00
def selectRunMain(classes: Seq[String]): Option[String] =
sbt.SelectMainClass(Some(SimpleReader readLine _), classes)
def selectPackageMain(classes: Seq[String]): Option[String] =
sbt.SelectMainClass(None, classes)
2011-02-26 00:35:52 +01:00
def runTask(classpath: ScopedTask[Classpath], mainClass: ScopedTask[Option[String]], run: ScopedSetting[ScalaRun]): Initialize[InputTask[Unit]] =
InputTask(_ => complete.Parsers.spaceDelimited("<arg>")) { result =>
2011-02-26 00:35:52 +01:00
(classpath, mainClass, run, streams, result) map { (cp, main, runner, s, args) =>
val mainClass = main getOrElse error("No main class detected.")
runner.run(mainClass, data(cp), args, s.log) foreach error
2011-02-06 03:40:10 +01:00
}
}
2011-02-26 00:35:52 +01:00
def runner =
Runner <<= (ScalaInstance, Base, JavaOptions, OutputStrategy, Fork, JavaHome) { (si, base, options, strategy, fork, javaHome) =>
if(fork) {
new ForkRun( ForkOptions(scalaJars = si.jars, javaHome = javaHome, outputStrategy = strategy,
runJVMOptions = options, workingDirectory = Some(base)) )
} else
new Run(si)
}
def docTask: Initialize[Task[File]] =
2011-02-06 17:33:29 +01:00
(CompileInputs, streams, DocDirectory, Config, ScaladocOptions) map { (in, s, target, config, options) =>
val d = new Scaladoc(in.config.maxErrors, in.compilers.scalac)
d(nameForSrc(config.name), in.config.sources, in.config.classpath, target, options)(s.log)
2011-02-10 14:16:07 +01:00
target
2011-02-06 17:33:29 +01:00
}
2011-02-26 00:35:52 +01:00
def mainRunTask = RunTask <<= runTask(FullClasspath in Configurations.Runtime, MainClass in RunTask, Runner in RunTask)
2011-02-06 03:40:10 +01:00
def discoverMainClasses(analysis: Analysis): Seq[String] =
compile.Discovery.applications(Test.allDefs(analysis)) collect { case (definition, discovered) if(discovered.hasMain) => definition.name }
def consoleProject = (EvaluateTask.state, streams, InitialCommands in ConsoleProject) map { (state, s, extra) => Console.sbt(state, extra)(s.log) }
2011-02-06 03:40:10 +01:00
def console = consoleTask(FullClasspath, ConsoleTask)
def consoleQuick = consoleTask(ExternalDependencyClasspath, ConsoleQuick)
def consoleTask(classpath: TaskKey[Classpath], task: TaskKey[_]) = (Compilers, classpath, ScalacOptions in task, InitialCommands in task, streams) map {
(cs, cp, options, initialCommands, s) =>
(new Console(cs.scalac))(data(cp), options, initialCommands, s.log).foreach(msg => error(msg))
println()
}
def compileTask = (CompileInputs, streams) map { (i,s) => Compile(i,s.log) }
def compileInputsTask =
(DependencyClasspath, Sources, JavaSourceRoots, Compilers, JavacOptions, ScalacOptions, CacheDirectory, ClassDirectory, streams) map {
2011-02-14 01:02:22 +01:00
(cp, sources, javaRoots, compilers, javacOptions, scalacOptions, cacheDirectory, classes, s) =>
val classpath = classes +: data(cp)
val analysis = analysisMap(cp)
val cache = cacheDirectory / "compile"
2011-02-06 17:33:29 +01:00
Compile.inputs(classpath, sources, classes, scalacOptions, javacOptions, javaRoots, analysis, cache, 100)(compilers, s.log)
}
2011-02-06 19:01:50 +01:00
def copyResources =
(ClassDirectory, CacheDirectory, Resources, ResourceDirectories, streams) map { (target, cache, resources, dirs, s) =>
val cacheFile = cache / "copy-resources"
val mappings = (resources --- dirs) x rebase(dirs, target)
2011-02-06 19:01:50 +01:00
s.log.debug("Copy resource mappings: " + mappings.mkString("\n\t","\n\t",""))
Sync(cacheFile)( mappings )
mappings
}
def testOnlyParser(resolved: ScopedKey[_]): State => Parser[(Seq[String],Seq[String])] =
{ state =>
import DefaultParsers._
def distinctParser(exs: Set[String]): Parser[Seq[String]] =
token(Space ~> NotSpace.examples(exs)).flatMap(ex => distinctParser(exs - ex).map(ex +: _)) ?? Nil
val tests = savedLines(state, resolved, DefinedTests)
val selectTests = distinctParser(tests.toSet) // todo: proper IDs
val options = (Space ~> "--" ~> spaceDelimited("<arg>")) ?? Nil
selectTests ~ options
}
def savedLines(state: State, reader: ScopedKey[_], readFrom: Scoped): Seq[String] =
{
val structure = Project.structure(state)
structure.data.definingScope(reader.scope, readFrom.key) match {
case Some(defined) =>
val key = ScopedKey(Scope.fillTaskAxis(defined, readFrom.key), readFrom.key)
structure.streams.use(reader){ ts => IO.readLines(ts.readText(key, CompletionsID)) }
case None => Nil
}
}
val CompletionsID = "completions"
2011-02-06 19:01:50 +01:00
def inConfig(conf: Configuration)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
2011-02-10 14:16:07 +01:00
inScope(ThisScope.copy(config = Select(conf)) )( (Config :== conf) +: ss)
def inTask(t: Scoped)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
inScope(ThisScope.copy(task = Select(t.key)) )( ss )
def inScope(scope: Scope)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
Project.transform(Scope.replaceThis(scope), ss)
2011-02-26 00:35:52 +01:00
lazy val defaultWebPaths = inConfig(CompileConf)(webPaths)
def noAggregation = Seq(RunTask, ConsoleTask, ConsoleQuick)
lazy val disableAggregation = noAggregation map disableAggregate
def disableAggregate(k: Scoped) =
Aggregate in Scope.GlobalScope.copy(task = Select(k.key)) :== false
2011-02-26 00:35:52 +01:00
lazy val baseTasks: Seq[Setting[_]] = projectTasks ++ packageBase
2011-02-06 03:40:10 +01:00
lazy val defaultWebTasks = Nil
2011-02-26 00:35:52 +01:00
lazy val baseClasspaths = Classpaths.publishSettings ++ Classpaths.baseSettings
lazy val configSettings = Classpaths.configSettings ++ configTasks ++ configPaths ++ packageConfig
lazy val compileSettings = configSettings ++ (mainRunTask +: addBaseSources)
lazy val testSettings = configSettings ++ testTasks
2011-02-26 00:35:52 +01:00
lazy val itSettings = inConfig(Configurations.IntegrationTest)(testSettings)
lazy val defaultConfigs = inConfig(CompileConf)(compileSettings) ++ inConfig(TestConf)(testSettings)
2011-02-26 00:35:52 +01:00
lazy val defaultSettings: Seq[Setting[_]] = core ++ paths ++ baseClasspaths ++ baseTasks ++ compileBase ++ defaultConfigs ++ disableAggregation
lazy val defaultWebSettings = defaultSettings ++ defaultWebPaths ++ defaultWebTasks
}
object Classpaths
{
import Path._
import GlobFilter._
import Keys._
import Scope.ThisScope
import Default._
import Attributed.{blank, blankSeq}
def concat[T](a: ScopedTaskable[Seq[T]], b: ScopedTaskable[Seq[T]]): Initialize[Task[Seq[T]]] = (a,b) map (_ ++ _)
2011-02-26 00:35:52 +01:00
lazy val configSettings: Seq[Project.Setting[_]] = Seq(
ExternalDependencyClasspath <<= concat(UnmanagedClasspath, ManagedClasspath),
DependencyClasspath <<= concat(InternalDependencyClasspath, ExternalDependencyClasspath),
FullClasspath <<= concat(Products, DependencyClasspath),
InternalDependencyClasspath <<= internalDependencies,
UnmanagedClasspath <<= unmanagedDependencies,
Products <<= makeProducts,
ManagedClasspath <<= (Config, Update) map { (config, up) => up.getOrElse(config.name, error("Configuration '" + config.name + "' unresolved by 'update'.")) },
UnmanagedJars <<= (Config, UnmanagedBase, ClasspathFilter, DefaultExcludes) map { (config, base, filter, excl) =>
(base * (filter -- excl) +++ (base / config.name).descendentsExcept(filter, excl)).getFiles.toSeq
}
)
2011-02-10 14:16:07 +01:00
def defaultPackageTasks: Seq[ScopedTask[_]] =
for(task <- Seq(Package, PackageSrc, PackageDoc); conf <- Seq(CompileConf, TestConf)) yield (task in conf)
val publishSettings: Seq[Project.Setting[_]] = Seq(
2011-02-10 14:16:07 +01:00
PublishMavenStyle in GlobalScope :== true,
PackageToPublish <<= defaultPackageTasks.dependOn,
DeliverDepends <<= (PublishMavenStyle, MakePom.setting, PackageToPublish.setting) { (mavenStyle, makePom, ptp) =>
if(mavenStyle) makePom.map(_ => ()) else ptp
},
MakePom <<= (IvyModule, MakePomConfig, PackageToPublish) map { (ivyModule, makePomConfig, _) => IvyActions.makePom(ivyModule, makePomConfig); makePomConfig.file },
Deliver <<= deliver(PublishConfig),
DeliverLocal <<= deliver(PublishLocalConfig),
Publish <<= publish(PublishConfig, Deliver),
PublishLocal <<= publish(PublishLocalConfig, DeliverLocal)
)
val baseSettings: Seq[Project.Setting[_]] = Seq(
UnmanagedBase <<= Base / "lib",
NormalizedName <<= Name(StringUtilities.normalize),
Organization :== NormalizedName,
2011-02-10 14:16:07 +01:00
ClasspathFilter in GlobalScope :== "*.jar",
Resolvers <<= (ProjectResolver,BaseResolvers).map( (pr,rs) => pr +: Resolver.withDefaultResolvers(rs)),
2011-02-10 14:16:07 +01:00
Offline in GlobalScope :== false,
ModuleName :== NormalizedName,
2011-02-10 14:16:07 +01:00
DefaultConfiguration in GlobalScope :== Some(Configurations.Compile),
DefaultConfigurationMapping in GlobalScope <<= DefaultConfiguration{ case Some(d) => "*->" + d.name; case None => "*->*" },
PathsIvy <<= Base(base => new IvyPaths(base, None)),
2011-02-10 14:16:07 +01:00
OtherResolvers in GlobalScope :== Nil,
ProjectResolver <<= projectResolver,
ProjectDependencies <<= projectDependencies,
2011-02-10 14:16:07 +01:00
LibraryDependencies in GlobalScope :== Nil,
AllDependencies <<= concat(ProjectDependencies,LibraryDependencies),
2011-02-10 14:16:07 +01:00
IvyLoggingLevel in GlobalScope :== UpdateLogging.Quiet,
IvyXML in GlobalScope :== NodeSeq.Empty,
IvyValidate in GlobalScope :== false,
2011-02-15 00:57:10 +01:00
IvyScalaConfig in GlobalScope <<= ScalaVersion(v => Some(new IvyScala(v, Nil, false, false))),
2011-02-10 14:16:07 +01:00
ModuleConfigurations in GlobalScope :== Nil,
PublishTo in GlobalScope :== None,
PomName <<= (ModuleName, Version, ScalaVersion, CrossPaths) { (n,v,sv, withCross) =>
ArtifactName(base = n, version = v, config = "", tpe = "", ext = "pom", cross = if(withCross) sv else "")
},
PomFile <<= (Target, PomName, NameToString) { (t, n, toString) => t / toString(n) },
2011-02-10 14:16:07 +01:00
PomArtifact <<= (PublishMavenStyle, ModuleName)( (mavenStyle, name) => if(mavenStyle) Artifact(name, "pom", "pom") :: Nil else Nil),
Artifacts <<= (PomArtifact,ModuleName)( (pom,name) => Artifact(name) +: pom),
ProjectID <<= (Organization,ModuleName,Version,Artifacts){ (org,module,version,as) => ModuleID(org, module, version).cross(true).artifacts(as : _*) },
2011-02-10 14:16:07 +01:00
BaseResolvers in GlobalScope :== Nil,
ProjectDescriptors <<= depMap,
RetrievePattern :== "[type]/[organisation]/[module]/[artifact](-[revision])(-[classifier]).[ext]",
UpdateConfig <<= (RetrieveConfig, IvyLoggingLevel)((conf,level) => new UpdateConfiguration(conf, level) ),
RetrieveConfig :== None, //Some(new RetrieveConfiguration(managedDependencyPath asFile, retrievePattern, true))
IvyConfig <<= (Resolvers, PathsIvy, OtherResolvers, ModuleConfigurations, Offline, AppConfig) map { (rs, paths, otherResolvers, moduleConfigurations, offline, app) =>
// todo: pass logger from streams directly to IvyActions
val lock = app.provider.scalaProvider.launcher.globalLock
new InlineIvyConfiguration(paths, rs, otherResolvers, moduleConfigurations, offline, Some(lock), ConsoleLogger())
},
ModuleSettingsTask <<= (ProjectID, AllDependencies, IvyXML, ThisProject, DefaultConfiguration, IvyScalaConfig, IvyValidate) map {
(pid, deps, ivyXML, project, defaultConf, ivyScala, validate) => new InlineConfiguration(pid, deps, ivyXML, project.configurations, defaultConf, ivyScala, validate)
},
MakePomConfig <<= PomFile(pomFile => makePomConfiguration(pomFile)),
PublishConfig <<= (Target, PublishTo, IvyLoggingLevel) map { (outputDirectory, publishTo, level) => publishConfiguration( publishPatterns(outputDirectory), resolverName = getPublishTo(publishTo).name, logging = level) },
PublishLocalConfig <<= (Target, IvyLoggingLevel) map { (outputDirectory, level) => publishConfiguration( publishPatterns(outputDirectory, true), logging = level ) },
IvySbtTask <<= IvyConfig map { conf => new IvySbt(conf) },
IvyModule <<= (IvySbtTask, ModuleSettingsTask) map { (ivySbt, settings) => new ivySbt.Module(settings) },
Update <<= (IvyModule, UpdateConfig, CacheDirectory, streams) map { (ivyModule, updateConfig, cacheDirectory, s) =>
cachedUpdate(cacheDirectory / "update", ivyModule, updateConfig, s.log)
}
)
def deliver(config: TaskKey[PublishConfiguration]): Initialize[Task[Unit]] =
(IvyModule, config, DeliverDepends) map { (ivyModule, config, _) => IvyActions.deliver(ivyModule, config) }
def publish(config: TaskKey[PublishConfiguration], deliverKey: TaskKey[_]): Initialize[Task[Unit]] =
(IvyModule, config, deliverKey) map { (ivyModule, config, _) => IvyActions.publish(ivyModule, config) }
import Cache._
import CacheIvy.{classpathFormat, publishIC, updateIC}
def cachedUpdate(cacheFile: File, module: IvySbt#Module, config: UpdateConfiguration, log: Logger): Map[String, Seq[File]] =
{
implicit val updateCache = updateIC
val work = (_: IvyConfiguration :+: ModuleSettings :+: UpdateConfiguration :+: HNil) match { case conf :+: settings :+: config :+: HNil =>
log.info("Updating...")
val r = IvyActions.update(module, config)
log.info("Done updating.")
r
}
val f = cached(cacheFile)(work)
f(module.owner.configuration :+: module.moduleSettings :+: config :+: HNil)
}
/*
// 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 makePomConfiguration(file: File, configurations: Option[Iterable[Configuration]] = None, extra: NodeSeq = NodeSeq.Empty, process: XNode => XNode = n => n, filterRepositories: MavenRepository => Boolean = _ => true) =
new MakePomConfiguration(file, configurations, extra, process, filterRepositories)
def getPublishTo(repo: Option[Resolver]): Resolver = repo getOrElse error("Repository for publishing is not specified.")
def publishConfiguration(patterns: PublishPatterns, resolverName: String = "local", status: String = "release", logging: UpdateLogging.Value = UpdateLogging.DownloadOnly) =
new PublishConfiguration(patterns, status, resolverName, None, logging)
def publishPatterns(outputPath: Path, publishIvy: Boolean = false): PublishPatterns =
{
val deliverPattern = (outputPath / "[artifact]-[revision](-[classifier]).[ext]").absolutePath
val srcArtifactPatterns: Seq[String] =
{
val pathPatterns =
(outputPath / "[artifact]-[revision]-[type](-[classifier]).[ext]") ::
(outputPath / "[artifact]-[revision](-[classifier]).[ext]") ::
Nil
pathPatterns.map(_.absolutePath)
}
new PublishPatterns( if(publishIvy) Some(deliverPattern) else None, srcArtifactPatterns)
}
def projectDependencies =
(ThisProject, Data) map { (p, data) =>
p.dependencies flatMap { dep => (ProjectID in dep.project) get data map { _.copy(configurations = dep.configuration) } }
}
def depMap: Initialize[Task[Map[ModuleRevisionId, ModuleDescriptor]]] =
(ThisProject, ThisProjectRef, Data) flatMap { (root, rootRef, data) =>
val dependencies = (p: (ProjectRef, Project)) => p._2.dependencies.flatMap(pr => ThisProject in pr.project get data map { (pr.project, _) })
depMap(Dag.topologicalSort((rootRef,root))(dependencies).dropRight(1), data)
}
def depMap(projects: Seq[(ProjectRef,Project)], data: Settings[Scope]): Task[Map[ModuleRevisionId, ModuleDescriptor]] =
projects.flatMap { case (p,_) => IvyModule in p get data }.join.map { mods =>
(mods.map{ mod =>
val md = mod.moduleDescriptor
(md.getModuleRevisionId, md)
}).toMap
}
def projectResolver: Initialize[Task[Resolver]] =
ProjectDescriptors map { m =>
new RawRepository(new ProjectResolver("inter-project", m))
}
def analyzed[T](data: T, analysis: Analysis) = Attributed.blank(data).put(Command.Analysis, analysis)
def makeProducts: Initialize[Task[Classpath]] =
2011-02-26 00:35:52 +01:00
(CompileTask, CompileInputs, CopyResources) map { (analysis, i, _) => analyzed(i.config.classesDirectory, analysis) :: Nil }
def internalDependencies: Initialize[Task[Classpath]] =
(ThisProjectRef, ThisProject, Config, Data) flatMap internalDependencies0
def unmanagedDependencies: Initialize[Task[Classpath]] =
(ThisProjectRef, ThisProject, Config, Data) flatMap unmanagedDependencies0
import java.util.LinkedHashSet
import collection.JavaConversions.asScalaSet
def interSort(projectRef: ProjectRef, project: Project, conf: Configuration, data: Settings[Scope]): Seq[(ProjectRef,String)] =
{
val visited = asScalaSet(new LinkedHashSet[(ProjectRef,String)])
def visit(p: ProjectRef, project: Project, c: Configuration)
{
val applicableConfigs = allConfigs(c)
for(ac <- applicableConfigs) // add all configurations in this project
visited add (p, ac.name)
val masterConfs = configurationNames(project)
for( Project.ClasspathDependency(dep, confMapping) <- project.dependencies)
{
val depProject = ThisProject in dep get data getOrElse error("Invalid project: " + dep)
val mapping = mapped(confMapping, masterConfs, configurationNames(depProject), "compile", "*->compile")
// map master configuration 'c' and all extended configurations to the appropriate dependency configuration
for(ac <- applicableConfigs; depConfName <- mapping(ac.name))
{
val depConf = configuration(dep, depProject, depConfName)
if( ! visited( (dep, depConfName) ) )
visit(dep, depProject, depConf)
}
}
}
visit(projectRef, project, conf)
visited.toSeq
}
def unmanagedDependencies0(projectRef: ProjectRef, project: Project, conf: Configuration, data: Settings[Scope]): Task[Classpath] =
interDependencies(projectRef, project, conf, data, true, unmanagedLibs)
def internalDependencies0(projectRef: ProjectRef, project: Project, conf: Configuration, data: Settings[Scope]): Task[Classpath] =
interDependencies(projectRef, project, conf, data, false, products)
def interDependencies(projectRef: ProjectRef, project: Project, conf: Configuration, data: Settings[Scope], includeSelf: Boolean,
f: (ProjectRef, String, Settings[Scope]) => Task[Classpath]): Task[Classpath] =
{
val visited = interSort(projectRef, project, conf, data)
val tasks = asScalaSet(new LinkedHashSet[Task[Classpath]])
for( (dep, c) <- visited )
if(includeSelf || (dep != projectRef) || conf.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 configurationNames(p: Project): Seq[String] = p.configurations.map( _.name)
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 configuration(ref: ProjectRef, dep: Project, conf: String): Configuration =
dep.configurations.find(_.name == conf) getOrElse missingConfiguration(Project display ref, conf)
def products(dep: ProjectRef, conf: String, data: Settings[Scope]): Task[Classpath] =
getClasspath(Products, dep, conf, data)
def unmanagedLibs(dep: ProjectRef, conf: String, data: Settings[Scope]): Task[Classpath] =
getClasspath(UnmanagedJars, dep, conf, data)
def getClasspath(key: TaskKey[Classpath], dep: ProjectRef, conf: String, data: Settings[Scope]): Task[Classpath] =
( key in (dep, ConfigKey(conf)) ) get data getOrElse const(Nil)
def defaultConfiguration(p: ProjectRef, data: Settings[Scope]): Configuration =
flatten(DefaultConfiguration in p get data) getOrElse Configurations.Default
def flatten[T](o: Option[Option[T]]): Option[T] = o flatMap identity
}