diff --git a/main/src/main/scala/sbt/Build.scala b/main/src/main/scala/sbt/Build.scala index 6fd43bda0..b44735843 100644 --- a/main/src/main/scala/sbt/Build.scala +++ b/main/src/main/scala/sbt/Build.scala @@ -45,7 +45,13 @@ object Build { def defaultID(base: File, prefix: String = "default"): String = prefix + "-" + Hash.trimHashString(base.getAbsolutePath, 6) @deprecated("Explicitly specify the ID", "0.13.0") def defaultProject(base: File): Project = defaultProject(defaultID(base), base) - def defaultProject(id: String, base: File): Project = Project(id, base).settings( + def defaultProject(id: String, base: File): Project = Project(id, base).settings(defaultProjectSettings: _*) + def defaultAggregatedProject(id: String, base: File, agg: Seq[ProjectRef]): Project = + defaultProject(id, base).aggregate(agg: _*) + + private[sbt] def generatedRootWithoutIvyPlugin(id: String, base: File, agg: Seq[ProjectRef]): Project = + Project.mkGeneratedRoot(id, base, agg).settings(defaultProjectSettings: _*) + private[sbt] def defaultProjectSettings: Seq[Setting[_]] = Seq( // TODO - Can we move this somewhere else? ordering of settings is causing this to get borked. // if the user has overridden the name, use the normal organization that is derived from the name. organization := { @@ -57,8 +63,6 @@ object Build { }, autoGeneratedProject := true ) - def defaultAggregatedProject(id: String, base: File, agg: Seq[ProjectRef]): Project = - defaultProject(id, base).aggregate(agg: _*) @deprecated("Use Attributed.data", "0.13.0") def data[T](in: Seq[Attributed[T]]): Seq[T] = Attributed.data(in) diff --git a/main/src/main/scala/sbt/BuildStructure.scala b/main/src/main/scala/sbt/BuildStructure.scala index 30dfcf4e2..a06fe97a3 100644 --- a/main/src/main/scala/sbt/BuildStructure.scala +++ b/main/src/main/scala/sbt/BuildStructure.scala @@ -135,8 +135,21 @@ final class DetectedPlugins(val plugins: DetectedModules[Plugin], val autoPlugin }.partition(nonTopLevelPlugin) /** A function to select the right [[AutoPlugin]]s from [[autoPlugins]] for a [[Project]]. */ + @deprecated("Use deducePluginsFromProject", "0.13.8") lazy val deducePlugins: (Plugins, Logger) => Seq[AutoPlugin] = Plugins.deducer(autoPlugins.toList map { _.value }) + /** Selects the right [[AutoPlugin]]s from a [[Project]]. */ + def deducePluginsFromProject(p: Project, log: Logger): Seq[AutoPlugin] = + { + val ps0 = p.plugins + val allDetected = autoPlugins.toList map { _.value } + val detected = p match { + case _: GeneratedRootProject => allDetected filterNot { _ == sbt.plugins.IvyPlugin } + case _ => allDetected + } + Plugins.deducer(detected)(ps0, log) + } + private[this] def autoImports(pluginNames: Seq[String]) = pluginNames.map(_ + ".autoImport") private[this] def nonTopLevelPlugin(name: String) = name.contains('.') diff --git a/main/src/main/scala/sbt/Load.scala b/main/src/main/scala/sbt/Load.scala index b9dad65e3..764c8a73a 100755 --- a/main/src/main/scala/sbt/Load.scala +++ b/main/src/main/scala/sbt/Load.scala @@ -585,7 +585,9 @@ object Load { val existingIds = otherProjects.projects map (_.id) val refs = existingIds map (id => ProjectRef(buildUri, id)) val defaultID = autoID(buildBase, context, existingIds) - val root = finalizeProject(Build.defaultAggregatedProject(defaultID, buildBase, refs), files) + val root0 = if (discovered.isEmpty || java.lang.Boolean.getBoolean("sbt.root.ivyplugin")) Build.defaultAggregatedProject(defaultID, buildBase, refs) + else Build.generatedRootWithoutIvyPlugin(defaultID, buildBase, refs) + val root = finalizeProject(root0, files) val result = root +: (acc ++ otherProjects.projects) log.debug(s"[Loading] Done in ${buildBase}, returning: ${result.map(_.id).mkString("(", ", ", ")")}") LoadedProjects(result, generated ++ otherGenerated ++ generatedConfigClassFiles) @@ -645,7 +647,7 @@ object Load { } // 2. Discover all the autoplugins and contributed configurations. val autoPlugins = - try loadedPlugins.detected.deducePlugins(transformedProject.plugins, log) + try loadedPlugins.detected.deducePluginsFromProject(transformedProject, log) catch { case e: AutoPluginException => throw translateAutoPluginException(e, transformedProject) } val autoConfigs = autoPlugins.flatMap(_.projectConfigurations) diff --git a/main/src/main/scala/sbt/Project.scala b/main/src/main/scala/sbt/Project.scala index 3221ea101..c6521271f 100755 --- a/main/src/main/scala/sbt/Project.scala +++ b/main/src/main/scala/sbt/Project.scala @@ -234,6 +234,13 @@ object Project extends ProjectExtra { auto: AddSettings = AddSettings.allDefaults): Project = unresolved(id, base, aggregate, dependencies, delegates, settings, configurations, auto, Plugins.empty, Nil) // Note: JvmModule/IvyModule auto included... + /** This is a variation of def apply that mixes in GeneratedRootProject. */ + private[sbt] def mkGeneratedRoot(id: String, base: File, aggregate: => Seq[ProjectReference]): Project = + { + validProjectID(id).foreach(errMsg => sys.error("Invalid project ID: " + errMsg)) + new ProjectDef[ProjectReference](id, base, aggregate, Nil, Nil, Nil, Nil, AddSettings.allDefaults, Plugins.empty, Nil) with Project with GeneratedRootProject + } + /** Returns None if `id` is a valid Project ID or Some containing the parser error message if it is not.*/ def validProjectID(id: String): Option[String] = DefaultParsers.parse(id, DefaultParsers.ID).left.toOption private[this] def validProjectIDStart(id: String): Boolean = DefaultParsers.parse(id, DefaultParsers.IDStart).isRight @@ -571,6 +578,8 @@ object Project extends ProjectExtra { } } +private[sbt] trait GeneratedRootProject + trait ProjectExtra { implicit def configDependencyConstructor[T <% ProjectReference](p: T): Constructor = new Constructor(p) implicit def classpathDependency[T <% ProjectReference](p: T): ClasspathDependency = new ClasspathDependency(p, None) diff --git a/notes/0.13.8.markdown b/notes/0.13.8.markdown index c85da9dd7..f35a9c981 100644 --- a/notes/0.13.8.markdown +++ b/notes/0.13.8.markdown @@ -5,6 +5,7 @@ [@ajozwik]: https://github.com/ajozwik [@dwickern]: https://github.com/dwickern + [@dwijnand]: http://github.com/dwijnand [@Duhemm]: https://github.com/Duhemm [@kretes]: https://github.com/kretes [@indrajitr]: https://github.com/indrajitr @@ -38,6 +39,8 @@ [1787]: https://github.com/sbt/sbt/pull/1787 [1793]: https://github.com/sbt/sbt/pull/1793 [1817]: https://github.com/sbt/sbt/pull/1817 + [1869]: https://github.com/sbt/sbt/issues/1869 + [1871]: https://github.com/sbt/sbt/pull/1871 ### Changes with compatibility implications @@ -71,6 +74,7 @@ - Fixes eviction warning being too noisy. [#1615][1615] by [@eed3si9n][@eed3si9n] - Issues warning if multiple dependencies to a same library is found with different version. [#1634][1634] by [@eed3si9n][@eed3si9n] - Removes "No main class detected" warning. [#1766][1766] by [@eed3si9n][@eed3si9n] +- Disable publishing on implicitly created root project by not enabling `IvyPlugin` by default (`-Dsbt.root.ivyplugin=true` will revert this behavior). [#1871][1871]/[#1869][1869] by [@dwijnand][@dwijnand] ### Rolling back XML parsing workaround diff --git a/sbt/src/sbt-test/project/generated-root-no-publish/build.sbt b/sbt/src/sbt-test/project/generated-root-no-publish/build.sbt new file mode 100644 index 000000000..974a291a9 --- /dev/null +++ b/sbt/src/sbt-test/project/generated-root-no-publish/build.sbt @@ -0,0 +1,10 @@ +val commonSettings = Seq( + organization := "com.example", + version := "0.1.0", + ivyPaths := new IvyPaths((baseDirectory in LocalRootProject).value, Some((target in LocalRootProject).value / "ivy-cache")) +) + +lazy val app = (project in file("app")). + settings(commonSettings: _*) + +commonSettings diff --git a/sbt/src/sbt-test/project/generated-root-no-publish/changes/bare.sbt b/sbt/src/sbt-test/project/generated-root-no-publish/changes/bare.sbt new file mode 100644 index 000000000..936367950 --- /dev/null +++ b/sbt/src/sbt-test/project/generated-root-no-publish/changes/bare.sbt @@ -0,0 +1,3 @@ +organization := "com.example" +version := "0.1.0" +ivyPaths := new IvyPaths((baseDirectory in LocalRootProject).value, Some((target in LocalRootProject).value / "ivy-cache")) diff --git a/sbt/src/sbt-test/project/generated-root-no-publish/test b/sbt/src/sbt-test/project/generated-root-no-publish/test new file mode 100644 index 000000000..3cfdd4401 --- /dev/null +++ b/sbt/src/sbt-test/project/generated-root-no-publish/test @@ -0,0 +1,10 @@ +> publishLocal +$ exists target/ivy-cache/local/com.example/app_2.10/0.1.0/poms/app_2.10.pom +$ exists target/ivy-cache/local/com.example/app_2.10/0.1.0/jars/app_2.10.jar +$ absent target/ivy-cache/local/com.example/default-root_2.10/0.1.0/ivys/ivy.xml + +$ copy-file changes/bare.sbt build.sbt +> reload +> publishLocal +$ exists target/ivy-cache/local/com.example/generated-root-no-publish_2.10/0.1.0/poms/generated-root-no-publish_2.10.pom +$ exists target/ivy-cache/local/com.example/generated-root-no-publish_2.10/0.1.0/jars/generated-root-no-publish_2.10.jar