diff --git a/main/Defaults.scala b/main/Defaults.scala index 3e922a8f0..4700f1e18 100644 --- a/main/Defaults.scala +++ b/main/Defaults.scala @@ -7,7 +7,7 @@ package sbt import Scope.{GlobalScope, ThisScope} import compiler.Discovery import Project.{inConfig, Initialize, inScope, inTask, ScopedKey, Setting} - import Configurations.{Compile => CompileConf, Test => TestConf} + import Configurations.{Compile => CompileConf, CompilerPlugin, Test => TestConf} import complete._ import std.TaskExtra._ @@ -61,6 +61,7 @@ object Defaults )) def globalCore: Seq[Setting[_]] = inScope(GlobalScope)(Seq( pollInterval :== 500, + autoCompilerPlugins :== true, initialize :== (), credentials :== Nil, scalaHome :== None, @@ -166,7 +167,7 @@ object Defaults } def watchTransitiveSourcesTask: Initialize[Task[Seq[File]]] = (state, thisProjectRef) flatMap { (s, base) => - inAllDependencies(base, watchSources.setting, Project structure s).join.map(_.flatten) + inAllDependencies(base, watchSources.task, Project structure s).join.map(_.flatten) } def watchSourcesTask: Initialize[Task[Seq[File]]] = Seq(sources, resources).map(inAllConfigurations).join { _.join.map(_.flatten.flatten) } @@ -409,7 +410,6 @@ object Defaults allProjects.flatMap { p => key in p get data } val CompletionsID = "completions" - def noAggregation = Seq(run, console, consoleQuick, consoleProject) lazy val disableAggregation = noAggregation map disableAggregate @@ -419,7 +419,7 @@ object Defaults lazy val baseTasks: Seq[Setting[_]] = projectTasks ++ packageBase lazy val baseClasspaths = Classpaths.publishSettings ++ Classpaths.baseSettings - lazy val configSettings = Classpaths.configSettings ++ configTasks ++ configPaths ++ packageConfig + lazy val configSettings = Classpaths.configSettings ++ configTasks ++ configPaths ++ packageConfig ++ Classpaths.compilerPluginConfig lazy val compileSettings = configSettings ++ (mainRunMainTask +: mainRunTask +: addBaseSources) lazy val testSettings = configSettings ++ testTasks @@ -460,7 +460,7 @@ object Classpaths val publishSettings: Seq[Setting[_]] = Seq( publishMavenStyle in GlobalScope :== true, packageToPublish <<= defaultPackageTasks.dependOn, - deliverDepends <<= (publishMavenStyle, makePom.setting, packageToPublish.setting) { (mavenStyle, mkpom, ptp) => + deliverDepends <<= (publishMavenStyle, makePom.task, packageToPublish.task) { (mavenStyle, mkpom, ptp) => if(mavenStyle) mkpom.map(_ => ()) else ptp }, makePom <<= (ivyModule, makePomConfiguration, packageToPublish, streams) map { (module, config, _, s) => IvyActions.makePom(module, config, s.log); config.file }, @@ -513,8 +513,11 @@ object Classpaths val lock = app.provider.scalaProvider.launcher.globalLock new InlineIvyConfiguration(paths, rs, other, moduleConfs, off, Some(lock), s.log) }, - moduleSettings <<= (projectID, allDependencies, ivyXML, thisProject, defaultConfiguration, ivyScala, ivyValidate) map { - (pid, deps, ivyXML, project, defaultConf, ivyS, validate) => new InlineConfiguration(pid, deps, ivyXML, project.configurations, defaultConf, ivyS, validate) + ivyConfigurations <<= (autoCompilerPlugins, thisProject) { (auto, project) => + project.configurations ++ (if(auto) CompilerPlugin :: Nil else Nil) + }, + moduleSettings <<= (projectID, allDependencies, ivyXML, ivyConfigurations, defaultConfiguration, ivyScala, ivyValidate) map { + (pid, deps, ivyXML, confs, defaultConf, ivyS, validate) => new InlineConfiguration(pid, deps, ivyXML, confs, defaultConf, ivyS, validate) }, makePomConfiguration <<= pomFile(file => makePomConfigurationTask(file)), publishConfiguration <<= (target, publishTo, ivyLoggingLevel, publishMavenStyle) map { (outputDirectory, publishTo, level, mavenStyle) => @@ -730,4 +733,28 @@ object Classpaths import DependencyFilter._ def managedJars(config: Configuration, jarTypes: Set[String], up: UpdateReport): Classpath = up.select( configuration = configurationFilter(config.name), artifact = artifactFilter(`type` = jarTypes) ) + + def autoPlugins(inputs: Compiler.Inputs, report: UpdateReport): Compiler.Inputs = + inputs.copy(config = inputs.config.copy(options = autoPlugins(report) ++ inputs.config.options)) + + def autoPlugins(report: UpdateReport): Seq[String] = + { + val pluginClasspath = report matching configurationFilter(CompilerPlugin.name) + classpath.ClasspathUtilities.compilerPlugins(pluginClasspath).map("-Xplugin:" + _.getAbsolutePath).toSeq + } + + lazy val compilerPluginConfig = Seq( + compileInputs <<= (compileInputs, autoCompilerPlugins, update) map { (inputs, auto, report) => + if(auto) autoPlugins(inputs, report) else inputs + } + ) } + +trait CompilerPluginExtra +{ + def compilerPlugin(dependency: ModuleID): ModuleID = + dependency.copy(configurations = Some("plugin->default(compile)")) + + def addCompilerPlugin(dependency: ModuleID): Setting[Seq[ModuleID]] = + libraryDependencies += compilerPlugin(dependency) +} \ No newline at end of file diff --git a/main/Keys.scala b/main/Keys.scala index 2d0fe1b3e..7cd541ad2 100644 --- a/main/Keys.scala +++ b/main/Keys.scala @@ -66,6 +66,7 @@ object Keys val crossPaths = SettingKey[Boolean]("cross-paths") // compile/doc keys + val autoCompilerPlugins = SettingKey[Boolean]("auto-compiler-plugins") val maxErrors = SettingKey[Int]("max-errors") val scaladocOptions = SettingKey[Seq[String]]("scaladoc-options") val scalacOptions = SettingKey[Seq[String]]("scalac-options") @@ -149,6 +150,7 @@ object Keys val fullClasspath = TaskKey[Classpath]("full-classpath") val ivyConfiguration = TaskKey[IvyConfiguration]("ivy-configuration") + val ivyConfigurations = SettingKey[Seq[Configuration]]("ivy-configurations") val moduleSettings = TaskKey[ModuleSettings]("module-settings") val unmanagedBase = SettingKey[File]("unmanaged-base") val updateConfiguration = SettingKey[UpdateConfiguration]("update-configuration") diff --git a/main/Structure.scala b/main/Structure.scala index 2e5cc41c0..61ddf560f 100644 --- a/main/Structure.scala +++ b/main/Structure.scala @@ -6,7 +6,7 @@ package sbt /** An abstraction on top of Settings for build configuration and task definition. */ import Types._ - import std.TaskExtra._ + import std.TaskExtra.{task => mktask, _} import Task._ import Project.{Initialize, ScopedKey, Setting, setting} import complete.Parser @@ -151,7 +151,7 @@ object Scoped final class RichInputScoped[T](val scope: Scope, val key: AttributeKey[InputTask[T]]) extends RichBaseScoped[InputTask[T]] final class RichSettingScoped[S](val scope: Scope, val key: AttributeKey[S]) extends RichBaseScoped[S] { - def map[T](f: S => T): Initialize[Task[T]] = flatMap(s => task(f(s)) ) + def map[T](f: S => T): Initialize[Task[T]] = flatMap(s => mktask(f(s)) ) def flatMap[T](f: S => Task[T]): Initialize[Task[T]] = Apply.single(scoped)(f) } final class RichTaskScoped[S](scope: Scope, key: AttributeKey[Task[S]]) @@ -159,14 +159,14 @@ object Scoped type ScS = Setting[Task[S]] def :==(value: S): ScS = :=(value) def ::=(value: Task[S]): ScS = Project.setting(scoped, Project.value( value )) - def := (value: => S): ScS = ::=(task(value)) + def := (value: => S): ScS = ::=(mktask(value)) def :== (v: ScopedTask[S]): ScS = Project.setting(scoped, Project.app(ScopedKey(v.scope, v.key) :^: KNil)(_.head) ) def :== (v: ScopedSetting[S]): ScS = <<=( v(const)) def ~= (f: S => S): ScS = Project.update(scoped)( _ map f ) def <<= (app: App[S]): ScS = Project.setting(scoped, app) - def setting: ScopedSetting[Task[S]] = scopedSetting(scope, key) + def task: ScopedSetting[Task[S]] = scopedSetting(scope, key) def get(settings: Settings[Scope]): Option[Task[S]] = settings.get(scope, key) type App[T] = Initialize[Task[T]] diff --git a/main/actions/Compiler.scala b/main/actions/Compiler.scala index 1d65be33d..cd45376e5 100644 --- a/main/actions/Compiler.scala +++ b/main/actions/Compiler.scala @@ -22,10 +22,10 @@ object Compiler case _ => Nil } - final class Inputs(val compilers: Compilers, val config: Options, val incSetup: IncSetup) - final class Options(val classpath: Seq[File], val sources: Seq[File], val classesDirectory: File, val options: Seq[String], val javacOptions: Seq[String], val maxErrors: Int, val order: CompileOrder.Value) - final class IncSetup(val analysisMap: Map[File, Analysis], val cacheDirectory: File) - final class Compilers(val scalac: AnalyzingCompiler, val javac: JavaCompiler) + final case class Inputs(compilers: Compilers, config: Options, incSetup: IncSetup) + final case class Options(classpath: Seq[File], sources: Seq[File], classesDirectory: File, options: Seq[String], javacOptions: Seq[String], maxErrors: Int, order: CompileOrder.Value) + final case class IncSetup(analysisMap: Map[File, Analysis], cacheDirectory: File) + final case class Compilers(scalac: AnalyzingCompiler, javac: JavaCompiler) def inputs(classpath: Seq[File], sources: Seq[File], outputDirectory: File, options: Seq[String], javacOptions: Seq[String], maxErrors: Int, order: CompileOrder.Value)(implicit compilers: Compilers, log: Logger): Inputs = { diff --git a/sbt/package.scala b/sbt/package.scala index 939b4901a..084314204 100644 --- a/sbt/package.scala +++ b/sbt/package.scala @@ -1,7 +1,8 @@ /* sbt -- Simple Build Tool * Copyright 2010, 2011 Mark Harrah */ -package object sbt extends sbt.std.TaskExtra with sbt.Types with sbt.ProcessExtra with sbt.impl.DependencyBuilders with sbt.PathExtra with sbt.ProjectExtra with sbt.DependencyFilterExtra +package object sbt extends sbt.std.TaskExtra with sbt.Types with sbt.ProcessExtra with sbt.impl.DependencyBuilders + with sbt.PathExtra with sbt.ProjectExtra with sbt.DependencyFilterExtra with sbt.CompilerPluginExtra { type Setting[T] = Project.Setting[T] type ScopedKey[T] = Project.ScopedKey[T]