From b8207607c9ae9f649541b62ea3865ca1c1b794a7 Mon Sep 17 00:00:00 2001 From: Erem Boto Date: Sat, 15 Oct 2016 18:12:41 -0700 Subject: [PATCH 1/2] Demonstrate failure to process property absence directives in profile activation --- .../scala/coursier/test/PomParsingTests.scala | 35 +++++++++++ .../scala/coursier/test/ResolutionTests.scala | 58 +++++++++++++++++-- 2 files changed, 88 insertions(+), 5 deletions(-) diff --git a/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala b/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala index 290c968cb..f4193b86b 100644 --- a/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala +++ b/tests/shared/src/test/scala/coursier/test/PomParsingTests.scala @@ -77,6 +77,41 @@ object PomParsingTests extends TestSuite { assert(result == expected) } + 'readProfileActiveByPropertyWithoutValue{ + val profileNode =""" + + profile1 + + + hadoop.profile + + + + """ + val expected = \/-(Profile("profile1", None, Profile.Activation(List("hadoop.profile" -> None)), Nil, Nil, Map.empty)) + val result = Pom.profile(xmlParse(profileNode).right.get) + + assert(result == expected) + } + + 'readProfileActiveByPropertyWithValue{ + val profileNode =""" + + profile1 + + + hadoop.profile + yes + + + + """ + val expected = \/-(Profile("profile1", None, Profile.Activation(List("hadoop.profile" -> Some("yes"))), Nil, Nil, Map.empty)) + val result = Pom.profile(xmlParse(profileNode).right.get) + + assert(result == expected) + } + 'readProfileDependencies{ val profileNode =""" diff --git a/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala b/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala index 87a2dc1e0..8e6a89c67 100644 --- a/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala +++ b/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala @@ -26,12 +26,12 @@ object ResolutionTests extends TestSuite { val projects = Seq( Project(Module("acme", "config"), "1.3.0"), - + Project(Module("acme", "play"), "2.4.0", Seq( "" -> Dependency(Module("acme", "play-json"), "2.4.0"))), - + Project(Module("acme", "play-json"), "2.4.0"), - + Project(Module("acme", "play"), "2.4.1", dependencies = Seq( "" -> Dependency(Module("acme", "play-json"), "${play_json_version}"), @@ -39,7 +39,7 @@ object ResolutionTests extends TestSuite { properties = Seq( "play_json_version" -> "2.4.0", "WithSpecialChar©" -> "config")), - + Project(Module("acme", "play-extra-no-config"), "2.4.1", Seq( "" -> Dependency(Module("acme", "play"), "2.4.1", @@ -135,6 +135,30 @@ object ResolutionTests extends TestSuite { Profile("default", activation = Profile.Activation(properties = Seq("special" -> Some("!false"))), dependencies = Seq( "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), + Project(Module("com.github.dummy", "libb"), "0.5.7", + // This project demonstrates a build profile that activates only when + // the property "special" is unset. Because "special" is set to "true" + // here, the build profile should not be active and "librairie-standard" + // should not be provided as a transitive dependency when resolved. + // + // We additionally include the property "!special" -> "true" to + // disambiguate the absence of the "special" property versus + // the presence of the "!special" property (which is probably not valid pom + // anyways) + properties = Seq("special" -> "true", "!special" -> "true"), + profiles = Seq( + Profile("default", activation = Profile.Activation(properties = Seq("!special" -> None)), dependencies = Seq( + "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), + + Project(Module("com.github.dummy", "libb"), "0.5.8", + // This project demonstrates a build profile that activates only when + // the property "special" is unset. Because that is the case here, + // the "default" build profile should be active and "librairie-standard" + // should be provided as a transitive dependency when resolved. + profiles = Seq( + Profile("default", activation = Profile.Activation(properties = Seq("!special" -> None)), dependencies = Seq( + "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))), + Project(Module("an-org", "a-name"), "1.0"), Project(Module("an-org", "a-name"), "1.2"), @@ -398,7 +422,7 @@ object ResolutionTests extends TestSuite { } 'depsFromPropertyActivatedProfile{ val f = - for (version <- Seq("0.5.3", "0.5.4", "0.5.5", "0.5.6")) yield { + for (version <- Seq("0.5.3", "0.5.4", "0.5.5", "0.5.6", "0.5.8")) yield { async { val dep = Dependency(Module("com.github.dummy", "libb"), version) val trDeps = Seq( @@ -418,6 +442,30 @@ object ResolutionTests extends TestSuite { scala.concurrent.Future.sequence(f) } + 'depsFromProfileDisactivatedByPropertyAbsence{ + // A build profile only activates in the absence of some property should + // not be activated when that property is present. + // --- + // The target dependency in this test (com.github.dummy % libb % 0.5.7) + // declares a profile that is only active when name=!special, + // and names a transitive dependency (librairie-standard) that is only + // active under that build profile. When we resolve a module with + // the "special" attribute set to "true", the transitive dependency + // should not appear. + async { + val dep = Dependency(Module("com.github.dummy", "libb"), "0.5.7") + val res = await(resolve0( + Set(dep) + )).clearCaches + + val expected = Resolution( + rootDependencies = Set(dep), + dependencies = Set(dep.withCompileScope) + ) + + assert(res == expected) + } + } 'depsScopeOverrideFromProfile{ async { // Like com.google.inject:guice:3.0 with org.sonatype.sisu.inject:cglib From b1f9cb96d4b2924edacbcab569e1b9f37af6e691 Mon Sep 17 00:00:00 2001 From: Erem Boto Date: Sat, 15 Oct 2016 18:21:12 -0700 Subject: [PATCH 2/2] Add support for property absence directives in profile activation --- .../main/scala/coursier/core/Resolution.scala | 18 +++++++++++------- .../scala/coursier/test/ResolutionTests.scala | 6 ++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/core/shared/src/main/scala/coursier/core/Resolution.scala b/core/shared/src/main/scala/coursier/core/Resolution.scala index 66cf5169b..f45c3bc4a 100644 --- a/core/shared/src/main/scala/coursier/core/Resolution.scala +++ b/core/shared/src/main/scala/coursier/core/Resolution.scala @@ -258,7 +258,7 @@ object Resolution { if (mgmtDep.optional) dep = dep.copy(optional = mgmtDep.optional) } - + (config, dep) } } @@ -448,12 +448,16 @@ object Resolution { activation.properties.nonEmpty && activation.properties.forall { case (name, valueOpt) => - props.get(name).exists { v => - valueOpt.forall { reqValue => - if (reqValue.startsWith("!")) - v != reqValue.drop(1) - else - v == reqValue + if (name.startsWith("!")) { + props.get(name.drop(1)).isEmpty + } else { + props.get(name).exists { v => + valueOpt.forall { reqValue => + if (reqValue.startsWith("!")) + v != reqValue.drop(1) + else + v == reqValue + } } } } diff --git a/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala b/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala index 8e6a89c67..7ed092605 100644 --- a/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala +++ b/tests/shared/src/test/scala/coursier/test/ResolutionTests.scala @@ -155,6 +155,12 @@ object ResolutionTests extends TestSuite { // the property "special" is unset. Because that is the case here, // the "default" build profile should be active and "librairie-standard" // should be provided as a transitive dependency when resolved. + // + // We additionally include the property "!special" -> "true" to + // disambiguate the absence of the "special" property versus + // the presence of the "!special" property (which is probably not valid pom + // anyways) + properties = Seq("!special" -> "true"), profiles = Seq( Profile("default", activation = Profile.Activation(properties = Seq("!special" -> None)), dependencies = Seq( "" -> Dependency(Module("org.escalier", "librairie-standard"), "2.11.6"))))),