mirror of https://github.com/sbt/sbt.git
fix update, default project supports triggered execution
This commit is contained in:
parent
eed8dfdbab
commit
1567de67b2
|
|
@ -15,14 +15,15 @@ import core.module.descriptor.{DefaultArtifact, DefaultDependencyArtifactDescrip
|
|||
import core.module.descriptor.{DefaultDependencyDescriptor, DefaultModuleDescriptor, DependencyDescriptor, ModuleDescriptor}
|
||||
import core.module.id.{ArtifactId,ModuleId, ModuleRevisionId}
|
||||
import core.publish.PublishOptions
|
||||
import core.report.ResolveReport
|
||||
import core.report.{ArtifactDownloadReport,ResolveReport}
|
||||
import core.resolve.ResolveOptions
|
||||
import core.retrieve.RetrieveOptions
|
||||
import plugins.parser.m2.{PomModuleDescriptorParser,PomModuleDescriptorWriter}
|
||||
|
||||
final class UpdateConfiguration(val retrieveDirectory: File, val outputPattern: String, val synchronize: Boolean, val logging: UpdateLogging.Value) extends NotNull
|
||||
final class UpdateConfiguration(val retrieve: Option[RetrieveConfiguration], val logging: UpdateLogging.Value)
|
||||
final class RetrieveConfiguration(val retrieveDirectory: File, val outputPattern: String, val synchronize: Boolean)
|
||||
final class MakePomConfiguration(val extraDependencies: Iterable[ModuleID], val configurations: Option[Iterable[Configuration]],
|
||||
val extra: NodeSeq, val process: Node => Node, val filterRepositories: MavenRepository => Boolean) extends NotNull
|
||||
val extra: NodeSeq, val process: Node => Node, val filterRepositories: MavenRepository => Boolean)
|
||||
object MakePomConfiguration
|
||||
{
|
||||
def apply(extraDependencies: Iterable[ModuleID], configurations: Option[Iterable[Configuration]], extra: NodeSeq) =
|
||||
|
|
@ -107,15 +108,20 @@ object IvyActions
|
|||
def update(module: IvySbt#Module, configuration: UpdateConfiguration) =
|
||||
{
|
||||
module.withModule { case (ivy, md, default) =>
|
||||
import configuration._
|
||||
import configuration.{retrieve => rConf, logging}
|
||||
val report = resolve(logging)(ivy, md, default)
|
||||
import IvyRetrieve._
|
||||
/*if(synchronize)
|
||||
IO delete retrieveDirectory
|
||||
IO createDirectory retrieveDirectory
|
||||
retrieve( cachePaths(report), , retrieveDirectory)*/
|
||||
cachePaths(report)
|
||||
/*val retrieveOptions = new RetrieveOptions
|
||||
rConf match
|
||||
{
|
||||
case None => IvyRetrieve.cachePaths(report)
|
||||
case Some(conf) => retrieve(ivy, md, conf, logging)
|
||||
}
|
||||
}
|
||||
}
|
||||
// doesn't work. perhaps replace retrieve/determineArtifactsToCopy with custom code
|
||||
private def retrieve(ivy: Ivy, md: ModuleDescriptor, conf: RetrieveConfiguration, logging: UpdateLogging.Value) =
|
||||
{
|
||||
import conf._
|
||||
val retrieveOptions = new RetrieveOptions
|
||||
retrieveOptions.setSync(synchronize)
|
||||
val patternBase = retrieveDirectory.getAbsolutePath
|
||||
val pattern =
|
||||
|
|
@ -123,8 +129,19 @@ object IvyActions
|
|||
patternBase + outputPattern
|
||||
else
|
||||
patternBase + File.separatorChar + outputPattern
|
||||
ivy.retrieve(md.getModuleRevisionId, pattern, retrieveOptions)*/
|
||||
}
|
||||
|
||||
val engine = ivy.getRetrieveEngine
|
||||
engine.retrieve(md.getModuleRevisionId, pattern, retrieveOptions)
|
||||
|
||||
//TODO: eliminate the duplication for better efficiency (retrieve already calls determineArtifactsToCopy once)
|
||||
val rawMap = engine.determineArtifactsToCopy(md.getModuleRevisionId, pattern, retrieveOptions)
|
||||
val map = rawMap.asInstanceOf[java.util.Map[ArtifactDownloadReport,java.util.Set[String]]]
|
||||
val confMap = new collection.mutable.HashMap[String, Seq[File]]
|
||||
|
||||
import collection.JavaConversions.{asScalaMap,asScalaSet}
|
||||
for( (report, all) <- map; retrieved <- all; val file = new File(retrieved); conf <- report.getArtifact.getConfigurations)
|
||||
confMap.put(conf, file +: confMap.getOrElse(conf, Nil))
|
||||
confMap.toMap
|
||||
}
|
||||
private def resolve(logging: UpdateLogging.Value)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String): ResolveReport =
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,10 +11,14 @@ package sbt
|
|||
import Path._
|
||||
import Types._
|
||||
import scala.xml.NodeSeq
|
||||
import scala.collection.mutable.{LinkedHashMap, LinkedHashSet}
|
||||
|
||||
trait ClasspathProject
|
||||
{
|
||||
def name: String
|
||||
def configurations: Seq[Configuration]
|
||||
def defaultConfiguration: Option[Configuration]
|
||||
|
||||
val products: Classpath
|
||||
val unmanagedClasspath: Classpath
|
||||
val managedClasspath: Classpath
|
||||
|
|
@ -39,6 +43,9 @@ trait ClasspathProject
|
|||
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
|
||||
|
|
@ -47,9 +54,7 @@ trait BasicClasspathProject extends ClasspathProject
|
|||
val moduleSettings: Task[ModuleSettings]
|
||||
val unmanagedBase: Task[File]
|
||||
|
||||
lazy val updateConfig: Task[UpdateConfiguration] = task {
|
||||
new UpdateConfiguration(null, null, true, UpdateLogging.Full)
|
||||
}
|
||||
val updateConfig: Task[UpdateConfiguration]
|
||||
|
||||
lazy val ivySbt: Task[IvySbt] =
|
||||
ivyConfiguration map { conf => new IvySbt(conf) }
|
||||
|
|
@ -60,7 +65,7 @@ trait BasicClasspathProject extends ClasspathProject
|
|||
}
|
||||
|
||||
def classpathFilter: FileFilter = GlobFilter("*.jar")
|
||||
def defaultExcludeFilter: FileFilter = MultiProject.defaultExcludes
|
||||
def defaultExcludes: FileFilter
|
||||
|
||||
override val managedClasspath: Classpath =
|
||||
TaskMap { configuration =>
|
||||
|
|
@ -70,14 +75,11 @@ trait BasicClasspathProject extends ClasspathProject
|
|||
val unmanagedClasspath: Classpath =
|
||||
TaskMap { configuration =>
|
||||
unmanagedBase map { base =>
|
||||
attributed( (base * (classpathFilter -- defaultExcludeFilter) +++
|
||||
(base / configuration.toString).descendentsExcept(classpathFilter, defaultExcludeFilter)).getFiles.toSeq )
|
||||
attributed( (base * (classpathFilter -- defaultExcludes) +++
|
||||
(base / configuration.toString).descendentsExcept(classpathFilter, defaultExcludes)).getFiles.toSeq )
|
||||
}
|
||||
}
|
||||
|
||||
lazy val configurationMap: Map[String, Configuration] =
|
||||
configurations map { conf => (conf.name, conf) } toMap;
|
||||
|
||||
import Types._
|
||||
lazy val update = (ivyModule, updateConfig) map { case module :+: config :+: HNil =>
|
||||
val confMap = configurationMap
|
||||
|
|
@ -94,6 +96,14 @@ trait DefaultClasspathProject extends BasicClasspathProject with Project
|
|||
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.Full)
|
||||
}
|
||||
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)
|
||||
|
||||
|
|
@ -104,6 +114,7 @@ trait DefaultClasspathProject extends BasicClasspathProject with Project
|
|||
|
||||
def libraryDependencies: Iterable[ModuleID] = ReflectUtilities.allVals[ModuleID](this).map(_._2)
|
||||
|
||||
def managedDependencyPath: Path = info.projectDirectory / "lib_managed"
|
||||
def dependencyPath: Path = info.projectDirectory / "lib"
|
||||
|
||||
def ivyXML: NodeSeq = NodeSeq.Empty
|
||||
|
|
@ -111,19 +122,7 @@ trait DefaultClasspathProject extends BasicClasspathProject with Project
|
|||
def ivyScala: Option[IvyScala] = None
|
||||
def ivyValidate: Boolean = false
|
||||
|
||||
//TODO: transitive dependencies
|
||||
lazy val internalDependencyClasspath: Classpath =
|
||||
TaskMap { (conf: Configuration) =>
|
||||
val confMap = configurationMap
|
||||
val productsTasks =
|
||||
for( (p: ClasspathProject, Some(confString)) <- ClasspathProject.resolvedDependencies(this)) yield
|
||||
{
|
||||
println("Project " + p.name + ", conf: " + confString)
|
||||
val to = parseSimpleConfigurations(confString).getOrElse(conf.toString, missingMapping(this.name, p.name, conf.toString))
|
||||
p.products(confMap(to))
|
||||
}
|
||||
(productsTasks.toSeq.join) named(name + "/join") map(_.flatten) named(name + "/int")
|
||||
}
|
||||
lazy val internalDependencyClasspath: Classpath = internalDependencies(this)
|
||||
|
||||
lazy val unmanagedBase = task { dependencyPath.asFile }
|
||||
|
||||
|
|
@ -209,18 +208,52 @@ object ClasspathProject
|
|||
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 = new LinkedHashSet[(Project,String)]
|
||||
def visit(p: Project, c: String)
|
||||
{
|
||||
for( (dep, confMapping) <- ClasspathProject.resolvedDependencies(p))
|
||||
{
|
||||
val depConf = mapped(c, confMapping, defaultConfiguration(dep).toString) { missingMapping(p.name, dep.name, c) }
|
||||
println("Dep: " + dep.name + " mapping: " + confMapping + " depConf: " + depConf)
|
||||
val unvisited = visited.add( (dep, depConf) )
|
||||
if(unvisited) visit(dep, depConf)
|
||||
}
|
||||
}
|
||||
visit(project, conf.toString)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
def parseSimpleConfigurations(confString: String): Map[String, String] =
|
||||
confString.split(";").flatMap( conf =>
|
||||
trim(conf.split("->",2)) match {
|
||||
case x :: Nil => (x,x) :: Nil
|
||||
case x :: y :: Nil => trim(x.split(",")) map { a => (a,y) }
|
||||
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 products(dep: ClasspathProject, conf: String) =
|
||||
dep.products(dep.configurationMap.getOrElse(conf,missingConfiguration(dep.name, conf)))
|
||||
def defaultConfiguration(p: Project): Configuration =
|
||||
p match
|
||||
{
|
||||
case cp: ClasspathProject => cp.defaultConfiguration getOrElse Configurations.Default
|
||||
case _ => Configurations.Default
|
||||
}
|
||||
}
|
||||
|
|
@ -8,11 +8,14 @@ package sbt
|
|||
import TaskExtra._
|
||||
import Configurations.{Compile => CompileConfig, Test => TestConfig}
|
||||
import ClasspathProject._
|
||||
|
||||
import Types._
|
||||
|
||||
import java.io.File
|
||||
|
||||
abstract class DefaultProject extends TestProject with MultiClasspathProject with ReflectiveClasspathProject
|
||||
{
|
||||
override def watchPaths: PathFinder = descendents("src","*")
|
||||
|
||||
def javacOptions: Seq[String] = Nil
|
||||
def scalacOptions: Seq[String] = Nil
|
||||
|
||||
|
|
@ -49,7 +52,7 @@ abstract class DefaultProject extends TestProject with MultiClasspathProject wit
|
|||
val scalaSrc = base / "scala"
|
||||
val out = "target" / compilers.scalac.scalaInstance.actualVersion
|
||||
|
||||
val sources = ((javaSrc +++ scalaSrc) ** sourceFilter) +++ (if(configuration == Compile) (".": Path) * sourceFilter else Path.emptyPathFinder)
|
||||
val sources = descendents((javaSrc +++ scalaSrc), sourceFilter) +++ (if(configuration == Compile) (".": Path) * (sourceFilter -- defaultExcludes) else Path.emptyPathFinder)
|
||||
println("Sources: " + sources)
|
||||
val classes = classesDirectory(configuration)
|
||||
val classpath = (classes +: data(prodcp)) ++ data(cp)
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ object MultiContext
|
|||
}
|
||||
}
|
||||
|
||||
trait Project extends Tasked with HistoryEnabled with Member[Project] with Named with ConsoleTask
|
||||
trait Project extends Tasked with HistoryEnabled with Member[Project] with Named with ConsoleTask with Watched
|
||||
{
|
||||
val info: ProjectInfo
|
||||
|
||||
|
|
@ -186,7 +186,9 @@ trait ProjectExtra
|
|||
/** 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 filter(simplePattern: String): NameFilter = GlobFilter(simplePattern)
|
||||
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
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue