From 54ba5d75beb75910517c4bd361729224ad3dbcf0 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Sat, 13 Nov 2010 20:21:06 -0500 Subject: [PATCH] work on products+configurations --- ivy/IvyInterface.scala | 10 +++++----- main/ClasspathProject.scala | 36 ++++++++++++++++++++++++++++-------- main/DefaultProject.scala | 24 ++++++++++++------------ 3 files changed, 45 insertions(+), 25 deletions(-) diff --git a/ivy/IvyInterface.scala b/ivy/IvyInterface.scala index 74f7fa876..52d02d876 100644 --- a/ivy/IvyInterface.scala +++ b/ivy/IvyInterface.scala @@ -292,11 +292,11 @@ object Configurations lazy val Default = config("default") lazy val Compile = config("compile") - lazy val IntegrationTest = config("it") hide + lazy val IntegrationTest = config("it") extend(Runtime) hide; lazy val Provided = config("provided") lazy val Javadoc = config("javadoc") - lazy val Runtime = config("runtime") - lazy val Test = config("test") hide + lazy val Runtime = config("runtime") extend(Compile) + lazy val Test = config("test") extend(Runtime) hide; lazy val Sources = config("sources") lazy val System = config("system") lazy val Optional = config("optional") @@ -310,7 +310,7 @@ object Configurations private[sbt] def removeDuplicates(configs: Iterable[Configuration]) = Set(scala.collection.mutable.Map(configs.map(config => (config.name, config)).toSeq: _*).values.toList: _*) } /** Represents an Ivy configuration. */ -final case class Configuration(name: String, description: String, isPublic: Boolean, extendsConfigs: List[Configuration], transitive: Boolean) extends NotNull +final case class Configuration(name: String, description: String, isPublic: Boolean, extendsConfigs: List[Configuration], transitive: Boolean) { require(name != null && !name.isEmpty) require(description != null) @@ -323,7 +323,7 @@ final case class Configuration(name: String, description: String, isPublic: Bool override def toString = name } -final case class Artifact(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL], extraAttributes: Map[String,String]) extends NotNull +final case class Artifact(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL], extraAttributes: Map[String,String]) { def extra(attributes: (String,String)*) = Artifact(name, `type`, extension, classifier, configurations, url, extraAttributes ++ ModuleID.checkE(attributes)) } diff --git a/main/ClasspathProject.scala b/main/ClasspathProject.scala index 0ad245839..0c0877bb6 100644 --- a/main/ClasspathProject.scala +++ b/main/ClasspathProject.scala @@ -183,6 +183,12 @@ object ClasspathProject analyzed(i.config.classesDirectory, analysis) } + def makeProducts(compile: Task[Analysis], inputs: Task[Compile.Inputs], name: String, prefix: String) = + { + 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) = @@ -222,19 +228,26 @@ object ClasspathProject val visited = new LinkedHashSet[(Project,String)] def visit(p: Project, c: String) { - for( (dep, confMapping) <- ClasspathProject.resolvedDependencies(p)) + 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) } - val unvisited = visited.add( (dep, depConf) ) - if(unvisited) visit(dep, depConf) + if( ! visited( (dep, depConf) ) ) + visit(dep, depConf) } } - visit(project, conf.toString) + visit(project, conf.name) val productsTasks = new LinkedHashSet[Task[Seq[Attributed[File]]]] - for( (dep: ClasspathProject, conf) <- visited ) - if(dep ne project) productsTasks += products(dep, conf) - (productsTasks.toSeq.join) named(project.name + "/join") map(_.flatten) + 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] = @@ -253,8 +266,15 @@ object ClasspathProject 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(dep.configurationMap.getOrElse(conf,missingConfiguration(dep.name, conf))) + dep.products(configuration(dep, conf)) def defaultConfiguration(p: Project): Configuration = p match { diff --git a/main/DefaultProject.scala b/main/DefaultProject.scala index da0bd5b0b..56effda51 100644 --- a/main/DefaultProject.scala +++ b/main/DefaultProject.scala @@ -7,7 +7,7 @@ package sbt import compile.{Discovered,Discovery} import inc.Analysis import TaskExtra._ - import Configurations.{Compile => CompileConfig, Test => TestConfig, Runtime => RunConfig} + import Configurations.{Compile => CompileConfig, Test => TestConfig, Runtime => RunConfig, Default => DefaultConfig} import ClasspathProject._ import Types._ import xsbti.api.Definition @@ -38,13 +38,14 @@ abstract class BasicProject extends TestProject with MultiClasspathProject with case x => outputDirectory / (x.toString + "-classes") } - // TODO: resources, jars, test classes - lazy val products: Classpath = - TaskMap { (conf: Configuration) => - conf match { - case CompileConfig | RunConfig => analyzed(compile, compileInputs) named(name + "/analyzed") map { _ :: Nil } named(name + "/products") - case x => error("Unknown compilation configuration: " + x) - } + lazy val products: Classpath = TaskMap(productsTask) + + // TODO: it config, include resources, perhaps handle jars v. directories + def productsTask(conf: Configuration) = + conf match { + case CompileConfig | DefaultConfig => makeProducts(compile, compileInputs, name, "") + case TestConfig => makeProducts(testCompile, testCompileInputs, name, "test-") + case x => task { Nil } } lazy val buildScalaInstance: Task[ScalaInstance] = task { @@ -88,8 +89,7 @@ abstract class BasicProject extends TestProject with MultiClasspathProject with def compileInputsTask(configuration: Configuration, base: PathFinder, scalaInstance: Task[ScalaInstance]): Task[Compile.Inputs] = { val dep = dependencyClasspath(configuration) - val prod: Task[Seq[Attributed[File]]] = (configuration.extendsConfigs map products).join.map(_.flatten) - (dep, prod, scalaInstance) map { case (cp :+: prodcp :+: si :+: HNil) => + (dep, scalaInstance) map { case (cp :+: si :+: HNil) => val log = ConsoleLogger() val compilers = Compile.compilers(si)(info.configuration, log) val javaSrc = base / "java" @@ -98,8 +98,8 @@ abstract class BasicProject extends TestProject with MultiClasspathProject with import Path._ val sources = descendents((javaSrc +++ scalaSrc), sourceFilter) +++ (if(configuration == CompileConfig) info.projectDirectory * (sourceFilter -- defaultExcludes) else Path.emptyPathFinder) val classes = classesDirectory(configuration) - val classpath = (classes +: data(prodcp)) ++ data(cp) - val analysis = analysisMap(prodcp ++ cp) + val classpath = classes +: data(cp) + val analysis = analysisMap(cp) val cache = cacheDirectory / "compile" / configuration.toString Compile.inputs(classpath, sources.getFiles.toSeq, classes, scalacOptions, javacOptions, javaSrc.getFiles.toSeq, analysis, cache, 100)(compilers, log) }