From eb10f7ee9411a3f5018e15f64a4a966143ddce31 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Fri, 4 Feb 2011 22:02:39 -0500 Subject: [PATCH] improve Setting construction - make all constructing methods end in = for lowest precedence - rename Scope constructing method 'apply' to 'in' to allow 'apply' to be used on single settings as well as tuples and 'in' reads better --- main/Act.scala | 2 +- main/Build.scala | 58 +++++++----- main/Default.scala | 158 ++++++++++++++++--------------- main/Main.scala | 20 +--- main/Project.scala | 11 ++- main/State.scala | 5 + main/Structure.scala | 53 +++++++---- util/collection/Attributes.scala | 1 + 8 files changed, 165 insertions(+), 143 deletions(-) diff --git a/main/Act.scala b/main/Act.scala index cbcc0a3d8..2a84b623b 100644 --- a/main/Act.scala +++ b/main/Act.scala @@ -26,7 +26,7 @@ object Act def toAxis[T](opt: Option[T], ifNone: ScopeAxis[T]): ScopeAxis[T] = opt match { case Some(t) => Select(t); case None => ifNone } def defaultConfig(data: Settings[Scope])(project: ProjectRef): Option[String] = - ThisProject(project) get data flatMap( _.configurations.headOption.map(_.name)) + ThisProject in project get data flatMap( _.configurations.headOption.map(_.name)) def config(confs: Set[String]): Parser[Option[String]] = token( (ID examples confs) <~ ':' ).? diff --git a/main/Build.scala b/main/Build.scala index cf2ea36e6..434984fb2 100644 --- a/main/Build.scala +++ b/main/Build.scala @@ -66,7 +66,6 @@ object EvaluateConfigurations def evaluateSetting(eval: Eval, name: String, imports: Seq[(String,Int)], expression: String, line: Int): Setting[_] = { - // TODO: need to persist the results, which is critical for start up time val result = eval.eval(expression, imports = new EvalImports(imports, name), srcName = name, tpeName = Some("sbt.Project.Setting[_]"), line = line) result.value.asInstanceOf[Setting[_]] } @@ -103,32 +102,34 @@ object EvaluateTask import BuildStreams.{Streams, TaskStreams} val SystemProcessors = Runtime.getRuntime.availableProcessors - val PluginTaskKey = TaskKey[(Seq[File], Analysis)]("plugin-task") + // TODO: we should use a Seq[Attributed[File]] so that we don't throw away Analysis information + val PluginDefinition = TaskKey[(Seq[File], Analysis)]("plugin-definition") val (state, dummyState) = dummy[State]("state") val (streams, dummyStreams) = dummy[TaskStreams]("streams") def injectSettings: Seq[Project.Setting[_]] = Seq( - state(Scope.GlobalScope) :== dummyState, - streams(Scope.GlobalScope) :== dummyStreams + (state in Scope.GlobalScope) :== dummyState, + (streams in Scope.GlobalScope) :== dummyStreams ) def dummy[T](name: String): (TaskKey[T], Task[T]) = (TaskKey[T](name), dummyTask(name)) def dummyTask[T](name: String): Task[T] = task( error("Dummy task '" + name + "' did not get converted to a full task.") ) named name - def evalPluginDef(state: State, log: Logger)(pluginDef: BuildStructure): (Seq[File], Analysis) = + def evalPluginDef(log: Logger)(pluginDef: BuildStructure, state: State): (Seq[File], Analysis) = { - val evaluated = evaluateTask(pluginDef, ScopedKey(Scope.ThisScope, PluginTaskKey.key), state) + val root = ProjectRef(pluginDef.root, Load.getRootProject(pluginDef.units)(pluginDef.root)) + val evaluated = evaluateTask(pluginDef, ScopedKey(Scope.ThisScope, PluginDefinition.key), state, root) val result = evaluated getOrElse error("Plugin task does not exist for plugin definition at " + pluginDef.root) processResult(result, log) } - def evaluateTask[T](structure: BuildStructure, taskKey: ScopedKey[Task[T]], state: State, checkCycles: Boolean = false, maxWorkers: Int = SystemProcessors): Option[Result[T]] = - for( (task, toNode) <- getTask(structure, taskKey, state) ) yield + def evaluateTask[T](structure: BuildStructure, taskKey: ScopedKey[Task[T]], state: State, thisProject: ProjectRef, checkCycles: Boolean = false, maxWorkers: Int = SystemProcessors): Option[Result[T]] = + for( (task, toNode) <- getTask(structure, taskKey, state, thisProject) ) yield runTask(task, checkCycles, maxWorkers)(toNode) - def getTask[T](structure: BuildStructure, taskKey: ScopedKey[Task[T]], state: State): Option[(Task[T], Execute.NodeView[Task])] = + def getTask[T](structure: BuildStructure, taskKey: ScopedKey[Task[T]], state: State, thisProject: ProjectRef): Option[(Task[T], Execute.NodeView[Task])] = { - val thisScope = Scope(Select(Project.currentRef(state)), Global, Global, Global) + val thisScope = Scope(Select(thisProject), Global, Global, Global) val resolvedScope = Scope.replaceThis(thisScope)( taskKey.scope ) for( t <- structure.data.get(resolvedScope, taskKey.key)) yield (t, nodeView(structure, state)) @@ -185,6 +186,7 @@ object Load import BuildPaths._ import BuildStreams._ + // note that there is State is passed in but not pulled out def defaultLoad(state: State, log: Logger): (() => Eval, BuildStructure) = { val stagingDirectory = defaultStaging.getCanonicalFile // TODO: properly configurable @@ -193,11 +195,11 @@ object Load val provider = state.configuration.provider val classpath = provider.mainClasspath ++ provider.scalaProvider.jars val compilers = Compile.compilers(state.configuration, log) - val evalPluginDef = EvaluateTask.evalPluginDef(state, log) _ + val evalPluginDef = EvaluateTask.evalPluginDef(log) _ val delegates = memo(defaultDelegates) - val inject: Seq[Project.Setting[_]] = (AppConfig(Scope.GlobalScope) :== state.configuration) +: EvaluateTask.injectSettings + val inject: Seq[Project.Setting[_]] = ((AppConfig in Scope.GlobalScope) :== state.configuration) +: EvaluateTask.injectSettings val config = new LoadBuildConfiguration(stagingDirectory, classpath, loader, compilers, evalPluginDef, delegates, inject, log) - apply(base, config) + apply(base, state, config) } def defaultDelegates: LoadedBuild => Scope => Seq[Scope] = (lb: LoadedBuild) => { val rootProject = getRootProject(lb.units) @@ -224,10 +226,10 @@ object Load // 6) Load all configurations using build definitions and plugins (their classpaths and loaded instances). // 7) Combine settings from projects, plugins, and configurations // 8) Evaluate settings - def apply(rootBase: File, config: LoadBuildConfiguration): (() => Eval, BuildStructure) = + def apply(rootBase: File, s: State, config: LoadBuildConfiguration): (() => Eval, BuildStructure) = { // load, which includes some resolution, but can't fill in project IDs yet, so follow with full resolution - val loaded = resolveProjects(load(rootBase, config)) + val loaded = resolveProjects(load(rootBase, s, config)) val projects = loaded.units lazy val rootEval = lazyEval(loaded.units(loaded.root).unit) val settings = config.injectSettings ++ buildConfigurations(loaded, getRootProject(projects), rootEval) @@ -259,7 +261,7 @@ object Load val projectSettings = build.defined flatMap { case (id, project) => val srcs = configurationSources(project.base) val ref = ProjectRef(Some(uri), Some(id)) - val defineConfig = for(c <- project.configurations) yield (Config(ref, ConfigKey(c.name)) :== c) + val defineConfig = for(c <- project.configurations) yield ( (Config in (ref, ConfigKey(c.name))) :== c) val settings = (ThisProject :== project) +: (ThisProjectRef :== ref) +: @@ -288,7 +290,8 @@ object Load def configurations(srcs: Seq[File], eval: () => Eval, imports: Seq[String]): Seq[Setting[_]] = if(srcs.isEmpty) Nil else EvaluateConfigurations(eval(), srcs, imports) - def load(file: File, config: LoadBuildConfiguration): LoadedBuild = load(file, uri => loadUnit(uri, RetrieveUnit(config.stagingDirectory, uri), config) ) + def load(file: File, s: State, config: LoadBuildConfiguration): LoadedBuild = + load(file, uri => loadUnit(uri, RetrieveUnit(config.stagingDirectory, uri), s, config) ) def load(file: File, loader: URI => BuildUnit): LoadedBuild = loadURI(IO.directoryURI(file), loader) def loadURI(uri: URI, loader: URI => BuildUnit): LoadedBuild = { @@ -402,12 +405,12 @@ object Load def noProject(uri: URI, id: String) = error("No project '" + id + "' defined in '" + uri + "'.") def noConfiguration(uri: URI, id: String, conf: String) = error("No configuration '" + conf + "' defined in project '" + id + "' in '" + uri +"'") - def loadUnit(uri: URI, localBase: File, config: LoadBuildConfiguration): BuildUnit = + def loadUnit(uri: URI, localBase: File, s: State, config: LoadBuildConfiguration): BuildUnit = { val normBase = localBase.getCanonicalFile val defDir = selectProjectDir(normBase) val pluginDir = pluginDirectory(defDir) - val plugs = plugins(pluginDir, config) + val plugs = plugins(pluginDir, s, config) val defs = definitionSources(defDir) val target = buildOutputDirectory(defDir, config.compilers) @@ -421,14 +424,17 @@ object Load new BuildUnit(uri, normBase, loadedDefs, plugs) } - def plugins(dir: File, config: LoadBuildConfiguration): LoadedPlugins = if(dir.exists) buildPlugins(dir, config) else noPlugins(config) + def plugins(dir: File, s: State, config: LoadBuildConfiguration): LoadedPlugins = if(dir.exists) buildPlugins(dir, s, config) else noPlugins(config) def noPlugins(config: LoadBuildConfiguration): LoadedPlugins = new LoadedPlugins(config.classpath, config.loader, Nil, Nil) - def buildPlugins(dir: File, config: LoadBuildConfiguration): LoadedPlugins = + def buildPlugins(dir: File, s: State, config: LoadBuildConfiguration): LoadedPlugins = { - val (_,pluginDef) = apply(dir, config) - val (pluginClasspath, pluginAnalysis) = config.evalPluginDef(pluginDef) - val pluginLoader = ClasspathUtilities.toLoader(pluginClasspath, config.loader) - loadPlugins(pluginClasspath, pluginLoader, pluginAnalysis) + val (eval,pluginDef) = apply(dir, s, config) + val pluginState = Project.setProject(Load.initialSession(pluginDef, eval), pluginDef, s) + + val (pluginClasspath, pluginAnalysis) = config.evalPluginDef(pluginDef, pluginState) + val definitionClasspath = (pluginClasspath ++ config.classpath).distinct + val pluginLoader = ClasspathUtilities.toLoader(definitionClasspath, config.loader) + loadPlugins(definitionClasspath, pluginLoader, pluginAnalysis) } def definitions(base: File, targetBase: File, srcs: Seq[File], plugins: LoadedPlugins, compilers: Compilers, log: Logger, buildBase: File): LoadedDefinitions = @@ -520,7 +526,7 @@ object Load final class BuildStructure(val units: Map[URI, LoadedBuildUnit], val root: URI, val settings: Seq[Setting[_]], val data: Settings[Scope], val index: StructureIndex, val streams: Streams, val delegates: Scope => Seq[Scope]) - final class LoadBuildConfiguration(val stagingDirectory: File, val classpath: Seq[File], val loader: ClassLoader, val compilers: Compilers, val evalPluginDef: BuildStructure => (Seq[File], Analysis), val delegates: LoadedBuild => Scope => Seq[Scope], val injectSettings: Seq[Setting[_]], val log: Logger) + final class LoadBuildConfiguration(val stagingDirectory: File, val classpath: Seq[File], val loader: ClassLoader, val compilers: Compilers, val evalPluginDef: (BuildStructure, State) => (Seq[File], Analysis), val delegates: LoadedBuild => Scope => Seq[Scope], val injectSettings: Seq[Setting[_]], val log: Logger) // information that is not original, but can be reconstructed from the rest of BuildStructure final class StructureIndex(val keyMap: Map[String, AttributeKey[_]], val taskToKey: Map[Task[_], ScopedKey[Task[_]]], val keyIndex: KeyIndex) diff --git a/main/Default.scala b/main/Default.scala index 59af20b9d..f705ba114 100755 --- a/main/Default.scala +++ b/main/Default.scala @@ -3,6 +3,7 @@ package sbt import java.io.File import Scoped.Apply import Project.{AppConfig, Config, Setting, ThisProject, ThisProjectRef} + import Configurations.{Compile => CompileConf, Test => TestConf} import Command.HistoryPath import EvaluateTask.streams import inc.Analysis @@ -150,54 +151,54 @@ object Default def core = Seq( Name :== "test", Version :== "0.1", - Data :- ( EvaluateTask.state map { state => Project.structure(state).data } ) + Data <<= EvaluateTask.state map { state => Project.structure(state).data } ) def paths = Seq( - Base :- ( ThisProject app (_.base) ), - Target :- Base / "target", + Base <<= ThisProject(_.base), + Target <<= Base / "target", DefaultExcludes :== (".*" - ".") || HiddenFileFilter, - HistoryPath :- Target.app(t => Some(t / ".history")), - CacheDirectory :- Target / "cache", - Source :- Base / "src", + HistoryPath <<= Target(t => Some(t / ".history")), + CacheDirectory <<= Target / "cache", + Source <<= Base / "src", SourceFilter :== ("*.java" | "*.scala"), - SourceManaged :- Base / "src_managed" + SourceManaged <<= Base / "src_managed" ) lazy val configPaths = Seq( - Source :- configSrcSub( Source(Scope(This,Global,This,This)) ), - SourceManaged :- configSrcSub(SourceManaged), - CacheDirectory :- (CacheDirectory, Config) { _ / _.name }, - ClassDirectory :- (Target, Config) { (target, conf) => target / (prefix(conf.name) + "classes") }, - 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) { _ +: _ }, - ResourceDirectories :- toSeq(ResourceDir) + 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") }, + 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) { _ +: _ }, + ResourceDirectories <<= toSeq(ResourceDir) ) def addBaseSources = Seq( - Sources :- ( (Sources, Base, SourceFilter, DefaultExcludes) map { (srcs,b,f,excl) => (srcs +++ b * (f -- excl)).getFiles.toSeq } ) + Sources <<= (Sources, Base, SourceFilter, DefaultExcludes) map { (srcs,b,f,excl) => (srcs +++ b * (f -- excl)).getFiles.toSeq } ) lazy val configTasks = Classpaths.configSettings ++ compileTasks def webPaths = Seq( - WebappDir :- Source / "webapp" + WebappDir <<= Source / "webapp" ) def compileBase = Seq( - Compilers :- (ScalaInstance, AppConfig) { (si, app) => Compile.compilers(si)(app, ConsoleLogger()) }, + Compilers <<= (ScalaInstance, AppConfig) { (si, app) => Compile.compilers(si)(app, ConsoleLogger()) }, JavacOptions :== Nil, ScalacOptions :== Nil, - ScalaInstance :- (AppConfig, ScalaVersion){ (app, version) => sbt.ScalaInstance(version, app.provider.scalaProvider) }, - ScalaVersion :- AppConfig.app( _.provider.scalaProvider.version) + ScalaInstance <<= (AppConfig, ScalaVersion){ (app, version) => sbt.ScalaInstance(version, app.provider.scalaProvider) }, + ScalaVersion <<= AppConfig( _.provider.scalaProvider.version) ) def compileTasks = Seq( - CompileTask :- compileTask, - CompileInputs :- compileInputsTask + CompileTask <<= compileTask, + CompileInputs <<= compileInputsTask ) - def compileTask = ( (CompileInputs, streams) map { (i,s) => Compile(i,s.log) } ) + def compileTask = (CompileInputs, streams) map { (i,s) => Compile(i,s.log) } def compileInputsTask = (DependencyClasspath, Sources, JavaSourceRoots, Compilers, JavacOptions, ScalacOptions, CacheDirectory, ClassDirectory, streams) map { (cp, sources, javaRoots, compilers, scalacOptions, javacOptions, cacheDirectory, classes, s) => @@ -212,16 +213,20 @@ object Default def inConfig(conf: Configuration)(ss: Seq[Setting[_]]): Seq[Setting[_]] = Project.transform(Scope.replaceThis(ThisScope.copy(config = Select(conf))), (Config :== conf) +: ss) - lazy val defaultPaths = paths ++ inConfig(Configurations.Compile)(configPaths ++ addBaseSources) ++ inConfig(Configurations.Test)(configPaths) - lazy val defaultWebPaths = defaultPaths ++ inConfig(Configurations.Compile)(webPaths) + lazy val defaultPaths = paths ++ inConfig(CompileConf)(configPaths ++ addBaseSources) ++ inConfig(TestConf)(configPaths) + lazy val defaultWebPaths = defaultPaths ++ inConfig(CompileConf)(webPaths) - lazy val defaultTasks = inConfig(Configurations.Compile)(configTasks) ++ inConfig(Configurations.Test)(configTasks) + lazy val defaultTasks = inConfig(CompileConf)(configTasks) ++ inConfig(TestConf)(configTasks) lazy val defaultWebTasks = Nil - lazy val defaultClasspaths = Classpaths.publishSettings ++ Classpaths.baseSettings ++ inConfig(Configurations.Compile)(Classpaths.configSettings) ++ inConfig(Configurations.Test)(Classpaths.configSettings) + def pluginDefinition = Seq( + EvaluateTask.PluginDefinition <<= (FullClasspath in CompileConf,CompileTask in CompileConf) map ( (c,a) => (data(c),a) ) + ) + + lazy val defaultClasspaths = Classpaths.publishSettings ++ Classpaths.baseSettings ++ inConfig(CompileConf)(Classpaths.configSettings) ++ inConfig(TestConf)(Classpaths.configSettings) - lazy val defaultSettings = core ++ defaultPaths ++ defaultClasspaths ++ defaultTasks ++ compileBase + lazy val defaultSettings = core ++ defaultPaths ++ defaultClasspaths ++ defaultTasks ++ compileBase ++ pluginDefinition lazy val defaultWebSettings = defaultSettings ++ defaultWebPaths ++ defaultWebTasks } object Classpaths @@ -231,79 +236,78 @@ object Classpaths import Keys._ import Scope.ThisScope import Default._ - - def attributed[T](in: Seq[T]): Seq[Attributed[T]] = in map Attributed.blank + import Attributed.{blank, blankSeq} def concat[T](a: ScopedTaskable[Seq[T]], b: ScopedTaskable[Seq[T]]): Apply[Task[Seq[T]]] = (a,b) map (_ ++ _) val configSettings: Seq[Project.Setting[_]] = Seq( - ExternalDependencyClasspath :- concat(UnmanagedClasspath, ManagedClasspath), - DependencyClasspath :- concat(InternalDependencyClasspath, ExternalDependencyClasspath), - FullClasspath :- concat(DependencyClasspath, Products), - InternalDependencyClasspath :- internalDependencies, - Products :- makeProducts, - ManagedClasspath :- ( (Config, Update) map { (config, up) => attributed(up.getOrElse(config.name, error("Configuration '" + config.name + "' unresolved by 'update'."))) } ), - UnmanagedClasspath :- ( (Config, UnmanagedBase, ClasspathFilter, DefaultExcludes) map { (config, base, filter, excl) => - attributed( (base * (filter -- excl) +++ (base / config.name).descendentsExcept(filter, excl)).getFiles.toSeq ) - }) + ExternalDependencyClasspath <<= concat(UnmanagedClasspath, ManagedClasspath), + DependencyClasspath <<= concat(InternalDependencyClasspath, ExternalDependencyClasspath), + FullClasspath <<= concat(DependencyClasspath, Products), + InternalDependencyClasspath <<= internalDependencies, + Products <<= makeProducts, + ManagedClasspath <<= (Config, Update) map { (config, up) => up.getOrElse(config.name, error("Configuration '" + config.name + "' unresolved by 'update'.")) }, + UnmanagedClasspath <<= (Config, UnmanagedBase, ClasspathFilter, DefaultExcludes) map { (config, base, filter, excl) => + (base * (filter -- excl) +++ (base / config.name).descendentsExcept(filter, excl)).getFiles.toSeq + } ) val publishSettings: Seq[Project.Setting[_]] = Seq( PublishMavenStyle :== true, PackageToPublish :== nop, DeliverDepends := (PublishMavenStyle, MakePom.setting, PackageToPublish.setting) { (mavenStyle, makePom, ptp) => if(mavenStyle) makePom 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) + 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 app StringUtilities.normalize), + UnmanagedBase <<= Base / "lib", + NormalizedName <<= Name(StringUtilities.normalize), Organization :== NormalizedName, ClasspathFilter :== "*.jar", - Resolvers :- (ProjectResolver,BaseResolvers).map( (pr,rs) => pr +: Resolver.withDefaultResolvers(rs)), + Resolvers <<= (ProjectResolver,BaseResolvers).map( (pr,rs) => pr +: Resolver.withDefaultResolvers(rs)), Offline :== false, ModuleName :== NormalizedName, DefaultConfiguration :== Some(Configurations.Compile), - DefaultConfigurationMapping :- DefaultConfiguration.app{ case Some(d) => "*->" + d.name; case None => "*->*" }, - PathsIvy :- Base.app(base => new IvyPaths(base, None)), + DefaultConfigurationMapping <<= DefaultConfiguration{ case Some(d) => "*->" + d.name; case None => "*->*" }, + PathsIvy <<= Base(base => new IvyPaths(base, None)), OtherResolvers :== Nil, - ProjectResolver :- projectResolver, - ProjectDependencies :- projectDependencies, + ProjectResolver <<= projectResolver, + ProjectDependencies <<= projectDependencies, LibraryDependencies :== Nil, - AllDependencies :- concat(ProjectDependencies,LibraryDependencies), + AllDependencies <<= concat(ProjectDependencies,LibraryDependencies), IvyLoggingLevel :== UpdateLogging.Quiet, IvyXML :== NodeSeq.Empty, IvyValidate :== false, IvyScalaConfig :== None, ModuleConfigurations :== Nil, PublishTo :== None, - PomFile :- (Target, Version, ModuleName)( (target, version, module) => target / (module + "-" + version + ".pom") ), - Artifacts :== Nil, - ProjectID :- (Organization,ModuleName,Version,Artifacts){ (org,module,version,as) => ModuleID(org, module, version).cross(true).artifacts(as : _*) }, + PomFile <<= (Target, Version, ModuleName)( (target, version, module) => target / (module + "-" + version + ".pom") ), + Artifacts <<= ModuleName(name => Artifact(name, "jar", "jar") :: Nil), + ProjectID <<= (Organization,ModuleName,Version,Artifacts){ (org,module,version,as) => ModuleID(org, module, version).cross(true).artifacts(as : _*) }, BaseResolvers :== Nil, - ProjectDescriptors :- depMap, + ProjectDescriptors <<= depMap, RetrievePattern :== "[type]/[organisation]/[module]/[artifact](-[revision])(-[classifier]).[ext]", - UpdateConfig :- (RetrieveConfig, IvyLoggingLevel)((conf,level) => new UpdateConfiguration(conf, level) ), + 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) => + 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 { + }, + 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.app(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) => + }, + 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) - }) + } ) @@ -362,17 +366,17 @@ object Classpaths def projectDependencies = (ThisProject, Data) map { (p, data) => - p.dependencies flatMap { dep => ProjectID(dep.project) get data map { _.copy(configurations = dep.configuration) } } + p.dependencies flatMap { dep => (ProjectID in dep.project) get data map { _.copy(configurations = dep.configuration) } } } def depMap: Apply[Task[Map[ModuleRevisionId, ModuleDescriptor]]] = (ThisProject, ThisProjectRef, Data) flatMap { (root, rootRef, data) => - val dependencies = (p: (ProjectRef, Project)) => p._2.dependencies.flatMap(pr => ThisProject(pr.project) get data map { (pr.project, _) }) + 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(p) get data }.join.map { mods => + projects.flatMap { case (p,_) => IvyModule in p get data }.join.map { mods => (mods.map{ mod => val md = mod.moduleDescriptor (md.getModuleRevisionId, md) @@ -405,7 +409,7 @@ object Classpaths for( Project.ClasspathDependency(dep, confMapping) <- project.dependencies) { - val depProject = ThisProject(dep) get data getOrElse error("Invalid project: " + dep) + 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)) @@ -462,8 +466,8 @@ object Classpaths 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] = - Products(dep, ConfigKey(conf)) get data getOrElse const(Nil) + Products in (dep, ConfigKey(conf)) get data getOrElse const(Nil) def defaultConfiguration(p: ProjectRef, data: Settings[Scope]): Configuration = - flatten(DefaultConfiguration(p) get data) getOrElse Configurations.Default + flatten(DefaultConfiguration in p get data) getOrElse Configurations.Default def flatten[T](o: Option[Option[T]]): Option[T] = o flatMap identity } diff --git a/main/Main.scala b/main/Main.scala index 80c9a02d3..d10ccc21a 100644 --- a/main/Main.scala +++ b/main/Main.scala @@ -6,7 +6,6 @@ package sbt import Execute.NodeView import complete.HistoryCommands import HistoryCommands.{Start => HistoryPrefix} - import Project.{SessionKey, StructureKey} import sbt.build.{AggressiveCompile, Auto, BuildException, LoadCommand, Parse, ParseException, ProjectLoad, SourceLoad} import compile.EvalImports import sbt.complete.{DefaultParsers, Parser} @@ -138,7 +137,7 @@ object Commands } def reload = Command.command(ReloadCommand, ReloadBrief, ReloadDetailed) { s => - runExitHooks(s).reload + s.runExitHooks().reload } def defaults = Command.command(DefaultsCommand) { s => @@ -226,7 +225,7 @@ object Commands { logger(s).info("Reapplying settings...") val newStructure = Load.reapply(newSession.mergeSettings, structure) - setProject(newSession, newStructure, s) + Project.setProject(newSession, newStructure, s) } def set = Command.single(SetCommand, setBrief, setDetailed) { (s, arg) => val extracted = Project extract s @@ -281,7 +280,7 @@ object Commands def exit = Command.command(TerminateAction, Help(exitBrief) :: Nil ) ( doExit ) - def doExit(s: State): State = runExitHooks(s).exit(true) + def doExit(s: State): State = s.runExitHooks().exit(true) // TODO: tab completion, low priority def discover = Command.single(Discover, DiscoverBrief, DiscoverDetailed) { (s, arg) => @@ -304,13 +303,7 @@ object Commands def loadProject = Command.command(LoadProject, LoadProjectBrief, LoadProjectDetailed) { s => val (eval, structure) = Load.defaultLoad(s, logger(s)) val session = Load.initialSession(structure, eval) - setProject(session, structure, s) - } - def setProject(session: SessionSettings, structure: Load.BuildStructure, s: State): State = - { - val newAttrs = s.attributes.put(StructureKey, structure).put(SessionKey, session) - val newState = s.copy(attributes = newAttrs) - Project.updateCurrent(runExitHooks(newState)) + Project.setProject(session, structure, s) } def handleException(e: Throwable, s: State, trace: Boolean = true): State = { @@ -320,11 +313,6 @@ object Commands s.fail } - def runExitHooks(s: State): State = { - ExitHooks.runExitHooks(s.exitHooks.toSeq) - s.copy(exitHooks = Set.empty) - } - // TODO: tab completion, low priority def loadCommands = Command.single(LoadCommand, Parse.helpBrief(LoadCommand, LoadCommandLabel), Parse.helpDetail(LoadCommand, LoadCommandLabel, true) ) { (s, arg) => applyCommands(s, buildCommands(arg, s.configuration)) diff --git a/main/Project.scala b/main/Project.scala index 3e4deb500..1968a0d82 100644 --- a/main/Project.scala +++ b/main/Project.scala @@ -49,6 +49,13 @@ object Project extends Init[Scope] case ProjectRef(Some(uri), Some(id)) => (structure.units get uri).flatMap(_.defined get id) case _ => None } + + def setProject(session: SessionSettings, structure: Load.BuildStructure, s: State): State = + { + val newAttrs = s.attributes.put(StructureKey, structure).put(SessionKey, session) + val newState = s.copy(attributes = newAttrs) + updateCurrent(newState.runExitHooks()) + } def current(state: State): (URI, String) = session(state).current def currentRef(state: State): ProjectRef = { @@ -64,7 +71,7 @@ object Project extends Init[Scope] logger(s).info("Set current project to " + id + " (in build " + uri +")") val data = structure.data - val historyPath = HistoryPath(ref).get(data).flatMap(identity) + val historyPath = HistoryPath in ref get data flatMap identity val newAttrs = s.attributes.put(Watch.key, makeWatched(data, ref, project)).put(HistoryPath.key, historyPath) s.copy(attributes = newAttrs) } @@ -72,7 +79,7 @@ object Project extends Init[Scope] def makeWatched(data: Settings[Scope], ref: ProjectRef, project: Project): Watched = { - def getWatch(ref: ProjectRef) = Watch(ref).get(data) + def getWatch(ref: ProjectRef) = Watch in ref get data getWatch(ref) match { case Some(currentWatch) => diff --git a/main/State.scala b/main/State.scala index 1b5b5dac9..c2c16fed3 100644 --- a/main/State.scala +++ b/main/State.scala @@ -39,6 +39,7 @@ trait StateOps { def get[T](key: AttributeKey[T]): Option[T] def put[T](key: AttributeKey[T], value: T): State def baseDir: File + def runExitHooks(): State } object State { @@ -74,5 +75,9 @@ object State else s.copy(commands = remaining) } + def runExitHooks(): State = { + ExitHooks.runExitHooks(s.exitHooks.toSeq) + s.copy(exitHooks = Set.empty) + } } } \ No newline at end of file diff --git a/main/Structure.scala b/main/Structure.scala index a5bf36921..e3f28e1f4 100644 --- a/main/Structure.scala +++ b/main/Structure.scala @@ -37,6 +37,8 @@ object Scoped implicit def richSettingScoped[T](s: ScopedSetting[T]): RichSettingScoped[T] = new RichSettingScoped[T](s.scope, s.key) implicit def richTaskScoped[T](s: ScopedTask[T]): RichTaskScoped[T] = new RichTaskScoped[T](s.scope, s.key) implicit def richInputScoped[T](s: ScopedInput[T]): RichInputScoped[T] = new RichInputScoped[T](s.scope, s.key) + implicit def richSettingListScoped[T](s: ScopedSetting[Seq[T]]): RichSettingList[T] = new RichSettingList[T](s.scope, s.key) + implicit def richListTaskScoped[T](s: ScopedTask[Seq[T]]): RichListTask[T] = new RichListTask[T](s.scope, s.key) implicit def taskScoping[T](s: TaskKey[T]): ScopingTask[T] = new ScopingTask[T](s.key) @@ -48,16 +50,16 @@ object Scoped final class ScopingSetting[T, Result](val key: AttributeKey[T], app0: Scope => Result) { - def apply(s: Scope): Result = app0(s) + def in(s: Scope): Result = app0(s) - def apply(p: ProjectRef): Result = apply(Select(p), This, This) - def apply(t: TaskKey[_]): Result = apply(This, This, Select(t)) - def apply(c: ConfigKey): Result = apply(This, Select(c), This) - def apply(c: ConfigKey, t: TaskKey[_]): Result = apply(This, Select(c), Select(t)) - def apply(p: ProjectRef, c: ConfigKey): Result = apply(Select(p), Select(c), This) - def apply(p: ProjectRef, t: TaskKey[_]): Result = apply(Select(p), This, Select(t)) - def apply(p: ProjectRef, c: ConfigKey, t: TaskKey[_]): Result = apply(Select(p), Select(c), Select(t)) - def apply(p: ScopeAxis[ProjectRef], c: ScopeAxis[ConfigKey], t: ScopeAxis[TaskKey[_]]): Result = apply( Scope(p, c, convert(t), This) ) + def in(p: ProjectRef): Result = in(Select(p), This, This) + def in(t: TaskKey[_]): Result = in(This, This, Select(t)) + def in(c: ConfigKey): Result = in(This, Select(c), This) + def in(c: ConfigKey, t: TaskKey[_]): Result = in(This, Select(c), Select(t)) + def in(p: ProjectRef, c: ConfigKey): Result = in(Select(p), Select(c), This) + def in(p: ProjectRef, t: TaskKey[_]): Result = in(Select(p), This, Select(t)) + def in(p: ProjectRef, c: ConfigKey, t: TaskKey[_]): Result = in(Select(p), Select(c), Select(t)) + def in(p: ScopeAxis[ProjectRef], c: ScopeAxis[ConfigKey], t: ScopeAxis[TaskKey[_]]): Result = in( Scope(p, c, convert(t), This) ) private def convert(tk: ScopeAxis[TaskKey[_]]): ScopeAxis[AttributeKey[_]] = tk match { case Select(t) => Select(t.key) @@ -71,14 +73,24 @@ object Scoped final class ScopingTask[T](taskKey: AttributeKey[Task[T]]) { - def apply(p: ProjectRef): RichTaskScoped[T] = apply(Select(p), This) - def apply(c: ConfigKey): RichTaskScoped[T] = apply(This, Select(c)) - def apply(p: ProjectRef, c: ConfigKey): RichTaskScoped[T] = apply(Select(p), Select(c)) - def apply(p: ScopeAxis[ProjectRef], c: ScopeAxis[ConfigKey]): ScopedTask[T] = apply(Scope(p, c, This, This)) - def apply(s: Scope): ScopedTask[T] = scopedTask(s, taskKey) + def in(p: ProjectRef): ScopedTask[T] = in(Select(p), This) + def in(c: ConfigKey): ScopedTask[T] = in(This, Select(c)) + def in(p: ProjectRef, c: ConfigKey): ScopedTask[T] = in(Select(p), Select(c)) + def in(p: ScopeAxis[ProjectRef], c: ScopeAxis[ConfigKey]): ScopedTask[T] = in(Scope(p, c, This, This)) + def in(s: Scope): ScopedTask[T] = scopedTask(s, taskKey) } private[this] def scopedTask[T](s: Scope, k: AttributeKey[Task[T]]): ScopedTask[T] = new ScopedTask[T] { val scope = s; val key = k } + final class RichSettingList[S](scope: Scope, key: AttributeKey[Seq[S]]) + { + def += (value: => S): Setting[Seq[S]] = ++=(value :: Nil) + def ++=(values: => Seq[S]): Setting[Seq[S]] = (new RichSettingScoped(scope, key)) ~= (_ ++ values ) + } + final class RichListTask[S](scope: Scope, key: AttributeKey[Task[Seq[S]]]) + { + def += (value: => S): Setting[Task[Seq[S]]] = ++=(value :: Nil) + def ++=(values: => Seq[S]): Setting[Task[Seq[S]]] = (new RichTaskScoped(scope, key)) ~= (_ ++ values ) + } sealed abstract class RichBaseScoped[S] { def scope: Scope @@ -87,13 +99,12 @@ 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: SettingKey[S]): Setting[S] = <<=(value(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 ~= (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) } @@ -110,10 +121,10 @@ 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 :== (v: SettingKey[S]): ScS = <<=( v(const)) + def ~= (f: S => S): ScS = Project.update(scoped)( _ map f ) - def :- (app: App[S]): ScS = app toSetting scoped + 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) diff --git a/util/collection/Attributes.scala b/util/collection/Attributes.scala index 0d9e9ade1..ba3f3293b 100644 --- a/util/collection/Attributes.scala +++ b/util/collection/Attributes.scala @@ -65,5 +65,6 @@ final case class Attributed[D](data: D)(val metadata: AttributeMap) } object Attributed { + implicit def blankSeq[T](in: Seq[T]): Seq[Attributed[T]] = in map blank implicit def blank[T](data: T): Attributed[T] = Attributed(data)(AttributeMap.empty) } \ No newline at end of file