diff --git a/main/Build.scala b/main/Build.scala index c471940f6..bd87b7775 100644 --- a/main/Build.scala +++ b/main/Build.scala @@ -11,7 +11,7 @@ package sbt import scala.annotation.tailrec import collection.mutable import Compile.{Compilers,Inputs} - import Project.{ScopedKey, Setting} + import Project.{AppConfig, ScopedKey, Setting, ThisProject, ThisProjectRef} import TypeFunctions.{Endo,Id} import tools.nsc.reporters.ConsoleReporter @@ -108,9 +108,9 @@ object EvaluateTask val (state, dummyState) = dummy[State]("state") val (streams, dummyStreams) = dummy[TaskStreams]("streams") - def injectSettings = Seq( - state :== dummyState, - streams :== dummyStreams + def injectSettings: Seq[Project.Setting[_]] = Seq( + state(Scope.GlobalScope) :== dummyState, + streams(Scope.GlobalScope) :== dummyStreams ) def dummy[T](name: String): (TaskKey[T], Task[T]) = (TaskKey[T](name), dummyTask(name)) @@ -195,7 +195,8 @@ object Load val compilers = Compile.compilers(state.configuration, log) val evalPluginDef = EvaluateTask.evalPluginDef(state, log) _ val delegates = memo(defaultDelegates) - val config = new LoadBuildConfiguration(stagingDirectory, classpath, loader, compilers, evalPluginDef, delegates, EvaluateTask.injectSettings, log) + val inject: Seq[Project.Setting[_]] = (AppConfig(Scope.GlobalScope) :== state.configuration) +: EvaluateTask.injectSettings + val config = new LoadBuildConfiguration(stagingDirectory, classpath, loader, compilers, evalPluginDef, delegates, inject, log) apply(base, config) } def defaultDelegates: LoadedBuild => Scope => Seq[Scope] = (lb: LoadedBuild) => { @@ -229,7 +230,7 @@ object Load val loaded = resolveProjects(load(rootBase, config)) val projects = loaded.units lazy val rootEval = lazyEval(loaded.units(loaded.root).unit) - val settings = buildConfigurations(loaded, getRootProject(projects), config.injectSettings, rootEval) + val settings = config.injectSettings ++ buildConfigurations(loaded, getRootProject(projects), rootEval) val delegates = config.delegates(loaded) val data = Project.make(settings)(delegates) val index = structureIndex(data) @@ -250,14 +251,17 @@ object Load } def isProjectThis(s: Setting[_]) = s.key.scope.project == This - def buildConfigurations(loaded: LoadedBuild, rootProject: URI => String, injectSettings: Seq[Setting[_]], rootEval: () => Eval): Seq[Setting[_]] = + def buildConfigurations(loaded: LoadedBuild, rootProject: URI => String, rootEval: () => Eval): Seq[Setting[_]] = loaded.units.toSeq flatMap { case (uri, build) => val eval = if(uri == loaded.root) rootEval else lazyEval(build.unit) val pluginSettings = build.unit.plugins.plugins val (pluginThisProject, pluginGlobal) = pluginSettings partition isProjectThis val projectSettings = build.defined flatMap { case (id, project) => val srcs = configurationSources(project.base) - val settings = injectSettings ++ project.settings ++ pluginThisProject ++ configurations(srcs, eval, build.imports) + val settings = + (ThisProject :== project) +: + (ThisProjectRef :== ProjectRef(Some(uri), Some(id))) +: + (project.settings ++ pluginThisProject ++ configurations(srcs, eval, build.imports)) // map This to thisScope, Select(p) to mapRef(uri, rootProject, p) transformSettings(projectScope(uri, id), uri, rootProject, settings) diff --git a/main/Project.scala b/main/Project.scala index 985de01da..ea3b6c8e7 100644 --- a/main/Project.scala +++ b/main/Project.scala @@ -88,6 +88,10 @@ object Project extends Init[Scope] val SessionKey = AttributeKey[SessionSettings]("session-settings") val StructureKey = AttributeKey[Load.BuildStructure]("build-structure") + val AppConfig = SettingKey[xsbti.AppConfiguration]("app-configuration") + val ThisProject = SettingKey[Project]("project") + val ThisProjectRef = SettingKey[ProjectRef]("project-ref") + } import SessionSettings._ diff --git a/main/Structure.scala b/main/Structure.scala index c187005b1..1b8c04dca 100644 --- a/main/Structure.scala +++ b/main/Structure.scala @@ -87,11 +87,13 @@ object Scoped protected final val scopedList = scoped :^: KNil final def :==(value: S): Setting[S] = :=(value) + final def :==(value: SettingKey[S]): Setting[S] = :-(value app identity) final def := (value: => S): Setting[S] = Project.value(scoped)(value) final def :~ (f: S => S): Setting[S] = Project.update(scoped)(f) final def :- (app: Apply[S]): Setting[S] = app toSetting scoped final def apply[T](f: S => T): Apply[T] = Apply.mk(scopedList)(hl => f(hl.head)) + final def app[T](f: S => T): Apply[T] = apply(f) final def get(settings: Settings[Scope]): Option[S] = settings.get(scope, key) } @@ -108,10 +110,12 @@ object Scoped def :==(value: Task[S]): ScS = Project.value(scoped)( value ) def := (value: => S): ScS = :==(task(value)) def :== (v: TaskKey[S]): ScS = Project.app(scoped, ScopedKey(scope, v.key) :^: KNil)(_.head) + def :== (v: SettingKey[S]): ScS = :-( v app const ) def :~ (f: S => S): ScS = Project.update(scoped)( _ map f ) def :- (app: App[S]): ScS = app toSetting scoped + def setting: ScopedSetting[Task[S]] = scopedSetting(scope, key) def get(settings: Settings[Scope]): Option[Task[S]] = settings.get(scope, key) type App[T] = Apply[Task[T]] @@ -204,7 +208,82 @@ object Scoped tasks flatMapR f } } + + // this is the least painful arrangement I came up with + implicit def t2ToTable2[A,B](t2: (ScopedTaskable[A], ScopedTaskable[B]) ): RichTaskable2[A,B] = new RichTaskable2(t2) + implicit def t3ToTable3[A,B,C](t3: (ScopedTaskable[A], ScopedTaskable[B], ScopedTaskable[C]) ): RichTaskable3[A,B,C] = new RichTaskable3(t3) + implicit def t4ToTable4[A,B,C,D](t4: (ScopedTaskable[A], ScopedTaskable[B], ScopedTaskable[C], ScopedTaskable[D]) ): RichTaskable4[A,B,C,D] = new RichTaskable4(t4) + implicit def t5ToTable5[A,B,C,D,E](t5: (ScopedTaskable[A], ScopedTaskable[B], ScopedTaskable[C], ScopedTaskable[D], ScopedTaskable[E]) ): RichTaskable5[A,B,C,D,E] = new RichTaskable5(t5) + implicit def t6ToTable6[A,B,C,D,E,F](t6: (ScopedTaskable[A], ScopedTaskable[B], ScopedTaskable[C], ScopedTaskable[D], ScopedTaskable[E], ScopedTaskable[F]) ): RichTaskable6[A,B,C,D,E,F] = new RichTaskable6(t6) + implicit def t7ToTable7[A,B,C,D,E,F,G](t7: (ScopedTaskable[A], ScopedTaskable[B], ScopedTaskable[C], ScopedTaskable[D], ScopedTaskable[E], ScopedTaskable[F], ScopedTaskable[G]) ): RichTaskable7[A,B,C,D,E,F,G] = new RichTaskable7(t7) + implicit def t8ToTable8[A,B,C,D,E,F,G,H](t8: (ScopedTaskable[A], ScopedTaskable[B], ScopedTaskable[C], ScopedTaskable[D], ScopedTaskable[E], ScopedTaskable[F], ScopedTaskable[G], ScopedTaskable[H]) ): RichTaskable8[A,B,C,D,E,F,G,H] = new RichTaskable8(t8) + implicit def t9ToTable9[A,B,C,D,E,F,G,H,I](t9: (ScopedTaskable[A], ScopedTaskable[B], ScopedTaskable[C], ScopedTaskable[D], ScopedTaskable[E], ScopedTaskable[F], ScopedTaskable[G], ScopedTaskable[H], ScopedTaskable[I]) ): RichTaskable9[A,B,C,D,E,F,G,H,I] = new RichTaskable9(t9) + + sealed abstract class RichTaskables[In <: HList](keys: KList[ScopedTaskable, In]) + { + type App[T] = Apply[Task[T]] + type Fun[M[_],Ret] + protected def convertH[Ret](f: Fun[Id,Ret]): In => Ret + protected def convertK[M[_],Ret](f: Fun[M,Ret]): KList[M,In] => Ret + private[this] val red = reduced(keys) + + def flatMap[T](f: Fun[Id,Task[T]]): App[T] = red.combine(Combine.flatMapR, convertH(f) compose allM) + def flatMapR[T](f: Fun[Result,Task[T]]): App[T] = red.combine(Combine.flatMapR, convertK(f)) + def map[T](f: Fun[Id, T]): App[T] = red.combine[Id,T](Combine.mapR, convertH(f) compose allM) + def mapR[T](f: Fun[Result,T]): App[T] = red.combine[Id,T](Combine.mapR, convertK(f)) + def flatFailure[T](f: Seq[Incomplete] => Task[T]): App[T] = red.combine(Combine.flatMapR, f compose anyFailM) + def mapFailure[T](f: Seq[Incomplete] => T): App[T] = red.combine[Id,T](Combine.mapR, f compose anyFailM) + } + final class RichTaskable2[A,B](t2: (ScopedTaskable[A], ScopedTaskable[B])) extends RichTaskables(t2._1 :^: t2._2 :^: KNil) + { + type Fun[M[_],Ret] = (M[A],M[B]) => Ret + protected def convertH[R](f: (A,B) => R) = { case a :+: b :+: HNil => f(a,b) } + protected def convertK[M[_],R](f: (M[A],M[B]) => R) = { case a :^: b :^: KNil => f(a,b) } + } + final class RichTaskable3[A,B,C](t3: (ScopedTaskable[A], ScopedTaskable[B], ScopedTaskable[C])) extends RichTaskables(t3._1 :^: t3._2 :^: t3._3 :^: KNil) + { + type Fun[M[_],Ret] = (M[A],M[B],M[C]) => Ret + protected def convertH[R](f: Fun[Id,R]) = { case a :+: b :+: c :+: HNil => f(a,b,c) } + protected def convertK[M[_],R](f: Fun[M,R]) = { case a :^: b :^: c :^: KNil => f(a,b,c) } + } + final class RichTaskable4[A,B,C,D](t4: (ScopedTaskable[A], ScopedTaskable[B], ScopedTaskable[C], ScopedTaskable[D])) extends RichTaskables(t4._1 :^: t4._2 :^: t4._3 :^: t4._4 :^: KNil) + { + type Fun[M[_],Ret] = (M[A],M[B],M[C],M[D]) => Ret + protected def convertH[R](f: Fun[Id,R]) = { case a :+: b :+: c :+: d :+: HNil => f(a,b,c,d) } + protected def convertK[M[_],R](f: Fun[M,R]) = { case a :^: b :^: c :^: d :^: KNil => f(a,b,c,d) } + } + final class RichTaskable5[A,B,C,D,E](t5: (ScopedTaskable[A], ScopedTaskable[B], ScopedTaskable[C], ScopedTaskable[D], ScopedTaskable[E])) extends RichTaskables(t5._1 :^: t5._2 :^: t5._3 :^: t5._4 :^: t5._5 :^: KNil) + { + type Fun[M[_],Ret] = (M[A],M[B],M[C],M[D],M[E]) => Ret + protected def convertH[R](f: Fun[Id,R]) = { case a :+: b :+: c :+: d :+: e :+: HNil => f(a,b,c,d,e) } + protected def convertK[M[_],R](f: Fun[M,R]) = { case a :^: b :^: c :^: d :^: e :^: KNil => f(a,b,c,d,e) } + } + final class RichTaskable6[A,B,C,D,E,F](t6: (ScopedTaskable[A], ScopedTaskable[B], ScopedTaskable[C], ScopedTaskable[D], ScopedTaskable[E], ScopedTaskable[F])) extends RichTaskables(t6._1 :^: t6._2 :^: t6._3 :^: t6._4 :^: t6._5 :^: t6._6 :^: KNil) + { + type Fun[M[_],Ret] = (M[A],M[B],M[C],M[D],M[E],M[F]) => Ret + protected def convertH[R](z: Fun[Id,R]) = { case a :+: b :+: c :+: d :+: e :+: f :+: HNil => z(a,b,c,d,e,f) } + protected def convertK[M[_],R](z: Fun[M,R]) = { case a :^: b :^: c :^: d :^: e :^: f :^: KNil => z(a,b,c,d,e,f) } + } + final class RichTaskable7[A,B,C,D,E,F,G](t7: (ScopedTaskable[A], ScopedTaskable[B], ScopedTaskable[C], ScopedTaskable[D], ScopedTaskable[E], ScopedTaskable[F], ScopedTaskable[G])) extends RichTaskables(t7._1 :^: t7._2 :^: t7._3 :^: t7._4 :^: t7._5 :^: t7._6 :^: t7._7 :^: KNil) + { + type Fun[M[_],Ret] = (M[A],M[B],M[C],M[D],M[E],M[F],M[G]) => Ret + protected def convertH[R](z: Fun[Id,R]) = { case a :+: b :+: c :+: d :+: e :+: f :+: g :+: HNil => z(a,b,c,d,e,f,g) } + protected def convertK[M[_],R](z: Fun[M,R]) = { case a :^: b :^: c :^: d :^: e :^: f :^: g :^: KNil => z(a,b,c,d,e,f,g) } + } + final class RichTaskable8[A,B,C,D,E,F,G,H](t8: (ScopedTaskable[A], ScopedTaskable[B], ScopedTaskable[C], ScopedTaskable[D], ScopedTaskable[E], ScopedTaskable[F], ScopedTaskable[G], ScopedTaskable[H])) extends RichTaskables(t8._1 :^: t8._2 :^: t8._3 :^: t8._4 :^: t8._5 :^: t8._6 :^: t8._7 :^: t8._8 :^: KNil) + { + type Fun[M[_],Ret] = (M[A],M[B],M[C],M[D],M[E],M[F],M[G],M[H]) => Ret + protected def convertH[R](z: Fun[Id,R]) = { case a :+: b :+: c :+: d :+: e :+: f :+: g :+: h :+: HNil => z(a,b,c,d,e,f,g,h) } + protected def convertK[M[_],R](z: Fun[M,R]) = { case a :^: b :^: c :^: d :^: e :^: f :^: g :^: h :^: KNil => z(a,b,c,d,e,f,g,h) } + } + final class RichTaskable9[A,B,C,D,E,F,G,H,I](t9: (ScopedTaskable[A], ScopedTaskable[B], ScopedTaskable[C], ScopedTaskable[D], ScopedTaskable[E], ScopedTaskable[F], ScopedTaskable[G], ScopedTaskable[H], ScopedTaskable[I])) extends RichTaskables(t9._1 :^: t9._2 :^: t9._3 :^: t9._4 :^: t9._5 :^: t9._6 :^: t9._7 :^: t9._8 :^: t9._9 :^: KNil) + { + type Fun[M[_],Ret] = (M[A],M[B],M[C],M[D],M[E],M[F],M[G],M[H],M[I]) => Ret + protected def convertH[R](z: Fun[Id,R]) = { case a :+: b :+: c :+: d :+: e :+: f :+: g :+: h :+: i :+: HNil => z(a,b,c,d,e,f,g,h,i) } + protected def convertK[M[_],R](z: Fun[M,R]) = { case a :^: b :^: c :^: d :^: e :^: f :^: g :^: h :^: i :^: KNil => z(a,b,c,d,e,f,g,h,i) } + } + // this doesn't actually work for mixed KLists because the compiler crashes trying to infer the bound when constructing the KList implicit def richTaskableKeys[HL <: HList](in: KList[ScopedTaskable, HL]): RichTaskableKeys[HL] = new RichTaskableKeys(in) final class RichTaskableKeys[In <: HList](keys: KList[ScopedTaskable, In]) { diff --git a/main/pending/ClasspathProject.scala b/main/pending/ClasspathProject.scala deleted file mode 100644 index cdcc1b2b9..000000000 --- a/main/pending/ClasspathProject.scala +++ /dev/null @@ -1,350 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2010 Mark Harrah - */ -package sbt - - import std._ - import inc.Analysis - import TaskExtra._ - import ClasspathProject._ - import java.io.File - import Path._ - import Types._ - import scala.xml.{Node => XNode,NodeSeq} - -trait ClasspathProject -{ - def name: String - def configurations: Seq[Configuration] - def defaultConfiguration: Option[Configuration] - - val products: Classpath - val unmanagedClasspath: Classpath - val managedClasspath: Classpath - val internalDependencyClasspath: Classpath - - lazy val externalDependencyClasspath: Classpath = - TaskMap { (configuration: Configuration) => - val un = unmanagedClasspath(configuration) - val m = managedClasspath(configuration) - (un, m) map concat[Attributed[File]] - } - - lazy val dependencyClasspath: Classpath = - TaskMap { (configuration: Configuration) => - val external = externalDependencyClasspath(configuration) - val internal = internalDependencyClasspath(configuration) - (external, internal) map concat[Attributed[File]] - } - lazy val fullClasspath: Classpath = - TaskMap { case (configuration: Configuration) => - val dep = dependencyClasspath(configuration) - val prod = products(configuration) - (dep, prod) map concat[Attributed[File]] - } - - lazy val configurationMap: Map[String, Configuration] = - configurations map { conf => (conf.name, conf) } toMap; -} - -trait BasicClasspathProject extends ClasspathProject -{ - val ivyConfiguration: Task[IvyConfiguration] - val moduleSettings: Task[ModuleSettings] - val unmanagedBase: Task[File] - def cacheDirectory: File - - val updateConfig: Task[UpdateConfiguration] - - lazy val ivySbt: Task[IvySbt] = - ivyConfiguration map { conf => new IvySbt(conf) } - - lazy val ivyModule: Task[IvySbt#Module] = - (ivySbt, moduleSettings) map { (ivySbt: IvySbt, settings: ModuleSettings) => - new ivySbt.Module(settings) - } - - def classpathFilter: FileFilter = GlobFilter("*.jar") - def defaultExcludes: FileFilter - - override lazy val managedClasspath: Classpath = - TaskMap { configuration => - update map { x => attributed(x.getOrElse(configuration, error("No such configuration '" + configuration.toString + "'")) ) } - } - - lazy val unmanagedClasspath: Classpath = - TaskMap { configuration => - unmanagedBase map { base => - attributed( (base * (classpathFilter -- defaultExcludes) +++ - (base / configuration.toString).descendentsExcept(classpathFilter, defaultExcludes)).getFiles.toSeq ) - } - } - - lazy val update = (ivyModule, updateConfig) map cachedUpdate(cacheDirectory / "update", configurationMap) -} -trait PublishProject extends BasicClasspathProject -{ - val publishConfig: Task[PublishConfiguration] - val publishLocalConfig: Task[PublishConfiguration] - val makePomConfig: Task[MakePomConfiguration] - def packageToPublish: Seq[Task[_]] - - def publishMavenStyle = true - def deliverDepends = if(publishMavenStyle) makePom :: Nil else packageToPublish - - lazy val makePom = (ivyModule, makePomConfig) map(IvyActions.makePom) dependsOn( packageToPublish : _*) - lazy val deliver = (ivyModule, publishConfig) map cachedPublish(cacheDirectory / "deliver")(IvyActions.deliver) dependsOn(deliverDepends : _*) - lazy val deliverLocal = (ivyModule, publishLocalConfig) map cachedPublish(cacheDirectory / "deliver-local")(IvyActions.deliver) dependsOn(deliverDepends : _*) - lazy val publish = (ivyModule, publishConfig) map cachedPublish(cacheDirectory / "publish")(IvyActions.publish) dependsOn(deliver) - lazy val publishLocal = (ivyModule, publishLocalConfig) map cachedPublish(cacheDirectory / "publish-local")(IvyActions.publish) dependsOn(deliverLocal) -} - -trait DefaultClasspathProject extends BasicClasspathProject with PublishProject with Project -{ - def outputDirectory: Path - def projectID: ModuleID - def baseResolvers: Seq[Resolver] - lazy val resolvers: Task[Seq[Resolver]] = task { baseResolvers } - - def otherResolvers: Seq[Resolver] = Nil - def moduleConfigurations: Seq[ModuleConfiguration] = Nil - - def retrievePattern = "[type]/[organisation]/[module]/[artifact](-[revision])(-[classifier]).[ext]" - override lazy val updateConfig: Task[UpdateConfiguration] = retrieveConfig map { rConf => - new UpdateConfiguration(rConf, UpdateLogging.Quiet) - } - lazy val retrieveConfig: Task[Option[RetrieveConfiguration]] = task { - None//Some(new RetrieveConfiguration(managedDependencyPath asFile, retrievePattern, true)) - } - - def offline: Boolean = false - def paths: IvyPaths = new IvyPaths(info.projectDirectory, None) - - lazy val ivyConfiguration: Task[IvyConfiguration] = resolvers map { rs => - // TODO: log should be passed directly to IvyActions and pulled from Streams - new InlineIvyConfiguration(paths, rs, otherResolvers, moduleConfigurations, offline, Some(info.globalLock), ConsoleLogger()) - } - - def libraryDependencies: Seq[ModuleID] = ReflectUtilities.allVals[ModuleID](this).toSeq.map(_._2) - - def managedDependencyPath: Path = info.projectDirectory / "lib_managed" - def dependencyPath: Path = info.projectDirectory / "lib" - - def ivyXML: NodeSeq = NodeSeq.Empty - def defaultConfiguration: Option[Configuration] = None - def ivyScala: Option[IvyScala] = None - def ivyValidate: Boolean = false - def moduleID = normalizedName - - def pomFile: File - def publishTo: Resolver = error("Repository for publishing is not specified.") - - lazy val internalDependencyClasspath: Classpath = internalDependencies(this) - - lazy val unmanagedBase = task { dependencyPath.asFile } - - lazy val moduleSettings: Task[ModuleSettings] = task { - new InlineConfiguration(projectID, libraryDependencies, ivyXML, configurations, defaultConfiguration, ivyScala, ivyValidate) - } - - lazy val publishConfig = task { publishConfiguration( publishPatterns(outputDirectory), resolverName = publishTo.name ) } - lazy val publishLocalConfig = task { publishConfiguration( publishPatterns(outputDirectory, true) ) } - lazy val makePomConfig = task { makePomConfiguration(pomFile) } -} -trait MultiClasspathProject extends DefaultClasspathProject -{ - def dependencies: Seq[ProjectDependency.Classpath] - def name: String - def organization: String - def version: String - def pomFile: File = outputDirectory / (moduleID + "-" + version + ".pom") - def artifacts: Seq[Artifact] = Nil - - def projectDependencies: Seq[ModuleID] = - resolvedDependencies(this) collect { case (p: DefaultClasspathProject, conf) => p.projectID.copy(configurations = conf) } - - lazy val projectResolver = - depMap(this) map { m => - new RawRepository(new ProjectResolver("inter-project", m)) - } - - override def projectID = ModuleID(organization, moduleID, version).cross(true).artifacts(artifacts.toSeq : _*) - override def libraryDependencies: Seq[ModuleID] = super.libraryDependencies ++ projectDependencies - - override lazy val resolvers: Task[Seq[Resolver]] = projectResolver map { _ +: baseResolvers } -} - -trait ReflectiveClasspathProject extends DefaultClasspathProject -{ - private[this] def vals[T: Manifest] = ReflectUtilities.allVals[T](this).toSeq.map(_._2) - def configurations: Seq[Configuration] = vals[Configuration] ++ Configurations.defaultMavenConfigurations - def baseResolvers: Seq[Resolver] = Resolver.withDefaultResolvers(vals[Resolver] ) -} - - import org.apache.ivy.core.module - import module.id.ModuleRevisionId - import module.descriptor.ModuleDescriptor - -object ClasspathProject -{ - type Classpath = Configuration => Task[Seq[Attributed[File]]] - - val Analyzed = AttributeKey[Analysis]("analysis") - - def attributed[T](in: Seq[T]): Seq[Attributed[T]] = in map Attributed.blank - - def analyzed[T](data: T, analysis: Analysis) = Attributed.blank(data).put(Analyzed, analysis) - - def analyzed(compile: Task[Analysis], inputs: Task[Compile.Inputs]): Task[Attributed[File]] = - (compile, inputs) map { case analysis :+: i :+: HNil => - analyzed(i.config.classesDirectory, analysis) - } - - def makeProducts(compile: Task[Analysis], inputs: Task[Compile.Inputs], name: String, prefix: String): Task[Seq[Attributed[File]]] = - { - def mkName(postfix: String) = name + "/" + prefix + postfix - analyzed(compile, inputs) named(mkName("analyzed")) map { _ :: Nil } named(mkName("products")) - } - - def concat[A]: (Seq[A], Seq[A]) => Seq[A] = _ ++ _ - - def extractAnalysis[T](a: Attributed[T]): (T, Analysis) = - (a.data, a.metadata get Analyzed getOrElse Analysis.Empty) - - def analysisMap[T](cp: Seq[Attributed[T]]): Map[T, Analysis] = - (cp map extractAnalysis).toMap - - def data[T](in: Seq[Attributed[T]]): Seq[T] = in.map(_.data) - def taskData[T](in: Task[Seq[Attributed[T]]]): Task[Seq[T]] = in map data - - def depMap(root: Project): Task[Map[ModuleRevisionId, ModuleDescriptor]] = - depMap(MultiProject.topologicalSort(root).dropRight(1) collect { case cp: DefaultClasspathProject => cp }) - - def depMap(projects: Seq[DefaultClasspathProject]): Task[Map[ModuleRevisionId, ModuleDescriptor]] = - projects.map( _.ivyModule ).join.map { mods => - (mods.map{ mod => - val md = mod.moduleDescriptor - (md.getModuleRevisionId, md) - }).toMap - } - - def resolvedDependencies(p: Project): Seq[(Project, Option[String])] = - p.dependencies map { cp => - (resolveProject(cp.project, p), cp.configuration) - } - - def resolveProject(e: Either[File, Project], context: Project): Project = - e match { - case Left(extPath) => context.info.externals(extPath) - case Right(proj) => proj - } - - def mapped(c: String, mapping: Option[String], default: String)(errMsg: => String): String = - parseSimpleConfigurations(mapping getOrElse default).getOrElse(c, errMsg) - def internalDependencies(project: Project): Classpath = - TaskMap { (conf: Configuration) => - val visited = asSet(new java.util.LinkedHashSet[(Project,String)]) - def visit(p: Project, c: String) - { - val applicableConfigs = allConfigs(p, c) - for(ac <- applicableConfigs) - visited add (p, ac) - - for( (dep, confMapping) <- resolvedDependencies(p)) - { - val depConf = mapped(c, confMapping, defaultConfiguration(dep).toString) { missingMapping(p.name, dep.name, c) } - if( ! visited( (dep, depConf) ) ) - visit(dep, depConf) - } - } - visit(project, conf.name) - - val productsTasks = asSet(new java.util.LinkedHashSet[Task[Seq[Attributed[File]]]]) - for( (dep: ClasspathProject, c) <- visited ) - if( (dep ne project) || conf.name != c ) - productsTasks += products(dep, c) - - def name(action: String) = project.name + "/" + conf + "/" + action + "-products" - (productsTasks.toSeq.join) named(name("join")) map(_.flatten) named(name("flatten")) - } - - def parseSimpleConfigurations(confString: String): Map[String, String] = - confString.split(";").flatMap( conf => - trim(conf.split("->",2)) match { - case x :: Nil => for(a <- parseList(x)) yield (a,a) - case x :: y :: Nil => for(a <- parseList(x); b <- parseList(x)) yield (a,b) - case _ => error("Invalid configuration '" + conf + "'") // shouldn't get here - } - ).toMap - - def parseList(s: String): Seq[String] = trim(s split ",") - private def trim(a: Array[String]): List[String] = a.toList.map(_.trim) - - def missingMapping(from: String, to: String, conf: String) = - error("No configuration mapping defined from '" + from + "' to '" + to + "' for '" + conf + "'") - def missingConfiguration(in: String, conf: String) = - error("Configuration '" + conf + "' not defined in '" + in + "'") - def allConfigs(dep: Project, conf: String): Seq[String] = - dep match { - case cp: ClasspathProject => Dag.topologicalSort(configuration(cp, conf))(_.extendsConfigs).map(_.name) - case _ => Nil - } - def configuration(dep: ClasspathProject, conf: String): Configuration = - dep.configurationMap.getOrElse(conf,missingConfiguration(dep.name, conf)) - def products(dep: ClasspathProject, conf: String) = - dep.products(configuration(dep, conf)) - def defaultConfiguration(p: Project): Configuration = - p match - { - case cp: ClasspathProject => cp.defaultConfiguration getOrElse Configurations.Default - case _ => Configurations.Default - } - - 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 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) - } - - import Cache._ - import Types._ - import CacheIvy.{classpathFormat, publishIC, updateIC} - - def cachedUpdate(cacheFile: File, configMap: Map[String, Configuration]): (IvySbt#Module :+: UpdateConfiguration :+: HNil) => Map[Configuration, Seq[File]] = - { case module :+: config :+: HNil => - implicit val updateCache = updateIC - val f = cached(cacheFile) { (conf: IvyConfiguration, settings: ModuleSettings, config: UpdateConfiguration) => - println("Updating...") - val r = IvyActions.update(module, config) - println("Done updating.") - r - } - val classpaths = f(module.owner.configuration :+: module.moduleSettings :+: config :+: HNil) - val confMap = configMap - classpaths map { case (key, value) => (confMap(key), value) } toMap; - } - - // 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): (IvySbt#Module :+: PublishConfiguration :+: HNil) => 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)*/ - } -} \ No newline at end of file diff --git a/main/pending/MultiProject.scala b/main/pending/MultiProject.scala deleted file mode 100644 index 479c3e408..000000000 --- a/main/pending/MultiProject.scala +++ /dev/null @@ -1,264 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2010 Mark Harrah - */ -package sbt - -import std._ -import Path._ -import TaskExtra._ -import GlobFilter._ -import Transform.Context -import inc.Analysis -import build.{Auto, Build} -import xsbti.AppConfiguration -import MultiProject.transformName - -import java.io.File -import annotation.tailrec - -object MultiProject -{ - val ScalaVersion = AttributeKey[String]("scala-version") - - val defaultExcludes: FileFilter = (".*" - ".") || HiddenFileFilter - def descendents(base: PathFinder, select: FileFilter) = base.descendentsExcept(select, defaultExcludes) - def children(base: PathFinder, select: FileFilter) = base * (select -- defaultExcludes) - def projectClassName = classOf[Project].getName - - def projectStandard(base: Path) = base / "project" - def projectHidden(base: Path) = base / ".sbt" - def selectProjectDir(base: Path) = - { - val a = projectHidden(base) - val b = projectStandard(base) - if(a.exists) a else b - } - - def crossPath(base: Path, instance: ScalaInstance) = base / ("scala_" + instance.actualVersion) - - def construct[T <: AnyRef](arg: T)(implicit mf: Manifest[T]): Class[_] => Any = clazz => - Build.constructor(clazz, mf.erasure) match { - case Some(c) => c.newInstance(arg) - case None => error("Couldn't find constructor with one argument of type " + mf.toString) - } - - // externals must not be evaluated until after _all_ projects have been loaded - def load(configuration: AppConfiguration, log: Logger, externals: ExternalProjects)(base: File): Project = - { - if(!base.isDirectory) throw new build.BuildException(base + " is not a project directory") - val projectDir = selectProjectDir(base) - val buildDir = projectDir / "build" - val srcMain = buildDir / "src" / "main" - val javaSrcBase = srcMain / "java" - val sources = children(buildDir +++ projectDir, "*.scala") +++ descendents(buildDir / "scala" +++ buildDir / "java", "*.scala" | "*.java") - val classpath = configuration.provider.mainClasspath.toSeq - val compilers = Compile.compilers(configuration, log) - val target = crossPath(buildDir / "target", compilers.scalac.scalaInstance) - val inputs = Compile.inputs(classpath, sources.getFiles.toSeq, target, Nil, Nil, javaSrcBase :: Nil, Compile.DefaultMaxErrors)(compilers, log) - - val analysis = Compile(inputs, log) - val info = ProjectInfo(None, base, projectDir, Nil, None)(configuration, analysis, inputs, load(configuration, log, externals), externals) - - val discovered = Build.discover(analysis, Some(false), Auto.Subclass, projectClassName) - val discoveredOrDefault = if(discovered.isEmpty) List(build.ToLoad("sbt.DefaultProject", false)) else discovered - val toLoad = Build.check(discoveredOrDefault, false) - Build.binaries(inputs.config.classpath, toLoad, getClass.getClassLoader)(construct(info)).head.asInstanceOf[Project] - } - - def loadExternals(from: Seq[Project], loadImpl: File => Project): Map[File, Project] = - { - def load(loaded: Map[File, Project], file: File): Map[File, Project] = - (loaded get file) match - { - case None => doLoad(loaded, file) - case Some(p) => loaded - } - def doLoad(loaded: Map[File, Project], file: File): Map[File, Project] = - { - val loadedProject = loadImpl(file) - val newMap = loaded.updated(file, loadedProject) - loadAll( externals(loadedProject :: Nil), newMap ) - } - def loadAll(files: Set[File], loaded: Map[File, Project]): Map[File, Project] = (loaded /: files)(load) - - loadAll( externals(from) , Map.empty) - } - - def externals(containers: Seq[Project]): Set[File] = - { - def exts(containers: Seq[Project]): Seq[File] = - containers flatMap { container => externalProjects(container) ++ exts(internalProjects(container)) } - exts(containers).toSet - } - def externalProjects(p: Project) = lefts( allDependencies(p) ) - def internalProjects(p: Project) = rights( allDependencies(p) ) - def allDependencies(p: Project) = (p.aggregate ++ p.dependencies).map(_.project) - - def internalTopologicalSort(root: Project): Seq[Project] = - Dag.topologicalSort(root)(internalProjects) - - def topologicalSort(root: Project): Seq[Project] = topologicalSort(root, root.info.externals) - def topologicalSort(root: Project, resolveExternal: File => Project): Seq[Project] = - Dag.topologicalSort(root) { p => - (externalProjects(p) map resolveExternal) ++ internalProjects(p) - } - - def makeContext(root: Project) = - { - val contexts = topologicalSort(root) map { p => (p, ReflectiveContext(p, p.name, root)) } - val externals = root.info.externals - def subs(f: Project => Seq[ProjectDependency]): Project => Seq[Project] = p => - f(p) map( _.project match { case Left(path) => externals(path); case Right(proj) => proj } ) - MultiContext(contexts, root)(subs(_.aggregate), subs(_.dependencies) ) - } - - def lefts[A,B](e: Seq[Either[A,B]]):Seq[A] = e collect { case Left(l) => l } - def rights[A,B](e: Seq[Either[A,B]]):Seq[B] = e collect { case Right(r)=> r } - - def transformName(s: String) = - { - val parts = s.split("-+") - (parts.take(1) ++ parts.drop(1).map(_.capitalize)).mkString - } -} - -object MultiContext -{ - def identityMap[A,B](in: Iterable[(A,B)]): collection.Map[A,B] = - { - import collection.JavaConversions._ - val map: collection.mutable.Map[A, B] = new java.util.IdentityHashMap[A,B] - for( (a,b) <- in) map(a) = b - map - } - - def fun[A,B](map: collection.Map[A,B]): A => Option[B] = map get _ - def apply[Owner <: AnyRef](contexts: Iterable[(Owner, Context[Owner])], root: Owner)(agg: Owner => Iterable[Owner], deps: Owner => Iterable[Owner]): Context[Owner] = new Context[Owner] - { - val ownerReverse = (for( (owner, context) <- contexts; name <- context.ownerName(owner).toList) yield (name, owner) ).toMap - val ownerMap = identityMap[Task[_],Owner]( for((owner, context) <- contexts; task <- context.allTasks(owner) ) yield (task, owner) ) - val context = identityMap(contexts) - def subMap(f: Owner => Iterable[Owner]) = identityMap( contexts.map { case (o,_) => (o,f(o)) }) - val aggMap = subMap(agg) - val depMap = subMap(deps) - - def rootOwner: Owner = root - def allTasks(owner: Owner): Iterable[Task[_]] = context(owner).allTasks(owner) - def ownerForName(name: String): Option[Owner] = ownerReverse get name - val staticName: Task[_] => Option[String] = t => owner(t) flatMap { o => context(o).staticName(t) } - val ownerName = (o: Owner) => context(o).ownerName(o) - val owner = (t: Task[_]) => ownerMap.get(t) - val aggregate = (o: Owner) => (aggMap get o).toList.flatten - def dependencies(o: Owner): Iterable[Owner] = (depMap get o).toList.flatten - val static = (o: Owner, s: String) => context(o).static(o, s) - } -} -final class MultiNavigation(val self: Project, val selectFun: (Project, Project, State) => State, val selectedProject: Project, val initialProject: Project) extends Navigation -{ - type Project = sbt.Project - def parent = self.info.parent map nav - def name = self.name - def select(s: State): State = if(selectedProject == self) s else selectFun(self, initialProject, s) - @tailrec final lazy val root: MultiNavigation = parent match { case Some(p) => p.root; case None => this } - def initial = nav(initialProject) - def closure = projectClosure map nav - - def selected = nav(selectedProject) - - def projectClosure: Seq[Project] = MultiProject.topologicalSort(initialProject) - - private val nav = (p: Project) => new MultiNavigation(p, selectFun, selectedProject, initialProject) -} -final class MultiWatched(val self: Project) extends Watched -{ - def watched(p: Project): Seq[Watched] = MultiProject.topologicalSort(p) - def sourcePaths(p: Project): PathFinder = (Path.emptyPathFinder /: watched(p))(_ +++ _.watchPaths) - override def watchPaths = sourcePaths(self) - override def terminateWatch(key: Int): Boolean = self.terminateWatch(key) -} -trait Project extends Tasked with ConsoleTask with Watched -{ - val info: ProjectInfo - - def name: String = info.name getOrElse error("'name' not overridden") - def normalizedName: String = StringUtilities.normalize(name) - - def base = info.projectDirectory - def outputRootPath = base / "target" - def historyPath: Option[File] = Some(outputRootPath / ".history") - def streamBase = outputRootPath / "streams" - - implicit def streams = Dummy.Streams - def input = Dummy.In - def state = Dummy.State - def context = Dummy.Context - - def aggregate: Seq[ProjectDependency.Execution] = info.dependencies collect { case ex: ProjectDependency.Execution => ex } - def dependencies: Seq[ProjectDependency.Classpath] = info.dependencies collect { case cp: ProjectDependency.Classpath => cp } - - type Task[T] = sbt.Task[T] - def act(input: Input, state: State): Option[(Task[State], Execute.NodeView[Task])] = - { - import Dummy._ - val context = MultiProject.makeContext(this) - val dummies = new Transform.Dummies(In, State, Streams, Context) - def name(t: Task[_]): String = context.staticName(t.original) getOrElse std.Streams.name(t) - val mklog = LogManager.construct(context) - def getOwner(t: Task[_]) = context.owner(t.original).getOrElse(error("No owner for " + name(t.original) + "\n\t" + t.original)) - val actualStreams = std.Streams(t => getOwner(t).streamBase / name(t), mklog ) - val injected = new Transform.Injected( input, state, actualStreams ) - context.static(this, transformName(input.name)) map { t => (t.merge.map(_ => state), Transform(dummies, injected, context) ) } - } - - def help: Seq[Help] = Nil -} -trait ProjectExtra -{ - val info: ProjectInfo - /** Converts a String to a path relative to the project directory of this project. */ - implicit def path(component: String): Path = info.projectDirectory / component - /** Converts a String to a simple name filter. * has the special meaning: zero or more of any character */ - implicit def globFilter(simplePattern: String): NameFilter = GlobFilter(simplePattern) - def defaultExcludes: FileFilter = MultiProject.defaultExcludes - def descendents(path: PathFinder, filter: FileFilter): PathFinder = path.descendentsExcept(filter, defaultExcludes) -} -trait ReflectiveProject extends Project -{ - private[this] def vals[T: Manifest] = ReflectUtilities.allVals[T](this).toSeq.map(_._2) - override def aggregate: Seq[ProjectDependency.Execution] = vals[ProjectDependency.Execution] ++ vals[Project].map(p => ProjectDependency.Execution(Right(p))) ++ super.aggregate - override def dependencies: Seq[ProjectDependency.Classpath] = vals[ProjectDependency.Classpath] ++ super.dependencies -} -trait ConsoleTask -{ - val info: ProjectInfo - lazy val projectConsole = task { Console.sbtDefault(info.compileInputs, this)(ConsoleLogger()) } -} - -trait ProjectConstructors extends Project -{ - val info: ProjectInfo - //def project(base: Path, name: String, deps: ProjectDependency*): Project = project(path, name, info => new DefaultProject(info), deps: _* ) - def project[P <: Project](path: Path, name: String, construct: ProjectInfo => P, deps: ProjectDependency*): P = - construct( info.copy(Some(name), projectDirectory = path.asFile, parent = Some(this), dependencies = deps)() ) - - def project(base: Path): ProjectDependency.Execution = new ProjectDependency.Execution(Left(base.asFile)) - - implicit def defaultProjectDependency(p: Project): ProjectDependency = new ProjectDependency.Classpath(Right(p), None) - - implicit def dependencyConstructor(p: Project): ProjectDependencyConstructor = dependencyConstructor(Right(p)) - implicit def extDependencyConstructor(p: File): ProjectDependencyConstructor = dependencyConstructor(Left(p)) - implicit def extDependencyConstructor(p: ProjectDependency.Execution): ProjectDependencyConstructor = dependencyConstructor(p.project) - - def dependencyConstructor(p: Either[File, Project]): ProjectDependencyConstructor = new ProjectDependencyConstructor { - def %(conf: String) = new ProjectDependency.Classpath(p, Some(conf)) - } -} -sealed trait ProjectDependency { val project: Either[File, Project] } -object ProjectDependency -{ - final case class Execution(project: Either[File, Project]) extends ProjectDependency - final case class Classpath(project: Either[File, Project], configuration: Option[String]) extends ProjectDependency -} -sealed trait ProjectDependencyConstructor { - def %(conf: String): ProjectDependency.Classpath -} \ No newline at end of file