mirror of https://github.com/sbt/sbt.git
Require projects to have unique target directories.
Configuring projects so that target directories overlap is usually unintentional and the error message that results is usually unrelated to the cause.
This commit is contained in:
parent
52f1ed1819
commit
2f9d68e869
|
|
@ -138,7 +138,8 @@ object Load
|
|||
lazy val rootEval = lazyEval(loaded.units(loaded.root).unit)
|
||||
val settings = finalTransforms(buildConfigurations(loaded, getRootProject(projects), config.injectSettings))
|
||||
val delegates = config.delegates(loaded)
|
||||
val data = makeSettings(settings, delegates, config.scopeLocal)( Project.showLoadingKey( loaded ) )
|
||||
val data = Def.make(settings)(delegates, config.scopeLocal, Project.showLoadingKey( loaded ) )
|
||||
Project.checkTargets(data) foreach error
|
||||
val index = structureIndex(data, settings, loaded.extra(data))
|
||||
val streams = mkStreams(projects, loaded.root, data)
|
||||
(rootEval, new sbt.BuildStructure(projects, loaded.root, settings, data, index, streams, delegates, config.scopeLocal))
|
||||
|
|
|
|||
|
|
@ -227,9 +227,33 @@ object Project extends ProjectExtra
|
|||
}
|
||||
def setCond[T](key: AttributeKey[T], vopt: Option[T], attributes: AttributeMap): AttributeMap =
|
||||
vopt match { case Some(v) => attributes.put(key, v); case None => attributes.remove(key) }
|
||||
@deprecated("Use Def.make", "0.13.0")
|
||||
def makeSettings(settings: Seq[Def.Setting[_]], delegates: Scope => Seq[Scope], scopeLocal: ScopedKey[_] => Seq[Def.Setting[_]])(implicit display: Show[ScopedKey[_]]) =
|
||||
Def.make(settings)(delegates, scopeLocal, display)
|
||||
|
||||
private[sbt] def checkTargets(data: Settings[Scope]): Option[String] =
|
||||
{
|
||||
val dups = overlappingTargets(allTargets(data))
|
||||
if(dups.isEmpty)
|
||||
None
|
||||
else {
|
||||
val dupStrs = dups map { case (dir, scopes) =>
|
||||
s"${dir.getAbsolutePath}:\n\t${scopes.mkString("\n\t")}"
|
||||
}
|
||||
Some( s"Overlapping output directories:${dupStrs.mkString}" )
|
||||
}
|
||||
}
|
||||
private[this] def overlappingTargets(targets: Seq[(ProjectRef,File)]): Map[File, Seq[ProjectRef]] =
|
||||
targets.groupBy(_._2).filter(_._2.size > 1).mapValues(_.map(_._1))
|
||||
|
||||
private[this] def allTargets(data: Settings[Scope]): Seq[(ProjectRef,File)] =
|
||||
{
|
||||
import ScopeFilter._
|
||||
val allProjects = ScopeFilter(Make.inAnyProject)
|
||||
val targetAndRef = Def.setting { (Keys.thisProjectRef.value, Keys.target.value) }
|
||||
new SettingKeyAll(targetAndRef).all(allProjects) evaluate data
|
||||
}
|
||||
|
||||
def equal(a: ScopedKey[_], b: ScopedKey[_], mask: ScopeMask): Boolean =
|
||||
a.key == b.key && Scope.equal(a.scope, b.scope, mask)
|
||||
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ object TestBuild
|
|||
def structure(env: Env, settings: Seq[Setting[_]], current: ProjectRef): Structure =
|
||||
{
|
||||
implicit val display = Def.showRelativeKey(current, env.allProjects.size > 1)
|
||||
val data = Project.makeSettings(settings, env.delegates, const(Nil))
|
||||
val data = Def.make(settings)(env.delegates, const(Nil), display)
|
||||
val keys = data.allKeys( (s, key) => ScopedKey(s, key))
|
||||
val keyMap = keys.map(k => (k.key.label, k.key)).toMap[String, AttributeKey[_]]
|
||||
new Structure(env, current, data, KeyIndex(keys), keyMap)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
lazy val x = project in file("x")
|
||||
|
||||
lazy val y = project in file(IO.read(file("ydir")).trim)
|
||||
|
|
@ -0,0 +1 @@
|
|||
x
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
$ copy-file changes/xdir ydir
|
||||
|
||||
# should detect collision between x and y both having a target directory of 'x/target'
|
||||
-> reload
|
||||
|
|
@ -0,0 +1 @@
|
|||
y
|
||||
|
|
@ -17,6 +17,7 @@ Features, fixes, changes with compatibility implications (incomplete, please hel
|
|||
- Fixed the default classifier for tests to be ``tests`` for proper Maven compatibility.
|
||||
- The global settings and plugins directories are now versioned. Global settings go in ``~/.sbt/0.13/`` and global plugins in ``~/.sbt/0.13/plugins/`` by default. Explicit overrides, such as via the ``sbt.global.base`` system property, are still respected. (gh-735)
|
||||
- sbt no longer canonicalizes files passed to scalac. (gh-723)
|
||||
- sbt now enforces that each project must have a unique ``target`` directory.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
|
|
|||
|
|
@ -496,7 +496,7 @@ trait Init[Scope]
|
|||
def mapConstant(g: MapConstant): Initialize[T] = new Optional(a map mapConstantT(g).fn, f)
|
||||
def evaluate(ss: Settings[Scope]): T = f( a.flatMap( i => trapBadRef(evaluateT(ss)(i)) ) )
|
||||
// proper solution is for evaluate to be deprecated or for external use only and a new internal method returning Either be used
|
||||
private[this] def trapBadRef[A](run: => A): Option[A] = try Some(run) catch { case e: InvalidReferenceException => None }
|
||||
private[this] def trapBadRef[A](run: => A): Option[A] = try Some(run) catch { case e: InvalidReference => None }
|
||||
}
|
||||
private[sbt] final class Value[T](val value: () => T) extends Initialize[T]
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue