diff --git a/main/src/main/scala/sbt/BuildStructure.scala b/main/src/main/scala/sbt/BuildStructure.scala index de2ff7763..221d227dd 100644 --- a/main/src/main/scala/sbt/BuildStructure.scala +++ b/main/src/main/scala/sbt/BuildStructure.scala @@ -108,16 +108,25 @@ case class DetectedAutoPlugin(val name: String, val value: AutoPlugin, val hasAu */ final class DetectedPlugins(val plugins: DetectedModules[Plugin], val autoPlugins: Seq[DetectedAutoPlugin], val builds: DetectedModules[Build]) { /** Sequence of import expressions for the build definition. This includes the names of the [[Plugin]], [[Build]], and [[AutoImport]] modules, but not the [[AutoPlugin]] modules. */ - lazy val imports: Seq[String] = BuildUtil.getImports(plugins.names ++ builds.names ++ - (autoPlugins flatMap { + lazy val imports: Seq[String] = BuildUtil.getImports(plugins.names ++ builds.names) ++ + BuildUtil.importAllRoot(autoImports(autoPluginAutoImports)) ++ + BuildUtil.importAll(autoImports(topLevelAutoPluginAutoImports)) ++ + BuildUtil.importNamesRoot(autoPlugins.map(_.name).filter(nonTopLevelPlugin)) + + private[this] lazy val (autoPluginAutoImports, topLevelAutoPluginAutoImports) = + autoPlugins.flatMap { case DetectedAutoPlugin(name, ap, hasAutoImport) => - if (hasAutoImport) Some(name + ".autoImport") + if (hasAutoImport) Some(name) else None - })) ++ - BuildUtil.importNamesRoot(autoPlugins map { _.name }) + }.partition(nonTopLevelPlugin) /** A function to select the right [[AutoPlugin]]s from [[autoPlugins]] for a [[Project]]. */ lazy val deducePlugins: (Plugins, Logger) => Seq[AutoPlugin] = Plugins.deducer(autoPlugins.toList map { _.value }) + + private[this] def autoImports(pluginNames: Seq[String]) = pluginNames.map(_ + ".autoImport") + + private[this] def nonTopLevelPlugin(name: String) = name.contains('.') + } /** diff --git a/sbt/src/sbt-test/project/auto-plugins/build.sbt b/sbt/src/sbt-test/project/auto-plugins/build.sbt index 27cdb97cd..5fd1c156a 100644 --- a/sbt/src/sbt-test/project/auto-plugins/build.sbt +++ b/sbt/src/sbt-test/project/auto-plugins/build.sbt @@ -15,6 +15,16 @@ lazy val projE = project.enablePlugins(S) lazy val projF = project +// with X enabled, TopA is loaded automatically +lazy val projG = project.enablePlugins(X) + +// only TopB should be enabled +lazy val projH = project.enablePlugins(TopB) + +// enables TopC, which declares topLevelKeyTest +lazy val projI = project.enablePlugins(TopC) + + disablePlugins(plugins.IvyPlugin) check := { @@ -49,10 +59,21 @@ check := { same(optInValue, " Q S R", "del in projE in q") val overrideOrgValue = (organization in projE).value same(overrideOrgValue, "S", "organization in projE") +// tests for top level plugins + val topLevelAValueG = (topLevelDemo in projG).value + same(topLevelAValueG, "TopA: topLevelDemo project projG", "topLevelDemo in projG") + val demoValueG = (demo in projG).value + same(demoValueG, "TopA: demo project projG", "demo in projG") + val topLevelBValueH = (topLevelDemo in projH).value + same(topLevelBValueH, "TopB: topLevelDemo project projH", "topLevelDemo in projH") + val hdel = (del in projH).?.value + same(hdel, None, "del in projH") } keyTest := "foo" +topLevelKeyTest := "bar" + def same[T](actual: T, expected: T, label: String) { assert(actual == expected, s"Expected '$expected' for `$label`, got '$actual'") } diff --git a/sbt/src/sbt-test/project/auto-plugins/project/A.scala b/sbt/src/sbt-test/project/auto-plugins/project/A.scala new file mode 100644 index 000000000..f28b8bec8 --- /dev/null +++ b/sbt/src/sbt-test/project/auto-plugins/project/A.scala @@ -0,0 +1,47 @@ +// no package +// plugins declared within no package should be visible to other plugins in the _root_ package + +import sbt._ +import sbt.Keys._ + +object TopLevelImports { + lazy val topLevelDemo = settingKey[String]("A top level demo setting.") +} + +object TopA extends AutoPlugin { + + import TopLevelImports._ + import sbttest.Imports._ + + val autoImport = TopLevelImports + + override def requires = sbttest.X + + override def trigger = AllRequirements + + override def projectSettings: scala.Seq[sbt.Setting[_]] = Seq( + topLevelDemo := s"TopA: topLevelDemo project ${name.value}", + demo := s"TopA: demo project ${name.value}" + ) + +} + +object TopB extends AutoPlugin { + + import TopLevelImports._ + + val autoImport = TopLevelImports + + override def projectSettings: Seq[Setting[_]] = Seq( + topLevelDemo := s"TopB: topLevelDemo project ${name.value}" + ) + +} + +object TopC extends AutoPlugin { + + object autoImport { + lazy val topLevelKeyTest = settingKey[String]("A top level setting declared in a plugin.") + } + +} \ No newline at end of file diff --git a/sbt/src/sbt-test/project/binary-plugin/changes/define/D.scala b/sbt/src/sbt-test/project/binary-plugin/changes/define/D.scala new file mode 100644 index 000000000..e4b47921d --- /dev/null +++ b/sbt/src/sbt-test/project/binary-plugin/changes/define/D.scala @@ -0,0 +1,11 @@ +// no package declaration + +import sbt._ + +object D extends AutoPlugin { + + object autoImport { + lazy val dKey = settingKey[String]("Test key") + } + +} \ No newline at end of file diff --git a/sbt/src/sbt-test/project/binary-plugin/test b/sbt/src/sbt-test/project/binary-plugin/test index 169511975..a8ccb21b4 100644 --- a/sbt/src/sbt-test/project/binary-plugin/test +++ b/sbt/src/sbt-test/project/binary-plugin/test @@ -1,12 +1,13 @@ # First we define the plugin project and publish it $ copy-file changes/define/build.sbt build.sbt $ copy-file changes/define/A.scala A.scala +$ copy-file changes/define/D.scala D.scala # reload implied > publishLocal # Now we remove the source code and define a project which uses the build. -$ delete build.sbt A.scala +$ delete build.sbt A.scala D.scala $ copy-file changes/use/plugins.sbt project/plugins.sbt > reload > check