From 6329098beb83cc02049f34cb8cf1b6c5d2139124 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 9 Jul 2019 07:39:12 -0400 Subject: [PATCH 01/19] Detect latest AdoptOpenJDK JDK 8 and 11 --- .travis.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index e1d3fa441..8d7443c0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ -sudo: false -dist: trusty +dist: xenial group: stable language: scala @@ -14,21 +13,21 @@ env: matrix: include: - env: - - TRAVIS_JDK=11.0.3.hs-adpt + - ADOPTOPENJDK=11 - env: - - TRAVIS_JDK=8.0.212.hs-adpt + - ADOPTOPENJDK=8 before_install: # adding $HOME/.sdkman to cache would create an empty directory, which interferes with the initial installation - - "[[ -d /home/travis/.sdkman/ ]] && [[ -d /home/travis/.sdkman/bin/ ]] || rm -rf /home/travis/.sdkman/" + - "[[ -d $HOME/.sdkman/bin/ ]] || rm -rf $HOME/.sdkman/" - curl -sL https://get.sdkman.io | bash - - echo sdkman_auto_answer=true > /home/travis/.sdkman/etc/config - - source "/home/travis/.sdkman/bin/sdkman-init.sh" + - echo sdkman_auto_answer=true > $HOME/.sdkman/etc/config + - source "$HOME/.sdkman/bin/sdkman-init.sh" install: - - sdk install java $TRAVIS_JDK + - sdk install java $(sdk list java | grep -o "$ADOPTOPENJDK\.[0-9\.]*hs-adpt" | tail -1) - bin/fixpreloaded.sh - - unset _JAVA_OPTIONS + - unset JAVA_HOME - java -Xmx32m -version # detect sbt version from project/build.properties # - export TRAVIS_SBT=$(grep sbt.version= project/build.properties | sed -e 's/sbt.version=//g' ) && echo "sbt $TRAVIS_SBT" From c89695b4b2a62fa0bd7e024aebaafb1f07fd4937 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Thu, 1 Aug 2019 16:20:22 -0400 Subject: [PATCH 02/19] Deprecate HTTP resolvers Ref https://github.com/sbt/sbt/issues/4905 --- .scalafmt.conf | 2 +- .../sbt/librarymanagement/URLRepository.scala | 2 +- .../main/contraband/librarymanagement.json | 5 +++- .../DependencyBuilders.scala | 1 + .../sbt/librarymanagement/ModuleIDExtra.scala | 5 +++- .../sbt/librarymanagement/ResolverExtra.scala | 25 +++++++++++++++++++ .../librarymanagement/ResolverSpec.scala | 16 ++++++++++++ 7 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 ivy/src/test/scala/sbt/internal/librarymanagement/ResolverSpec.scala diff --git a/.scalafmt.conf b/.scalafmt.conf index 718ce5aed..e98e60599 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = 2.0.0-RC6 +version = 2.0.0 maxColumn = 100 project.git = true project.excludeFilters = [ /sbt-test/, /input_sources/, /contraband-scala/ ] diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/URLRepository.scala b/core/src/main/contraband-scala/sbt/librarymanagement/URLRepository.scala index 1768cacda..fc39dda73 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/URLRepository.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/URLRepository.scala @@ -7,7 +7,7 @@ package sbt.librarymanagement final class URLRepository private ( name: String, patterns: sbt.librarymanagement.Patterns) extends sbt.librarymanagement.PatternsBasedRepository(name, patterns) with Serializable { - + Resolver.validatePatterns(patterns) override def equals(o: Any): Boolean = o match { diff --git a/core/src/main/contraband/librarymanagement.json b/core/src/main/contraband/librarymanagement.json index 52cb34905..2fc2c6fbb 100644 --- a/core/src/main/contraband/librarymanagement.json +++ b/core/src/main/contraband/librarymanagement.json @@ -641,7 +641,10 @@ "name": "URLRepository", "namespace": "sbt.librarymanagement", "target": "Scala", - "type": "record" + "type": "record", + "extra": [ + "Resolver.validatePatterns(patterns)" + ] }, { "name": "SshBasedRepository", diff --git a/core/src/main/scala/sbt/librarymanagement/DependencyBuilders.scala b/core/src/main/scala/sbt/librarymanagement/DependencyBuilders.scala index 09b1d8468..a9c9d86fd 100755 --- a/core/src/main/scala/sbt/librarymanagement/DependencyBuilders.scala +++ b/core/src/main/scala/sbt/librarymanagement/DependencyBuilders.scala @@ -69,6 +69,7 @@ object DependencyBuilders { final class RepositoryName private[sbt] (name: String) { def at(location: String) = { nonEmpty(location, "Repository location") + Resolver.validateUrlString(location) MavenRepository(name, location) } } diff --git a/core/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala b/core/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala index f15c5acb3..d8c6ca6f2 100644 --- a/core/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala @@ -99,7 +99,10 @@ private[librarymanagement] abstract class ModuleIDExtra { * This value is only consulted if the module is not found in a repository. * It is not included in published metadata. */ - def from(url: String) = artifacts(Artifact(name, new URL(url))) + def from(url: String) = { + Resolver.validateUrlString(url) + artifacts(Artifact(name, new URL(url))) + } /** Adds a dependency on the artifact for this module with classifier `c`. */ def classifier(c: String) = artifacts(Artifact(name, c)) diff --git a/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala b/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala index d359f31ad..d1d435014 100644 --- a/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala @@ -7,6 +7,7 @@ import java.io.{ IOException, File } import java.net.URL import scala.xml.XML import org.xml.sax.SAXParseException +import sbt.util.{ Level, LogExchange } final class RawRepository(val resolver: AnyRef, name: String) extends Resolver(name) { override def toString = "Raw(" + resolver.toString + ")" @@ -403,4 +404,28 @@ private[librarymanagement] abstract class ResolverFunctions { val pList = Vector(localBasePattern) Patterns().withIvyPatterns(pList).withArtifactPatterns(pList).withIsMavenCompatible(false) } + + lazy val log = { + val log0 = LogExchange.logger("sbt.librarymanagement.ResolverExtra") + LogExchange.bindLoggerAppenders( + "sbt.librarymanagement.ResolverExtra", + List(LogExchange.buildAsyncStdout -> Level.Info) + ) + log0 + } + private[sbt] def warnHttp(value: String): Unit = { + log.warn(s"insecure HTTP request is deprecated '$value'; switch to HTTPS") + } + private[sbt] def validatePatterns(patterns: Patterns): Unit = { + val ivy = patterns.ivyPatterns.headOption map (_.startsWith("http:")) + val art = patterns.artifactPatterns.headOption map (_.startsWith("http:")) + (ivy orElse art) foreach { _ => + warnHttp(patterns.toString) + } + } + private[sbt] def validateUrlString(url: String): Unit = { + if (url.startsWith("http:")) { + warnHttp(url) + } + } } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/ResolverSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/ResolverSpec.scala new file mode 100644 index 000000000..64afda27e --- /dev/null +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/ResolverSpec.scala @@ -0,0 +1,16 @@ +package sbttest + +import java.net.URL +import org.scalatest._ +import sbt.librarymanagement._ +import sbt.librarymanagement.syntax._ + +class ResolverSpec extends FunSuite with DiagrammedAssertions { + test("Resolver.url") { + Resolver.url("Test Repo", new URL("http://example.com/"))(Resolver.ivyStylePatterns) + } + + test("at") { + "something" at "http://example.com" + } +} From fcc8b610112fdee9c28fb821df8d0011b87ef3d6 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Thu, 1 Aug 2019 17:47:38 -0400 Subject: [PATCH 03/19] use head -1 SDKMAN lists the latest one first. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8d7443c0e..a8a7e50e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ before_install: - source "$HOME/.sdkman/bin/sdkman-init.sh" install: - - sdk install java $(sdk list java | grep -o "$ADOPTOPENJDK\.[0-9\.]*hs-adpt" | tail -1) + - sdk install java $(sdk list java | grep -o "$ADOPTOPENJDK\.[0-9\.]*hs-adpt" | head -1) - bin/fixpreloaded.sh - unset JAVA_HOME - java -Xmx32m -version From 8fee1e2666ddf391d5ba7c7cc9ac33a196a2b534 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 13 Aug 2019 23:35:50 -0400 Subject: [PATCH 04/19] improve "X is evicted completely" Fixes https://github.com/sbt/sbt/issues/4946 1. This rewords "evicted completely" to "evicted for all versions" 2. Skips transitive and complete evictions (eviction that has no winner version) --- .../main/scala/sbt/librarymanagement/EvictionWarning.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/sbt/librarymanagement/EvictionWarning.scala b/core/src/main/scala/sbt/librarymanagement/EvictionWarning.scala index 22405934c..c090cd2ad 100644 --- a/core/src/main/scala/sbt/librarymanagement/EvictionWarning.scala +++ b/core/src/main/scala/sbt/librarymanagement/EvictionWarning.scala @@ -183,7 +183,7 @@ object EvictionPair { } val winnerRev = a.winner match { case Some(r) => s":${r.module.revision} is selected over ${revsStr}" - case _ => " is evicted completely" + case _ => " is evicted for all versions" } val title = s"\t* ${a.organization}:${a.name}$winnerRev" title :: (if (a.showCallers) callers.reverse else Nil) ::: List("") @@ -312,7 +312,9 @@ object EvictionWarning { binaryIncompatibleEvictionExists = true } case p => - if (!guessCompatible(p)) { + // don't report on a transitive eviction that does not have a winner + // https://github.com/sbt/sbt/issues/4946 + if (!guessCompatible(p) && p.winner.isDefined) { if (options.warnTransitiveEvictions) transitiveEvictions += p if (options.warnEvictionSummary) From 8c16fd0edf52b7c33116f86dc9ef834235180896 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Wed, 14 Aug 2019 02:21:24 -0400 Subject: [PATCH 05/19] switch to using scala-verify --- build.sbt | 5 +- .../AbstractEngineSpec.scala | 3 +- .../librarymanagement/ResolutionSpec.scala | 34 +- .../internal/librarymanagement/UnitSpec.scala | 5 - .../ComponentManagerTest.scala | 60 +- .../CustomPomParserTest.scala | 15 +- .../DMSerializationSpec.scala | 56 +- .../EvictionWarningSpec.scala | 524 +++++++++--------- .../FakeResolverSpecification.scala | 36 +- .../librarymanagement/FrozenModeSpec.scala | 4 +- .../librarymanagement/InclExclSpec.scala | 97 ++-- .../InconsistentDuplicateSpec.scala | 25 +- .../librarymanagement/IvyRepoSpec.scala | 20 +- .../librarymanagement/MakePomSpec.scala | 48 +- .../ManagedChecksumsSpec.scala | 4 +- .../MergeDescriptorSpec.scala | 8 +- .../ModuleResolversTest.scala | 4 +- .../librarymanagement/OfflineModeSpec.scala | 15 +- .../librarymanagement/ResolverSpec.scala | 6 +- .../librarymanagement/ScalaOverrideTest.scala | 198 ++++--- .../librarymanagement/SftpRepoSpec.scala | 4 +- .../librarymanagement/UpdateOptionsSpec.scala | 22 +- project/Dependencies.scala | 1 + 23 files changed, 641 insertions(+), 553 deletions(-) delete mode 100644 common-test/src/main/scala/sbt/internal/librarymanagement/UnitSpec.scala diff --git a/build.sbt b/build.sbt index f47cccaf3..923df2598 100644 --- a/build.sbt +++ b/build.sbt @@ -27,6 +27,7 @@ def commonSettings: Seq[Setting[_]] = Def.settings( resolvers += Resolver.sonatypeRepo("snapshots"), resolvers += Resolver.sbtPluginRepo("releases"), resolvers += "bintray-sbt-maven-releases" at "https://dl.bintray.com/sbt/maven-releases/", + testFrameworks += new TestFramework("verify.runner.Framework"), // concurrentRestrictions in Global += Util.testExclusiveRestriction, testOptions += Tests.Argument(TestFrameworks.ScalaCheck, "-w", "1"), javacOptions in compile ++= Seq("-Xlint", "-Xlint:-serial"), @@ -96,7 +97,7 @@ lazy val lmCore = (project in file("core")) okhttpUrlconnection, sjsonnewScalaJson.value % Optional, scalaTest % Test, - scalaCheck % Test + scalaCheck % Test, ), libraryDependencies += scalaXml, resourceGenerators in Compile += Def @@ -222,7 +223,7 @@ lazy val lmCommonTest = (project in file("common-test")) commonSettings, skip in publish := true, name := "common-test", - libraryDependencies ++= Seq(scalaTest, scalaCheck), + libraryDependencies ++= Seq(scalaTest, scalaCheck, scalaVerify), scalacOptions in (Compile, console) --= Vector("-Ywarn-unused-import", "-Ywarn-unused", "-Xlint"), mimaSettings, diff --git a/common-test/src/main/scala/sbt/internal/librarymanagement/AbstractEngineSpec.scala b/common-test/src/main/scala/sbt/internal/librarymanagement/AbstractEngineSpec.scala index e676b7857..55089330d 100644 --- a/common-test/src/main/scala/sbt/internal/librarymanagement/AbstractEngineSpec.scala +++ b/common-test/src/main/scala/sbt/internal/librarymanagement/AbstractEngineSpec.scala @@ -1,8 +1,9 @@ package sbt.internal.librarymanagement import sbt.librarymanagement._ +import verify.BasicTestSuite -abstract class AbstractEngineSpec extends UnitSpec { +abstract class AbstractEngineSpec extends BasicTestSuite { def cleanCache(): Unit def module( diff --git a/common-test/src/main/scala/sbt/internal/librarymanagement/ResolutionSpec.scala b/common-test/src/main/scala/sbt/internal/librarymanagement/ResolutionSpec.scala index fe14d1370..818da8155 100644 --- a/common-test/src/main/scala/sbt/internal/librarymanagement/ResolutionSpec.scala +++ b/common-test/src/main/scala/sbt/internal/librarymanagement/ResolutionSpec.scala @@ -8,7 +8,7 @@ import sbt.librarymanagement.syntax._ abstract class ResolutionSpec extends AbstractEngineSpec { import ShowLines._ - "Resolving the same module twice" should "work" in { + test("Resolving the same module twice should work") { cleanCache() val m = module( exampleModuleId("0.1.0"), @@ -22,10 +22,10 @@ abstract class ResolutionSpec extends AbstractEngineSpec { println(report) // second resolution reads from the minigraph println(report.configurations.head.modules.head.artifacts) - report.configurations.size shouldBe 3 + assert(report.configurations.size == 3) } - "Resolving the unsolvable module should" should "not work" in { + test("Resolving the unsolvable module should should not work") { // log.setLevel(Level.Debug) val m = module( exampleModuleId("0.2.0"), @@ -40,11 +40,15 @@ abstract class ResolutionSpec extends AbstractEngineSpec { updateEither(m) match { case Right(_) => sys.error("this should've failed 2") case Left(uw) => - uw.lines should contain allOf ("\n\tNote: Unresolved dependencies path:", - "\t\tfoundrylogic.vpp:vpp:2.2.1", - "\t\t +- org.apache.cayenne:cayenne-tools:3.0.2", - "\t\t +- org.apache.cayenne.plugins:maven-cayenne-plugin:3.0.2", - "\t\t +- com.example:foo:0.2.0") + List( + "\n\tNote: Unresolved dependencies path:", + "\t\tfoundrylogic.vpp:vpp:2.2.1", + "\t\t +- org.apache.cayenne:cayenne-tools:3.0.2", + "\t\t +- org.apache.cayenne.plugins:maven-cayenne-plugin:3.0.2", + "\t\t +- com.example:foo:0.2.0" + ) foreach { line => + assert(uw.lines.contains[String](line)) + } } } @@ -52,7 +56,7 @@ abstract class ResolutionSpec extends AbstractEngineSpec { // data-avro:1.9.40 depends on avro:1.4.0, which depends on netty:3.2.1.Final. // avro:1.4.0 will be evicted by avro:1.7.7. // #2046 says that netty:3.2.0.Final is incorrectly evicted by netty:3.2.1.Final - "Resolving a module with a pseudo-conflict" should "work" in { + test("Resolving a module with a pseudo-conflict should work") { // log.setLevel(Level.Debug) cleanCache() val m = module( @@ -74,7 +78,7 @@ abstract class ResolutionSpec extends AbstractEngineSpec { })) } - "Resolving a module with sbt cross build" should "work" in { + test("Resolving a module with sbt cross build should work") { cleanCache() val attributes013 = Map("e:sbtVersion" -> "0.13", "e:scalaVersion" -> "2.10") val attributes10 = Map("e:sbtVersion" -> "1.0", "e:scalaVersion" -> "2.12") @@ -88,11 +92,13 @@ abstract class ResolutionSpec extends AbstractEngineSpec { Vector(sbtRelease.withExtraAttributes(attributes10)), Some("2.12.3") ) - update(module013).configurations.head.modules.map(_.toString).loneElement should include( - "com.github.gseitz:sbt-release:1.0.6 (scalaVersion=2.10, sbtVersion=0.13)" + assert( + update(module013).configurations.head.modules.map(_.toString).loneElement + contains "com.github.gseitz:sbt-release:1.0.6 (scalaVersion=2.10, sbtVersion=0.13)" ) - update(module10).configurations.head.modules.map(_.toString).loneElement should include( - "com.github.gseitz:sbt-release:1.0.6 (scalaVersion=2.12, sbtVersion=1.0)" + assert( + update(module10).configurations.head.modules.map(_.toString).loneElement + contains "com.github.gseitz:sbt-release:1.0.6 (scalaVersion=2.12, sbtVersion=1.0)" ) } diff --git a/common-test/src/main/scala/sbt/internal/librarymanagement/UnitSpec.scala b/common-test/src/main/scala/sbt/internal/librarymanagement/UnitSpec.scala deleted file mode 100644 index dfd947c8f..000000000 --- a/common-test/src/main/scala/sbt/internal/librarymanagement/UnitSpec.scala +++ /dev/null @@ -1,5 +0,0 @@ -package sbt.internal.librarymanagement - -import org.scalatest._ - -abstract class UnitSpec extends FlatSpec with Matchers diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/ComponentManagerTest.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/ComponentManagerTest.scala index 2a9f3f675..dc2947e26 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/ComponentManagerTest.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/ComponentManagerTest.scala @@ -7,65 +7,83 @@ import sbt.io.IO import org.apache.ivy.util.ChecksumHelper import IfMissing.Fail import xsbti.ComponentProvider +import verify.BasicTestSuite // TODO - We need to re-enable this test. Right now, we dont' have a "stub" launcher for this. // This is testing something which uses a launcher interface, but was grabbing the underlying class directly // when it really should, instead, be stubbing out the underyling class. -class ComponentManagerTest extends UnitSpec { +object ComponentManagerTest extends BasicTestSuite { val TestID = "manager-test" - "Component manager" should "throw an exception if 'file' is called for a non-existing component" in { + test( + "Component manager should throw an exception if 'file' is called for a non-existing component" + ) { withManager { manager => - intercept[InvalidComponent] { manager.file(TestID)(Fail) } - () + intercept[InvalidComponent] { + manager.file(TestID)(Fail) + () + } } } - it should "throw an exception if 'file' is called for an empty component" in { + + test("it should throw an exception if 'file' is called for an empty component") { withManager { manager => manager.define(TestID, Nil) - intercept[InvalidComponent] { manager.file(TestID)(Fail) } - () + intercept[InvalidComponent] { + manager.file(TestID)(Fail) + () + } } } - it should "return the file for a single-file component" in { + + test("it should return the file for a single-file component") { withManager { manager => val hash = defineFile(manager, TestID, "a") - checksum(manager.file(TestID)(Fail)) shouldBe hash + assert(checksum(manager.file(TestID)(Fail)) == hash) } } - it should "throw an exception if 'file' is called for multi-file component" in { + + test("it should throw an exception if 'file' is called for multi-file component") { withManager { manager => defineFiles(manager, TestID, "a", "b") - intercept[InvalidComponent] { manager.file(TestID)(Fail) } - () + intercept[InvalidComponent] { + manager.file(TestID)(Fail) + () + } } } - it should "return the files for a multi-file component" in { + + test("it should return the files for a multi-file component") { withManager { manager => val hashes = defineFiles(manager, TestID, "a", "b") - checksum(manager.files(TestID)(Fail)) should contain theSameElementsAs (hashes) + assert(checksum(manager.files(TestID)(Fail)).toSet == hashes.toSet) } } - it should "return the files for a single-file component" in { + + test("it should return the files for a single-file component") { withManager { manager => val hashes = defineFiles(manager, TestID, "a") - checksum(manager.files(TestID)(Fail)) should contain theSameElementsAs (hashes) + assert(checksum(manager.files(TestID)(Fail)).toSet == hashes.toSet) } } - it should "throw an exception if 'files' is called for a non-existing component" in { + + test("it should throw an exception if 'files' is called for a non-existing component") { withManager { manager => - intercept[InvalidComponent] { manager.files(TestID)(Fail) } - () + intercept[InvalidComponent] { + manager.files(TestID)(Fail) + () + } } } - it should "properly cache a file and then retrieve it to an unresolved component" in { + + test("it should properly cache a file and then retrieve it to an unresolved component") { withTemporaryDirectory { ivyHome => withManagerHome(ivyHome) { definingManager => val hash = defineFile(definingManager, TestID, "a") try { definingManager.cache(TestID) withManagerHome(ivyHome) { usingManager => - checksum(usingManager.file(TestID)(Fail)) shouldBe hash + assert(checksum(usingManager.file(TestID)(Fail)) == hash) } } finally { definingManager.clearCache(TestID) diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/CustomPomParserTest.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/CustomPomParserTest.scala index 97d5c54cb..e987b7c18 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/CustomPomParserTest.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/CustomPomParserTest.scala @@ -8,9 +8,12 @@ import sbt.librarymanagement._ import sbt.librarymanagement.ivy.{ InlineIvyConfiguration, IvyPaths } import sbt.io.IO.withTemporaryDirectory import sbt.internal.util.ConsoleLogger +import verify.BasicTestSuite -class CustomPomParserTest extends UnitSpec { - "CustomPomParser" should "resolve an artifact with packaging 'scala-jar' as a regular jar file." in { +object CustomPomParserTest extends BasicTestSuite { + test( + "CustomPomParser should resolve an artifact with packaging 'scala-jar' as a regular jar file." + ) { val log = ConsoleLogger() withTemporaryDirectory { cacheDir => val repoUrl = getClass.getResource("/test-maven-repo") @@ -28,12 +31,12 @@ class CustomPomParserTest extends UnitSpec { ivy.resolve(mrid, resolveOpts, true) } - resolveReport.hasError shouldBe false - resolveReport.getArtifacts.size() shouldBe 1 + assert(!resolveReport.hasError) + assert(resolveReport.getArtifacts.size() == 1) val artifact: IvyArtifact = resolveReport.getArtifacts.asInstanceOf[java.util.List[IvyArtifact]].get(0) - artifact.getModuleRevisionId shouldBe mrid - artifact.getExt shouldBe "jar" + assert(artifact.getModuleRevisionId == mrid) + assert(artifact.getExt == "jar") } } } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/DMSerializationSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/DMSerializationSpec.scala index 586b04531..ace394002 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/DMSerializationSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/DMSerializationSpec.scala @@ -6,47 +6,59 @@ import java.io.File import sbt.librarymanagement._ import sjsonnew.shaded.scalajson.ast.unsafe._ import sjsonnew._, support.scalajson.unsafe._ -import org.scalatest.Assertion import LibraryManagementCodec._ +import verify.BasicTestSuite -class DMSerializationSpec extends UnitSpec { - "CrossVersion.full" should "roundtrip" in { +object DMSerializationSpec extends BasicTestSuite { + test("CrossVersion.full should roundtrip") { roundtripStr(CrossVersion.full: CrossVersion) } - "CrossVersion.binary" should "roundtrip" in { + + test("CrossVersion.binary should roundtrip") { roundtripStr(CrossVersion.binary: CrossVersion) } - "CrossVersion.Disabled" should "roundtrip" in { + + test("CrossVersion.Disabled should roundtrip") { roundtrip(Disabled(): CrossVersion) } - """Artifact("foo")""" should "roundtrip" in { + + test("""Artifact("foo") should roundtrip""") { roundtrip(Artifact("foo")) } - """Artifact("foo", "sources")""" should "roundtrip" in { + + test("""Artifact("foo", "sources") should roundtrip""") { roundtrip(Artifact("foo", "sources")) } - """Artifact.pom("foo")""" should "roundtrip" in { + + test("""Artifact.pom("foo") should roundtrip""") { roundtrip(Artifact.pom("foo")) } - """Artifact("foo", url("http://example.com/"))""" should "roundtrip" in { + + test("""Artifact("foo", url("http://example.com/")) should roundtrip""") { roundtrip(Artifact("foo", new URL("http://example.com/"))) } - """Artifact("foo").extra(("key", "value"))""" should "roundtrip" in { + + test("""Artifact("foo").extra(("key", "value")) should roundtrip""") { roundtrip(Artifact("foo").extra(("key", "value"))) } - """ModuleID("org", "name", "1.0")""" should "roundtrip" in { + + test("""ModuleID("org", "name", "1.0") should roundtrip""") { roundtrip(ModuleID("org", "name", "1.0")) } - """ModuleReport(ModuleID("org", "name", "1.0"), Nil, Nil)""" should "roundtrip" in { + + test("""ModuleReport(ModuleID("org", "name", "1.0"), Nil, Nil) should roundtrip""") { roundtripStr(ModuleReport(ModuleID("org", "name", "1.0"), Vector.empty, Vector.empty)) } - "Organization artifact report" should "roundtrip" in { + + test("Organization artifact report should roundtrip") { roundtripStr(organizationArtifactReportExample) } - "Configuration report" should "roundtrip" in { + + test("Configuration report should roundtrip") { roundtripStr(configurationReportExample) } - "Update report" should "roundtrip" in { + + test("Update report should roundtrip") { roundtripStr(updateReportExample) } @@ -68,13 +80,17 @@ class DMSerializationSpec extends UnitSpec { lazy val moduleReportExample = ModuleReport(ModuleID("org", "name", "1.0"), Vector.empty, Vector.empty) - def roundtrip[A: JsonReader: JsonWriter](a: A): Assertion = - roundtripBuilder(a) { _ shouldBe _ } + def roundtrip[A: JsonReader: JsonWriter](a: A): Unit = + roundtripBuilder(a) { (x1, x2) => + assert(x1 == x2) + } - def roundtripStr[A: JsonReader: JsonWriter](a: A): Assertion = - roundtripBuilder(a) { _.toString shouldBe _.toString } + def roundtripStr[A: JsonReader: JsonWriter](a: A): Unit = + roundtripBuilder(a) { (x1, x2) => + assert(x1.toString == x2.toString) + } - def roundtripBuilder[A: JsonReader: JsonWriter](a: A)(f: (A, A) => Assertion): Assertion = { + def roundtripBuilder[A: JsonReader: JsonWriter](a: A)(f: (A, A) => Unit): Unit = { val json = isoString to (Converter toJsonUnsafe a) println(json) val obj = Converter fromJsonUnsafe [A] (isoString from json) diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/EvictionWarningSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/EvictionWarningSpec.scala index 3a90fc05a..925bdb599 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/EvictionWarningSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/EvictionWarningSpec.scala @@ -4,52 +4,269 @@ import sbt.librarymanagement._ import sbt.internal.librarymanagement.cross.CrossVersionUtil import sbt.librarymanagement.syntax._ -class EvictionWarningSpec extends BaseIvySpecification { +object EvictionWarningSpec extends BaseIvySpecification { // This is a specification to check the eviction warnings - """Eviction of non-overridden scala-library whose scalaVersion - """ should "be detected" in scalaVersionWarn1() - it should "not be detected if it's disabled" in scalaVersionWarn2() - it should "print out message about the eviction" in scalaVersionWarn3() - it should "print out message about the eviction with callers" in scalaVersionWarn4() - it should "print out summary about the eviction if warn eviction summary enabled" in scalaVersionWarn5() + import sbt.util.ShowLines._ + def scalaVersionDeps = Vector(scala2102, akkaActor230) - """Non-eviction of overridden scala-library whose scalaVersion - """ should "not be detected if it's enabled" in scalaVersionNoWarn1() - it should "not be detected if it's disabled" in scalaVersionNoWarn2() + test("Eviction of non-overridden scala-library whose scalaVersion should be detected") { + val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2"), overrideScalaVersion = false) + val report = ivyUpdate(m) + assert(EvictionWarning(m, fullOptions, report).scalaEvictions.size == 1) + } - """Including two (suspect) binary incompatible Java libraries to direct dependencies - """ should "be detected as eviction" in javaLibWarn1() - it should "not be detected if it's disabled" in javaLibWarn2() - it should "print out message about the eviction" in javaLibWarn3() - it should "print out message about the eviction with callers" in javaLibWarn4() - it should "print out summary about the eviction if warn eviction summary enabled" in javaLibWarn5() + test("it should not be detected if it's disabled") { + val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2"), overrideScalaVersion = false) + val report = ivyUpdate(m) + assert( + EvictionWarning(m, fullOptions.withWarnScalaVersionEviction(false), report).scalaEvictions.size == 0 + ) + } - """Including two (suspect) binary compatible Java libraries to direct dependencies - """ should "not be detected as eviction" in javaLibNoWarn1() - it should "not print out message about the eviction" in javaLibNoWarn2() + test("it should print out message about the eviction") { + val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2"), overrideScalaVersion = false) + val report = ivyUpdate(m) + assert( + EvictionWarning(m, fullOptions.withShowCallers(false), report).lines == + List( + "Scala version was updated by one of library dependencies:", + "\t* org.scala-lang:scala-library:2.10.3 is selected over 2.10.2", + "", + "To force scalaVersion, add the following:", + "\tscalaModuleInfo ~= (_.map(_.withOverrideScalaVersion(true)))" + ) + ) + } - """Including two (suspect) transitively binary incompatible Java libraries to direct dependencies - """ should "be detected as eviction" in javaLibTransitiveWarn2() + test("it should print out message about the eviction with callers") { + val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2"), overrideScalaVersion = false) + val report = ivyUpdate(m) + assert( + EvictionWarning(m, fullOptions, report).lines == + List( + "Scala version was updated by one of library dependencies:", + "\t* org.scala-lang:scala-library:2.10.3 is selected over 2.10.2", + "\t +- com.typesafe.akka:akka-actor_2.10:2.3.0 (depends on 2.10.3)", + "\t +- com.example:foo:0.1.0 (depends on 2.10.2)", + "", + "To force scalaVersion, add the following:", + "\tscalaModuleInfo ~= (_.map(_.withOverrideScalaVersion(true)))" + ) + ) + } - //it should "print out message about the eviction if it's enabled" in javaLibTransitiveWarn3() + test("it should print out summary about the eviction if warn eviction summary enabled") { + val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2"), overrideScalaVersion = false) + val report = ivyUpdate(m) + assert( + EvictionWarning(m, EvictionWarningOptions.summary, report).lines == + List( + "There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings." + ) + ) + } - """Including two (suspect) binary incompatible Scala libraries to direct dependencies - """ should "be detected as eviction" in scalaLibWarn1() - it should "print out message about the eviction" in scalaLibWarn2() - it should "print out summary about the eviction if warn eviction summary enabled" in scalaLibWarn3() + test( + """Non-eviction of overridden scala-library whose scalaVersion should "not be detected if it's enabled"""" + ) { + val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2")) + val report = ivyUpdate(m) + assert(EvictionWarning(m, fullOptions, report).scalaEvictions.size == 0) + } - """Including two (suspect) binary compatible Scala libraries to direct dependencies - """ should "not be detected as eviction" in scalaLibNoWarn1() - it should "not print out message about the eviction" in scalaLibNoWarn2() - it should "not print out summary about the eviction even if warn eviction summary enabled" in scalaLibNoWarn3() + test("it should not be detected if it's disabled") { + val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2")) + val report = ivyUpdate(m) + assert( + EvictionWarning(m, fullOptions.withWarnScalaVersionEviction(false), report).scalaEvictions.size == 0 + ) + } - """Including two (suspect) transitively binary incompatible Scala libraries to direct dependencies - """ should "be detected as eviction" in scalaLibTransitiveWarn2() - it should "print out message about the eviction if it's enabled" in scalaLibTransitiveWarn3() - it should "print out summary about the eviction if warn eviction summary enabled" in scalaLibTransitiveWarn4() + test( + """Including two (suspect) binary incompatible Java libraries to direct dependencies should be detected as eviction""" + ) { + val m = module(defaultModuleId, javaLibDirectDeps, Some("2.10.3")) + val report = ivyUpdate(m) + assert(EvictionWarning(m, fullOptions, report).reportedEvictions.size == 1) + } - "Comparing sbt 0.x" should "use Second Segment Variation semantics" in { + test("it should not be detected if it's disabled") { + val m = module(defaultModuleId, javaLibDirectDeps, Some("2.10.3")) + val report = ivyUpdate(m) + assert( + EvictionWarning( + m, + fullOptions + .withWarnDirectEvictions(false) + .withWarnTransitiveEvictions(false), + report + ).reportedEvictions.size == 0 + ) + } + + test("it should print out message about the eviction") { + val m = module(defaultModuleId, javaLibDirectDeps, Some("2.10.3")) + val report = ivyUpdate(m) + assert( + EvictionWarning(m, fullOptions, report).lines == + List( + "Found version conflict(s) in library dependencies; some are suspected to be binary incompatible:", + "", + "\t* commons-io:commons-io:2.4 is selected over 1.4", + "\t +- com.example:foo:0.1.0 (depends on 1.4)", + "" + ) + ) + } + + test("it should print out message about the eviction with callers") { + val m = module(defaultModuleId, javaLibDirectDeps, Some("2.10.3")) + val report = ivyUpdate(m) + assert( + EvictionWarning(m, fullOptions.withShowCallers(true), report).lines == + List( + "Found version conflict(s) in library dependencies; some are suspected to be binary incompatible:", + "", + "\t* commons-io:commons-io:2.4 is selected over 1.4", + "\t +- com.example:foo:0.1.0 (depends on 1.4)", + "" + ) + ) + } + + test("it should print out summary about the eviction if warn eviction summary enabled") { + val m = module(defaultModuleId, javaLibDirectDeps, Some("2.10.3")) + val report = ivyUpdate(m) + assert( + EvictionWarning(m, EvictionWarningOptions.summary, report).lines == + List( + "There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings." + ) + ) + } + + test( + """Including two (suspect) binary compatible Java libraries to direct dependencies should not be detected as eviction""" + ) { + val deps = Vector(commonsIo14, commonsIo13) + val m = module(defaultModuleId, deps, Some("2.10.3")) + val report = ivyUpdate(m) + assert(EvictionWarning(m, fullOptions, report).reportedEvictions.size == 0) + } + + test("it should not print out message about the eviction") { + val deps = Vector(commonsIo14, commonsIo13) + val m = module(defaultModuleId, deps, Some("2.10.3")) + val report = ivyUpdate(m) + assert(EvictionWarning(m, fullOptions, report).lines == Nil) + } + + test( + """Including two (suspect) transitively binary incompatible Java libraries to direct dependencies should be detected as eviction""" + ) { + val m = module(defaultModuleId, javaLibTransitiveDeps, Some("2.10.3")) + val report = ivyUpdate(m) + assert(EvictionWarning(m, fullOptions, report).reportedEvictions.size == 1) + } + + test( + """Including two (suspect) binary incompatible Scala libraries to direct dependencies should be detected as eviction""" + ) { + val deps = Vector(scala2104, akkaActor214, akkaActor234) + val m = module(defaultModuleId, deps, Some("2.10.4")) + val report = ivyUpdate(m) + assert(EvictionWarning(m, fullOptions, report).reportedEvictions.size == 1) + } + + test("it should print out message about the eviction") { + val deps = Vector(scala2104, akkaActor214, akkaActor234) + val m = module(defaultModuleId, deps, Some("2.10.4")) + val report = ivyUpdate(m) + assert( + EvictionWarning(m, fullOptions, report).lines == + List( + "Found version conflict(s) in library dependencies; some are suspected to be binary incompatible:", + "", + "\t* com.typesafe.akka:akka-actor_2.10:2.3.4 is selected over 2.1.4", + "\t +- com.example:foo:0.1.0 (depends on 2.1.4)", + "" + ) + ) + } + + test("it should print out summary about the eviction if warn eviction summary enabled") { + val deps = Vector(scala2104, akkaActor214, akkaActor234) + val m = module(defaultModuleId, deps, Some("2.10.4")) + val report = ivyUpdate(m) + assert( + EvictionWarning(m, EvictionWarningOptions.summary, report).lines == + List( + "There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings." + ) + ) + } + + test( + """Including two (suspect) binary compatible Scala libraries to direct dependencies should not be detected as eviction""" + ) { + val deps = Vector(scala2104, akkaActor230, akkaActor234) + val m = module(defaultModuleId, deps, Some("2.10.4")) + val report = ivyUpdate(m) + assert(EvictionWarning(m, fullOptions, report).reportedEvictions.size == 0) + } + + test("it should not print out message about the eviction") { + val deps = Vector(scala2104, akkaActor230, akkaActor234) + val m = module(defaultModuleId, deps, Some("2.10.4")) + val report = ivyUpdate(m) + assert(EvictionWarning(m, fullOptions, report).lines == Nil) + } + + test("it should not print out summary about the eviction even if warn eviction summary enabled") { + val deps = Vector(scala2104, akkaActor230, akkaActor234) + val m = module(defaultModuleId, deps, Some("2.10.4")) + val report = ivyUpdate(m) + assert(EvictionWarning(m, EvictionWarningOptions.summary, report).lines == Nil) + } + + test( + """Including two (suspect) transitively binary incompatible Scala libraries to direct dependencies should be detected as eviction""" + ) { + val m = module(defaultModuleId, scalaLibTransitiveDeps, Some("2.10.4")) + val report = ivyUpdate(m) + assert(EvictionWarning(m, fullOptions, report).reportedEvictions.size == 1) + } + + test("it should print out message about the eviction if it's enabled") { + val m = module(defaultModuleId, scalaLibTransitiveDeps, Some("2.10.4")) + val report = ivyUpdate(m) + assert( + EvictionWarning(m, fullOptions, report).lines == + List( + "Found version conflict(s) in library dependencies; some are suspected to be binary incompatible:", + "", + "\t* com.typesafe.akka:akka-actor_2.10:2.3.4 is selected over 2.1.4", + "\t +- com.typesafe.akka:akka-remote_2.10:2.3.4 (depends on 2.3.4)", + "\t +- org.w3:banana-rdf_2.10:0.4 (depends on 2.1.4)", + "\t +- org.w3:banana-sesame_2.10:0.4 (depends on 2.1.4)", + "" + ) + ) + } + + test("it should print out summary about the eviction if warn eviction summary enabled") { + val m = module(defaultModuleId, scalaLibTransitiveDeps, Some("2.10.4")) + val report = ivyUpdate(m) + assert( + EvictionWarning(m, EvictionWarningOptions.summary, report).lines == + List( + "There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings." + ) + ) + } + + test("Comparing sbt 0.x should use Second Segment Variation semantics") { val m1 = "org.scala-sbt" % "util-logging" % "0.13.16" val m2 = "org.scala-sbt" % "util-logging" % "0.13.1" assert( @@ -57,7 +274,7 @@ class EvictionWarningSpec extends BaseIvySpecification { ) } - "Comparing sbt 1.x" should "use Semantic Versioning semantics" in { + test("Comparing sbt 1.x should use Semantic Versioning semantics") { val m1 = "org.scala-sbt" % "util-logging_2.12" % "1.0.0" val m2 = "org.scala-sbt" % "util-logging_2.12" % "1.1.0" assert( @@ -91,244 +308,9 @@ class EvictionWarningSpec extends BaseIvySpecification { ModuleID("com.typesafe.akka", "akka-remote", "2.3.4").withConfigurations(Some("compile")) cross CrossVersion.binary // uses akka-actor 2.3.4 def fullOptions = EvictionWarningOptions.full - - import sbt.util.ShowLines._ - - def scalaVersionDeps = Vector(scala2102, akkaActor230) - - def scalaVersionWarn1() = { - val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2"), overrideScalaVersion = false) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).scalaEvictions should have size (1) - } - - def scalaVersionWarn2() = { - val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2"), overrideScalaVersion = false) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions.withWarnScalaVersionEviction(false), report).scalaEvictions should have size (0) - } - - def scalaVersionWarn3() = { - val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2"), overrideScalaVersion = false) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions.withShowCallers(false), report).lines shouldBe - List( - "Scala version was updated by one of library dependencies:", - "\t* org.scala-lang:scala-library:2.10.3 is selected over 2.10.2", - "", - "To force scalaVersion, add the following:", - "\tscalaModuleInfo ~= (_.map(_.withOverrideScalaVersion(true)))" - ) - } - - def scalaVersionWarn4() = { - val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2"), overrideScalaVersion = false) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).lines shouldBe - List( - "Scala version was updated by one of library dependencies:", - "\t* org.scala-lang:scala-library:2.10.3 is selected over 2.10.2", - "\t +- com.typesafe.akka:akka-actor_2.10:2.3.0 (depends on 2.10.3)", - "\t +- com.example:foo:0.1.0 (depends on 2.10.2)", - "", - "To force scalaVersion, add the following:", - "\tscalaModuleInfo ~= (_.map(_.withOverrideScalaVersion(true)))" - ) - } - - def scalaVersionWarn5() = { - val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2"), overrideScalaVersion = false) - val report = ivyUpdate(m) - EvictionWarning(m, EvictionWarningOptions.summary, report).lines shouldBe - List( - "There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings." - ) - } - - def scalaVersionNoWarn1() = { - val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).scalaEvictions should have size (0) - } - - def scalaVersionNoWarn2() = { - val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions.withWarnScalaVersionEviction(false), report).scalaEvictions should have size (0) - } - def javaLibDirectDeps = Vector(commonsIo14, commonsIo24) - - def javaLibWarn1() = { - val m = module(defaultModuleId, javaLibDirectDeps, Some("2.10.3")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).reportedEvictions should have size (1) - } - - def javaLibWarn2() = { - val m = module(defaultModuleId, javaLibDirectDeps, Some("2.10.3")) - val report = ivyUpdate(m) - EvictionWarning( - m, - fullOptions - .withWarnDirectEvictions(false) - .withWarnTransitiveEvictions(false), - report - ).reportedEvictions should have size (0) - } - - def javaLibWarn3() = { - val m = module(defaultModuleId, javaLibDirectDeps, Some("2.10.3")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).lines shouldBe - List( - "Found version conflict(s) in library dependencies; some are suspected to be binary incompatible:", - "", - "\t* commons-io:commons-io:2.4 is selected over 1.4", - "\t +- com.example:foo:0.1.0 (depends on 1.4)", - "" - ) - } - - def javaLibWarn4() = { - val m = module(defaultModuleId, javaLibDirectDeps, Some("2.10.3")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions.withShowCallers(true), report).lines shouldBe - List( - "Found version conflict(s) in library dependencies; some are suspected to be binary incompatible:", - "", - "\t* commons-io:commons-io:2.4 is selected over 1.4", - "\t +- com.example:foo:0.1.0 (depends on 1.4)", - "" - ) - } - - def javaLibWarn5() = { - val m = module(defaultModuleId, javaLibDirectDeps, Some("2.10.3")) - val report = ivyUpdate(m) - EvictionWarning(m, EvictionWarningOptions.summary, report).lines shouldBe - List( - "There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings." - ) - } - - def javaLibNoWarn1() = { - val deps = Vector(commonsIo14, commonsIo13) - val m = module(defaultModuleId, deps, Some("2.10.3")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).reportedEvictions should have size (0) - } - - def javaLibNoWarn2() = { - val deps = Vector(commonsIo14, commonsIo13) - val m = module(defaultModuleId, deps, Some("2.10.3")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).lines shouldBe Nil - } - def javaLibTransitiveDeps = Vector(unfilteredUploads080, bnfparser10) - - def javaLibTransitiveWarn2() = { - val m = module(defaultModuleId, javaLibTransitiveDeps, Some("2.10.3")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).reportedEvictions should have size (1) - } - - def javaLibTransitiveWarn3() = { - val m = module(defaultModuleId, javaLibTransitiveDeps, Some("2.10.3")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).lines shouldBe - List( - "There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings.", - "Here are some of the libraries that were evicted:", - "\t* commons-io:commons-io:1.4 -> 2.4 (caller: ca.gobits.bnf:bnfparser:1.0, net.databinder:unfiltered-uploads_2.10:0.8.0)" - ) - } - - def scalaLibWarn1() = { - val deps = Vector(scala2104, akkaActor214, akkaActor234) - val m = module(defaultModuleId, deps, Some("2.10.4")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).reportedEvictions should have size (1) - } - - def scalaLibWarn2() = { - val deps = Vector(scala2104, akkaActor214, akkaActor234) - val m = module(defaultModuleId, deps, Some("2.10.4")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).lines shouldBe - List( - "Found version conflict(s) in library dependencies; some are suspected to be binary incompatible:", - "", - "\t* com.typesafe.akka:akka-actor_2.10:2.3.4 is selected over 2.1.4", - "\t +- com.example:foo:0.1.0 (depends on 2.1.4)", - "" - ) - } - - def scalaLibWarn3() = { - val deps = Vector(scala2104, akkaActor214, akkaActor234) - val m = module(defaultModuleId, deps, Some("2.10.4")) - val report = ivyUpdate(m) - EvictionWarning(m, EvictionWarningOptions.summary, report).lines shouldBe - List( - "There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings." - ) - } - - def scalaLibNoWarn1() = { - val deps = Vector(scala2104, akkaActor230, akkaActor234) - val m = module(defaultModuleId, deps, Some("2.10.4")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).reportedEvictions should have size (0) - } - - def scalaLibNoWarn2() = { - val deps = Vector(scala2104, akkaActor230, akkaActor234) - val m = module(defaultModuleId, deps, Some("2.10.4")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).lines shouldBe Nil - } - - def scalaLibNoWarn3() = { - val deps = Vector(scala2104, akkaActor230, akkaActor234) - val m = module(defaultModuleId, deps, Some("2.10.4")) - val report = ivyUpdate(m) - EvictionWarning(m, EvictionWarningOptions.summary, report).lines shouldBe Nil - } - def scalaLibTransitiveDeps = Vector(scala2104, bananaSesame04, akkaRemote234) - - def scalaLibTransitiveWarn2() = { - val m = module(defaultModuleId, scalaLibTransitiveDeps, Some("2.10.4")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).reportedEvictions should have size (1) - } - - def scalaLibTransitiveWarn3() = { - val m = module(defaultModuleId, scalaLibTransitiveDeps, Some("2.10.4")) - val report = ivyUpdate(m) - EvictionWarning(m, fullOptions, report).lines shouldBe - List( - "Found version conflict(s) in library dependencies; some are suspected to be binary incompatible:", - "", - "\t* com.typesafe.akka:akka-actor_2.10:2.3.4 is selected over 2.1.4", - "\t +- com.typesafe.akka:akka-remote_2.10:2.3.4 (depends on 2.3.4)", - "\t +- org.w3:banana-rdf_2.10:0.4 (depends on 2.1.4)", - "\t +- org.w3:banana-sesame_2.10:0.4 (depends on 2.1.4)", - "" - ) - } - - def scalaLibTransitiveWarn4() = { - val m = module(defaultModuleId, scalaLibTransitiveDeps, Some("2.10.4")) - val report = ivyUpdate(m) - EvictionWarning(m, EvictionWarningOptions.summary, report).lines shouldBe - List( - "There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings." - ) - } - def dummyScalaModuleInfo(v: String): ScalaModuleInfo = ScalaModuleInfo( scalaFullVersion = v, diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/FakeResolverSpecification.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/FakeResolverSpecification.scala index fdb5cc413..89095a51c 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/FakeResolverSpecification.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/FakeResolverSpecification.scala @@ -6,7 +6,7 @@ import java.io.File import sbt.librarymanagement.{ ModuleID, RawRepository, Resolver, UpdateReport, ResolveException } -class FakeResolverSpecification extends BaseIvySpecification { +object FakeResolverSpecification extends BaseIvySpecification { import FakeResolver._ val myModule = @@ -17,36 +17,42 @@ class FakeResolverSpecification extends BaseIvySpecification { val nonExisting = ModuleID("com.example", "does-not-exist", "1.2.3").withConfigurations(Some("compile")) - "The FakeResolver" should "find modules with only one artifact" in { + test("The FakeResolver should find modules with only one artifact") { val m = getModule(myModule) val report = ivyUpdate(m) val allFiles = getAllFiles(report) - report.allModules.length shouldBe 1 - report.configurations.length shouldBe 3 - allFiles.toSet.size shouldBe 1 - allFiles(1).getName shouldBe "artifact1-0.0.1-SNAPSHOT.jar" + assert(report.allModules.length == 1) + assert(report.configurations.length == 3) + assert(allFiles.toSet.size == 1) + assert(allFiles(1).getName == "artifact1-0.0.1-SNAPSHOT.jar") } - it should "find modules with more than one artifact" in { + test("it should find modules with more than one artifact") { val m = getModule(example) val report = ivyUpdate(m) val allFiles = getAllFiles(report).toSet - report.allModules.length shouldBe 1 - report.configurations.length shouldBe 3 - allFiles.toSet.size shouldBe 2 - allFiles map (_.getName) shouldBe Set("artifact1-1.0.0.jar", "artifact2-1.0.0.txt") + assert(report.allModules.length == 1) + assert(report.configurations.length == 3) + assert(allFiles.toSet.size == 2) + assert(allFiles.map(_.getName) == Set("artifact1-1.0.0.jar", "artifact2-1.0.0.txt")) } - it should "fail gracefully when asked for unknown modules" in { + test("it should fail gracefully when asked for unknown modules") { val m = getModule(nonExisting) - a[ResolveException] should be thrownBy ivyUpdate(m) + intercept[ResolveException] { + ivyUpdate(m) + () + } } - it should "fail gracefully when some artifacts cannot be found" in { + test("it should fail gracefully when some artifacts cannot be found") { val m = getModule(anotherExample) - the[ResolveException] thrownBy ivyUpdate(m) should have message "download failed: com.example#another-example;1.0.0!non-existing.txt" + intercept[ResolveException] { + ivyUpdate(m) + () + } } private def artifact1 = new File(getClass.getResource("/artifact1.jar").toURI.getPath) diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/FrozenModeSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/FrozenModeSpec.scala index c6620bee7..cae7b3f48 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/FrozenModeSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/FrozenModeSpec.scala @@ -4,7 +4,7 @@ import sbt.librarymanagement._ import sbt.librarymanagement.ivy.UpdateOptions import sbt.librarymanagement.syntax._ -class FrozenModeSpec extends BaseIvySpecification { +object FrozenModeSpec extends BaseIvySpecification { private final val targetDir = Some(currentDependency) private final val onlineConf = makeUpdateConfiguration(false, targetDir) private final val frozenConf = makeUpdateConfiguration(false, targetDir).withFrozen(true) @@ -26,7 +26,7 @@ class FrozenModeSpec extends BaseIvySpecification { "com.lihaoyi" % "sourcecode_2.12" % "0.1.3" % "compile" ) - it should "fail when artifacts are missing in the cache" in { + test("fail when artifacts are missing in the cache") { cleanIvyCache() def update(module: IvySbt#Module, conf: UpdateConfiguration) = IvyActions.updateEither(module, conf, warningConf, log) diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/InclExclSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/InclExclSpec.scala index 1c35fc007..d05f115ef 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/InclExclSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/InclExclSpec.scala @@ -2,10 +2,53 @@ package sbt.internal.librarymanagement import sbt.librarymanagement._ import sbt.librarymanagement.syntax._ -import org.scalatest.Assertion import DependencyBuilders.OrganizationArtifactName -class InclExclSpec extends BaseIvySpecification { +object InclExclSpec extends BaseIvySpecification { + val scala210 = Some("2.10.4") + test("it should exclude any version of lift-json via a new exclusion rule") { + val toExclude = ExclusionRule("net.liftweb", "lift-json_2.10") + val report = getIvyReport(createLiftDep(toExclude), scala210) + testLiftJsonIsMissing(report) + } + + test("it should exclude any version of lift-json with explicit Scala version") { + val excluded: OrganizationArtifactName = "net.liftweb" % "lift-json_2.10" + val report = getIvyReport(createLiftDep(excluded), scala210) + testLiftJsonIsMissing(report) + } + + test("it should exclude any version of cross-built lift-json") { + val excluded: OrganizationArtifactName = "net.liftweb" %% "lift-json" + val report = getIvyReport(createLiftDep(excluded), scala210) + testLiftJsonIsMissing(report) + } + + val scala2122 = Some("2.12.2") + test("it should exclude a concrete version of lift-json when it's full cross version") { + val excluded: ModuleID = ("org.scalameta" % "scalahost" % "1.7.0").cross(CrossVersion.full) + val report = getIvyReport(createMetaDep(excluded), scala2122) + testScalahostIsMissing(report) + } + + test("it should exclude any version of lift-json when it's full cross version") { + val excluded = new OrganizationArtifactName("net.liftweb", "lift-json", CrossVersion.full) + val report = getIvyReport(createMetaDep(excluded), scala2122) + testScalahostIsMissing(report) + } + + test("it should exclude any version of scala-library via * artifact id") { + val toExclude = ExclusionRule("org.scala-lang", "*") + val report = getIvyReport(createLiftDep(toExclude), scala210) + testScalaLibraryIsMissing(report) + } + + test("it should exclude any version of scala-library via * org id") { + val toExclude = ExclusionRule("*", "scala-library") + val report = getIvyReport(createLiftDep(toExclude), scala210) + testScalaLibraryIsMissing(report) + } + def createLiftDep(toExclude: ExclusionRule): ModuleID = ("net.liftweb" %% "lift-mapper" % "2.6-M4" % "compile").excludeAll(toExclude) @@ -20,68 +63,24 @@ class InclExclSpec extends BaseIvySpecification { ivyUpdate(ivyModule) } - def testLiftJsonIsMissing(report: UpdateReport): Assertion = { + def testLiftJsonIsMissing(report: UpdateReport): Unit = { assert( !report.allModules.exists(_.name.contains("lift-json")), "lift-json has not been excluded." ) } - def testScalaLibraryIsMissing(report: UpdateReport): Assertion = { + def testScalaLibraryIsMissing(report: UpdateReport): Unit = { assert( !report.allModules.exists(_.name.contains("scala-library")), "scala-library has not been excluded." ) } - def testScalahostIsMissing(report: UpdateReport): Assertion = { + def testScalahostIsMissing(report: UpdateReport): Unit = { assert( !report.allModules.exists(_.name.contains("scalahost")), "scalahost has not been excluded." ) } - - val scala210 = Some("2.10.4") - it should "exclude any version of lift-json via a new exclusion rule" in { - val toExclude = ExclusionRule("net.liftweb", "lift-json_2.10") - val report = getIvyReport(createLiftDep(toExclude), scala210) - testLiftJsonIsMissing(report) - } - - it should "exclude any version of lift-json with explicit Scala version" in { - val excluded: OrganizationArtifactName = "net.liftweb" % "lift-json_2.10" - val report = getIvyReport(createLiftDep(excluded), scala210) - testLiftJsonIsMissing(report) - } - - it should "exclude any version of cross-built lift-json" in { - val excluded: OrganizationArtifactName = "net.liftweb" %% "lift-json" - val report = getIvyReport(createLiftDep(excluded), scala210) - testLiftJsonIsMissing(report) - } - - val scala2122 = Some("2.12.2") - it should "exclude a concrete version of lift-json when it's full cross version" in { - val excluded: ModuleID = ("org.scalameta" % "scalahost" % "1.7.0").cross(CrossVersion.full) - val report = getIvyReport(createMetaDep(excluded), scala2122) - testScalahostIsMissing(report) - } - - it should "exclude any version of lift-json when it's full cross version" in { - val excluded = new OrganizationArtifactName("net.liftweb", "lift-json", CrossVersion.full) - val report = getIvyReport(createMetaDep(excluded), scala2122) - testScalahostIsMissing(report) - } - - it should "exclude any version of scala-library via * artifact id" in { - val toExclude = ExclusionRule("org.scala-lang", "*") - val report = getIvyReport(createLiftDep(toExclude), scala210) - testScalaLibraryIsMissing(report) - } - - it should "exclude any version of scala-library via * org id" in { - val toExclude = ExclusionRule("*", "scala-library") - val report = getIvyReport(createLiftDep(toExclude), scala210) - testScalaLibraryIsMissing(report) - } } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/InconsistentDuplicateSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/InconsistentDuplicateSpec.scala index 8ba690221..db9344070 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/InconsistentDuplicateSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/InconsistentDuplicateSpec.scala @@ -1,23 +1,26 @@ package sbt.internal.librarymanagement import sbt.librarymanagement._ +import verify.BasicTestSuite // This is a specification to check the inconsistent duplicate warnings -class InconsistentDuplicateSpec extends UnitSpec { - "Duplicate with different version" should "be warned" in { - IvySbt.inconsistentDuplicateWarning(Seq(akkaActor214, akkaActor230)) shouldBe - List( - "Multiple dependencies with the same organization/name but different versions. To avoid conflict, pick one version:", - " * com.typesafe.akka:akka-actor:(2.1.4, 2.3.0)" - ) +object InconsistentDuplicateSpec extends BasicTestSuite { + test("Duplicate with different version should be warned") { + assert( + IvySbt.inconsistentDuplicateWarning(Seq(akkaActor214, akkaActor230)) == + List( + "Multiple dependencies with the same organization/name but different versions. To avoid conflict, pick one version:", + " * com.typesafe.akka:akka-actor:(2.1.4, 2.3.0)" + ) + ) } - it should "not be warned if in different configurations" in { - IvySbt.inconsistentDuplicateWarning(Seq(akkaActor214, akkaActor230Test)) shouldBe Nil + test("it should not be warned if in different configurations") { + assert(IvySbt.inconsistentDuplicateWarning(Seq(akkaActor214, akkaActor230Test)) == Nil) } - "Duplicate with same version" should "not be warned" in { - IvySbt.inconsistentDuplicateWarning(Seq(akkaActor230Test, akkaActor230)) shouldBe Nil + test("Duplicate with same version should not be warned") { + assert(IvySbt.inconsistentDuplicateWarning(Seq(akkaActor230Test, akkaActor230)) == Nil) } def akkaActor214 = diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala index 468b9fef6..97515d9ef 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala @@ -5,7 +5,7 @@ import sbt.librarymanagement._ import sbt.librarymanagement.syntax._ import InternalDefaults._ -class IvyRepoSpec extends BaseIvySpecification { +object IvyRepoSpec extends BaseIvySpecification { val ourModuleID = ModuleID("com.example", "foo", "0.1.0").withConfigurations(Some("compile")) @@ -21,7 +21,9 @@ class IvyRepoSpec extends BaseIvySpecification { ) } - "ivyUpdate from ivy repository" should "resolve only binary artifact from module which also contains a sources artifact under the same configuration." in { + test( + "ivyUpdate from ivy repository should resolve only binary artifact from module which also contains a sources artifact under the same configuration." + ) { cleanIvyCache() val m = makeModuleForDepWithSources @@ -33,13 +35,15 @@ class IvyRepoSpec extends BaseIvySpecification { case Some(Seq(mr)) => inside(mr.artifacts) { case Seq((ar, _)) => - ar.`type` shouldBe "jar" - ar.extension shouldBe "jar" + assert(ar.`type` == "jar") + assert(ar.extension == "jar") } } } - it should "resolve only sources artifact of an acceptable artifact type, \"src\", when calling updateClassifiers." in { + test( + "it should resolve only sources artifact of an acceptable artifact type, \"src\", when calling updateClassifiers." + ) { cleanIvyCache() val m = makeModuleForDepWithSources @@ -90,9 +94,9 @@ class IvyRepoSpec extends BaseIvySpecification { case Some(Seq(mr)) => inside(mr.artifacts) { case Seq((ar, _)) => - ar.name shouldBe "libmodule-source" - ar.`type` shouldBe "src" - ar.extension shouldBe "jar" + assert(ar.name == "libmodule-source") + assert(ar.`type` == "src") + assert(ar.extension == "jar") } } } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/MakePomSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/MakePomSpec.scala index 886b2018e..30c36e093 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/MakePomSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/MakePomSpec.scala @@ -1,79 +1,87 @@ package sbt.internal.librarymanagement import sbt.internal.util.ConsoleLogger +import verify.BasicTestSuite // http://ant.apache.org/ivy/history/2.3.0/ivyfile/dependency.html // http://maven.apache.org/enforcer/enforcer-rules/versionRanges.html -class MakePomSpec extends UnitSpec { +object MakePomSpec extends BasicTestSuite { // This is a specification to check the Ivy revision number conversion to pom. - "1.0" should "convert to 1.0" in convertTo("1.0", "1.0") + test("1.0 should convert to 1.0") { + convertTo("1.0", "1.0") + } - "[1.0,2.0]" should "convert to [1.0,2.0]" in { + test("[1.0,2.0] should convert to [1.0,2.0]") { convertTo("[1.0,2.0]", "[1.0,2.0]") } - "[1.0,2.0[" should "convert to [1.0,2.0)" in { + test("[1.0,2.0[ should convert to [1.0,2.0)") { convertTo("[1.0,2.0[", "[1.0,2.0)") } - "]1.0,2.0]" should "convert to (1.0,2.0]" in { + test("]1.0,2.0] should convert to (1.0,2.0]") { convertTo("]1.0,2.0]", "(1.0,2.0]") } - "]1.0,2.0[" should "convert to (1.0,2.0)" in { + test("]1.0,2.0[ should convert to (1.0,2.0)") { convertTo("]1.0,2.0[", "(1.0,2.0)") } - "[1.0,)" should "convert to [1.0,)" in { + test("[1.0,) should convert to [1.0,)") { convertTo("[1.0,)", "[1.0,)") } - "]1.0,)" should "convert to (1.0,)" in { + test("]1.0,) should convert to (1.0,)") { convertTo("]1.0,)", "(1.0,)") } - "(,2.0]" should "convert to (,2.0]" in { + test("(,2.0] should convert to (,2.0]") { convertTo("(,2.0]", "(,2.0]") } - "(,2.0[" should "convert to (,2.0)" in { + test("(,2.0[ should convert to (,2.0)") { convertTo("(,2.0[", "(,2.0)") } - "1.+" should "convert to [1,2)" in { + test("1.+ should convert to [1,2)") { convertTo("1.+", "[1,2)") } - "1.2.3.4.+" should "convert to [1.2.3.4,1.2.3.5)" in { + test("1.2.3.4.+ should convert to [1.2.3.4,1.2.3.5)") { convertTo("1.2.3.4.+", "[1.2.3.4,1.2.3.5)") } - "12.31.42.+" should "convert to [12.31.42,12.31.43)" in { + test("12.31.42.+ should convert to [12.31.42,12.31.43)") { convertTo("12.31.42.+", "[12.31.42,12.31.43)") } - "1.1+" should "convert to [1.1,1.2),[1.10,1.20),[1.100,1.200),[1.1000,1.2000),[1.10000,1.20000)" in { + test( + "1.1+ should convert to [1.1,1.2),[1.10,1.20),[1.100,1.200),[1.1000,1.2000),[1.10000,1.20000)" + ) { convertTo("1.1+", "[1.1,1.2),[1.10,1.20),[1.100,1.200),[1.1000,1.2000),[1.10000,1.20000)") } - "1+" should "convert to [1,2),[10,20),[100,200),[1000,2000),[10000,20000)" in { + test("1+ should convert to [1,2),[10,20),[100,200),[1000,2000),[10000,20000)") { convertTo("1+", "[1,2),[10,20),[100,200),[1000,2000),[10000,20000)") } - "+" should "convert to [0,)" in convertTo("+", "[0,)") + test("+ should convert to [0,)") { + convertTo("+", "[0,)") + } - "foo+" should "convert to foo+" in beParsedAsError("foo+") + test("foo+ should convert to foo+") { + beParsedAsError("foo+") + } val mp = new MakePom(ConsoleLogger()) def convertTo(s: String, expected: String): Unit = { - MakePom.makeDependencyVersion(s) shouldBe expected - () + assert(MakePom.makeDependencyVersion(s) == expected) } def beParsedAsError(s: String): Unit = { intercept[Throwable] { MakePom.makeDependencyVersion(s) + () } - () } } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/ManagedChecksumsSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/ManagedChecksumsSpec.scala index 7ef540583..e9e133d4c 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/ManagedChecksumsSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/ManagedChecksumsSpec.scala @@ -7,7 +7,7 @@ import sbt.librarymanagement._ import sbt.librarymanagement.ivy._ import sbt.io.IO -class ManagedChecksumsSpec extends BaseIvySpecification { +object ManagedChecksumsSpec extends BaseIvySpecification { private final def targetDir = Some(currentDependency) private final def onlineConf = makeUpdateConfiguration(false, targetDir) private final def warningConf = UnresolvedWarningConfiguration() @@ -47,7 +47,7 @@ class ManagedChecksumsSpec extends BaseIvySpecification { assert(shaFile.exists(), s"The checksum $Checksum for $file does not exist") } - "Managed checksums" should "should download the checksum files" in { + test("Managed checksums should should download the checksum files") { cleanAll() val updateOptions = UpdateOptions() val toResolve = module(defaultModuleId, dependencies, None, updateOptions) diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/MergeDescriptorSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/MergeDescriptorSpec.scala index ded1a9f15..898402224 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/MergeDescriptorSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/MergeDescriptorSpec.scala @@ -5,8 +5,8 @@ import sbt.librarymanagement._ import sbt.librarymanagement.ivy.UpdateOptions import sbt.internal.librarymanagement.ivyint._ -class MergeDescriptorSpec extends BaseIvySpecification { - "Merging duplicate dependencies" should "work" in { +object MergeDescriptorSpec extends BaseIvySpecification { + test("Merging duplicate dependencies should work") { cleanIvyCache() val m = module( ModuleID("com.example", "foo", "0.1.0").withConfigurations(Some("compile")), @@ -25,8 +25,8 @@ class MergeDescriptorSpec extends BaseIvySpecification { val a1: DependencyArtifactDescriptor = arts.toList(1) val configs0 = a0.getConfigurations.toList val configs1 = a1.getConfigurations.toList - configs0 shouldEqual List("compile") - configs1 shouldEqual List("test") + assert(configs0 == List("compile")) + assert(configs1 == List("test")) } } } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/ModuleResolversTest.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/ModuleResolversTest.scala index 8519a6d95..d1b06b242 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/ModuleResolversTest.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/ModuleResolversTest.scala @@ -5,7 +5,7 @@ import sbt.librarymanagement.syntax._ import sbt.librarymanagement.ivy.UpdateOptions import Resolver._ -class ModuleResolversTest extends BaseIvySpecification { +object ModuleResolversTest extends BaseIvySpecification { override final val resolvers = Vector( DefaultMavenRepository, JavaNet2Repository, @@ -20,7 +20,7 @@ class ModuleResolversTest extends BaseIvySpecification { "com.jfrog.bintray.client" % "bintray-client-java-api" % "0.9.2" % "compile" ).map(_.withIsTransitive(false)) - "The direct resolvers in update options" should "skip the rest of resolvers" in { + test("The direct resolvers in update options should skip the rest of resolvers") { cleanIvyCache() val updateOptions = UpdateOptions() val ivyModule = module(stubModule, dependencies, None, updateOptions) diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/OfflineModeSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/OfflineModeSpec.scala index 028c2b0b3..5044be951 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/OfflineModeSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/OfflineModeSpec.scala @@ -2,10 +2,9 @@ package sbt.internal.librarymanagement import sbt.librarymanagement._ import sbt.librarymanagement.ivy.UpdateOptions -import org.scalatest.{ Assertion, DiagrammedAssertions } import sbt.io.IO -class OfflineModeSpec extends BaseIvySpecification with DiagrammedAssertions { +object OfflineModeSpec extends BaseIvySpecification { private final def targetDir = Some(currentDependency) private final def onlineConf = makeUpdateConfiguration(false, targetDir) private final def offlineConf = makeUpdateConfiguration(true, targetDir) @@ -26,7 +25,7 @@ class OfflineModeSpec extends BaseIvySpecification with DiagrammedAssertions { IO.delete(currentDependency) } - def checkOnlineAndOfflineResolution(updateOptions: UpdateOptions): Assertion = { + def checkOnlineAndOfflineResolution(updateOptions: UpdateOptions): Unit = { cleanAll() val toResolve = module(defaultModuleId, dependencies, None, updateOptions) if (updateOptions.cachedResolution) @@ -46,15 +45,15 @@ class OfflineModeSpec extends BaseIvySpecification with DiagrammedAssertions { assert(originalResolveTime > resolveTime) } - "Offline update configuration" should "reuse the caches when offline is enabled" in { + test("Offline update configuration should reuse the caches when offline is enabled") { checkOnlineAndOfflineResolution(normalOptions) } - it should "reuse the caches when offline and cached resolution are enabled" in { + test("it should reuse the caches when offline and cached resolution are enabled") { checkOnlineAndOfflineResolution(cachedOptions) } - def checkFailingResolution(updateOptions: UpdateOptions): Assertion = { + def checkFailingResolution(updateOptions: UpdateOptions): Unit = { cleanAll() val toResolve = module(defaultModuleId, dependencies, None, updateOptions) if (updateOptions.cachedResolution) cleanCachedResolutionCache(toResolve) @@ -63,11 +62,11 @@ class OfflineModeSpec extends BaseIvySpecification with DiagrammedAssertions { assert(failedOfflineResolution.isLeft) } - it should "fail when artifacts are missing in the cache" in { + test("it should fail when artifacts are missing in the cache") { checkFailingResolution(normalOptions) } - it should "fail when artifacts are missing in the cache for cached resolution" in { + test("it should fail when artifacts are missing in the cache for cached resolution") { checkFailingResolution(cachedOptions) } } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/ResolverSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/ResolverSpec.scala index 64afda27e..92cb9fa32 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/ResolverSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/ResolverSpec.scala @@ -1,16 +1,18 @@ package sbttest import java.net.URL -import org.scalatest._ import sbt.librarymanagement._ import sbt.librarymanagement.syntax._ +import verify.BasicTestSuite -class ResolverSpec extends FunSuite with DiagrammedAssertions { +class ResolverSpec extends BasicTestSuite { test("Resolver.url") { Resolver.url("Test Repo", new URL("http://example.com/"))(Resolver.ivyStylePatterns) + () } test("at") { "something" at "http://example.com" + () } } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/ScalaOverrideTest.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/ScalaOverrideTest.scala index 3dcfff33f..d9ed46cf3 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/ScalaOverrideTest.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/ScalaOverrideTest.scala @@ -6,8 +6,9 @@ import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor import sbt.internal.librarymanagement.IvyScalaUtil.OverrideScalaMediator import sbt.librarymanagement._ import sbt.librarymanagement.ScalaArtifacts._ +import verify.BasicTestSuite -class ScalaOverrideTest extends UnitSpec { +object ScalaOverrideTest extends BasicTestSuite { val OtherOrgID = "other.org" def check(org0: String, version0: String)(org1: String, name1: String, version1: String) = { @@ -21,85 +22,126 @@ class ScalaOverrideTest extends UnitSpec { dd.addDependencyConfiguration("compile", "compile") val res = osm.mediate(dd) - res.getDependencyRevisionId shouldBe ModuleRevisionId.newInstance(org0, name1, version0) + assert(res.getDependencyRevisionId == ModuleRevisionId.newInstance(org0, name1, version0)) } - """OverrideScalaMediator - """ should "Override compiler version" in check(Organization, "2.11.8")( - Organization, - CompilerID, - "2.11.9" - ) - it should "Override library version" in check(Organization, "2.11.8")( - Organization, - LibraryID, - "2.11.8" - ) - it should "Override reflect version" in check(Organization, "2.11.8")( - Organization, - ReflectID, - "2.11.7" - ) - it should "Override actors version" in check(Organization, "2.11.8")( - Organization, - ActorsID, - "2.11.6" - ) - it should "Override scalap version" in check(Organization, "2.11.8")( - Organization, - ScalapID, - "2.11.5" - ) + test("""OverrideScalaMediator should override compiler version""") { + check(Organization, "2.11.8")( + Organization, + CompilerID, + "2.11.9" + ) + } - it should "Override default compiler organization" in check(OtherOrgID, "2.11.8")( - Organization, - CompilerID, - "2.11.9" - ) - it should "Override default library organization" in check(OtherOrgID, "2.11.8")( - Organization, - LibraryID, - "2.11.8" - ) - it should "Override default reflect organization" in check(OtherOrgID, "2.11.8")( - Organization, - ReflectID, - "2.11.7" - ) - it should "Override default actors organization" in check(OtherOrgID, "2.11.8")( - Organization, - ActorsID, - "2.11.6" - ) - it should "Override default scalap organization" in check(OtherOrgID, "2.11.8")( - Organization, - ScalapID, - "2.11.5" - ) + test("it should override library version") { + check(Organization, "2.11.8")( + Organization, + LibraryID, + "2.11.8" + ) + } - it should "Override custom compiler organization" in check(Organization, "2.11.8")( - OtherOrgID, - CompilerID, - "2.11.9" - ) - it should "Override custom library organization" in check(Organization, "2.11.8")( - OtherOrgID, - LibraryID, - "2.11.8" - ) - it should "Override custom reflect organization" in check(Organization, "2.11.8")( - OtherOrgID, - ReflectID, - "2.11.7" - ) - it should "Override custom actors organization" in check(Organization, "2.11.8")( - OtherOrgID, - ActorsID, - "2.11.6" - ) - it should "Override custom scalap organization" in check(Organization, "2.11.8")( - OtherOrgID, - ScalapID, - "2.11.5" - ) + test("it should override reflect version") { + check(Organization, "2.11.8")( + Organization, + ReflectID, + "2.11.7" + ) + } + + test("it should override actors version") { + check(Organization, "2.11.8")( + Organization, + ActorsID, + "2.11.6" + ) + } + + test("it should override scalap version") { + check(Organization, "2.11.8")( + Organization, + ScalapID, + "2.11.5" + ) + } + + test("it should override default compiler organization") { + check(OtherOrgID, "2.11.8")( + Organization, + CompilerID, + "2.11.9" + ) + } + + test("it should override default library organization") { + check(OtherOrgID, "2.11.8")( + Organization, + LibraryID, + "2.11.8" + ) + } + + test("it should override default reflect organization") { + check(OtherOrgID, "2.11.8")( + Organization, + ReflectID, + "2.11.7" + ) + } + + test("it should override default actors organization") { + check(OtherOrgID, "2.11.8")( + Organization, + ActorsID, + "2.11.6" + ) + } + + test("it should override default scalap organization") { + check(OtherOrgID, "2.11.8")( + Organization, + ScalapID, + "2.11.5" + ) + } + + test("it should override custom compiler organization") { + check(Organization, "2.11.8")( + OtherOrgID, + CompilerID, + "2.11.9" + ) + } + + test("it should override custom library organization") { + check(Organization, "2.11.8")( + OtherOrgID, + LibraryID, + "2.11.8" + ) + } + + test("it should override custom reflect organization") { + check(Organization, "2.11.8")( + OtherOrgID, + ReflectID, + "2.11.7" + ) + } + + test("it should override custom actors organization") { + check(Organization, "2.11.8")( + OtherOrgID, + ActorsID, + "2.11.6" + ) + } + + test("it should override custom scalap organization") { + check(Organization, "2.11.8")( + OtherOrgID, + ScalapID, + "2.11.5" + ) + } } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/SftpRepoSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/SftpRepoSpec.scala index 8da14644a..2bf13668d 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/SftpRepoSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/SftpRepoSpec.scala @@ -10,7 +10,7 @@ import java.nio.file.Paths //by default this test is ignored //to run this you need to change "repo" to point to some sftp repository which contains a dependency referring a dependency in same repo //it will then attempt to authenticate via key file and fetch the dependency specified via "org" and "module" -class SftpRepoSpec extends BaseIvySpecification { +object SftpRepoSpec extends BaseIvySpecification { val repo: Option[String] = None // val repo: Option[String] = Some("some repo") //a dependency which depends on another in the repo @@ -25,7 +25,7 @@ class SftpRepoSpec extends BaseIvySpecification { }.toVector ++ super.resolvers } - "resolving multiple deps from sftp repo" should "not hang or fail" in { + test("resolving multiple deps from sftp repo should not hang or fail") { repo match { case Some(repo) => IO.delete(currentTarget / "cache" / org(repo)) diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/UpdateOptionsSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/UpdateOptionsSpec.scala index 9b7c9c126..5729bd06e 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/UpdateOptionsSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/UpdateOptionsSpec.scala @@ -1,24 +1,26 @@ package sbt.internal.librarymanagement import sbt.librarymanagement.ivy._ +import verify.BasicTestSuite -class UpdateOptionsSpec extends UnitSpec { - - "UpdateOptions" should "have proper toString defined" in { - UpdateOptions().toString() should be("""|UpdateOptions( +class UpdateOptionsSpec extends BasicTestSuite { + test("UpdateOptions should have proper toString defined") { + assert(UpdateOptions().toString() == """|UpdateOptions( | circularDependencyLevel = warn, | latestSnapshots = true, | cachedResolution = false |)""".stripMargin) - UpdateOptions() - .withCircularDependencyLevel(CircularDependencyLevel.Error) - .withCachedResolution(true) - .withLatestSnapshots(false) - .toString() should be("""|UpdateOptions( + assert( + UpdateOptions() + .withCircularDependencyLevel(CircularDependencyLevel.Error) + .withCachedResolution(true) + .withLatestSnapshots(false) + .toString() == """|UpdateOptions( | circularDependencyLevel = error, | latestSnapshots = false, | cachedResolution = true - |)""".stripMargin) + |)""".stripMargin + ) } } diff --git a/project/Dependencies.scala b/project/Dependencies.scala index d9a1e088a..b321b2cbb 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -51,6 +51,7 @@ object Dependencies { val scalaCompiler = Def.setting { "org.scala-lang" % "scala-compiler" % scalaVersion.value } val scalaXml = "org.scala-lang.modules" %% "scala-xml" % "1.2.0" val scalaTest = "org.scalatest" %% "scalatest" % "3.0.6-SNAP5" + val scalaVerify = "com.eed3si9n.verify" %% "verify" % "0.1.0" val scalaCheck = "org.scalacheck" %% "scalacheck" % "1.14.0" val sjsonnew = Def.setting { "com.eed3si9n" %% "sjson-new-core" % contrabandSjsonNewVersion.value From a9873101bf4290c48de3e8008545ada22155b9f1 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 17 Aug 2019 22:17:58 -0400 Subject: [PATCH 06/19] Fix validatePatterns https://github.com/sbt/librarymanagement/pull/312 had a bug. --- .../scala/sbt/librarymanagement/ResolverExtra.scala | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala b/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala index d1d435014..835445ec1 100644 --- a/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala @@ -417,9 +417,15 @@ private[librarymanagement] abstract class ResolverFunctions { log.warn(s"insecure HTTP request is deprecated '$value'; switch to HTTPS") } private[sbt] def validatePatterns(patterns: Patterns): Unit = { - val ivy = patterns.ivyPatterns.headOption map (_.startsWith("http:")) - val art = patterns.artifactPatterns.headOption map (_.startsWith("http:")) - (ivy orElse art) foreach { _ => + val ivy = patterns.ivyPatterns.headOption match { + case Some(x) => x.startsWith("http:") + case _ => false + } + val art = patterns.artifactPatterns.headOption match { + case Some(x) => x.startsWith("http:") + case _ => false + } + if (ivy || art) { warnHttp(patterns.toString) } } From cc6147c8d2f8523e86e45f503c1fbdad982c0c1d Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 17 Aug 2019 23:06:52 -0400 Subject: [PATCH 07/19] Remove lmCommonTest --- build.sbt | 24 +++++++------------ .../AbstractEngineSpec.scala | 0 .../librarymanagement/ResolutionSpec.scala | 0 3 files changed, 9 insertions(+), 15 deletions(-) rename {common-test/src/main => ivy/src/test}/scala/sbt/internal/librarymanagement/AbstractEngineSpec.scala (100%) rename {common-test/src/main => ivy/src/test}/scala/sbt/internal/librarymanagement/ResolutionSpec.scala (100%) diff --git a/build.sbt b/build.sbt index 923df2598..1c06bbb25 100644 --- a/build.sbt +++ b/build.sbt @@ -98,6 +98,7 @@ lazy val lmCore = (project in file("core")) sjsonnewScalaJson.value % Optional, scalaTest % Test, scalaCheck % Test, + scalaVerify % Test, ), libraryDependencies += scalaXml, resourceGenerators in Compile += Def @@ -217,25 +218,18 @@ lazy val lmCore = (project in file("core")) ) .configure(addSbtIO, addSbtUtilLogging, addSbtUtilPosition, addSbtUtilCache) -lazy val lmCommonTest = (project in file("common-test")) +lazy val lmIvy = (project in file("ivy")) + .enablePlugins(ContrabandPlugin, JsonCodecPlugin) .dependsOn(lmCore) - .settings( - commonSettings, - skip in publish := true, - name := "common-test", - libraryDependencies ++= Seq(scalaTest, scalaCheck, scalaVerify), - scalacOptions in (Compile, console) --= - Vector("-Ywarn-unused-import", "-Ywarn-unused", "-Xlint"), - mimaSettings, - ) - -lazy val lmIvy = (project in file("ivy")) - .enablePlugins(ContrabandPlugin, JsonCodecPlugin) - .dependsOn(lmCore, lmCommonTest % Test) .settings( commonSettings, name := "librarymanagement-ivy", - libraryDependencies ++= Seq(ivy), + libraryDependencies ++= Seq( + ivy, + scalaTest % Test, + scalaCheck % Test, + scalaVerify % Test, + ), managedSourceDirectories in Compile += baseDirectory.value / "src" / "main" / "contraband-scala", sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala", diff --git a/common-test/src/main/scala/sbt/internal/librarymanagement/AbstractEngineSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/AbstractEngineSpec.scala similarity index 100% rename from common-test/src/main/scala/sbt/internal/librarymanagement/AbstractEngineSpec.scala rename to ivy/src/test/scala/sbt/internal/librarymanagement/AbstractEngineSpec.scala diff --git a/common-test/src/main/scala/sbt/internal/librarymanagement/ResolutionSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/ResolutionSpec.scala similarity index 100% rename from common-test/src/main/scala/sbt/internal/librarymanagement/ResolutionSpec.scala rename to ivy/src/test/scala/sbt/internal/librarymanagement/ResolutionSpec.scala From 153ac7161df5baf5ae8a2a625cd463bb25774540 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 18 Aug 2019 23:56:20 -0400 Subject: [PATCH 08/19] bump modules --- project/Dependencies.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index b321b2cbb..e36f10fba 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -7,8 +7,8 @@ object Dependencies { def nightlyVersion: Option[String] = sys.props.get("sbt.build.version") - private val ioVersion = nightlyVersion.getOrElse("1.3.0-M10") - private val utilVersion = nightlyVersion.getOrElse("1.3.0-M7") + private val ioVersion = nightlyVersion.getOrElse("1.3.0-M16") + private val utilVersion = nightlyVersion.getOrElse("1.3.0-M9") private val sbtIO = "org.scala-sbt" %% "io" % ioVersion From c22cb34e7b3f4cf0fad9edca8d191af561c2cad2 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Thu, 22 Aug 2019 01:54:14 -0400 Subject: [PATCH 09/19] Make CrossVersion.Disabled stable Fixes https://github.com/sbt/sbt/issues/4975 This makes `CrossVersion.Disabled` a stable identifier by reverting `final def` back to `final val`. This is to fix Scala.JS build ``` [error] ScalaJSCrossVersion.scala:34:23: stable identifier required, but sbt.`package`.CrossVersion.Disabled found. [error] case CrossVersion.Disabled => [error] ^ [error] one error found [error] (Compile / compileIncremental) Compilation failed ``` ### notes - #121 added `final val Disabled = sbt.librarymanagement.Disabled` but it was just a companion object - #280 actually made it `final val Disabled = sbt.librarymanagement.Disabled()`, but this broke Cat's build that was calling `CrossVersion.Disabled()` - #290 changed to `final def Disabled = sbt.librarymanagement.Disabled` and `object Disabled extends sbt.librarymanagement.Disabled` - This changes back to `final val Disabled = sbt.librarymanagement.Disabled` (but because we changed the companion object in #290 that's ok) --- .../sbt/librarymanagement/CrossVersion.scala | 2 +- .../librarymanagement/CrossVersionExtra.scala | 2 +- .../tests/CrossVersionCompatTest.scala | 70 +++++++++++++++++++ 3 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 core/src/test/scala/example/tests/CrossVersionCompatTest.scala diff --git a/core/src/main/scala/sbt/librarymanagement/CrossVersion.scala b/core/src/main/scala/sbt/librarymanagement/CrossVersion.scala index 6c37596b3..19e712981 100644 --- a/core/src/main/scala/sbt/librarymanagement/CrossVersion.scala +++ b/core/src/main/scala/sbt/librarymanagement/CrossVersion.scala @@ -39,7 +39,7 @@ sealed class Disabled private () extends sbt.librarymanagement.CrossVersion() wi } object Disabled extends sbt.librarymanagement.Disabled { - def apply(): Disabled = new Disabled() + def apply(): Disabled = Disabled } /** diff --git a/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala b/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala index d8e54d8c8..4db8c7516 100644 --- a/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala @@ -8,7 +8,7 @@ final case class ScalaVersion(full: String, binary: String) private[librarymanagement] abstract class CrossVersionFunctions { /** Compatibility with 0.13 */ - final def Disabled = sbt.librarymanagement.Disabled + final val Disabled = sbt.librarymanagement.Disabled final val Binary = sbt.librarymanagement.Binary final val Constant = sbt.librarymanagement.Constant final val Full = sbt.librarymanagement.Full diff --git a/core/src/test/scala/example/tests/CrossVersionCompatTest.scala b/core/src/test/scala/example/tests/CrossVersionCompatTest.scala new file mode 100644 index 000000000..11eaa54ea --- /dev/null +++ b/core/src/test/scala/example/tests/CrossVersionCompatTest.scala @@ -0,0 +1,70 @@ +package example.tests + +import sbt.librarymanagement.{ CrossVersion, Disabled } +import verify.BasicTestSuite + +object CrossVersionCompatTest extends BasicTestSuite { + test("CrossVersion.Disabled is typed to be Disabled") { + assert(CrossVersion.Disabled match { + case _: Disabled => true + case _ => false + }) + } + + test("CrossVersion.Disabled functions as disabled") { + assert(CrossVersion(CrossVersion.disabled, "1.0.0", "1.0") == None) + assert(CrossVersion(CrossVersion.Disabled, "1.0.0", "1.0") == None) + } + + test("CrossVersion.Disabled() is typed to be Disabled") { + assert(CrossVersion.Disabled() match { + case _: Disabled => true + case _ => false + }) + } + + test("CrossVersion.Disabled() functions as disabled") { + assert(CrossVersion(CrossVersion.disabled, "1.0.0", "1.0") == None) + assert(CrossVersion(CrossVersion.Disabled(), "1.0.0", "1.0") == None) + } + + test("CrossVersion.Disabled is stable") { + assert(CrossVersion.Disabled match { + case CrossVersion.Disabled => true + case _ => false + }) + } + + test("sbt.librarymanagement.Disabled is typed to be Disabled") { + assert(Disabled match { + case _: Disabled => true + case _ => false + }) + } + + test("sbt.librarymanagement.Disabled is stable") { + assert(Disabled match { + case Disabled => true + case _ => false + }) + } + + test("sbt.librarymanagement.Disabled() is typed to be Disabled") { + assert(Disabled() match { + case _: Disabled => true + case _ => false + }) + } + + test("CrossVersion.disabled is sbt.librarymanagement.Disabled") { + assert(CrossVersion.disabled == Disabled) + } + + test("CrossVersion.Disabled is sbt.librarymanagement.Disabled") { + assert(CrossVersion.Disabled == Disabled) + } + + test("CrossVersion.Disabled() is sbt.librarymanagement.Disabled") { + assert(CrossVersion.Disabled() == Disabled) + } +} From 4a1b6232e44216b244ab116e2fb9d4550e660597 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Thu, 22 Aug 2019 10:33:11 -0400 Subject: [PATCH 10/19] deprecate CrossVersion.Disabled --- build.sbt | 4 ++++ .../scala/sbt/librarymanagement/CrossVersionExtra.scala | 6 +++++- .../test/scala/example/tests/CrossVersionCompatTest.scala | 2 ++ project/Dependencies.scala | 1 + 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 1c06bbb25..b6804e2e4 100644 --- a/build.sbt +++ b/build.sbt @@ -100,6 +100,10 @@ lazy val lmCore = (project in file("core")) scalaCheck % Test, scalaVerify % Test, ), + libraryDependencies ++= (scalaVersion.value match { + case v if v.startsWith("2.12.") => List(compilerPlugin(silencerPlugin)) + case _ => List() + }), libraryDependencies += scalaXml, resourceGenerators in Compile += Def .task( diff --git a/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala b/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala index 4db8c7516..43a46073f 100644 --- a/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala @@ -8,6 +8,10 @@ final case class ScalaVersion(full: String, binary: String) private[librarymanagement] abstract class CrossVersionFunctions { /** Compatibility with 0.13 */ + @deprecated( + "use CrossVersion.disabled instead. prior to sbt 1.3.0, Diabled did not work without apply(). sbt/sbt#4977", + "1.3.0" + ) final val Disabled = sbt.librarymanagement.Disabled final val Binary = sbt.librarymanagement.Binary final val Constant = sbt.librarymanagement.Constant @@ -37,7 +41,7 @@ private[librarymanagement] abstract class CrossVersionFunctions { def binary: CrossVersion = Binary() /** Disables cross versioning for a module. */ - def disabled: CrossVersion = Disabled + def disabled: CrossVersion = sbt.librarymanagement.Disabled /** Cross-versions a module with a constant string (typically the binary Scala version). */ def constant(value: String): CrossVersion = Constant(value) diff --git a/core/src/test/scala/example/tests/CrossVersionCompatTest.scala b/core/src/test/scala/example/tests/CrossVersionCompatTest.scala index 11eaa54ea..8aa136e8c 100644 --- a/core/src/test/scala/example/tests/CrossVersionCompatTest.scala +++ b/core/src/test/scala/example/tests/CrossVersionCompatTest.scala @@ -2,7 +2,9 @@ package example.tests import sbt.librarymanagement.{ CrossVersion, Disabled } import verify.BasicTestSuite +import com.github.ghik.silencer.silent +@silent object CrossVersionCompatTest extends BasicTestSuite { test("CrossVersion.Disabled is typed to be Disabled") { assert(CrossVersion.Disabled match { diff --git a/project/Dependencies.scala b/project/Dependencies.scala index e36f10fba..a6cf0fdef 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -61,4 +61,5 @@ object Dependencies { } val gigahorseOkhttp = "com.eed3si9n" %% "gigahorse-okhttp" % "0.5.0" val okhttpUrlconnection = "com.squareup.okhttp3" % "okhttp-urlconnection" % "3.7.0" + val silencerPlugin = "com.github.ghik" %% "silencer-plugin" % "1.4.1" } From d0ce65378c2cb4cba75393a2a01fce7b2434af38 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 27 Aug 2019 17:18:05 -0400 Subject: [PATCH 11/19] Refactor system properties lookup --- .../librarymanagement/LMSysProp.scala | 58 +++++++++++++++++++ .../sbt/librarymanagement/ResolverExtra.scala | 3 +- .../librarymanagement/CustomPomParser.scala | 5 +- .../ivyint/ErrorMessageAuthenticator.scala | 12 +--- .../librarymanagement/ivy/UpdateOptions.scala | 3 +- 5 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 core/src/main/scala/sbt/internal/librarymanagement/LMSysProp.scala diff --git a/core/src/main/scala/sbt/internal/librarymanagement/LMSysProp.scala b/core/src/main/scala/sbt/internal/librarymanagement/LMSysProp.scala new file mode 100644 index 000000000..1fe46916f --- /dev/null +++ b/core/src/main/scala/sbt/internal/librarymanagement/LMSysProp.scala @@ -0,0 +1,58 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt +package internal +package librarymanagement + +import java.util.Locale + +object LMSysProp { + def booleanOpt(name: String): Option[Boolean] = + sys.props.get(name).flatMap { x => + x.toLowerCase(Locale.ENGLISH) match { + case "1" | "always" | "true" => Some(true) + case "0" | "never" | "false" => Some(false) + case "auto" => None + case _ => None + } + } + + def getOrFalse(name: String): Boolean = booleanOpt(name).getOrElse(false) + def getOrTrue(name: String): Boolean = booleanOpt(name).getOrElse(true) + + // System property style: + // 1. use sbt. prefix + // 2. prefer short nouns + // 3. use dot for namespacing, and avoid making dot-separated English phrase + // 4. make active/enable properties, instead of "sbt.disable." + // + // Good: sbt.offline + // + // Bad: + // sbt.disable.interface.classloader.cache + // sbt.task.timings.on.shutdown + // sbt.skip.version.write -> sbt.genbuildprops=false + + val useSecureResolvers: Boolean = getOrTrue("sbt.repository.secure") + + def modifyVersionRange: Boolean = getOrTrue("sbt.modversionrange") + + lazy val isJavaVersion9Plus: Boolean = javaVersion > 8 + lazy val javaVersion: Int = { + // See Oracle section 1.5.3 at: + // https://docs.oracle.com/javase/8/docs/technotes/guides/versioning/spec/versioning2.html + val version = sys.props("java.specification.version").split("\\.").toList.map(_.toInt) + version match { + case 1 :: minor :: _ => minor + case major :: _ => major + case _ => 0 + } + } + + lazy val useGigahorse: Boolean = getOrTrue("sbt.gigahorse") +} diff --git a/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala b/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala index 835445ec1..d45166997 100644 --- a/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala @@ -95,8 +95,7 @@ private[sbt] class FakeRepository(resolver: AnyRef, name: String) extends xsbti. } private[librarymanagement] abstract class ResolverFunctions { - private[sbt] def useSecureResolvers = - sys.props.get("sbt.repository.secure") map { _.toLowerCase == "true" } getOrElse true + import sbt.internal.librarymanagement.LMSysProp.useSecureResolvers val TypesafeRepositoryRoot = typesafeRepositoryRoot(useSecureResolvers) val SbtRepositoryRoot = sbtRepositoryRoot(useSecureResolvers) diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/CustomPomParser.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/CustomPomParser.scala index c906fc818..591e3e881 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/CustomPomParser.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/CustomPomParser.scala @@ -242,9 +242,6 @@ object CustomPomParser { transform(dd, _ => newId) case None => dd } - private[sbt] lazy val versionRangeFlag = sys.props.get("sbt.modversionrange") map { - _.toLowerCase == "true" - } getOrElse true import collection.JavaConverters._ def addExtra( @@ -281,7 +278,7 @@ object CustomPomParser { addExtra(dd, dependencyExtra) } val withVersionRangeMod: Seq[DependencyDescriptor] = - if (versionRangeFlag) withExtra map { stripVersionRange } else withExtra + if (LMSysProp.modifyVersionRange) withExtra map { stripVersionRange } else withExtra val unique = IvySbt.mergeDuplicateDefinitions(withVersionRangeMod) unique foreach dmd.addDependency diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/ErrorMessageAuthenticator.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/ErrorMessageAuthenticator.scala index 1e842c458..2ba03b741 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/ErrorMessageAuthenticator.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/ErrorMessageAuthenticator.scala @@ -15,7 +15,8 @@ object ErrorMessageAuthenticator { private var securityWarningLogged = false private def originalAuthenticator: Option[Authenticator] = { - if (isJavaVersion9Plus) getDefaultAuthenticator else getTheAuthenticator + if (LMSysProp.isJavaVersion9Plus) getDefaultAuthenticator + else getTheAuthenticator } private[this] def getTheAuthenticator: Option[Authenticator] = { @@ -100,15 +101,6 @@ object ErrorMessageAuthenticator { } doInstallIfIvy(originalAuthenticator) } - - private[this] def isJavaVersion9Plus = javaVersion > 8 - private[this] def javaVersion = { - // See Oracle section 1.5.3 at: - // https://docs.oracle.com/javase/8/docs/technotes/guides/versioning/spec/versioning2.html - val version = sys.props("java.specification.version").split("\\.").map(_.toInt) - if (version(0) == 1) version(1) else version(0) - } - } /** diff --git a/ivy/src/main/scala/sbt/librarymanagement/ivy/UpdateOptions.scala b/ivy/src/main/scala/sbt/librarymanagement/ivy/UpdateOptions.scala index 6f12ba053..1ac339eec 100644 --- a/ivy/src/main/scala/sbt/librarymanagement/ivy/UpdateOptions.scala +++ b/ivy/src/main/scala/sbt/librarymanagement/ivy/UpdateOptions.scala @@ -4,6 +4,7 @@ package ivy import org.apache.ivy.plugins.resolver.DependencyResolver import org.apache.ivy.core.settings.IvySettings import sbt.util.Logger +import sbt.internal.librarymanagement.LMSysProp /** * Represents configurable options for update task. @@ -109,7 +110,7 @@ object UpdateOptions { interProjectFirst = true, latestSnapshots = true, cachedResolution = false, - gigahorse = sys.props.get("sbt.gigahorse") map { _.toLowerCase == "true" } getOrElse true, + gigahorse = LMSysProp.useGigahorse, resolverConverter = PartialFunction.empty, moduleResolvers = Map.empty ) From c5ce6363764b4256e2d70e470634d8e75fc2f565 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 27 Aug 2019 17:47:32 -0400 Subject: [PATCH 12/19] Flip the default to not use Gigahorse by default Fixes https://github.com/sbt/sbt/issues/3570 The primary motivation for bringing in Gigahorse was to speed up the dependency resolution, especially in a high-latency environment like Australia, by enabling keep-alive. One of unintended consequences was that it ended up exposing either a bug in okhttp or Nexus / Artifactory's handling of keep-alive, since corporate users behind these proxy repositories started to experience problem publishing. Multiple people have also reported that putting network proxies like HAProxy works around this issue, which seems consistent with the theory. Now that dependency resolution has switched to using Coursier by default, I am just going to flip the default here so publishing would use Ivy's default URL handler based on `java.net.HttpURLConnection` - https://github.com/sbt/ivy/blob/5681e1a77a149b93a4cfbe4a86d0263d7bd223eb/src/java/org/apache/ivy/util/url/BasicURLHandler.java --- .../main/scala/sbt/internal/librarymanagement/LMSysProp.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/sbt/internal/librarymanagement/LMSysProp.scala b/core/src/main/scala/sbt/internal/librarymanagement/LMSysProp.scala index 1fe46916f..15bb4a9e5 100644 --- a/core/src/main/scala/sbt/internal/librarymanagement/LMSysProp.scala +++ b/core/src/main/scala/sbt/internal/librarymanagement/LMSysProp.scala @@ -54,5 +54,5 @@ object LMSysProp { } } - lazy val useGigahorse: Boolean = getOrTrue("sbt.gigahorse") + lazy val useGigahorse: Boolean = getOrFalse("sbt.gigahorse") } From 54806467156f00b520c90c50ef07591693e6de6f Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 27 Aug 2019 17:51:19 -0400 Subject: [PATCH 13/19] pass in Locale toLowerCase would act differently in Turkey. --- .../librarymanagement/SemanticSelectorExtra.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/src/main/scala/sbt/internal/librarymanagement/SemanticSelectorExtra.scala b/core/src/main/scala/sbt/internal/librarymanagement/SemanticSelectorExtra.scala index c609a1529..f3f28cf7a 100644 --- a/core/src/main/scala/sbt/internal/librarymanagement/SemanticSelectorExtra.scala +++ b/core/src/main/scala/sbt/internal/librarymanagement/SemanticSelectorExtra.scala @@ -4,6 +4,7 @@ import sbt.librarymanagement.VersionNumber import sbt.internal.librarymanagement.SemSelOperator.{ Lt, Lte, Gt, Gte, Eq } import scala.annotation.tailrec +import java.util.Locale private[librarymanagement] abstract class SemSelAndChunkFunctions { protected def parse(andClauseToken: String): SemSelAndChunk = { @@ -123,10 +124,11 @@ private[librarymanagement] abstract class SemComparatorExtra { // Identifiers consisting of only digits are compared numerically. // Numeric identifiers always have lower precedence than non-numeric identifiers. // Identifiers with letters are compared case insensitive lexical order. - case (true, true) => implicitly[Ordering[Long]].compare(ts1head.toLong, ts2head.toLong) - case (false, true) => 1 - case (true, false) => -1 - case (false, false) => ts1head.toLowerCase.compareTo(ts2head.toLowerCase) + case (true, true) => implicitly[Ordering[Long]].compare(ts1head.toLong, ts2head.toLong) + case (false, true) => 1 + case (true, false) => -1 + case (false, false) => + ts1head.toLowerCase(Locale.ENGLISH).compareTo(ts2head.toLowerCase(Locale.ENGLISH)) } if (cmp == 0) compareTags(ts1.tail, ts2.tail) else cmp From 40598cc5a47d298ed3688e95a86f5fbecceb4663 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 27 Aug 2019 18:50:17 -0400 Subject: [PATCH 14/19] mima + scalafmt --- build.sbt | 163 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 111 insertions(+), 52 deletions(-) diff --git a/build.sbt b/build.sbt index b6804e2e4..2ed58e87d 100644 --- a/build.sbt +++ b/build.sbt @@ -42,7 +42,9 @@ def commonSettings: Seq[Setting[_]] = Def.settings( case _ => old ++ List("-Ywarn-unused", "-Ywarn-unused-import", "-YdisableFlatCpCaching") } }, - inCompileAndTest(scalacOptions in console --= Vector("-Ywarn-unused-import", "-Ywarn-unused", "-Xlint")), + inCompileAndTest( + scalacOptions in console --= Vector("-Ywarn-unused-import", "-Ywarn-unused", "-Xlint") + ), scalafmtOnCompile := true, Test / scalafmtOnCompile := true, publishArtifact in Compile := true, @@ -52,13 +54,22 @@ def commonSettings: Seq[Setting[_]] = Def.settings( val mimaSettings = Def settings ( mimaPreviousArtifacts := Set( - "1.0.0", "1.0.1", "1.0.2", "1.0.3", "1.0.4", - "1.1.0", "1.1.1", "1.1.2", "1.1.3", "1.1.4", + "1.0.0", + "1.0.1", + "1.0.2", + "1.0.3", + "1.0.4", + "1.1.0", + "1.1.1", + "1.1.2", + "1.1.3", + "1.1.4", "1.2.0", - ) map (version => - organization.value %% moduleName.value % version - cross (if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled) - ), + ) map ( + version => + organization.value %% moduleName.value % version + cross (if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled) + ), ) lazy val lmRoot = (project in file(".")) @@ -73,7 +84,8 @@ lazy val lmRoot = (project in file(".")) Some(ScmInfo(url(s"https://github.com/$slug"), s"git@github.com:$slug.git")) }, bintrayPackage := "librarymanagement", - )), + ) + ), commonSettings, name := "LM Root", publish := {}, @@ -134,33 +146,32 @@ lazy val lmCore = (project in file("core")) mimaBinaryIssueFilters ++= Seq( exclude[DirectMissingMethodProblem]("sbt.librarymanagement.EvictionWarningOptions.this"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.EvictionWarningOptions.copy"), - exclude[IncompatibleResultTypeProblem]("sbt.librarymanagement.EvictionWarningOptions.copy$default$7"), - + exclude[IncompatibleResultTypeProblem]( + "sbt.librarymanagement.EvictionWarningOptions.copy$default$7" + ), // internal class moved exclude[MissingClassProblem]("sbt.internal.librarymanagement.InlineConfigurationFunctions"), // dropped internal class parent (InlineConfigurationFunctions) exclude[MissingTypesProblem]("sbt.librarymanagement.ModuleDescriptorConfiguration$"), - // Configuration's copy method was never meant to be public exclude[DirectMissingMethodProblem]("sbt.librarymanagement.Configuration.copy"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.Configuration.copy$default$*"), - // the data type copy methods were never meant to be public exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ArtifactExtra.copy"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ArtifactExtra.copy$default$*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ModuleReportExtra.copy"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ModuleReportExtra.copy$default$*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ArtifactTypeFilterExtra.copy"), - exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ArtifactTypeFilterExtra.copy$default$*"), + exclude[DirectMissingMethodProblem]( + "sbt.librarymanagement.ArtifactTypeFilterExtra.copy$default$*" + ), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ModuleIDExtra.copy"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ModuleIDExtra.copy$default$*"), - // these abstract classes are private[librarymanagement] so it's fine if they have more methods exclude[ReversedMissingMethodProblem]("sbt.librarymanagement.ArtifactExtra.*"), exclude[ReversedMissingMethodProblem]("sbt.librarymanagement.ModuleReportExtra.*"), exclude[ReversedMissingMethodProblem]("sbt.librarymanagement.ArtifactTypeFilterExtra.*"), exclude[ReversedMissingMethodProblem]("sbt.librarymanagement.ModuleIDExtra.*"), - // these abstract classes are private[librarymanagement] so they can lose these abstract methods exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ArtifactExtra.type"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ArtifactExtra.url"), @@ -170,9 +181,10 @@ lazy val lmCore = (project in file("core")) exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ArtifactExtra.classifier"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ArtifactExtra.extension"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ArtifactTypeFilterExtra.types"), - // contraband issue - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.ConfigurationReportLite.copy*"), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.ConfigurationReportLite.copy*" + ), exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.UpdateReportLite.copy*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.Artifact.copy*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ArtifactTypeFilter.copy*"), @@ -189,7 +201,9 @@ lazy val lmCore = (project in file("core")) exclude[DirectMissingMethodProblem]("sbt.librarymanagement.FileConfiguration.copy*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.FileRepository.copy*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.Full.copy*"), - exclude[DirectMissingMethodProblem]("sbt.librarymanagement.GetClassifiersConfiguration.copy*"), + exclude[DirectMissingMethodProblem]( + "sbt.librarymanagement.GetClassifiersConfiguration.copy*" + ), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.GetClassifiersModule.copy*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.InclExclRule.copy*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.IvyFileConfiguration.copy*"), @@ -198,7 +212,9 @@ lazy val lmCore = (project in file("core")) exclude[DirectMissingMethodProblem]("sbt.librarymanagement.MavenCache.copy*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.MavenRepo.copy*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ModuleConfiguration.copy*"), - exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ModuleDescriptorConfiguration.copy*"), + exclude[DirectMissingMethodProblem]( + "sbt.librarymanagement.ModuleDescriptorConfiguration.copy*" + ), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ModuleID.copy*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ModuleInfo.copy*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ModuleReport.copy*"), @@ -218,6 +234,10 @@ lazy val lmCore = (project in file("core")) exclude[DirectMissingMethodProblem]("sbt.librarymanagement.UpdateReport.copy*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.UpdateStats.copy*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.URLRepository.copy*"), + // private[sbt] + exclude[DirectMissingMethodProblem]( + "sbt.librarymanagement.ResolverFunctions.useSecureResolvers" + ), ), ) .configure(addSbtIO, addSbtUtilLogging, addSbtUtilPosition, addSbtUtilCache) @@ -242,33 +262,68 @@ lazy val lmIvy = (project in file("ivy")) Vector("-Ywarn-unused-import", "-Ywarn-unused", "-Xlint"), mimaSettings, mimaBinaryIssueFilters ++= Seq( - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler#SbtUrlInfo.this"), - exclude[IncompatibleMethTypeProblem]("sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler#SbtUrlInfo.this"), - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler.checkStatusCode"), - + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler#SbtUrlInfo.this" + ), + exclude[IncompatibleMethTypeProblem]( + "sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler#SbtUrlInfo.this" + ), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler.checkStatusCode" + ), // sbt.internal methods that changed type signatures and aren't used elsewhere in production code - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.IvySbt#ParallelCachedResolutionResolveEngine.mergeErrors"), - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.IvySbt.cleanCachedResolutionCache"), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.IvySbt#ParallelCachedResolutionResolveEngine.mergeErrors" + ), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.IvySbt.cleanCachedResolutionCache" + ), exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.IvyRetrieve.artifacts"), - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.IvyScalaUtil.checkModule"), - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.ivyint.CachedResolutionResolveEngine.mergeErrors"), - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.ivyint.CachedResolutionResolveCache.buildArtificialModuleDescriptor"), - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.ivyint.CachedResolutionResolveCache.buildArtificialModuleDescriptors"), - exclude[ReversedMissingMethodProblem]("sbt.internal.librarymanagement.ivyint.CachedResolutionResolveEngine.mergeErrors"), - - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler#SbtUrlInfo.this"), - exclude[IncompatibleMethTypeProblem]("sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler#SbtUrlInfo.this"), - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler.checkStatusCode"), - + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.IvyScalaUtil.checkModule" + ), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.ivyint.CachedResolutionResolveEngine.mergeErrors" + ), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.ivyint.CachedResolutionResolveCache.buildArtificialModuleDescriptor" + ), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.ivyint.CachedResolutionResolveCache.buildArtificialModuleDescriptors" + ), + exclude[ReversedMissingMethodProblem]( + "sbt.internal.librarymanagement.ivyint.CachedResolutionResolveEngine.mergeErrors" + ), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler#SbtUrlInfo.this" + ), + exclude[IncompatibleMethTypeProblem]( + "sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler#SbtUrlInfo.this" + ), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler.checkStatusCode" + ), // contraband issue - exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ivy.ExternalIvyConfiguration.copy*"), + exclude[DirectMissingMethodProblem]( + "sbt.librarymanagement.ivy.ExternalIvyConfiguration.copy*" + ), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ivy.InlineIvyConfiguration.copy*"), exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ivy.IvyPaths.copy*"), - - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler.urlFactory"), - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler.http"), - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler.open"), - exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler.this"), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler.urlFactory" + ), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler.http" + ), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler.open" + ), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler.this" + ), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.CustomPomParser.versionRangeFlag" + ), ), ) @@ -278,11 +333,13 @@ lazy val lmScriptedTest = (project in file("scripted-test")) commonSettings, skip in publish := true, name := "scripted-test", - scriptedLaunchOpts := { scriptedLaunchOpts.value ++ - Seq("-Xmx1024M", "-Dplugin.version=" + version.value) + scriptedLaunchOpts := { + scriptedLaunchOpts.value ++ + Seq("-Xmx1024M", "-Dplugin.version=" + version.value) }, scriptedBufferLog := false - ).enablePlugins(SbtScriptedIT) + ) + .enablePlugins(SbtScriptedIT) // we are updating the nightly process, so we are commenting this out for now // addCommandAlias("scriptedIvy", Seq( @@ -303,14 +360,16 @@ def customCommands: Seq[Setting[_]] = Seq( } ) -inThisBuild(Seq( - whitesourceProduct := "Lightbend Reactive Platform", - whitesourceAggregateProjectName := "sbt-lm-master", - whitesourceAggregateProjectToken := "9bde4ccbaab7401a91f8cda337af84365d379e13abaf473b85cb16e3f5c65cb6", - whitesourceIgnoredScopes += "scalafmt", - whitesourceFailOnError := sys.env.contains("WHITESOURCE_PASSWORD"), // fail if pwd is present - whitesourceForceCheckAllDependencies := true, -)) +inThisBuild( + Seq( + whitesourceProduct := "Lightbend Reactive Platform", + whitesourceAggregateProjectName := "sbt-lm-master", + whitesourceAggregateProjectToken := "9bde4ccbaab7401a91f8cda337af84365d379e13abaf473b85cb16e3f5c65cb6", + whitesourceIgnoredScopes += "scalafmt", + whitesourceFailOnError := sys.env.contains("WHITESOURCE_PASSWORD"), // fail if pwd is present + whitesourceForceCheckAllDependencies := true, + ) +) def inCompileAndTest(ss: SettingsDefinition*): Seq[Setting[_]] = Seq(Compile, Test) flatMap (inConfig(_)(Def.settings(ss: _*))) From 7ad02276e90580b5fe87779570dcc4b373b158d3 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 27 Aug 2019 23:37:45 -0400 Subject: [PATCH 15/19] adding try-catch per review --- .../librarymanagement/LMSysProp.scala | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/core/src/main/scala/sbt/internal/librarymanagement/LMSysProp.scala b/core/src/main/scala/sbt/internal/librarymanagement/LMSysProp.scala index 15bb4a9e5..d2a28d3eb 100644 --- a/core/src/main/scala/sbt/internal/librarymanagement/LMSysProp.scala +++ b/core/src/main/scala/sbt/internal/librarymanagement/LMSysProp.scala @@ -10,6 +10,7 @@ package internal package librarymanagement import java.util.Locale +import scala.util.control.NonFatal object LMSysProp { def booleanOpt(name: String): Option[Boolean] = @@ -40,17 +41,21 @@ object LMSysProp { val useSecureResolvers: Boolean = getOrTrue("sbt.repository.secure") - def modifyVersionRange: Boolean = getOrTrue("sbt.modversionrange") + lazy val modifyVersionRange: Boolean = getOrTrue("sbt.modversionrange") lazy val isJavaVersion9Plus: Boolean = javaVersion > 8 lazy val javaVersion: Int = { - // See Oracle section 1.5.3 at: - // https://docs.oracle.com/javase/8/docs/technotes/guides/versioning/spec/versioning2.html - val version = sys.props("java.specification.version").split("\\.").toList.map(_.toInt) - version match { - case 1 :: minor :: _ => minor - case major :: _ => major - case _ => 0 + try { + // See Oracle section 1.5.3 at: + // https://docs.oracle.com/javase/8/docs/technotes/guides/versioning/spec/versioning2.html + val version = sys.props("java.specification.version").split("\\.").toList.map(_.toInt) + version match { + case 1 :: minor :: _ => minor + case major :: _ => major + case _ => 0 + } + } catch { + case NonFatal(_) => 0 } } From 337716830f7f34c2bc828788505c6833df8a6bc0 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Wed, 28 Aug 2019 15:07:35 -0400 Subject: [PATCH 16/19] Deprecate HTTP resolvers (take 2) Ref https://github.com/sbt/sbt/issues/4905 Ref https://github.com/sbt/librarymanagement/pull/312 Based on the discussion in https://github.com/sbt/sbt/issues/4905, this will exempt localhost, and also allows per-resolver opt-in for HTTP. --- build.sbt | 3 + .../sbt/librarymanagement/Artifact.scala | 22 ++++-- .../librarymanagement/ArtifactFormats.scala | 4 +- .../librarymanagement/ChainedResolver.scala | 2 +- .../sbt/librarymanagement/MavenCache.scala | 3 +- .../sbt/librarymanagement/MavenRepo.scala | 23 ++++-- .../librarymanagement/MavenRepoFormats.scala | 4 +- .../librarymanagement/MavenRepository.scala | 6 ++ .../sbt/librarymanagement/Resolver.scala | 3 +- .../sbt/librarymanagement/URLRepository.scala | 21 +++-- .../URLRepositoryFormats.scala | 4 +- .../main/contraband/librarymanagement.json | 43 +++++++++-- .../sbt/librarymanagement/ArtifactExtra.scala | 8 +- .../DependencyBuilders.scala | 3 +- .../sbt/librarymanagement/ModuleIDExtra.scala | 52 ++++++++----- .../sbt/librarymanagement/ResolverExtra.scala | 77 +++++++++++++------ 16 files changed, 194 insertions(+), 84 deletions(-) diff --git a/build.sbt b/build.sbt index 2ed58e87d..25e1d9eab 100644 --- a/build.sbt +++ b/build.sbt @@ -238,6 +238,9 @@ lazy val lmCore = (project in file("core")) exclude[DirectMissingMethodProblem]( "sbt.librarymanagement.ResolverFunctions.useSecureResolvers" ), + exclude[ReversedMissingMethodProblem]( + "sbt.librarymanagement.MavenRepository.allowInsecureProtocol" + ) ), ) .configure(addSbtIO, addSbtUtilLogging, addSbtUtilPosition, addSbtUtilCache) diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/Artifact.scala b/core/src/main/contraband-scala/sbt/librarymanagement/Artifact.scala index d337cb364..9cae77dca 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/Artifact.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/Artifact.scala @@ -12,22 +12,24 @@ final class Artifact private ( val configurations: Vector[sbt.librarymanagement.ConfigRef], val url: Option[java.net.URL], val extraAttributes: Map[String, String], - val checksum: Option[sbt.librarymanagement.Checksum]) extends sbt.librarymanagement.ArtifactExtra with Serializable { - - private def this(name: String) = this(name, Artifact.DefaultType, Artifact.DefaultExtension, None, Vector.empty, None, Map.empty, None) + val checksum: Option[sbt.librarymanagement.Checksum], + val allowInsecureProtocol: Boolean) extends sbt.librarymanagement.ArtifactExtra with Serializable { + private[sbt] def validateProtocol(logger: sbt.util.Logger): Unit = Resolver.validateArtifact(this, logger) + private def this(name: String) = this(name, Artifact.DefaultType, Artifact.DefaultExtension, None, Vector.empty, None, Map.empty, None, false) + private def this(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Vector[sbt.librarymanagement.ConfigRef], url: Option[java.net.URL], extraAttributes: Map[String, String], checksum: Option[sbt.librarymanagement.Checksum]) = this(name, `type`, extension, classifier, configurations, url, extraAttributes, checksum, false) override def equals(o: Any): Boolean = o match { - case x: Artifact => (this.name == x.name) && (this.`type` == x.`type`) && (this.extension == x.extension) && (this.classifier == x.classifier) && (this.configurations == x.configurations) && (this.url == x.url) && (this.extraAttributes == x.extraAttributes) && (this.checksum == x.checksum) + case x: Artifact => (this.name == x.name) && (this.`type` == x.`type`) && (this.extension == x.extension) && (this.classifier == x.classifier) && (this.configurations == x.configurations) && (this.url == x.url) && (this.extraAttributes == x.extraAttributes) && (this.checksum == x.checksum) && (this.allowInsecureProtocol == x.allowInsecureProtocol) case _ => false } override def hashCode: Int = { - 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.Artifact".##) + name.##) + `type`.##) + extension.##) + classifier.##) + configurations.##) + url.##) + extraAttributes.##) + checksum.##) + 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.Artifact".##) + name.##) + `type`.##) + extension.##) + classifier.##) + configurations.##) + url.##) + extraAttributes.##) + checksum.##) + allowInsecureProtocol.##) } override def toString: String = { - "Artifact(" + name + ", " + `type` + ", " + extension + ", " + classifier + ", " + configurations + ", " + url + ", " + extraAttributes + ", " + checksum + ")" + "Artifact(" + name + ", " + `type` + ", " + extension + ", " + classifier + ", " + configurations + ", " + url + ", " + extraAttributes + ", " + checksum + ", " + allowInsecureProtocol + ")" } - private[this] def copy(name: String = name, `type`: String = `type`, extension: String = extension, classifier: Option[String] = classifier, configurations: Vector[sbt.librarymanagement.ConfigRef] = configurations, url: Option[java.net.URL] = url, extraAttributes: Map[String, String] = extraAttributes, checksum: Option[sbt.librarymanagement.Checksum] = checksum): Artifact = { - new Artifact(name, `type`, extension, classifier, configurations, url, extraAttributes, checksum) + private[this] def copy(name: String = name, `type`: String = `type`, extension: String = extension, classifier: Option[String] = classifier, configurations: Vector[sbt.librarymanagement.ConfigRef] = configurations, url: Option[java.net.URL] = url, extraAttributes: Map[String, String] = extraAttributes, checksum: Option[sbt.librarymanagement.Checksum] = checksum, allowInsecureProtocol: Boolean = allowInsecureProtocol): Artifact = { + new Artifact(name, `type`, extension, classifier, configurations, url, extraAttributes, checksum, allowInsecureProtocol) } def withName(name: String): Artifact = { copy(name = name) @@ -53,9 +55,13 @@ final class Artifact private ( def withChecksum(checksum: Option[sbt.librarymanagement.Checksum]): Artifact = { copy(checksum = checksum) } + def withAllowInsecureProtocol(allowInsecureProtocol: Boolean): Artifact = { + copy(allowInsecureProtocol = allowInsecureProtocol) + } } object Artifact extends sbt.librarymanagement.ArtifactFunctions { def apply(name: String): Artifact = new Artifact(name) def apply(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Vector[sbt.librarymanagement.ConfigRef], url: Option[java.net.URL], extraAttributes: Map[String, String], checksum: Option[sbt.librarymanagement.Checksum]): Artifact = new Artifact(name, `type`, extension, classifier, configurations, url, extraAttributes, checksum) + def apply(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Vector[sbt.librarymanagement.ConfigRef], url: Option[java.net.URL], extraAttributes: Map[String, String], checksum: Option[sbt.librarymanagement.Checksum], allowInsecureProtocol: Boolean): Artifact = new Artifact(name, `type`, extension, classifier, configurations, url, extraAttributes, checksum, allowInsecureProtocol) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ArtifactFormats.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ArtifactFormats.scala index 4dfc42b54..2c9b2a02d 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ArtifactFormats.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ArtifactFormats.scala @@ -19,8 +19,9 @@ implicit lazy val ArtifactFormat: JsonFormat[sbt.librarymanagement.Artifact] = n val url = unbuilder.readField[Option[java.net.URL]]("url") val extraAttributes = unbuilder.readField[Map[String, String]]("extraAttributes") val checksum = unbuilder.readField[Option[sbt.librarymanagement.Checksum]]("checksum") + val allowInsecureProtocol = unbuilder.readField[Boolean]("allowInsecureProtocol") unbuilder.endObject() - sbt.librarymanagement.Artifact(name, `type`, extension, classifier, configurations, url, extraAttributes, checksum) + sbt.librarymanagement.Artifact(name, `type`, extension, classifier, configurations, url, extraAttributes, checksum, allowInsecureProtocol) case None => deserializationError("Expected JsObject but found None") } @@ -35,6 +36,7 @@ implicit lazy val ArtifactFormat: JsonFormat[sbt.librarymanagement.Artifact] = n builder.addField("url", obj.url) builder.addField("extraAttributes", obj.extraAttributes) builder.addField("checksum", obj.checksum) + builder.addField("allowInsecureProtocol", obj.allowInsecureProtocol) builder.endObject() } } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ChainedResolver.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ChainedResolver.scala index d98e6d1cb..fa950e86b 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ChainedResolver.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ChainedResolver.scala @@ -7,7 +7,7 @@ package sbt.librarymanagement final class ChainedResolver private ( name: String, val resolvers: Vector[sbt.librarymanagement.Resolver]) extends sbt.librarymanagement.Resolver(name) with Serializable { - + private[sbt] override def validateProtocol(logger: sbt.util.Logger): Unit = resolvers.foreach(_.validateProtocol(logger)) override def equals(o: Any): Boolean = o match { diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/MavenCache.scala b/core/src/main/contraband-scala/sbt/librarymanagement/MavenCache.scala index b1501e3d4..1ed824c7b 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/MavenCache.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/MavenCache.scala @@ -14,7 +14,8 @@ final class MavenCache private ( localIfFile: Boolean, val rootFile: java.io.File) extends sbt.librarymanagement.MavenRepository(name, root, localIfFile) with Serializable { def this(name: String, rootFile: java.io.File) = this(name, rootFile.toURI.toURL.toString, true, rootFile) - def isCache: Boolean = true + override def isCache: Boolean = true + override def allowInsecureProtocol: Boolean = false private def this(name: String, root: String, rootFile: java.io.File) = this(name, root, true, rootFile) override def equals(o: Any): Boolean = o match { diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepo.scala b/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepo.scala index b01c6d8a9..a23e1a225 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepo.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepo.scala @@ -4,25 +4,30 @@ // DO NOT EDIT MANUALLY package sbt.librarymanagement +/** This is the internal implementation of actual Maven Repository (as opposed to a file cache). */ final class MavenRepo private ( name: String, root: String, - localIfFile: Boolean) extends sbt.librarymanagement.MavenRepository(name, root, localIfFile) with Serializable { - def isCache: Boolean = false - private def this(name: String, root: String) = this(name, root, true) + localIfFile: Boolean, + val _allowInsecureProtocol: Boolean) extends sbt.librarymanagement.MavenRepository(name, root, localIfFile) with Serializable { + override def isCache: Boolean = false + override def allowInsecureProtocol: Boolean = _allowInsecureProtocol + private[sbt] override def validateProtocol(logger: sbt.util.Logger): Unit = Resolver.validateMavenRepo(this, logger) + private def this(name: String, root: String) = this(name, root, true, false) + private def this(name: String, root: String, localIfFile: Boolean) = this(name, root, localIfFile, false) override def equals(o: Any): Boolean = o match { - case x: MavenRepo => (this.name == x.name) && (this.root == x.root) && (this.localIfFile == x.localIfFile) + case x: MavenRepo => (this.name == x.name) && (this.root == x.root) && (this.localIfFile == x.localIfFile) && (this._allowInsecureProtocol == x._allowInsecureProtocol) case _ => false } override def hashCode: Int = { - 37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.MavenRepo".##) + name.##) + root.##) + localIfFile.##) + 37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.MavenRepo".##) + name.##) + root.##) + localIfFile.##) + _allowInsecureProtocol.##) } override def toString: String = { s"$name: $root" } - private[this] def copy(name: String = name, root: String = root, localIfFile: Boolean = localIfFile): MavenRepo = { - new MavenRepo(name, root, localIfFile) + private[this] def copy(name: String = name, root: String = root, localIfFile: Boolean = localIfFile, _allowInsecureProtocol: Boolean = _allowInsecureProtocol): MavenRepo = { + new MavenRepo(name, root, localIfFile, _allowInsecureProtocol) } def withName(name: String): MavenRepo = { copy(name = name) @@ -33,9 +38,13 @@ final class MavenRepo private ( def withLocalIfFile(localIfFile: Boolean): MavenRepo = { copy(localIfFile = localIfFile) } + def with_allowInsecureProtocol(_allowInsecureProtocol: Boolean): MavenRepo = { + copy(_allowInsecureProtocol = _allowInsecureProtocol) + } } object MavenRepo { def apply(name: String, root: String): MavenRepo = new MavenRepo(name, root) def apply(name: String, root: String, localIfFile: Boolean): MavenRepo = new MavenRepo(name, root, localIfFile) + def apply(name: String, root: String, localIfFile: Boolean, _allowInsecureProtocol: Boolean): MavenRepo = new MavenRepo(name, root, localIfFile, _allowInsecureProtocol) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepoFormats.scala b/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepoFormats.scala index 235de9643..e4c979985 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepoFormats.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepoFormats.scala @@ -14,8 +14,9 @@ implicit lazy val MavenRepoFormat: JsonFormat[sbt.librarymanagement.MavenRepo] = val name = unbuilder.readField[String]("name") val root = unbuilder.readField[String]("root") val localIfFile = unbuilder.readField[Boolean]("localIfFile") + val _allowInsecureProtocol = unbuilder.readField[Boolean]("_allowInsecureProtocol") unbuilder.endObject() - sbt.librarymanagement.MavenRepo(name, root, localIfFile) + sbt.librarymanagement.MavenRepo(name, root, localIfFile, _allowInsecureProtocol) case None => deserializationError("Expected JsObject but found None") } @@ -25,6 +26,7 @@ implicit lazy val MavenRepoFormat: JsonFormat[sbt.librarymanagement.MavenRepo] = builder.addField("name", obj.name) builder.addField("root", obj.root) builder.addField("localIfFile", obj.localIfFile) + builder.addField("_allowInsecureProtocol", obj._allowInsecureProtocol) builder.endObject() } } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepository.scala b/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepository.scala index f1bbb608c..3f891ef19 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepository.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepository.scala @@ -10,6 +10,12 @@ abstract class MavenRepository( val root: String, val localIfFile: Boolean) extends sbt.librarymanagement.Resolver(name) with Serializable { def isCache: Boolean + def allowInsecureProtocol: Boolean + def withAllowInsecureProtocol(allowInsecureProtocol: Boolean): MavenRepository = + this match { + case x: MavenRepo => x.with_allowInsecureProtocol(allowInsecureProtocol) + case x: MavenCache => x + } def this(name: String, root: String) = this(name, root, true) diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/Resolver.scala b/core/src/main/contraband-scala/sbt/librarymanagement/Resolver.scala index c6caf7eaf..448b04334 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/Resolver.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/Resolver.scala @@ -6,7 +6,8 @@ package sbt.librarymanagement abstract class Resolver( val name: String) extends Serializable { - + /** check for HTTP */ + private[sbt] def validateProtocol(logger: sbt.util.Logger): Unit = () diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/URLRepository.scala b/core/src/main/contraband-scala/sbt/librarymanagement/URLRepository.scala index fc39dda73..9f0efa520 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/URLRepository.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/URLRepository.scala @@ -6,22 +6,23 @@ package sbt.librarymanagement final class URLRepository private ( name: String, - patterns: sbt.librarymanagement.Patterns) extends sbt.librarymanagement.PatternsBasedRepository(name, patterns) with Serializable { - Resolver.validatePatterns(patterns) - + patterns: sbt.librarymanagement.Patterns, + val allowInsecureProtocol: Boolean) extends sbt.librarymanagement.PatternsBasedRepository(name, patterns) with Serializable { + private[sbt] override def validateProtocol(logger: sbt.util.Logger): Unit = Resolver.validateURLRepository(this, logger) + private def this(name: String, patterns: sbt.librarymanagement.Patterns) = this(name, patterns, false) override def equals(o: Any): Boolean = o match { - case x: URLRepository => (this.name == x.name) && (this.patterns == x.patterns) + case x: URLRepository => (this.name == x.name) && (this.patterns == x.patterns) && (this.allowInsecureProtocol == x.allowInsecureProtocol) case _ => false } override def hashCode: Int = { - 37 * (37 * (37 * (17 + "sbt.librarymanagement.URLRepository".##) + name.##) + patterns.##) + 37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.URLRepository".##) + name.##) + patterns.##) + allowInsecureProtocol.##) } override def toString: String = { - "URLRepository(" + name + ", " + patterns + ")" + "URLRepository(" + name + ", " + patterns + ", " + allowInsecureProtocol + ")" } - private[this] def copy(name: String = name, patterns: sbt.librarymanagement.Patterns = patterns): URLRepository = { - new URLRepository(name, patterns) + private[this] def copy(name: String = name, patterns: sbt.librarymanagement.Patterns = patterns, allowInsecureProtocol: Boolean = allowInsecureProtocol): URLRepository = { + new URLRepository(name, patterns, allowInsecureProtocol) } def withName(name: String): URLRepository = { copy(name = name) @@ -29,8 +30,12 @@ final class URLRepository private ( def withPatterns(patterns: sbt.librarymanagement.Patterns): URLRepository = { copy(patterns = patterns) } + def withAllowInsecureProtocol(allowInsecureProtocol: Boolean): URLRepository = { + copy(allowInsecureProtocol = allowInsecureProtocol) + } } object URLRepository { def apply(name: String, patterns: sbt.librarymanagement.Patterns): URLRepository = new URLRepository(name, patterns) + def apply(name: String, patterns: sbt.librarymanagement.Patterns, allowInsecureProtocol: Boolean): URLRepository = new URLRepository(name, patterns, allowInsecureProtocol) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/URLRepositoryFormats.scala b/core/src/main/contraband-scala/sbt/librarymanagement/URLRepositoryFormats.scala index dbf9e9cfa..4ab1b23c8 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/URLRepositoryFormats.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/URLRepositoryFormats.scala @@ -13,8 +13,9 @@ implicit lazy val URLRepositoryFormat: JsonFormat[sbt.librarymanagement.URLRepos unbuilder.beginObject(js) val name = unbuilder.readField[String]("name") val patterns = unbuilder.readField[sbt.librarymanagement.Patterns]("patterns") + val allowInsecureProtocol = unbuilder.readField[Boolean]("allowInsecureProtocol") unbuilder.endObject() - sbt.librarymanagement.URLRepository(name, patterns) + sbt.librarymanagement.URLRepository(name, patterns, allowInsecureProtocol) case None => deserializationError("Expected JsObject but found None") } @@ -23,6 +24,7 @@ implicit lazy val URLRepositoryFormat: JsonFormat[sbt.librarymanagement.URLRepos builder.beginObject() builder.addField("name", obj.name) builder.addField("patterns", obj.patterns) + builder.addField("allowInsecureProtocol", obj.allowInsecureProtocol) builder.endObject() } } diff --git a/core/src/main/contraband/librarymanagement.json b/core/src/main/contraband/librarymanagement.json index 2fc2c6fbb..67d655470 100644 --- a/core/src/main/contraband/librarymanagement.json +++ b/core/src/main/contraband/librarymanagement.json @@ -143,7 +143,11 @@ { "name": "configurations", "type": "sbt.librarymanagement.ConfigRef*", "default": "Vector.empty", "since": "0.0.1" }, { "name": "url", "type": "Option[java.net.URL]", "default": "None", "since": "0.0.1" }, { "name": "extraAttributes", "type": "Map[String, String]", "default": "Map.empty", "since": "0.0.1" }, - { "name": "checksum", "type": "Option[sbt.librarymanagement.Checksum]", "default": "None", "since": "0.0.1" } + { "name": "checksum", "type": "Option[sbt.librarymanagement.Checksum]", "default": "None", "since": "0.0.1" }, + { "name": "allowInsecureProtocol", "type": "Boolean", "default": "false", "since": "1.3.0" } + ], + "extra": [ + "private[sbt] def validateProtocol(logger: sbt.util.Logger): Unit = Resolver.validateArtifact(this, logger)" ], "parentsCompanion": "sbt.librarymanagement.ArtifactFunctions" }, @@ -557,6 +561,10 @@ "fields": [ { "name": "name", "type": "String" } ], + "extra": [ + "/** check for HTTP */", + "private[sbt] def validateProtocol(logger: sbt.util.Logger): Unit = ()" + ], "types": [ { "name": "ChainedResolver", @@ -565,6 +573,9 @@ "type": "record", "fields": [ { "name": "resolvers", "type": "sbt.librarymanagement.Resolver*" } + ], + "extra": [ + "private[sbt] override def validateProtocol(logger: sbt.util.Logger): Unit = resolvers.foreach(_.validateProtocol(logger))" ] }, { @@ -583,7 +594,17 @@ "namespace": "sbt.librarymanagement", "target": "Scala", "type": "record", - "extra": "def isCache: Boolean = false", + "doc": [ + "This is the internal implementation of actual Maven Repository (as opposed to a file cache)." + ], + "fields": [ + { "name": "_allowInsecureProtocol", "type": "Boolean", "default": "false", "since": "1.3.0" } + ], + "extra": [ + "override def isCache: Boolean = false", + "override def allowInsecureProtocol: Boolean = _allowInsecureProtocol", + "private[sbt] override def validateProtocol(logger: sbt.util.Logger): Unit = Resolver.validateMavenRepo(this, logger)" + ], "toString": "s\"$name: $root\"" }, { @@ -600,13 +621,22 @@ ], "extra": [ "def this(name: String, rootFile: java.io.File) = this(name, rootFile.toURI.toURL.toString, true, rootFile)", - "def isCache: Boolean = true" + "override def isCache: Boolean = true", + "override def allowInsecureProtocol: Boolean = false" ], "toString": "s\"cache:$name: ${rootFile.getAbsolutePath}\"", "extraCompanion": "def apply(name: String, rootFile: java.io.File): MavenCache = new MavenCache(name, rootFile)" } ], - "extra": "def isCache: Boolean", + "extra": [ + "def isCache: Boolean", + "def allowInsecureProtocol: Boolean", + "def withAllowInsecureProtocol(allowInsecureProtocol: Boolean): MavenRepository =", + " this match {", + " case x: MavenRepo => x.with_allowInsecureProtocol(allowInsecureProtocol)", + " case x: MavenCache => x", + " }" + ], "parentsCompanion": "sbt.librarymanagement.MavenRepositoryFunctions" }, { @@ -642,8 +672,11 @@ "namespace": "sbt.librarymanagement", "target": "Scala", "type": "record", + "fields": [ + { "name": "allowInsecureProtocol", "type": "boolean", "default": "false", "since": "1.3.0" } + ], "extra": [ - "Resolver.validatePatterns(patterns)" + "private[sbt] override def validateProtocol(logger: sbt.util.Logger): Unit = Resolver.validateURLRepository(this, logger)" ] }, { diff --git a/core/src/main/scala/sbt/librarymanagement/ArtifactExtra.scala b/core/src/main/scala/sbt/librarymanagement/ArtifactExtra.scala index f90b9e29b..63a992d2d 100644 --- a/core/src/main/scala/sbt/librarymanagement/ArtifactExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/ArtifactExtra.scala @@ -26,14 +26,18 @@ private[librarymanagement] abstract class ArtifactFunctions { Artifact(name, `type`, extension, None, Vector.empty, None) def apply(name: String, `type`: String, extension: String, classifier: String): Artifact = Artifact(name, `type`, extension, Some(classifier), Vector.empty, None) - def apply(name: String, url: URL): Artifact = + def apply(name: String, url: URL): Artifact = Artifact(name, url, false) + def apply(name: String, url: URL, allowInsecureProtocol: Boolean): Artifact = Artifact( name, extract(url, DefaultType), extract(url, DefaultExtension), None, Vector.empty, - Some(url) + Some(url), + Map.empty, + None, + allowInsecureProtocol ) private final val empty = Map.empty[String, String] diff --git a/core/src/main/scala/sbt/librarymanagement/DependencyBuilders.scala b/core/src/main/scala/sbt/librarymanagement/DependencyBuilders.scala index a9c9d86fd..99e64106d 100755 --- a/core/src/main/scala/sbt/librarymanagement/DependencyBuilders.scala +++ b/core/src/main/scala/sbt/librarymanagement/DependencyBuilders.scala @@ -67,9 +67,8 @@ object DependencyBuilders { } final class RepositoryName private[sbt] (name: String) { - def at(location: String) = { + def at(location: String): MavenRepository = { nonEmpty(location, "Repository location") - Resolver.validateUrlString(location) MavenRepository(name, location) } } diff --git a/core/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala b/core/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala index d8c6ca6f2..40db9def1 100644 --- a/core/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala @@ -8,6 +8,7 @@ import java.net.URL import sbt.internal.librarymanagement.mavenint.SbtPomExtraProperties import scala.collection.mutable.ListBuffer import sbt.librarymanagement.syntax._ +import sbt.util.Logger private[librarymanagement] abstract class ModuleIDExtra { def organization: String @@ -75,10 +76,10 @@ private[librarymanagement] abstract class ModuleIDExtra { // () required for chaining /** Do not follow dependencies of this module. Synonym for `intransitive`.*/ - def notTransitive() = intransitive() + def notTransitive(): ModuleID = intransitive() /** Do not follow dependencies of this module. Synonym for `notTransitive`.*/ - def intransitive() = withIsTransitive(false) + def intransitive(): ModuleID = withIsTransitive(false) /** * Marks this dependency as "changing". Ivy will always check if the metadata has changed and then if the artifact has changed, @@ -86,49 +87,58 @@ private[librarymanagement] abstract class ModuleIDExtra { * * See the "Changes in artifacts" section of https://ant.apache.org/ivy/history/trunk/concept.html for full details. */ - def changing() = withIsChanging(true) + def changing(): ModuleID = withIsChanging(true) /** * Indicates that conflict resolution should only select this module's revision. * This prevents a newer revision from being pulled in by a transitive dependency, for example. */ - def force() = withIsForce(true) + def force(): ModuleID = withIsForce(true) + + private[sbt] def validateProtocol(logger: Logger): Unit = { + explicitArtifacts foreach { _.validateProtocol(logger) } + } /** * Specifies a URL from which the main artifact for this dependency can be downloaded. * This value is only consulted if the module is not found in a repository. * It is not included in published metadata. */ - def from(url: String) = { - Resolver.validateUrlString(url) - artifacts(Artifact(name, new URL(url))) - } + def from(url: String): ModuleID = from(url, false) + + /** + * Specifies a URL from which the main artifact for this dependency can be downloaded. + * This value is only consulted if the module is not found in a repository. + * It is not included in published metadata. + */ + def from(url: String, allowInsecureProtocol: Boolean): ModuleID = + artifacts(Artifact(name, new URL(url), allowInsecureProtocol)) /** Adds a dependency on the artifact for this module with classifier `c`. */ - def classifier(c: String) = artifacts(Artifact(name, c)) + def classifier(c: String): ModuleID = artifacts(Artifact(name, c)) /** * Declares the explicit artifacts for this module. If this ModuleID represents a dependency, * these artifact definitions override the information in the dependency's published metadata. */ - def artifacts(newArtifacts: Artifact*) = + def artifacts(newArtifacts: Artifact*): ModuleID = withExplicitArtifacts(newArtifacts.toVector ++ explicitArtifacts) /** * Applies the provided exclusions to dependencies of this module. Note that only exclusions that specify * both the exact organization and name and nothing else will be included in a pom.xml. */ - def excludeAll(rules: ExclusionRule*) = withExclusions(exclusions ++ rules) + def excludeAll(rules: ExclusionRule*): ModuleID = withExclusions(exclusions ++ rules) /** Excludes the dependency with organization `org` and `name` from being introduced by this dependency during resolution. */ - def exclude(org: String, name: String) = + def exclude(org: String, name: String): ModuleID = excludeAll(ExclusionRule().withOrganization(org).withName(name)) /** * Adds extra attributes for this module. All keys are prefixed with `e:` if they are not already so prefixed. * This information will only be published in an ivy.xml and not in a pom.xml. */ - def extra(attributes: (String, String)*) = + def extra(attributes: (String, String)*): ModuleID = withExtraAttributes(extraAttributes ++ ModuleID.checkE(attributes)) /** @@ -136,30 +146,30 @@ private[librarymanagement] abstract class ModuleIDExtra { * for performance and correctness. This method adds a dependency on this module's artifact with the "sources" * classifier. If you want to also depend on the main artifact, be sure to also call `jar()` or use `withSources()` instead. */ - def sources() = artifacts(Artifact.sources(name)) + def sources(): ModuleID = artifacts(Artifact.sources(name)) /** * Not recommended for new use. This method is not deprecated, but the `update-classifiers` task is preferred * for performance and correctness. This method adds a dependency on this module's artifact with the "javadoc" * classifier. If you want to also depend on the main artifact, be sure to also call `jar()` or use `withJavadoc()` instead. */ - def javadoc() = artifacts(Artifact.javadoc(name)) + def javadoc(): ModuleID = artifacts(Artifact.javadoc(name)) - def pomOnly() = artifacts(Artifact.pom(name)) + def pomOnly(): ModuleID = artifacts(Artifact.pom(name)) /** * Not recommended for new use. This method is not deprecated, but the `update-classifiers` task is preferred * for performance and correctness. This method adds a dependency on this module's artifact with the "sources" * classifier. If there is not already an explicit dependency on the main artifact, this adds one. */ - def withSources() = jarIfEmpty.sources() + def withSources(): ModuleID = jarIfEmpty.sources() /** * Not recommended for new use. This method is not deprecated, but the `update-classifiers` task is preferred * for performance and correctness. This method adds a dependency on this module's artifact with the "javadoc" * classifier. If there is not already an explicit dependency on the main artifact, this adds one. */ - def withJavadoc() = jarIfEmpty.javadoc() + def withJavadoc(): ModuleID = jarIfEmpty.javadoc() private def jarIfEmpty = if (explicitArtifacts.isEmpty) jar() else this @@ -167,14 +177,14 @@ private[librarymanagement] abstract class ModuleIDExtra { * Declares a dependency on the main artifact. This is implied by default unless artifacts are explicitly declared, such * as when adding a dependency on an artifact with a classifier. */ - def jar() = artifacts(Artifact(name)) + def jar(): ModuleID = artifacts(Artifact(name)) /** * Sets the Ivy branch of this module. */ - def branch(branchName: String) = withBranchName(Some(branchName)) + def branch(branchName: String): ModuleID = withBranchName(Some(branchName)) - def branch(branchName: Option[String]) = withBranchName(branchName) + def branch(branchName: Option[String]): ModuleID = withBranchName(branchName) } private[librarymanagement] abstract class ModuleIDFunctions { diff --git a/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala b/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala index d45166997..33944a268 100644 --- a/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala @@ -7,7 +7,7 @@ import java.io.{ IOException, File } import java.net.URL import scala.xml.XML import org.xml.sax.SAXParseException -import sbt.util.{ Level, LogExchange } +import sbt.util.Logger final class RawRepository(val resolver: AnyRef, name: String) extends Resolver(name) { override def toString = "Raw(" + resolver.toString + ")" @@ -404,33 +404,60 @@ private[librarymanagement] abstract class ResolverFunctions { Patterns().withIvyPatterns(pList).withArtifactPatterns(pList).withIsMavenCompatible(false) } - lazy val log = { - val log0 = LogExchange.logger("sbt.librarymanagement.ResolverExtra") - LogExchange.bindLoggerAppenders( - "sbt.librarymanagement.ResolverExtra", - List(LogExchange.buildAsyncStdout -> Level.Info) - ) - log0 + private[sbt] def warnHttp(value: String, suggestion: String, logger: Logger): Unit = { + logger.warn(s"insecure HTTP request is deprecated '$value'; switch to HTTPS$suggestion") } - private[sbt] def warnHttp(value: String): Unit = { - log.warn(s"insecure HTTP request is deprecated '$value'; switch to HTTPS") + private[sbt] def isInsecureUrl(str: String): Boolean = { + // don't try to parse str as URL because it could contain $variable from Ivy pattern + str.startsWith("http:") && + !(str.startsWith("http://localhost/") + || str.startsWith("http://localhost:") + || str.startsWith("http://127.0.0.1/") + || str.startsWith("http://127.0.0.1:")) } - private[sbt] def validatePatterns(patterns: Patterns): Unit = { - val ivy = patterns.ivyPatterns.headOption match { - case Some(x) => x.startsWith("http:") - case _ => false - } - val art = patterns.artifactPatterns.headOption match { - case Some(x) => x.startsWith("http:") - case _ => false - } - if (ivy || art) { - warnHttp(patterns.toString) + private[sbt] def validateURLRepository(repo: URLRepository, logger: Logger): Unit = { + if (repo.allowInsecureProtocol) () + else { + val patterns = repo.patterns + val ivy = patterns.ivyPatterns.headOption match { + case Some(x) => isInsecureUrl(x) + case _ => false + } + val art = patterns.artifactPatterns.headOption match { + case Some(x) => isInsecureUrl(x) + case _ => false + } + if (ivy || art) { + warnHttp( + patterns.toString, + s""" or opt-in as Resolver.url("${repo.name}", url(...)).withAllowInsecureProtocol(true)""", + logger + ) + } } } - private[sbt] def validateUrlString(url: String): Unit = { - if (url.startsWith("http:")) { - warnHttp(url) + + private[sbt] def validateMavenRepo(repo: MavenRepo, logger: Logger): Unit = + if (repo.allowInsecureProtocol) () + else if (isInsecureUrl(repo.root)) { + warnHttp( + repo.root, + s""" or opt-in as ("${repo.name}" at "${repo.root}").withAllowInsecureProtocol(true)""", + logger + ) + } + + private[sbt] def validateArtifact(art: Artifact, logger: Logger): Unit = + if (art.allowInsecureProtocol) () + else { + art.url foreach { url => + if (isInsecureUrl(url.toString)) { + warnHttp( + art.toString, + " or opt-in using from(url(...), allowInsecureProtocol = true) on ModuleID or .withAllowInsecureProtocol(true) on Artifact", + logger + ) + } + } } - } } From 2071b297481bc25e60a624e2532ac7eec2b9283d Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Wed, 28 Aug 2019 18:28:30 -0400 Subject: [PATCH 17/19] Remove unused file --- .../librarymanagement/DisabledFormats.scala | 27 ------------------- 1 file changed, 27 deletions(-) delete mode 100644 core/src/main/contraband-scala/sbt/librarymanagement/DisabledFormats.scala diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/DisabledFormats.scala b/core/src/main/contraband-scala/sbt/librarymanagement/DisabledFormats.scala deleted file mode 100644 index 7c0602834..000000000 --- a/core/src/main/contraband-scala/sbt/librarymanagement/DisabledFormats.scala +++ /dev/null @@ -1,27 +0,0 @@ -/** - * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. - */ - -// DO NOT EDIT MANUALLY -package sbt.librarymanagement -import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } -trait DisabledFormats { self: sjsonnew.BasicJsonProtocol => -implicit lazy val DisabledFormat: JsonFormat[sbt.librarymanagement.Disabled] = new JsonFormat[sbt.librarymanagement.Disabled] { - override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.Disabled = { - jsOpt match { - case Some(js) => - unbuilder.beginObject(js) - - unbuilder.endObject() - sbt.librarymanagement.Disabled() - case None => - deserializationError("Expected JsObject but found None") - } - } - override def write[J](obj: sbt.librarymanagement.Disabled, builder: Builder[J]): Unit = { - builder.beginObject() - - builder.endObject() - } -} -} From b01b61384e7e51442089e7bde0b727101fc53de9 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Wed, 28 Aug 2019 18:33:46 -0400 Subject: [PATCH 18/19] Add custom handling for Disabled companion object https://github.com/sbt/librarymanagement/pull/316 started returning Disabled companion object for `apply()` instead of creating a new instance. This leaked into JSON as it uses runtime types for union. This works around that by providing a hand-crafted format. Ref https://github.com/sbt/sbt/pull/4997 --- .../sbt/librarymanagement/CrossVersion.scala | 34 ++++++++++++++----- .../sbt/librarymanagement/ModuleIdTest.scala | 14 ++++++++ 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/core/src/main/scala/sbt/librarymanagement/CrossVersion.scala b/core/src/main/scala/sbt/librarymanagement/CrossVersion.scala index 19e712981..4ab1b6446 100644 --- a/core/src/main/scala/sbt/librarymanagement/CrossVersion.scala +++ b/core/src/main/scala/sbt/librarymanagement/CrossVersion.scala @@ -331,14 +331,30 @@ trait CrossVersionFormats { with sbt.librarymanagement.ConstantFormats with sbt.librarymanagement.PatchFormats with sbt.librarymanagement.FullFormats => - implicit lazy val CrossVersionFormat: JsonFormat[sbt.librarymanagement.CrossVersion] = - flatUnionFormat6[ - sbt.librarymanagement.CrossVersion, - sbt.librarymanagement.Disabled, - sbt.librarymanagement.Disabled.type, - sbt.librarymanagement.Binary, - sbt.librarymanagement.Constant, - sbt.librarymanagement.Patch, - sbt.librarymanagement.Full + implicit lazy val CrossVersionFormat: JsonFormat[CrossVersion] = { + val format = flatUnionFormat6[ + CrossVersion, + Disabled, + Disabled.type, + Binary, + Constant, + Patch, + Full ]("type") + // This is a hand-crafted formatter to avoid Disabled$ showing up in JSON + new JsonFormat[CrossVersion] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): CrossVersion = + format.read(jsOpt, unbuilder) + override def write[J](obj: CrossVersion, builder: Builder[J]): Unit = { + if (obj == Disabled) { + builder.beginPreObject() + builder.addFieldName("type") + builder.writeString("Disabled") + builder.endPreObject() + builder.beginObject() + builder.endObject() + } else format.write(obj, builder) + } + } + } } diff --git a/core/src/test/scala/sbt/librarymanagement/ModuleIdTest.scala b/core/src/test/scala/sbt/librarymanagement/ModuleIdTest.scala index a9bab61f0..1698f317a 100644 --- a/core/src/test/scala/sbt/librarymanagement/ModuleIdTest.scala +++ b/core/src/test/scala/sbt/librarymanagement/ModuleIdTest.scala @@ -1,8 +1,11 @@ package sbt.librarymanagement import sbt.internal.librarymanagement.UnitSpec +import sjsonnew.support.scalajson.unsafe.{ Converter, CompactPrinter, Parser } class ModuleIdTest extends UnitSpec { + val expectedJson = + """{"organization":"com.acme","name":"foo","revision":"1","isChanging":false,"isTransitive":true,"isForce":false,"explicitArtifacts":[],"inclusions":[],"exclusions":[],"extraAttributes":{},"crossVersion":{"type":"Disabled"}}""" "Module Id" should "return cross-disabled module id as equal to a copy" in { ModuleID("com.acme", "foo", "1") shouldBe ModuleID("com.acme", "foo", "1") } @@ -14,4 +17,15 @@ class ModuleIdTest extends UnitSpec { (ModuleID("com.acme", "foo", "1") cross CrossVersion.binary) shouldBe (ModuleID("com.acme", "foo", "1") cross CrossVersion.binary) } + it should "format itself into JSON" in { + import LibraryManagementCodec._ + val json = Converter.toJson(ModuleID("com.acme", "foo", "1")).get + assert(CompactPrinter(json) == expectedJson) + } + it should "thaw back from JSON" in { + import LibraryManagementCodec._ + val json = Parser.parseUnsafe(expectedJson) + val m = Converter.fromJsonUnsafe[ModuleID](json) + assert(m == ModuleID("com.acme", "foo", "1")) + } } From d4f2b237810c2b51c8a6f40dc8bff93e567b6853 Mon Sep 17 00:00:00 2001 From: Vincent PERICART Date: Thu, 12 Sep 2019 10:34:44 +0900 Subject: [PATCH 19/19] Fix typo: cachedResolution --- .../main/scala/sbt/librarymanagement/ivy/UpdateOptions.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ivy/src/main/scala/sbt/librarymanagement/ivy/UpdateOptions.scala b/ivy/src/main/scala/sbt/librarymanagement/ivy/UpdateOptions.scala index 1ac339eec..0a41509bb 100644 --- a/ivy/src/main/scala/sbt/librarymanagement/ivy/UpdateOptions.scala +++ b/ivy/src/main/scala/sbt/librarymanagement/ivy/UpdateOptions.scala @@ -37,8 +37,8 @@ final class UpdateOptions private[sbt] ( copy(interProjectFirst = interProjectFirst) def withLatestSnapshots(latestSnapshots: Boolean): UpdateOptions = copy(latestSnapshots = latestSnapshots) - def withCachedResolution(cachedResoluton: Boolean): UpdateOptions = - copy(cachedResolution = cachedResoluton) + def withCachedResolution(cachedResolution: Boolean): UpdateOptions = + copy(cachedResolution = cachedResolution) def withGigahorse(gigahorse: Boolean): UpdateOptions = copy(gigahorse = gigahorse)