diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 11c60e59..6ef1c3da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,31 +21,15 @@ jobs: JVM_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M steps: - name: Checkout - uses: actions/checkout@v1 - - name: Setup - uses: olafurpg/setup-scala@v10 + uses: actions/checkout@v3 + - name: Setup JDK + uses: actions/setup-java@v3 with: - java-version: "adopt@1.${{ matrix.java }}" - - name: Coursier cache - uses: coursier/cache-action@v5 - - name: Cache sbt - uses: actions/cache@v1 - with: - path: $HOME/.sbt - key: ${{ runner.os }}-sbt-cache-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} - - name: Build and test + distribution: temurin + java-version: "${{ matrix.java }}" + cache: sbt + - name: Build and test (1) + if: ${{ matrix.jobtype == 1 }} + shell: bash run: | - case ${{ matrix.jobtype }} in - 1) - sbt -v -Dfile.encoding=UTF8 scalafmtCheckAll whitesourceCheckPolicies test packagedArtifacts - ;; - *) - echo unknown jobtype - exit 1 - esac - rm -rf "$HOME/.ivy2/local" - find $HOME/Library/Caches/Coursier/v1 -name "ivydata-*.properties" -delete || true - find $HOME/.ivy2/cache -name "ivydata-*.properties" -delete || true - find $HOME/.ivy2/cache -name "*-LM-SNAPSHOT*" -delete || true - find $HOME/.cache/coursier/v1 -name "ivydata-*.properties" -delete || true - find $HOME/.sbt -name "*.lock" -delete || true + sbt -v -Dfile.encoding=UTF8 scalafmtCheckAll +test +packagedArtifacts diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml new file mode 100644 index 00000000..abbf9f3b --- /dev/null +++ b/.github/workflows/cla.yml @@ -0,0 +1,24 @@ +name: Scala CLA +on: [pull_request] +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Check CLA + env: + AUTHOR: ${{ github.event.pull_request.user.login }} + run: | + echo "Pull request submitted by $AUTHOR"; + signed=$(curl -s "https://www.lightbend.com/contribute/cla/scala/check/$AUTHOR" | jq -r ".signed"); + if [ "$signed" = "true" ] ; then + echo "CLA check for $AUTHOR successful"; + else + echo "CLA check for $AUTHOR failed"; + echo "Please sign the Scala CLA to contribute to the Scala compiler."; + echo "Go to https://www.lightbend.com/contribute/cla/scala and then"; + echo "comment on the pull request to ask for a new check."; + echo ""; + echo "Check if CLA is signed: https://www.lightbend.com/contribute/cla/scala/check/$AUTHOR"; + exit 1; + fi; diff --git a/.gitignore b/.gitignore index 49523147..99e785f4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,9 @@ __pycache__ scripted-test/src/sbt-test/*/*/project/build.properties scripted-test/src/sbt-test/*/*/project/plugins.sbt + +.idea +.bloop +.metals +.bsp/ +metals.sbt diff --git a/.scalafmt.conf b/.scalafmt.conf index e98e6059..4bcacf16 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,11 +1,12 @@ -version = 2.0.0 +version = 3.7.4 maxColumn = 100 project.git = true project.excludeFilters = [ /sbt-test/, /input_sources/, /contraband-scala/ ] # http://docs.scala-lang.org/style/scaladoc.html recommends the JavaDoc style. # scala/scala is written that way too https://github.com/scala/scala/blob/v2.12.2/src/library/scala/Predef.scala -docstrings = JavaDoc +docstrings.style = Asterisk +docstrings.wrap = no # This also seems more idiomatic to include whitespace in import x.{ yyy } spaces.inImportCurlyBraces = true @@ -16,6 +17,8 @@ align.openParenCallSite = false align.openParenDefnSite = false # For better code clarity -danglingParentheses = true +danglingParentheses.preset = true trailingCommas = preserve + +runner.dialect = Scala212Source3 diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..5c4a3cff --- /dev/null +++ b/LICENSE @@ -0,0 +1,204 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2023, Scala Center + Copyright (c) 2011 - 2022, Lightbend, Inc. + Copyright (c) 2008 - 2010, Mark Harrah + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/build.sbt b/build.sbt index 62640cfb..70ffc174 100644 --- a/build.sbt +++ b/build.sbt @@ -3,22 +3,22 @@ import Path._ import com.typesafe.tools.mima.core._, ProblemFilters._ val _ = { - //https://github.com/sbt/contraband/issues/122 + // https://github.com/sbt/contraband/issues/122 sys.props += ("line.separator" -> "\n") } - +Global / semanticdbEnabled := !(Global / insideCI).value +Global / semanticdbVersion := "4.7.8" ThisBuild / version := { val old = (ThisBuild / version).value nightlyVersion match { case Some(v) => v case _ => - if ((ThisBuild / isSnapshot).value) "1.4.0-SNAPSHOT" + if ((ThisBuild / isSnapshot).value) "1.7.2-SNAPSHOT" else old } } ThisBuild / versionScheme := Some("early-semver") ThisBuild / organization := "org.scala-sbt" -ThisBuild / bintrayPackage := sys.env.get("BINTRAY_PACKAGE").getOrElse("librarymanagement") ThisBuild / homepage := Some(url("https://github.com/sbt/librarymanagement")) ThisBuild / description := "Library management module for sbt" ThisBuild / scmInfo := { @@ -32,6 +32,11 @@ ThisBuild / developers := List( Developer("eed3si9n", "Eugene Yokota", "@eed3si9n", url("http://eed3si9n.com/")), Developer("dwijnand", "Dale Wijnand", "@dwijnand", url("https://github.com/dwijnand")), ) +ThisBuild / pomIncludeRepository := (_ => false) // drop repos other than Maven Central from POM +ThisBuild / publishTo := { + val nexus = "https://oss.sonatype.org/" + Some("releases" at nexus + "service/local/staging/deploy/maven2") +} ThisBuild / Test / classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat @@ -41,12 +46,11 @@ def commonSettings: Seq[Setting[_]] = Def.settings( resolvers += Resolver.typesafeIvyRepo("releases"), 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"), - crossScalaVersions := Seq(scala212), + compile / javacOptions ++= Seq("-Xlint", "-Xlint:-serial"), + crossScalaVersions := Seq(scala212, scala213), resolvers += Resolver.sonatypeRepo("public"), scalacOptions := { val old = scalacOptions.value @@ -54,17 +58,19 @@ def commonSettings: Seq[Setting[_]] = Def.settings( case sv if sv.startsWith("2.10") => old diff List("-Xfuture", "-Ywarn-unused", "-Ywarn-unused-import") case sv if sv.startsWith("2.11") => old ++ List("-Ywarn-unused", "-Ywarn-unused-import") - case _ => old ++ List("-Ywarn-unused", "-Ywarn-unused-import", "-YdisableFlatCpCaching") + case sv if sv.startsWith("2.12") => + old ++ List("-Ywarn-unused", "-Ywarn-unused-import", "-YdisableFlatCpCaching") + case _ => old } }, inCompileAndTest( - scalacOptions in console --= Vector("-Ywarn-unused-import", "-Ywarn-unused", "-Xlint") + (console / scalacOptions) --= Vector("-Ywarn-unused-import", "-Ywarn-unused", "-Xlint") ), scalafmtOnCompile := true, Test / scalafmtOnCompile := true, - publishArtifact in Compile := true, - publishArtifact in Test := false, - parallelExecution in Test := false + Compile / publishArtifact := true, + Test / publishArtifact := false, + Test / parallelExecution := false ) val mimaSettings = Def settings ( @@ -81,11 +87,13 @@ val mimaSettings = Def settings ( "1.1.4", "1.2.0", "1.3.0", - ) map ( - version => - organization.value %% moduleName.value % version - cross (if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled) - ), + "1.4.0", + "1.5.0", + "1.6.0", + ) map (version => + organization.value %% moduleName.value % version + cross (if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled) + ), ) lazy val lmRoot = (project in file(".")) @@ -95,7 +103,7 @@ lazy val lmRoot = (project in file(".")) name := "LM Root", publish := {}, publishLocal := {}, - publishArtifact in Compile := false, + Compile / publishArtifact := false, publishArtifact := false, mimaPreviousArtifacts := Set.empty, customCommands, @@ -111,25 +119,20 @@ lazy val lmCore = (project in file("core")) scalaReflect.value, scalaCompiler.value, launcherInterface, - gigahorseOkhttp, - okhttpUrlconnection, + gigahorseApacheHttp, sjsonnewScalaJson.value % Optional, scalaTest % Test, 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 + Compile / resourceGenerators += Def .task( Util.generateVersionFile( version.value, resourceManaged.value, streams.value, - (compile in Compile).value + (Compile / compile).value ) ) .taskValue, @@ -137,14 +140,14 @@ lazy val lmCore = (project in file("core")) case v if v.startsWith("2.12.") => List("-Ywarn-unused:-locals,-explicits,-privates") case _ => List() }), - managedSourceDirectories in Compile += + Compile / managedSourceDirectories += baseDirectory.value / "src" / "main" / "contraband-scala", - sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala", - contrabandFormatsForType in generateContrabands in Compile := DatatypeConfig.getFormats, + Compile / generateContrabands / sourceManaged := baseDirectory.value / "src" / "main" / "contraband-scala", + Compile / generateContrabands / contrabandFormatsForType := DatatypeConfig.getFormats, // WORKAROUND sbt/sbt#2205 include managed sources in packageSrc - mappings in (Compile, packageSrc) ++= { - val srcs = (managedSources in Compile).value - val sdirs = (managedSourceDirectories in Compile).value + Compile / packageSrc / mappings ++= { + val srcs = (Compile / managedSources).value + val sdirs = (Compile / managedSourceDirectories).value val base = baseDirectory.value (((srcs --- sdirs --- base) pair (relativeTo(sdirs) | relativeTo(base) | flat)) toSeq) }, @@ -257,6 +260,12 @@ lazy val lmCore = (project in file("core")) "sbt.librarymanagement.ResolverFunctions.validateArtifact" ), exclude[IncompatibleResultTypeProblem]("sbt.librarymanagement.*.validateProtocol"), + exclude[DirectMissingMethodProblem]( + "sbt.internal.librarymanagement.cross.CrossVersionUtil.TransitionDottyVersion" + ), + exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ScalaArtifacts.dottyID"), + exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ScalaArtifacts.DottyIDPrefix"), + exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ScalaArtifacts.toolDependencies*"), ), ) .configure(addSbtIO, addSbtUtilLogging, addSbtUtilPosition, addSbtUtilCache) @@ -273,11 +282,11 @@ lazy val lmIvy = (project in file("ivy")) scalaCheck % Test, scalaVerify % Test, ), - managedSourceDirectories in Compile += + Compile / managedSourceDirectories += baseDirectory.value / "src" / "main" / "contraband-scala", - sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala", - contrabandFormatsForType in generateContrabands in Compile := DatatypeConfig.getFormats, - scalacOptions in (Compile, console) --= + Compile / generateContrabands / sourceManaged := baseDirectory.value / "src" / "main" / "contraband-scala", + Compile / generateContrabands / contrabandFormatsForType := DatatypeConfig.getFormats, + Compile / console / scalacOptions --= Vector("-Ywarn-unused-import", "-Ywarn-unused", "-Xlint"), mimaSettings, mimaBinaryIssueFilters ++= Seq( @@ -344,6 +353,15 @@ lazy val lmIvy = (project in file("ivy")) "sbt.internal.librarymanagement.CustomPomParser.versionRangeFlag" ), exclude[MissingClassProblem]("sbt.internal.librarymanagement.FixedParser*"), + exclude[MissingClassProblem]("sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler*"), + exclude[MissingClassProblem]("sbt.internal.librarymanagement.JavaNetAuthenticator"), + exclude[MissingClassProblem]("sbt.internal.librarymanagement.CustomHttp*"), + exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.IvySbt.http"), + exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.IvySbt.this"), + exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ivy.IvyPublisher.apply"), + exclude[DirectMissingMethodProblem]( + "sbt.librarymanagement.ivy.IvyDependencyResolution.apply" + ), ), ) @@ -380,16 +398,5 @@ 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, - ) -) - def inCompileAndTest(ss: SettingsDefinition*): Seq[Setting[_]] = Seq(Compile, Test) flatMap (inConfig(_)(Def.settings(ss: _*))) diff --git a/core/src/main/contraband-scala/sbt/internal/librarymanagement/ConfigurationReportLite.scala b/core/src/main/contraband-scala/sbt/internal/librarymanagement/ConfigurationReportLite.scala index b9a9c46f..d277f7ca 100644 --- a/core/src/main/contraband-scala/sbt/internal/librarymanagement/ConfigurationReportLite.scala +++ b/core/src/main/contraband-scala/sbt/internal/librarymanagement/ConfigurationReportLite.scala @@ -10,10 +10,10 @@ final class ConfigurationReportLite private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: ConfigurationReportLite => (this.configuration == x.configuration) && (this.details == x.details) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (17 + "sbt.internal.librarymanagement.ConfigurationReportLite".##) + configuration.##) + details.##) } diff --git a/core/src/main/contraband-scala/sbt/internal/librarymanagement/SemComparator.scala b/core/src/main/contraband-scala/sbt/internal/librarymanagement/SemComparator.scala index fda56f60..2baccd6b 100644 --- a/core/src/main/contraband-scala/sbt/internal/librarymanagement/SemComparator.scala +++ b/core/src/main/contraband-scala/sbt/internal/librarymanagement/SemComparator.scala @@ -21,10 +21,10 @@ final class SemComparator private ( } -override def equals(o: Any): Boolean = o match { +override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: SemComparator => (this.op == x.op) && (this.major == x.major) && (this.minor == x.minor) && (this.patch == x.patch) && (this.tags == x.tags) case _ => false -} +}) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.librarymanagement.SemComparator".##) + op.##) + major.##) + minor.##) + patch.##) + tags.##) } diff --git a/core/src/main/contraband-scala/sbt/internal/librarymanagement/SemSelAndChunk.scala b/core/src/main/contraband-scala/sbt/internal/librarymanagement/SemSelAndChunk.scala index 3b8ab91a..820fc323 100644 --- a/core/src/main/contraband-scala/sbt/internal/librarymanagement/SemSelAndChunk.scala +++ b/core/src/main/contraband-scala/sbt/internal/librarymanagement/SemSelAndChunk.scala @@ -9,10 +9,10 @@ final class SemSelAndChunk private ( def matches(version: sbt.librarymanagement.VersionNumber): Boolean = comparators.forall(_.matches(version)) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: SemSelAndChunk => (this.comparators == x.comparators) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (17 + "sbt.internal.librarymanagement.SemSelAndChunk".##) + comparators.##) } diff --git a/core/src/main/contraband-scala/sbt/internal/librarymanagement/UpdateReportLite.scala b/core/src/main/contraband-scala/sbt/internal/librarymanagement/UpdateReportLite.scala index 94828053..f5040d97 100644 --- a/core/src/main/contraband-scala/sbt/internal/librarymanagement/UpdateReportLite.scala +++ b/core/src/main/contraband-scala/sbt/internal/librarymanagement/UpdateReportLite.scala @@ -9,10 +9,10 @@ final class UpdateReportLite private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: UpdateReportLite => (this.configurations == x.configurations) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (17 + "sbt.internal.librarymanagement.UpdateReportLite".##) + configurations.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/Artifact.scala b/core/src/main/contraband-scala/sbt/librarymanagement/Artifact.scala index 86d7a218..24764d0c 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/Artifact.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/Artifact.scala @@ -18,10 +18,10 @@ final class Artifact private ( 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 { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (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) && (this.allowInsecureProtocol == x.allowInsecureProtocol) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.Artifact".##) + name.##) + `type`.##) + extension.##) + classifier.##) + configurations.##) + url.##) + extraAttributes.##) + checksum.##) + allowInsecureProtocol.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ArtifactTypeFilter.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ArtifactTypeFilter.scala index fbdbc8dc..6d9676e7 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ArtifactTypeFilter.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ArtifactTypeFilter.scala @@ -17,10 +17,10 @@ final class ArtifactTypeFilter private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: ArtifactTypeFilter => (this.types == x.types) && (this.inverted == x.inverted) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (17 + "sbt.librarymanagement.ArtifactTypeFilter".##) + types.##) + inverted.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/Caller.scala b/core/src/main/contraband-scala/sbt/librarymanagement/Caller.scala index 07474050..30b0b937 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/Caller.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/Caller.scala @@ -15,10 +15,10 @@ final class Caller private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: Caller => (this.caller == x.caller) && (this.callerConfigurations == x.callerConfigurations) && (this.callerExtraAttributes == x.callerExtraAttributes) && (this.isForceDependency == x.isForceDependency) && (this.isChangingDependency == x.isChangingDependency) && (this.isTransitiveDependency == x.isTransitiveDependency) && (this.isDirectlyForceDependency == x.isDirectlyForceDependency) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.Caller".##) + caller.##) + callerConfigurations.##) + callerExtraAttributes.##) + isForceDependency.##) + isChangingDependency.##) + isTransitiveDependency.##) + isDirectlyForceDependency.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ChainedResolver.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ChainedResolver.scala index 3fe0ce54..b91c5db8 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ChainedResolver.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ChainedResolver.scala @@ -10,10 +10,10 @@ final class ChainedResolver private ( private[sbt] override def validateProtocol(logger: sbt.util.Logger): Boolean = !resolvers.forall(!_.validateProtocol(logger)) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: ChainedResolver => (this.name == x.name) && (this.resolvers == x.resolvers) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (17 + "sbt.librarymanagement.ChainedResolver".##) + name.##) + resolvers.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/Checksum.scala b/core/src/main/contraband-scala/sbt/librarymanagement/Checksum.scala index fafa5e34..13676bc3 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/Checksum.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/Checksum.scala @@ -10,10 +10,10 @@ final class Checksum private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: Checksum => (this.digest == x.digest) && (this.`type` == x.`type`) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (17 + "sbt.librarymanagement.Checksum".##) + digest.##) + `type`.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ConfigRef.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ConfigRef.scala deleted file mode 100644 index 383c5e77..00000000 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ConfigRef.scala +++ /dev/null @@ -1,36 +0,0 @@ -/** - * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. - */ - -// DO NOT EDIT MANUALLY -package sbt.librarymanagement -/** - * A reference to Configuration. - * @param name The name of the configuration that eventually get used by Maven. - */ -final class ConfigRef private ( - val name: String) extends Serializable { - - - - override def equals(o: Any): Boolean = o match { - case x: ConfigRef => (this.name == x.name) - case _ => false - } - override def hashCode: Int = { - 37 * (37 * (17 + "sbt.librarymanagement.ConfigRef".##) + name.##) - } - override def toString: String = { - name - } - private[this] def copy(name: String = name): ConfigRef = { - new ConfigRef(name) - } - def withName(name: String): ConfigRef = { - copy(name = name) - } -} -object ConfigRef extends sbt.librarymanagement.ConfigRefFunctions { - - def apply(name: String): ConfigRef = new ConfigRef(name) -} diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ConfigRefFormats.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ConfigRefFormats.scala deleted file mode 100644 index ffbb7f29..00000000 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ConfigRefFormats.scala +++ /dev/null @@ -1,27 +0,0 @@ -/** - * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. - */ - -// DO NOT EDIT MANUALLY -package sbt.librarymanagement -import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } -trait ConfigRefFormats { self: sjsonnew.BasicJsonProtocol => -implicit lazy val ConfigRefFormat: JsonFormat[sbt.librarymanagement.ConfigRef] = new JsonFormat[sbt.librarymanagement.ConfigRef] { - override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.ConfigRef = { - __jsOpt match { - case Some(__js) => - unbuilder.beginObject(__js) - val name = unbuilder.readField[String]("name") - unbuilder.endObject() - sbt.librarymanagement.ConfigRef(name) - case None => - deserializationError("Expected JsObject but found None") - } - } - override def write[J](obj: sbt.librarymanagement.ConfigRef, builder: Builder[J]): Unit = { - builder.beginObject() - builder.addField("name", obj.name) - builder.endObject() - } -} -} diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ConfigurationReport.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ConfigurationReport.scala index 379a090f..99b421dd 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ConfigurationReport.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ConfigurationReport.scala @@ -17,10 +17,10 @@ final class ConfigurationReport private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: ConfigurationReport => (this.configuration == x.configuration) && (this.modules == x.modules) && (this.details == x.details) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.ConfigurationReport".##) + configuration.##) + modules.##) + details.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ConflictManager.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ConflictManager.scala index 3779a980..cef31049 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ConflictManager.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ConflictManager.scala @@ -12,10 +12,10 @@ final class ConflictManager private ( private def this(name: String) = this(name, "*", "*") - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: ConflictManager => (this.name == x.name) && (this.organization == x.organization) && (this.module == x.module) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.ConflictManager".##) + name.##) + organization.##) + module.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/Developer.scala b/core/src/main/contraband-scala/sbt/librarymanagement/Developer.scala index eb12f67f..fc52d4e7 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/Developer.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/Developer.scala @@ -12,10 +12,10 @@ final class Developer private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: Developer => (this.id == x.id) && (this.name == x.name) && (this.email == x.email) && (this.url == x.url) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.Developer".##) + id.##) + name.##) + email.##) + url.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/FileConfiguration.scala b/core/src/main/contraband-scala/sbt/librarymanagement/FileConfiguration.scala index 26be3bbc..daf2e6d3 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/FileConfiguration.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/FileConfiguration.scala @@ -11,10 +11,10 @@ final class FileConfiguration private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: FileConfiguration => (this.isLocal == x.isLocal) && (this.isTransactional == x.isTransactional) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (17 + "sbt.librarymanagement.FileConfiguration".##) + isLocal.##) + isTransactional.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/FileRepository.scala b/core/src/main/contraband-scala/sbt/librarymanagement/FileRepository.scala index ceb376bd..ca1fb7b7 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/FileRepository.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/FileRepository.scala @@ -13,10 +13,10 @@ final class FileRepository private ( this(name, patterns, configuration) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: FileRepository => (this.name == x.name) && (this.patterns == x.patterns) && (this.configuration == x.configuration) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.FileRepository".##) + name.##) + patterns.##) + configuration.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/GetClassifiersConfiguration.scala b/core/src/main/contraband-scala/sbt/librarymanagement/GetClassifiersConfiguration.scala index dfcc0a03..85deb700 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/GetClassifiersConfiguration.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/GetClassifiersConfiguration.scala @@ -13,10 +13,10 @@ final class GetClassifiersConfiguration private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: GetClassifiersConfiguration => (this.module == x.module) && (this.excludes == x.excludes) && (this.updateConfiguration == x.updateConfiguration) && (this.sourceArtifactTypes == x.sourceArtifactTypes) && (this.docArtifactTypes == x.docArtifactTypes) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.GetClassifiersConfiguration".##) + module.##) + excludes.##) + updateConfiguration.##) + sourceArtifactTypes.##) + docArtifactTypes.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/GetClassifiersModule.scala b/core/src/main/contraband-scala/sbt/librarymanagement/GetClassifiersModule.scala index 57459661..dfdaa72c 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/GetClassifiersModule.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/GetClassifiersModule.scala @@ -13,10 +13,10 @@ final class GetClassifiersModule private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: GetClassifiersModule => (this.id == x.id) && (this.scalaModuleInfo == x.scalaModuleInfo) && (this.dependencies == x.dependencies) && (this.configurations == x.configurations) && (this.classifiers == x.classifiers) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.GetClassifiersModule".##) + id.##) + scalaModuleInfo.##) + dependencies.##) + configurations.##) + classifiers.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/InclExclRule.scala b/core/src/main/contraband-scala/sbt/librarymanagement/InclExclRule.scala index 65bbf030..23da54f2 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/InclExclRule.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/InclExclRule.scala @@ -22,10 +22,10 @@ final class InclExclRule private ( private def this() = this("*", "*", "*", Vector.empty, sbt.librarymanagement.Disabled()) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: InclExclRule => (this.organization == x.organization) && (this.name == x.name) && (this.artifact == x.artifact) && (this.configurations == x.configurations) && (this.crossVersion == x.crossVersion) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.InclExclRule".##) + organization.##) + name.##) + artifact.##) + configurations.##) + crossVersion.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/InclExclRuleFormats.scala b/core/src/main/contraband-scala/sbt/librarymanagement/InclExclRuleFormats.scala index a6a4bcd2..837b478e 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/InclExclRuleFormats.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/InclExclRuleFormats.scala @@ -5,7 +5,7 @@ // DO NOT EDIT MANUALLY package sbt.librarymanagement import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } -trait InclExclRuleFormats { self: sbt.librarymanagement.ConfigRefFormats with sbt.librarymanagement.CrossVersionFormats with sbt.librarymanagement.DisabledFormats with sbt.librarymanagement.BinaryFormats with sbt.librarymanagement.ConstantFormats with sbt.librarymanagement.PatchFormats with sbt.librarymanagement.FullFormats with sjsonnew.BasicJsonProtocol => +trait InclExclRuleFormats { self: sbt.librarymanagement.ConfigRefFormats with sbt.librarymanagement.CrossVersionFormats with sbt.librarymanagement.DisabledFormats with sbt.librarymanagement.BinaryFormats with sbt.librarymanagement.ConstantFormats with sbt.librarymanagement.PatchFormats with sbt.librarymanagement.FullFormats with sbt.librarymanagement.For3Use2_13Formats with sbt.librarymanagement.For2_13Use3Formats with sjsonnew.BasicJsonProtocol => implicit lazy val InclExclRuleFormat: JsonFormat[sbt.librarymanagement.InclExclRule] = new JsonFormat[sbt.librarymanagement.InclExclRule] { override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.InclExclRule = { __jsOpt match { diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/IvyFileConfiguration.scala b/core/src/main/contraband-scala/sbt/librarymanagement/IvyFileConfiguration.scala index 4413ba31..0611fbab 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/IvyFileConfiguration.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/IvyFileConfiguration.scala @@ -12,10 +12,10 @@ final class IvyFileConfiguration private ( private def this(file: java.io.File, autoScalaTools: Boolean) = this(false, None, file, autoScalaTools) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: IvyFileConfiguration => (this.validate == x.validate) && (this.scalaModuleInfo == x.scalaModuleInfo) && (this.file == x.file) && (this.autoScalaTools == x.autoScalaTools) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.IvyFileConfiguration".##) + validate.##) + scalaModuleInfo.##) + file.##) + autoScalaTools.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/KeyFileAuthentication.scala b/core/src/main/contraband-scala/sbt/librarymanagement/KeyFileAuthentication.scala index 82431520..7366734e 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/KeyFileAuthentication.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/KeyFileAuthentication.scala @@ -11,10 +11,10 @@ final class KeyFileAuthentication private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: KeyFileAuthentication => (this.user == x.user) && (this.keyfile == x.keyfile) && (this.password == x.password) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.KeyFileAuthentication".##) + user.##) + keyfile.##) + password.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/LibraryManagementCodec.scala b/core/src/main/contraband-scala/sbt/librarymanagement/LibraryManagementCodec.scala index 06f3bfa2..7334fd85 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/LibraryManagementCodec.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/LibraryManagementCodec.scala @@ -4,8 +4,8 @@ // DO NOT EDIT MANUALLY package sbt.librarymanagement -trait LibraryManagementCodec extends sjsonnew.BasicJsonProtocol - with sbt.librarymanagement.ConfigRefFormats +trait LibraryManagementCodec extends sbt.librarymanagement.ConfigRefFormats + with sjsonnew.BasicJsonProtocol with sbt.librarymanagement.RetrieveConfigurationFormats with sbt.librarymanagement.UpdateLoggingFormats with sbt.internal.librarymanagement.formats.LogicalClockFormats @@ -19,6 +19,8 @@ trait LibraryManagementCodec extends sjsonnew.BasicJsonProtocol with sbt.librarymanagement.ConstantFormats with sbt.librarymanagement.PatchFormats with sbt.librarymanagement.FullFormats + with sbt.librarymanagement.For3Use2_13Formats + with sbt.librarymanagement.For2_13Use3Formats with sbt.librarymanagement.InclExclRuleFormats with sbt.librarymanagement.ModuleIDFormats with sbt.librarymanagement.ConfigurationFormats diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/MakePomConfiguration.scala b/core/src/main/contraband-scala/sbt/librarymanagement/MakePomConfiguration.scala index 5ff0e386..320fe372 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/MakePomConfiguration.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/MakePomConfiguration.scala @@ -16,10 +16,10 @@ final class MakePomConfiguration private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: MakePomConfiguration => (this.file == x.file) && (this.moduleInfo == x.moduleInfo) && (this.configurations == x.configurations) && (this.extra == x.extra) && (this.process == x.process) && (this.filterRepositories == x.filterRepositories) && (this.allRepositories == x.allRepositories) && (this.includeTypes == x.includeTypes) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.MakePomConfiguration".##) + file.##) + moduleInfo.##) + configurations.##) + extra.##) + process.##) + filterRepositories.##) + allRepositories.##) + includeTypes.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/MavenCache.scala b/core/src/main/contraband-scala/sbt/librarymanagement/MavenCache.scala index aac4cf77..dc69f0ab 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/MavenCache.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/MavenCache.scala @@ -18,10 +18,10 @@ final class MavenCache private ( 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 { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: MavenCache => (this.name == x.name) && (this.root == x.root) && (this.localIfFile == x.localIfFile) && (this.rootFile == x.rootFile) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.MavenCache".##) + name.##) + root.##) + localIfFile.##) + rootFile.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepo.scala b/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepo.scala index 32ce0d0a..b8fa7157 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepo.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepo.scala @@ -16,10 +16,10 @@ final class MavenRepo private ( 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 { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { 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 * (37 * (17 + "sbt.librarymanagement.MavenRepo".##) + name.##) + root.##) + localIfFile.##) + _allowInsecureProtocol.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepository.scala b/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepository.scala index 73623d6e..7618f2b0 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepository.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/MavenRepository.scala @@ -19,10 +19,10 @@ abstract class MavenRepository( def this(name: String, root: String) = this(name, root, true) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: MavenRepository => (this.name == x.name) && (this.root == x.root) && (this.localIfFile == x.localIfFile) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.MavenRepository".##) + name.##) + root.##) + localIfFile.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ModuleConfiguration.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ModuleConfiguration.scala index 9953ac69..7b407592 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ModuleConfiguration.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ModuleConfiguration.scala @@ -12,10 +12,10 @@ final class ModuleConfiguration private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: ModuleConfiguration => (this.organization == x.organization) && (this.name == x.name) && (this.revision == x.revision) && (this.resolver == x.resolver) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.ModuleConfiguration".##) + organization.##) + name.##) + revision.##) + resolver.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ModuleDescriptorConfiguration.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ModuleDescriptorConfiguration.scala index 5a093be1..11d51997 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ModuleDescriptorConfiguration.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ModuleDescriptorConfiguration.scala @@ -19,10 +19,10 @@ final class ModuleDescriptorConfiguration private ( private def this(module: sbt.librarymanagement.ModuleID, moduleInfo: sbt.librarymanagement.ModuleInfo) = this(false, None, module, moduleInfo, Vector.empty, Vector.empty, Vector.empty, scala.xml.NodeSeq.Empty, sbt.librarymanagement.Configurations.default, Option(sbt.librarymanagement.Configurations.Compile), sbt.librarymanagement.ConflictManager.default) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: ModuleDescriptorConfiguration => (this.validate == x.validate) && (this.scalaModuleInfo == x.scalaModuleInfo) && (this.module == x.module) && (this.moduleInfo == x.moduleInfo) && (this.dependencies == x.dependencies) && (this.overrides == x.overrides) && (this.excludes == x.excludes) && (this.ivyXML == x.ivyXML) && (this.configurations == x.configurations) && (this.defaultConfiguration == x.defaultConfiguration) && (this.conflictManager == x.conflictManager) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.ModuleDescriptorConfiguration".##) + validate.##) + scalaModuleInfo.##) + module.##) + moduleInfo.##) + dependencies.##) + overrides.##) + excludes.##) + ivyXML.##) + configurations.##) + defaultConfiguration.##) + conflictManager.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ModuleID.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ModuleID.scala index 144e5058..49ef7ff3 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ModuleID.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ModuleID.scala @@ -21,10 +21,10 @@ final class ModuleID private ( private def this(organization: String, name: String, revision: String) = this(organization, name, revision, None, false, true, false, Vector.empty, Vector.empty, Vector.empty, Map.empty, sbt.librarymanagement.Disabled(), None) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: ModuleID => (this.organization == x.organization) && (this.name == x.name) && (this.revision == x.revision) && (this.configurations == x.configurations) && (this.isChanging == x.isChanging) && (this.isTransitive == x.isTransitive) && (this.isForce == x.isForce) && (this.explicitArtifacts == x.explicitArtifacts) && (this.inclusions == x.inclusions) && (this.exclusions == x.exclusions) && (this.extraAttributes == x.extraAttributes) && (this.crossVersion == x.crossVersion) && (this.branchName == x.branchName) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.ModuleID".##) + organization.##) + name.##) + revision.##) + configurations.##) + isChanging.##) + isTransitive.##) + isForce.##) + explicitArtifacts.##) + inclusions.##) + exclusions.##) + extraAttributes.##) + crossVersion.##) + branchName.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ModuleIDFormats.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ModuleIDFormats.scala index f09a501c..b1c27558 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ModuleIDFormats.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ModuleIDFormats.scala @@ -5,7 +5,7 @@ // DO NOT EDIT MANUALLY package sbt.librarymanagement import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } -trait ModuleIDFormats { self: sbt.librarymanagement.ArtifactFormats with sbt.librarymanagement.InclExclRuleFormats with sbt.librarymanagement.CrossVersionFormats with sbt.librarymanagement.DisabledFormats with sbt.librarymanagement.BinaryFormats with sbt.librarymanagement.ConstantFormats with sbt.librarymanagement.PatchFormats with sbt.librarymanagement.FullFormats with sjsonnew.BasicJsonProtocol => +trait ModuleIDFormats { self: sbt.librarymanagement.ArtifactFormats with sbt.librarymanagement.InclExclRuleFormats with sbt.librarymanagement.CrossVersionFormats with sbt.librarymanagement.DisabledFormats with sbt.librarymanagement.BinaryFormats with sbt.librarymanagement.ConstantFormats with sbt.librarymanagement.PatchFormats with sbt.librarymanagement.FullFormats with sbt.librarymanagement.For3Use2_13Formats with sbt.librarymanagement.For2_13Use3Formats with sjsonnew.BasicJsonProtocol => implicit lazy val ModuleIDFormat: JsonFormat[sbt.librarymanagement.ModuleID] = new JsonFormat[sbt.librarymanagement.ModuleID] { override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.ModuleID = { __jsOpt match { diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ModuleInfo.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ModuleInfo.scala index a86e285d..383a144e 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ModuleInfo.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ModuleInfo.scala @@ -18,10 +18,10 @@ final class ModuleInfo private ( private def this(nameFormal: String) = this(nameFormal, "", None, None, Vector.empty, "", None, None, Vector.empty) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: ModuleInfo => (this.nameFormal == x.nameFormal) && (this.description == x.description) && (this.homepage == x.homepage) && (this.startYear == x.startYear) && (this.licenses == x.licenses) && (this.organizationName == x.organizationName) && (this.organizationHomepage == x.organizationHomepage) && (this.scmInfo == x.scmInfo) && (this.developers == x.developers) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.ModuleInfo".##) + nameFormal.##) + description.##) + homepage.##) + startYear.##) + licenses.##) + organizationName.##) + organizationHomepage.##) + scmInfo.##) + developers.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ModuleReport.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ModuleReport.scala index 372468f1..2c338694 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ModuleReport.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ModuleReport.scala @@ -30,10 +30,10 @@ final class ModuleReport private ( private def this(module: sbt.librarymanagement.ModuleID, artifacts: Vector[scala.Tuple2[sbt.librarymanagement.Artifact, java.io.File]], missingArtifacts: Vector[sbt.librarymanagement.Artifact]) = this(module, artifacts, missingArtifacts, None, None, None, None, false, None, None, None, None, Map.empty, None, None, Vector.empty, Vector.empty, Vector.empty) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: ModuleReport => (this.module == x.module) && (this.artifacts == x.artifacts) && (this.missingArtifacts == x.missingArtifacts) && (this.status == x.status) && (this.publicationDate == x.publicationDate) && (this.resolver == x.resolver) && (this.artifactResolver == x.artifactResolver) && (this.evicted == x.evicted) && (this.evictedData == x.evictedData) && (this.evictedReason == x.evictedReason) && (this.problem == x.problem) && (this.homepage == x.homepage) && (this.extraAttributes == x.extraAttributes) && (this.isDefault == x.isDefault) && (this.branch == x.branch) && (this.configurations == x.configurations) && (this.licenses == x.licenses) && (this.callers == x.callers) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.ModuleReport".##) + module.##) + artifacts.##) + missingArtifacts.##) + status.##) + publicationDate.##) + resolver.##) + artifactResolver.##) + evicted.##) + evictedData.##) + evictedReason.##) + problem.##) + homepage.##) + extraAttributes.##) + isDefault.##) + branch.##) + configurations.##) + licenses.##) + callers.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ModuleSettings.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ModuleSettings.scala index e210651b..5fac9f2f 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ModuleSettings.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ModuleSettings.scala @@ -11,10 +11,10 @@ abstract class ModuleSettings( def this() = this(false, None) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: ModuleSettings => (this.validate == x.validate) && (this.scalaModuleInfo == x.scalaModuleInfo) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (17 + "sbt.librarymanagement.ModuleSettings".##) + validate.##) + scalaModuleInfo.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/OrganizationArtifactReport.scala b/core/src/main/contraband-scala/sbt/librarymanagement/OrganizationArtifactReport.scala index 69313425..83624f2c 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/OrganizationArtifactReport.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/OrganizationArtifactReport.scala @@ -22,10 +22,10 @@ final class OrganizationArtifactReport private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: OrganizationArtifactReport => (this.organization == x.organization) && (this.name == x.name) && (this.modules == x.modules) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.OrganizationArtifactReport".##) + organization.##) + name.##) + modules.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/PasswordAuthentication.scala b/core/src/main/contraband-scala/sbt/librarymanagement/PasswordAuthentication.scala index fb4c1bf1..56a07dc6 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/PasswordAuthentication.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/PasswordAuthentication.scala @@ -10,10 +10,10 @@ final class PasswordAuthentication private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: PasswordAuthentication => (this.user == x.user) && (this.password == x.password) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (17 + "sbt.librarymanagement.PasswordAuthentication".##) + user.##) + password.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/Patterns.scala b/core/src/main/contraband-scala/sbt/librarymanagement/Patterns.scala index 609fc59d..a87caca6 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/Patterns.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/Patterns.scala @@ -13,10 +13,10 @@ final class Patterns private ( private def this() = this(Vector.empty, Vector.empty, true, false, false) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: Patterns => (this.ivyPatterns == x.ivyPatterns) && (this.artifactPatterns == x.artifactPatterns) && (this.isMavenCompatible == x.isMavenCompatible) && (this.descriptorOptional == x.descriptorOptional) && (this.skipConsistencyCheck == x.skipConsistencyCheck) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.Patterns".##) + ivyPatterns.##) + artifactPatterns.##) + isMavenCompatible.##) + descriptorOptional.##) + skipConsistencyCheck.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/PatternsBasedRepository.scala b/core/src/main/contraband-scala/sbt/librarymanagement/PatternsBasedRepository.scala index 3ddc7b1c..494baf2e 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/PatternsBasedRepository.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/PatternsBasedRepository.scala @@ -12,10 +12,10 @@ abstract class PatternsBasedRepository( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: PatternsBasedRepository => (this.name == x.name) && (this.patterns == x.patterns) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (17 + "sbt.librarymanagement.PatternsBasedRepository".##) + name.##) + patterns.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/PomConfiguration.scala b/core/src/main/contraband-scala/sbt/librarymanagement/PomConfiguration.scala index 8359588b..441ce8b6 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/PomConfiguration.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/PomConfiguration.scala @@ -12,10 +12,10 @@ final class PomConfiguration private ( private def this(file: java.io.File, autoScalaTools: Boolean) = this(false, None, file, autoScalaTools) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: PomConfiguration => (this.validate == x.validate) && (this.scalaModuleInfo == x.scalaModuleInfo) && (this.file == x.file) && (this.autoScalaTools == x.autoScalaTools) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.PomConfiguration".##) + validate.##) + scalaModuleInfo.##) + file.##) + autoScalaTools.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/PublishConfiguration.scala b/core/src/main/contraband-scala/sbt/librarymanagement/PublishConfiguration.scala index 6391c8c3..63864882 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/PublishConfiguration.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/PublishConfiguration.scala @@ -17,10 +17,10 @@ final class PublishConfiguration private ( private def this() = this(true, None, None, None, None, Vector(), Vector("sha1", "md5"), None, false) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: PublishConfiguration => (this.publishMavenStyle == x.publishMavenStyle) && (this.deliverIvyPattern == x.deliverIvyPattern) && (this.status == x.status) && (this.configurations == x.configurations) && (this.resolverName == x.resolverName) && (this.artifacts == x.artifacts) && (this.checksums == x.checksums) && (this.logging == x.logging) && (this.overwrite == x.overwrite) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.PublishConfiguration".##) + publishMavenStyle.##) + deliverIvyPattern.##) + status.##) + configurations.##) + resolverName.##) + artifacts.##) + checksums.##) + logging.##) + overwrite.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/Resolver.scala b/core/src/main/contraband-scala/sbt/librarymanagement/Resolver.scala index f4a7c962..13c57e0d 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/Resolver.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/Resolver.scala @@ -11,10 +11,10 @@ abstract class Resolver( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: Resolver => (this.name == x.name) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (17 + "sbt.librarymanagement.Resolver".##) + name.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/RetrieveConfiguration.scala b/core/src/main/contraband-scala/sbt/librarymanagement/RetrieveConfiguration.scala index 7daf0d5f..1aa3a2e2 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/RetrieveConfiguration.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/RetrieveConfiguration.scala @@ -13,10 +13,10 @@ final class RetrieveConfiguration private ( private def this() = this(None, None, false, None) private def this(retrieveDirectory: Option[java.io.File], outputPattern: Option[String]) = this(retrieveDirectory, outputPattern, false, None) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: RetrieveConfiguration => (this.retrieveDirectory == x.retrieveDirectory) && (this.outputPattern == x.outputPattern) && (this.sync == x.sync) && (this.configurationsToRetrieve == x.configurationsToRetrieve) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.RetrieveConfiguration".##) + retrieveDirectory.##) + outputPattern.##) + sync.##) + configurationsToRetrieve.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ScalaModuleInfo.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ScalaModuleInfo.scala index c8b8ee74..772d7b9e 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ScalaModuleInfo.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ScalaModuleInfo.scala @@ -16,10 +16,10 @@ final class ScalaModuleInfo private ( private def this(scalaFullVersion: String, scalaBinaryVersion: String, configurations: Vector[sbt.librarymanagement.Configuration], checkExplicit: Boolean, filterImplicit: Boolean, overrideScalaVersion: Boolean) = this(scalaFullVersion, scalaBinaryVersion, configurations, checkExplicit, filterImplicit, overrideScalaVersion, sbt.librarymanagement.ScalaArtifacts.Organization, sbt.librarymanagement.ScalaArtifacts.Artifacts) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: ScalaModuleInfo => (this.scalaFullVersion == x.scalaFullVersion) && (this.scalaBinaryVersion == x.scalaBinaryVersion) && (this.configurations == x.configurations) && (this.checkExplicit == x.checkExplicit) && (this.filterImplicit == x.filterImplicit) && (this.overrideScalaVersion == x.overrideScalaVersion) && (this.scalaOrganization == x.scalaOrganization) && (this.scalaArtifacts == x.scalaArtifacts) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.ScalaModuleInfo".##) + scalaFullVersion.##) + scalaBinaryVersion.##) + configurations.##) + checkExplicit.##) + filterImplicit.##) + overrideScalaVersion.##) + scalaOrganization.##) + scalaArtifacts.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/ScmInfo.scala b/core/src/main/contraband-scala/sbt/librarymanagement/ScmInfo.scala index 837f9e11..4fadcae1 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/ScmInfo.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/ScmInfo.scala @@ -12,10 +12,10 @@ final class ScmInfo private ( private def this(browseUrl: java.net.URL, connection: String) = this(browseUrl, connection, None) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: ScmInfo => (this.browseUrl == x.browseUrl) && (this.connection == x.connection) && (this.devConnection == x.devConnection) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.ScmInfo".##) + browseUrl.##) + connection.##) + devConnection.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/SemanticSelector.scala b/core/src/main/contraband-scala/sbt/librarymanagement/SemanticSelector.scala index 4faf5ff1..ca5386b3 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/SemanticSelector.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/SemanticSelector.scala @@ -63,10 +63,10 @@ final class SemanticSelector private ( def matches(versionNumber: VersionNumber): Boolean = selectors.exists(_.matches(versionNumber)) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: SemanticSelector => (this.selectors == x.selectors) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (17 + "sbt.librarymanagement.SemanticSelector".##) + selectors.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/SftpRepository.scala b/core/src/main/contraband-scala/sbt/librarymanagement/SftpRepository.scala index f79ae577..b20a2f25 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/SftpRepository.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/SftpRepository.scala @@ -13,10 +13,10 @@ final class SftpRepository private ( this(name, patterns, connection) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: SftpRepository => (this.name == x.name) && (this.patterns == x.patterns) && (this.connection == x.connection) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.SftpRepository".##) + name.##) + patterns.##) + connection.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/SshAuthentication.scala b/core/src/main/contraband-scala/sbt/librarymanagement/SshAuthentication.scala index e85c1454..eaeb29bf 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/SshAuthentication.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/SshAuthentication.scala @@ -9,10 +9,10 @@ abstract class SshAuthentication() extends Serializable { -override def equals(o: Any): Boolean = o match { +override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case _: SshAuthentication => true case _ => false -} +}) override def hashCode: Int = { 37 * (17 + "sbt.librarymanagement.SshAuthentication".##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/SshBasedRepository.scala b/core/src/main/contraband-scala/sbt/librarymanagement/SshBasedRepository.scala index ef5e743a..ec3af1b7 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/SshBasedRepository.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/SshBasedRepository.scala @@ -13,10 +13,10 @@ abstract class SshBasedRepository( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: SshBasedRepository => (this.name == x.name) && (this.patterns == x.patterns) && (this.connection == x.connection) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.SshBasedRepository".##) + name.##) + patterns.##) + connection.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/SshConnection.scala b/core/src/main/contraband-scala/sbt/librarymanagement/SshConnection.scala index 796cdb96..68161ac8 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/SshConnection.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/SshConnection.scala @@ -11,10 +11,10 @@ final class SshConnection private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: SshConnection => (this.authentication == x.authentication) && (this.hostname == x.hostname) && (this.port == x.port) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.SshConnection".##) + authentication.##) + hostname.##) + port.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/SshRepository.scala b/core/src/main/contraband-scala/sbt/librarymanagement/SshRepository.scala index a71e2bd5..0c7a4c5e 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/SshRepository.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/SshRepository.scala @@ -14,10 +14,10 @@ final class SshRepository private ( this(name, patterns, connection, publishPermissions) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: SshRepository => (this.name == x.name) && (this.patterns == x.patterns) && (this.connection == x.connection) && (this.publishPermissions == x.publishPermissions) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.SshRepository".##) + name.##) + patterns.##) + connection.##) + publishPermissions.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/URLRepository.scala b/core/src/main/contraband-scala/sbt/librarymanagement/URLRepository.scala index 9acb17c4..6bdb70fd 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/URLRepository.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/URLRepository.scala @@ -11,10 +11,10 @@ final class URLRepository private ( private[sbt] override def validateProtocol(logger: sbt.util.Logger): Boolean = 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 { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: URLRepository => (this.name == x.name) && (this.patterns == x.patterns) && (this.allowInsecureProtocol == x.allowInsecureProtocol) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.URLRepository".##) + name.##) + patterns.##) + allowInsecureProtocol.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/UpdateConfiguration.scala b/core/src/main/contraband-scala/sbt/librarymanagement/UpdateConfiguration.scala index f1fd781f..69b7e696 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/UpdateConfiguration.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/UpdateConfiguration.scala @@ -25,10 +25,10 @@ final class UpdateConfiguration private ( private def this() = this(None, false, sbt.librarymanagement.UpdateLogging.Default, sbt.librarymanagement.LogicalClock.unknown, None, None, false, false) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: UpdateConfiguration => (this.retrieveManaged == x.retrieveManaged) && (this.missingOk == x.missingOk) && (this.logging == x.logging) && (this.logicalClock == x.logicalClock) && (this.metadataDirectory == x.metadataDirectory) && (this.artifactFilter == x.artifactFilter) && (this.offline == x.offline) && (this.frozen == x.frozen) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.UpdateConfiguration".##) + retrieveManaged.##) + missingOk.##) + logging.##) + logicalClock.##) + metadataDirectory.##) + artifactFilter.##) + offline.##) + frozen.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/UpdateReport.scala b/core/src/main/contraband-scala/sbt/librarymanagement/UpdateReport.scala index fd5f22a7..0e3c68f1 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/UpdateReport.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/UpdateReport.scala @@ -20,10 +20,10 @@ final class UpdateReport private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: UpdateReport => (this.cachedDescriptor == x.cachedDescriptor) && (this.configurations == x.configurations) && (this.stats == x.stats) && (this.stamps == x.stamps) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.UpdateReport".##) + cachedDescriptor.##) + configurations.##) + stats.##) + stamps.##) } diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/UpdateStats.scala b/core/src/main/contraband-scala/sbt/librarymanagement/UpdateStats.scala index 96e40831..a2ea73ce 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/UpdateStats.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/UpdateStats.scala @@ -12,10 +12,10 @@ final class UpdateStats private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: UpdateStats => (this.resolveTime == x.resolveTime) && (this.downloadTime == x.downloadTime) && (this.downloadSize == x.downloadSize) && (this.cached == x.cached) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.UpdateStats".##) + resolveTime.##) + downloadTime.##) + downloadSize.##) + cached.##) } diff --git a/core/src/main/contraband/librarymanagement.json b/core/src/main/contraband/librarymanagement.json index 0b9d307f..59767a82 100644 --- a/core/src/main/contraband/librarymanagement.json +++ b/core/src/main/contraband/librarymanagement.json @@ -192,24 +192,6 @@ ], "toString": "s\"$caller\"" }, - { - "name": "ConfigRef", - "namespace": "sbt.librarymanagement", - "target": "Scala", - "type": "record", - "doc": [ - "A reference to Configuration." - ], - "fields": [ - { - "name": "name", - "type": "String", - "doc": [ "The name of the configuration that eventually get used by Maven." ] - } - ], - "parentsCompanion": "sbt.librarymanagement.ConfigRefFunctions", - "toString": "name" - }, { "name": "ConfigurationReport", "namespace": "sbt.librarymanagement", diff --git a/core/src/main/java/sbt/internal/librarymanagement/mavenint/SbtPomExtraProperties.java b/core/src/main/java/sbt/internal/librarymanagement/mavenint/SbtPomExtraProperties.java index 8bc61d54..b7033925 100644 --- a/core/src/main/java/sbt/internal/librarymanagement/mavenint/SbtPomExtraProperties.java +++ b/core/src/main/java/sbt/internal/librarymanagement/mavenint/SbtPomExtraProperties.java @@ -14,6 +14,7 @@ public class SbtPomExtraProperties { public static final String POM_SBT_VERSION = "sbtVersion"; public static final String POM_API_KEY = "info.apiURL"; public static final String VERSION_SCHEME_KEY = "info.versionScheme"; + public static final String POM_RELEASE_NOTES_KEY = "info.releaseNotesUrl"; public static final String LICENSE_COUNT_KEY = "license.count"; diff --git a/core/src/main/scala/sbt/internal/librarymanagement/JsonUtil.scala b/core/src/main/scala/sbt/internal/librarymanagement/JsonUtil.scala index 85f5c387..8d15a64c 100644 --- a/core/src/main/scala/sbt/internal/librarymanagement/JsonUtil.scala +++ b/core/src/main/scala/sbt/internal/librarymanagement/JsonUtil.scala @@ -15,7 +15,7 @@ private[sbt] object JsonUtil { log: Logger ): UpdateReport = { try { - val lite = CacheStore(path).read[UpdateReportLite] + val lite = CacheStore(path).read[UpdateReportLite]() fromLite(lite, cachedDescriptor) } catch { case e: Throwable => @@ -34,34 +34,33 @@ private[sbt] object JsonUtil { UpdateReportLite(ur.configurations map { cr => ConfigurationReportLite( cr.configuration.name, - cr.details map { - oar => - OrganizationArtifactReport( - oar.organization, - oar.name, - oar.modules map { mr => - ModuleReport( - mr.module, - mr.artifacts, - mr.missingArtifacts, - mr.status, - mr.publicationDate, - mr.resolver, - mr.artifactResolver, - mr.evicted, - mr.evictedData, - mr.evictedReason, - mr.problem, - mr.homepage, - mr.extraAttributes, - mr.isDefault, - mr.branch, - mr.configurations, - mr.licenses, - filterOutArtificialCallers(mr.callers) - ) - } - ) + cr.details map { oar => + OrganizationArtifactReport( + oar.organization, + oar.name, + oar.modules map { mr => + ModuleReport( + mr.module, + mr.artifacts, + mr.missingArtifacts, + mr.status, + mr.publicationDate, + mr.resolver, + mr.artifactResolver, + mr.evicted, + mr.evictedData, + mr.evictedReason, + mr.problem, + mr.homepage, + mr.extraAttributes, + mr.isDefault, + mr.branch, + mr.configurations, + mr.licenses, + filterOutArtificialCallers(mr.callers) + ) + } + ) } ) }) diff --git a/core/src/main/scala/sbt/internal/librarymanagement/SemanticSelectorExtra.scala b/core/src/main/scala/sbt/internal/librarymanagement/SemanticSelectorExtra.scala index f3f28cf7..d9a7fb24 100644 --- a/core/src/main/scala/sbt/internal/librarymanagement/SemanticSelectorExtra.scala +++ b/core/src/main/scala/sbt/internal/librarymanagement/SemanticSelectorExtra.scala @@ -58,8 +58,8 @@ private[librarymanagement] abstract class SemComparatorExtra { protected def toStringImpl: String = { val versionStr = Seq(major, minor, patch) - .collect { - case Some(v) => v.toString + .collect { case Some(v) => + v.toString } .mkString(".") val tagsStr = if (tags.nonEmpty) s"-${tags.mkString("-")}" else "" @@ -148,7 +148,7 @@ private[librarymanagement] abstract class SemComparatorFunctions { (?:\.(\d+|[xX*]) (?:\.(\d+|[xX*]))? )? - )((?:-\w+)*)$ + )((?:-\w+(?:\.\w+)*)*)$ """.r protected def parse(comparator: String): SemComparator = { comparator match { @@ -177,8 +177,8 @@ private[librarymanagement] abstract class SemComparatorFunctions { } parse( numbers - .collect { - case Some(v) => v.toString + .collect { case Some(v) => + v.toString } .mkString(".") ) diff --git a/core/src/main/scala/sbt/internal/librarymanagement/UpdateClassifiersUtil.scala b/core/src/main/scala/sbt/internal/librarymanagement/UpdateClassifiersUtil.scala index c01e781a..9f87ff5e 100644 --- a/core/src/main/scala/sbt/internal/librarymanagement/UpdateClassifiersUtil.scala +++ b/core/src/main/scala/sbt/internal/librarymanagement/UpdateClassifiersUtil.scala @@ -35,7 +35,7 @@ object UpdateClassifiersUtil { classifiers: Vector[String], exclude: Map[ModuleID, Set[ConfigRef]] )(m: ModuleID): Option[ModuleID] = { - val excluded: Set[ConfigRef] = exclude getOrElse (restrictedCopy(m, false), Set.empty) + val excluded: Set[ConfigRef] = exclude.getOrElse(restrictedCopy(m, false), Set.empty) val exls = excluded map { _.name } val included = classifiers filterNot exls if (included.isEmpty) None diff --git a/core/src/main/scala/sbt/internal/librarymanagement/VersionRange.scala b/core/src/main/scala/sbt/internal/librarymanagement/VersionRange.scala index eed2eebb..3bf85a9e 100644 --- a/core/src/main/scala/sbt/internal/librarymanagement/VersionRange.scala +++ b/core/src/main/scala/sbt/internal/librarymanagement/VersionRange.scala @@ -18,7 +18,7 @@ object VersionRange { // See https://github.com/sbt/sbt/issues/2954 def stripMavenVersionRange(version: String): Option[String] = if (isVersionRange(version)) { - val noSpace = version.replaceAllLiterally(" ", "") + val noSpace = version.replace(" ", "") noSpace match { case MavenVersionSetPattern(open1, x1, comma, x2, close1, _) => // http://maven.apache.org/components/enforcer/enforcer-rules/versionRanges.html @@ -64,14 +64,14 @@ object VersionRange { val start = rev(0) val stop = rev(rev.length - 1) val mid = rev.substring(1, rev.length - 1) - (if (start == ']') "(" else start) + mid + (if (stop == '[') ")" else stop) + (if (start == ']') "(" else start.toString) + mid + (if (stop == '[') ")" else stop) case _ => revision } } catch { case _: NumberFormatException => // TODO - if the version doesn't meet our expectations, maybe we just issue a hard // error instead of softly ignoring the attempt to rewrite. - //sys.error(s"Could not fix version [$revision] into maven style version") + // sys.error(s"Could not fix version [$revision] into maven style version") revision } } diff --git a/core/src/main/scala/sbt/internal/librarymanagement/VersionSchemes.scala b/core/src/main/scala/sbt/internal/librarymanagement/VersionSchemes.scala index 7e2179f3..11242002 100644 --- a/core/src/main/scala/sbt/internal/librarymanagement/VersionSchemes.scala +++ b/core/src/main/scala/sbt/internal/librarymanagement/VersionSchemes.scala @@ -10,17 +10,19 @@ package internal package librarymanagement import sbt.internal.librarymanagement.mavenint.SbtPomExtraProperties -import sbt.librarymanagement.ModuleID +import sbt.librarymanagement.{ EvictionWarningOptions, ModuleID, ScalaModuleInfo } // See APIMappings.scala private[sbt] object VersionSchemes { final val EarlySemVer = "early-semver" final val SemVerSpec = "semver-spec" final val PackVer = "pvp" + final val Strict = "strict" + final val Always = "always" def validateScheme(value: String): Unit = value match { - case EarlySemVer | SemVerSpec | PackVer => () + case EarlySemVer | SemVerSpec | PackVer | Strict | Always => () case "semver" => sys.error( s"""'semver' is ambiguous. @@ -34,10 +36,22 @@ private[sbt] object VersionSchemes { case x => sys.error(s"unknown version scheme: $x") } - /** info.versionScheme property will be included into POM after sbt 1.4.0. + /** + * info.versionScheme property will be included into POM after sbt 1.4.0. */ def extractFromId(mid: ModuleID): Option[String] = extractFromExtraAttributes(mid.extraAttributes) def extractFromExtraAttributes(extraAttributes: Map[String, String]): Option[String] = extraAttributes.get(SbtPomExtraProperties.VERSION_SCHEME_KEY) + + def evalFunc( + scheme: String + ): Function1[(ModuleID, Option[ModuleID], Option[ScalaModuleInfo]), Boolean] = + scheme match { + case EarlySemVer => EvictionWarningOptions.guessEarlySemVer + case SemVerSpec => EvictionWarningOptions.guessSemVer + case PackVer => EvictionWarningOptions.evalPvp + case Strict => EvictionWarningOptions.guessStrict + case Always => EvictionWarningOptions.guessTrue + } } diff --git a/core/src/main/scala/sbt/internal/librarymanagement/cross/CrossVersionUtil.scala b/core/src/main/scala/sbt/internal/librarymanagement/cross/CrossVersionUtil.scala index c95f035f..e8e518ec 100644 --- a/core/src/main/scala/sbt/internal/librarymanagement/cross/CrossVersionUtil.scala +++ b/core/src/main/scala/sbt/internal/librarymanagement/cross/CrossVersionUtil.scala @@ -1,6 +1,8 @@ package sbt.internal.librarymanagement package cross +import sbt.librarymanagement.ScalaArtifacts + object CrossVersionUtil { val trueString = "true" val falseString = "false" @@ -8,7 +10,6 @@ object CrossVersionUtil { val noneString = "none" val disabledString = "disabled" val binaryString = "binary" - val TransitionDottyVersion = "" // Dotty always respects binary compatibility val TransitionScalaVersion = "2.10" // ...but scalac doesn't until Scala 2.10 val TransitionSbtVersion = "0.12" @@ -21,11 +22,14 @@ object CrossVersionUtil { private val longPattern = """\d{1,19}""" private val basicVersion = raw"""($longPattern)\.($longPattern)\.($longPattern)""" + private val tagPattern = raw"""(?:\w+(?:\.\w+)*)""" private val ReleaseV = raw"""$basicVersion(-\d+)?""".r - private val BinCompatV = raw"""$basicVersion-bin(-.*)?""".r + private[sbt] val BinCompatV = raw"""$basicVersion(-$tagPattern)?-bin(-.*)?""".r private val CandidateV = raw"""$basicVersion(-RC\d+)""".r - private val NonReleaseV_n = raw"""$basicVersion([-\w]*)""".r // 0-n word suffixes, with leading dashes - private val NonReleaseV_1 = raw"""$basicVersion(-\w+)""".r // 1 word suffix, after a dash + private val MilestonV = raw"""$basicVersion(-M$tagPattern)""".r + private val NonReleaseV_n = + raw"""$basicVersion((?:-$tagPattern)*)""".r // 0-n word suffixes, with leading dashes + private val NonReleaseV_1 = raw"""$basicVersion(-$tagPattern)""".r // 1 word suffix, after a dash private[sbt] val PartialVersion = raw"""($longPattern)\.($longPattern)(?:\..+)?""".r private[sbt] def isSbtApiCompatible(v: String): Boolean = sbtApiVersion(v).isDefined @@ -61,7 +65,7 @@ object CrossVersionUtil { */ private[sbt] def scalaApiVersion(v: String): Option[(Long, Long)] = v match { case ReleaseV(x, y, _, _) => Some((x.toLong, y.toLong)) - case BinCompatV(x, y, _, _) => Some((x.toLong, y.toLong)) + case BinCompatV(x, y, _, _, _) => Some((x.toLong, y.toLong)) case NonReleaseV_1(x, y, z, _) if z.toInt > 0 => Some((x.toLong, y.toLong)) case _ => None } @@ -72,9 +76,44 @@ object CrossVersionUtil { case _ => None } + private[sbt] def binaryScala3Version(full: String): String = full match { + case ReleaseV(maj, _, _, _) => maj + case NonReleaseV_n(maj, min, patch, _) if min.toLong > 0 || patch.toLong > 0 => maj + case BinCompatV(maj, min, patch, stageOrNull, _) => + val stage = if (stageOrNull != null) stageOrNull else "" + binaryScala3Version(s"$maj.$min.$patch$stage") + case _ => full + } + + // Uses the following rules: + // + // - Forwards and backwards compatibility is guaranteed for Scala 2.N.x (https://docs.scala-lang.org/overviews/core/binary-compatibility-of-scala-releases.html) + // + // - A Scala compiler in version 3.x1.y1 is able to read TASTy files produced by another compiler in version 3.x2.y2 if x1 >= x2 (https://docs.scala-lang.org/scala3/reference/language-versions/binary-compatibility.html) + // + // - For non-stable Scala 3 versions, compiler versions can read TASTy in an older stable format but their TASTY versions are not compatible between each other even if the compilers have the same minor version (https://docs.scala-lang.org/scala3/reference/language-versions/binary-compatibility.html) + // + private[sbt] def isScalaBinaryCompatibleWith(newVersion: String, origVersion: String): Boolean = { + (newVersion, origVersion) match { + case (NonReleaseV_n("2", _, _, _), NonReleaseV_n("2", _, _, _)) => + val api1 = scalaApiVersion(newVersion) + val api2 = scalaApiVersion(origVersion) + (api1.isDefined && api1 == api2) || (newVersion == origVersion) + case (ReleaseV(nMaj, nMin, _, _), ReleaseV(oMaj, oMin, _, _)) + if nMaj == oMaj && nMaj.toLong >= 3 => + nMin.toInt >= oMin.toInt + case (NonReleaseV_1(nMaj, nMin, _, _), ReleaseV(oMaj, oMin, _, _)) + if nMaj == oMaj && nMaj.toLong >= 3 => + nMin.toInt > oMin.toInt + case _ => + newVersion == origVersion + } + } + def binaryScalaVersion(full: String): String = { - val cutoff = if (full.startsWith("0.")) TransitionDottyVersion else TransitionScalaVersion - binaryVersionWithApi(full, cutoff)(scalaApiVersion) + if (ScalaArtifacts.isScala3(full)) binaryScala3Version(full) + else + binaryVersionWithApi(full, TransitionScalaVersion)(scalaApiVersion) // Scala 2 binary version } def binarySbtVersion(full: String): String = diff --git a/core/src/main/scala/sbt/librarymanagement/ConfigRef.scala b/core/src/main/scala/sbt/librarymanagement/ConfigRef.scala new file mode 100644 index 00000000..6143642b --- /dev/null +++ b/core/src/main/scala/sbt/librarymanagement/ConfigRef.scala @@ -0,0 +1,75 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ +package sbt.librarymanagement + +import scala.collection.concurrent.TrieMap + +/** + * A reference to Configuration. + * @param name The name of the configuration that eventually get used by Maven. + */ +final class ConfigRef private (val name: String) extends Serializable { + + override def equals(o: Any): Boolean = + this.eq(o.asInstanceOf[AnyRef]) + + override val hashCode: Int = { + 37 * (37 * (17 + "sbt.librarymanagement.ConfigRef".##) + name.##) + } + + override def toString: String = { + name + } + + private[this] def copy(name: String = name): ConfigRef = { + ConfigRef(name) + } + + def withName(name: String): ConfigRef = { + copy(name = name) + } +} + +object ConfigRef extends sbt.librarymanagement.ConfigRefFunctions { + // cache the reference to ConfigRefs + private val cache = new TrieMap[String, ConfigRef] + private lazy val Default = new ConfigRef("default") + private lazy val Compile = new ConfigRef("compile") + private lazy val IntegrationTest = new ConfigRef("it") + private lazy val Provided = new ConfigRef("provided") + private lazy val Runtime = new ConfigRef("runtime") + private lazy val Test = new ConfigRef("test") + private lazy val System = new ConfigRef("system") + private lazy val Optional = new ConfigRef("optional") + private lazy val Pom = new ConfigRef("pom") + private lazy val ScalaTool = new ConfigRef("scala-tool") + private lazy val ScalaDocTool = new ConfigRef("scala-doc-tool") + private lazy val CompilerPlugin = new ConfigRef("plugin") + private lazy val Component = new ConfigRef("component") + private lazy val RuntimeInternal = new ConfigRef("runtime-internal") + private lazy val TestInternal = new ConfigRef("test-internal") + private lazy val IntegrationTestInternal = new ConfigRef("it-internal") + private lazy val CompileInternal = new ConfigRef("compile-internal") + + def apply(name: String): ConfigRef = name match { + case "default" => Default + case "compile" => Compile + case "it" => IntegrationTest + case "provided" => Provided + case "runtime" => Runtime + case "test" => Test + case "system" => System + case "optional" => Optional + case "pom" => Pom + case "scala-tool" => ScalaTool + case "scala-doc-tool" => ScalaDocTool + case "plugin" => CompilerPlugin + case "component" => Component + case "runtime-internal" => RuntimeInternal + case "test-internal" => TestInternal + case "it-internal" => IntegrationTestInternal + case "compile-internal" => CompileInternal + case _ => cache.getOrElseUpdate(name, new ConfigRef(name)) + } +} diff --git a/core/src/main/scala/sbt/librarymanagement/ConfigRefFormats.scala b/core/src/main/scala/sbt/librarymanagement/ConfigRefFormats.scala new file mode 100644 index 00000000..b7d8d0b0 --- /dev/null +++ b/core/src/main/scala/sbt/librarymanagement/ConfigRefFormats.scala @@ -0,0 +1,31 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ +package sbt.librarymanagement + +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } + +trait ConfigRefFormats { self: sjsonnew.BasicJsonProtocol => + implicit lazy val ConfigRefFormat: JsonFormat[sbt.librarymanagement.ConfigRef] = + new JsonFormat[sbt.librarymanagement.ConfigRef] { + override def read[J]( + __jsOpt: Option[J], + unbuilder: Unbuilder[J] + ): sbt.librarymanagement.ConfigRef = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val name = unbuilder.readField[String]("name") + unbuilder.endObject() + sbt.librarymanagement.ConfigRef(name) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.librarymanagement.ConfigRef, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("name", obj.name) + builder.endObject() + } + } +} diff --git a/core/src/main/scala/sbt/librarymanagement/Configuration.scala b/core/src/main/scala/sbt/librarymanagement/Configuration.scala index e82d7513..53c40983 100644 --- a/core/src/main/scala/sbt/librarymanagement/Configuration.scala +++ b/core/src/main/scala/sbt/librarymanagement/Configuration.scala @@ -21,11 +21,11 @@ final class Configuration private[sbt] ( override def equals(o: Any): Boolean = o match { case x: Configuration => (this.id == x.id) && - (this.name == x.name) && - (this.description == x.description) && - (this.isPublic == x.isPublic) && - (this.extendsConfigs == x.extendsConfigs) && - (this.transitive == x.transitive) + (this.name == x.name) && + (this.description == x.description) && + (this.isPublic == x.isPublic) && + (this.extendsConfigs == x.extendsConfigs) && + (this.transitive == x.transitive) case _ => false } diff --git a/core/src/main/scala/sbt/librarymanagement/ConfigurationExtra.scala b/core/src/main/scala/sbt/librarymanagement/ConfigurationExtra.scala index d1529719..ecdd2d87 100644 --- a/core/src/main/scala/sbt/librarymanagement/ConfigurationExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/ConfigurationExtra.scala @@ -3,7 +3,7 @@ */ package sbt.librarymanagement -import scala.annotation.tailrec +import scala.annotation.{ nowarn, tailrec } import scala.language.experimental.macros object Configurations { @@ -19,9 +19,11 @@ object Configurations { lazy val RuntimeInternal = optionalInternal(Runtime) lazy val TestInternal = fullInternal(Test) + @nowarn lazy val IntegrationTestInternal = fullInternal(IntegrationTest) lazy val CompileInternal = fullInternal(Compile) + @nowarn def internalMap(c: Configuration) = c match { case Compile => CompileInternal case Test => TestInternal @@ -39,6 +41,7 @@ object Configurations { lazy val Default = Configuration.of("Default", "default") lazy val Compile = Configuration.of("Compile", "compile") + @deprecated("Create a separate subproject for testing instead", "1.9.0") lazy val IntegrationTest = Configuration.of("IntegrationTest", "it") extend (Runtime) lazy val Provided = Configuration.of("Provided", "provided") lazy val Runtime = Configuration.of("Runtime", "runtime") extend (Compile) @@ -48,6 +51,7 @@ object Configurations { lazy val Pom = Configuration.of("Pom", "pom") lazy val ScalaTool = Configuration.of("ScalaTool", "scala-tool").hide + lazy val ScalaDocTool = Configuration.of("ScalaDocTool", "scala-doc-tool").hide lazy val CompilerPlugin = Configuration.of("CompilerPlugin", "plugin").hide lazy val Component = Configuration.of("Component", "component").hide @@ -66,6 +70,7 @@ object Configurations { ) /** Returns true if the configuration should be under the influence of scalaVersion. */ + @nowarn private[sbt] def underScalaVersion(c: Configuration): Boolean = c match { case Default | Compile | IntegrationTest | Provided | Runtime | Test | Optional | diff --git a/core/src/main/scala/sbt/librarymanagement/ConflictWarning.scala b/core/src/main/scala/sbt/librarymanagement/ConflictWarning.scala index 5fea69f3..bed99916 100644 --- a/core/src/main/scala/sbt/librarymanagement/ConflictWarning.scala +++ b/core/src/main/scala/sbt/librarymanagement/ConflictWarning.scala @@ -59,7 +59,7 @@ object ConflictWarning { private[this] def groupByRawName(ms: Seq[ModuleID]): Map[(String, String), Seq[ModuleID]] = ms.groupBy(m => (m.organization, dropCrossSuffix(m.name))) - private[this] val CrossSuffixPattern = """(.+)_(\d+\.\d+(?:\.\d+)?(?:-.+)?)""".r + private[this] val CrossSuffixPattern = """(.+)_(\d+(?:\.\d+)?(?:\.\d+)?(?:-.+)?)""".r private[this] def dropCrossSuffix(s: String): String = s match { case CrossSuffixPattern(raw, _) => raw case _ => s diff --git a/core/src/main/scala/sbt/librarymanagement/CrossVersion.scala b/core/src/main/scala/sbt/librarymanagement/CrossVersion.scala index 4ab1b644..e447cb6a 100644 --- a/core/src/main/scala/sbt/librarymanagement/CrossVersion.scala +++ b/core/src/main/scala/sbt/librarymanagement/CrossVersion.scala @@ -172,6 +172,82 @@ object Full { def apply(prefix: String, suffix: String): Full = new Full(prefix, suffix) } +/** + * Similar to Binary except that if the binary version is 3 + * (or if it is of the form 3.0.0-x) it uses 2.13 instead. + * For example, if `prefix = "foo_"` and `suffix = "_bar"` and the binary version is "3", + * the module is cross-versioned with "foo_2.13_bar". + */ +final class For3Use2_13 private (val prefix: String, val suffix: String) + extends sbt.librarymanagement.CrossVersion() + with Serializable { + + private def this() = this("", "") + + override def equals(o: Any): Boolean = o match { + case x: For3Use2_13 => (this.prefix == x.prefix) && (this.suffix == x.suffix) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.librarymanagement.For3Use2_13".##) + prefix.##) + suffix.##) + } + override def toString: String = { + "For3Use2_13(" + prefix + ", " + suffix + ")" + } + private[this] def copy(prefix: String = prefix, suffix: String = suffix): For3Use2_13 = { + new For3Use2_13(prefix, suffix) + } + def withPrefix(prefix: String): For3Use2_13 = { + copy(prefix = prefix) + } + def withSuffix(suffix: String): For3Use2_13 = { + copy(suffix = suffix) + } +} +object For3Use2_13 { + + def apply(): For3Use2_13 = new For3Use2_13() + def apply(prefix: String, suffix: String): For3Use2_13 = new For3Use2_13(prefix, suffix) +} + +/** + * Similar to Binary except that if the binary version is 2.13 + * it uses 3 instead. + * For example, if `prefix = "foo_"` and `suffix = "_bar"` and the binary version is "2.13", + * the module is cross-versioned with "foo_3_bar". + */ +final class For2_13Use3 private (val prefix: String, val suffix: String) + extends sbt.librarymanagement.CrossVersion() + with Serializable { + + private def this() = this("", "") + + override def equals(o: Any): Boolean = o match { + case x: For2_13Use3 => (this.prefix == x.prefix) && (this.suffix == x.suffix) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.librarymanagement.For3Use2_13".##) + prefix.##) + suffix.##) + } + override def toString: String = { + "For3Use2_13(" + prefix + ", " + suffix + ")" + } + private[this] def copy(prefix: String = prefix, suffix: String = suffix): For2_13Use3 = { + new For2_13Use3(prefix, suffix) + } + def withPrefix(prefix: String): For2_13Use3 = { + copy(prefix = prefix) + } + def withSuffix(suffix: String): For2_13Use3 = { + copy(suffix = suffix) + } +} +object For2_13Use3 { + + def apply(): For2_13Use3 = new For2_13Use3() + def apply(prefix: String, suffix: String): For2_13Use3 = new For2_13Use3(prefix, suffix) +} + trait DisabledFormats { self: sjsonnew.BasicJsonProtocol => implicit lazy val DisabledFormat: JsonFormat[sbt.librarymanagement.Disabled] = new JsonFormat[sbt.librarymanagement.Disabled] { @@ -324,22 +400,80 @@ trait FullFormats { self: sjsonnew.BasicJsonProtocol => } } +trait For3Use2_13Formats { self: sjsonnew.BasicJsonProtocol => + implicit lazy val For3Use2_13Format: JsonFormat[sbt.librarymanagement.For3Use2_13] = + new JsonFormat[sbt.librarymanagement.For3Use2_13] { + override def read[J]( + jsOpt: Option[J], + unbuilder: Unbuilder[J] + ): sbt.librarymanagement.For3Use2_13 = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val prefix = unbuilder.readField[String]("prefix") + val suffix = unbuilder.readField[String]("suffix") + unbuilder.endObject() + sbt.librarymanagement.For3Use2_13(prefix, suffix) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.librarymanagement.For3Use2_13, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("prefix", obj.prefix) + builder.addField("suffix", obj.suffix) + builder.endObject() + } + } +} + +trait For2_13Use3Formats { self: sjsonnew.BasicJsonProtocol => + implicit lazy val For2_13Use3Format: JsonFormat[sbt.librarymanagement.For2_13Use3] = + new JsonFormat[sbt.librarymanagement.For2_13Use3] { + override def read[J]( + jsOpt: Option[J], + unbuilder: Unbuilder[J] + ): sbt.librarymanagement.For2_13Use3 = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val prefix = unbuilder.readField[String]("prefix") + val suffix = unbuilder.readField[String]("suffix") + unbuilder.endObject() + sbt.librarymanagement.For2_13Use3(prefix, suffix) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.librarymanagement.For2_13Use3, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("prefix", obj.prefix) + builder.addField("suffix", obj.suffix) + builder.endObject() + } + } +} + trait CrossVersionFormats { self: sjsonnew.BasicJsonProtocol with sbt.librarymanagement.DisabledFormats with sbt.librarymanagement.BinaryFormats with sbt.librarymanagement.ConstantFormats with sbt.librarymanagement.PatchFormats - with sbt.librarymanagement.FullFormats => + with sbt.librarymanagement.FullFormats + with sbt.librarymanagement.For3Use2_13Formats + with sbt.librarymanagement.For2_13Use3Formats => implicit lazy val CrossVersionFormat: JsonFormat[CrossVersion] = { - val format = flatUnionFormat6[ + val format = flatUnionFormat8[ CrossVersion, Disabled, Disabled.type, Binary, Constant, Patch, - Full + Full, + For3Use2_13, + For2_13Use3 ]("type") // This is a hand-crafted formatter to avoid Disabled$ showing up in JSON new JsonFormat[CrossVersion] { diff --git a/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala b/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala index 43a46073..54608992 100644 --- a/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala @@ -9,7 +9,7 @@ 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", + "use CrossVersion.disabled instead. prior to sbt 1.3.0, Disabled did not work without apply(). sbt/sbt#4977", "1.3.0" ) final val Disabled = sbt.librarymanagement.Disabled @@ -37,13 +37,13 @@ private[librarymanagement] abstract class CrossVersionFunctions { */ def fullWith(prefix: String, suffix: String): CrossVersion = Full(prefix, suffix) - /** Cross-versions a module with the binary version (typically the binary Scala version). */ + /** Cross-versions a module with the binary version (typically the binary Scala version). */ def binary: CrossVersion = Binary() /** Disables cross versioning for a module. */ def disabled: CrossVersion = sbt.librarymanagement.Disabled - /** Cross-versions a module with a constant string (typically the binary Scala version). */ + /** Cross-versions a module with a constant string (typically the binary Scala version). */ def constant(value: String): CrossVersion = Constant(value) /** @@ -57,8 +57,52 @@ private[librarymanagement] abstract class CrossVersionFunctions { */ def patch: CrossVersion = Patch() + /** + * Cross-versions a module with the binary version but + * if the binary version is 3 (or of the form 3.0.0-x), cross-versions it with 2.13 instead + */ + def for3Use2_13: CrossVersion = For3Use2_13() + + /** + * Cross-versions a module with the binary version but + * if the binary version is 3 (or of the form 3.0.0-x), cross-versions it with 2.13 instead + * Always prepend `prefix` and append `suffix` + */ + def for3Use2_13With(prefix: String, suffix: String): CrossVersion = For3Use2_13(prefix, suffix) + + /** + * Cross-versions a module with the binary version but + * if the binary version is 2.13 cross-versions it with 3 instead + */ + def for2_13Use3: CrossVersion = For2_13Use3() + + /** + * Cross-versions a module with the binary version but + * if the binary version is 2.13 cross-versions it with 3 instead + * Always prepend `prefix` and append `suffix` + */ + def for2_13Use3With(prefix: String, suffix: String): CrossVersion = For2_13Use3(prefix, suffix) + + private[sbt] def getPrefixSuffix(value: CrossVersion): (String, String) = + value match { + case (_: Disabled | _: Constant | _: Patch) => ("", "") + case b: Binary => (b.prefix, b.suffix) + case f: Full => (f.prefix, f.suffix) + case c: For3Use2_13 => (c.prefix, c.suffix) + case c: For2_13Use3 => (c.prefix, c.suffix) + } + + private[sbt] def setPrefixSuffix(value: CrossVersion, p: String, s: String): CrossVersion = + value match { + case (_: Disabled | _: Constant | _: Patch) => value + case b: Binary => b.withPrefix(p).withSuffix(s) + case f: Full => f.withPrefix(p).withSuffix(s) + case c: For3Use2_13 => c.withPrefix(p).withSuffix(s) + case c: For2_13Use3 => c.withPrefix(p).withSuffix(s) + } + private[sbt] def patchFun(fullVersion: String): String = { - val BinCompatV = """(\d+)\.(\d+)\.(\d+)(-\w+)??-bin(-.*)?""".r + import sbt.internal.librarymanagement.cross.CrossVersionUtil.BinCompatV fullVersion match { case BinCompatV(x, y, z, w, _) => s"""$x.$y.$z${if (w == null) "" else w}""" case other => other @@ -83,6 +127,16 @@ private[librarymanagement] abstract class CrossVersionFunctions { case c: Constant => append(c.value) case _: Patch => append(patchFun(fullVersion)) case f: Full => append(f.prefix + fullVersion + f.suffix) + case c: For3Use2_13 => + val compat = + if (binaryVersion == "3" || binaryVersion.startsWith("3.0.0")) "2.13" + else binaryVersion + append(c.prefix + compat + c.suffix) + case c: For2_13Use3 => + val compat = + if (binaryVersion == "2.13") "3" + else binaryVersion + append(c.prefix + compat + c.suffix) } /** Constructs the cross-version function defined by `module` and `is`, if one is configured. */ @@ -164,7 +218,7 @@ private[librarymanagement] abstract class CrossVersionFunctions { */ def scalaApiVersion(v: String): Option[(Long, Long)] = CrossVersionUtil.scalaApiVersion(v) - /** Regular expression that extracts the major and minor components of a version into matched groups 1 and 2.*/ + /** Regular expression that extracts the major and minor components of a version into matched groups 1 and 2. */ val PartialVersion = CrossVersionUtil.PartialVersion /** Extracts the major and minor components of a version string `s` or returns `None` if the version is improperly formatted. */ @@ -181,4 +235,10 @@ private[librarymanagement] abstract class CrossVersionFunctions { * Full sbt versions earlier than [[sbt.librarymanagement.CrossVersion.TransitionSbtVersion]] are returned as is. */ def binarySbtVersion(full: String): String = CrossVersionUtil.binarySbtVersion(full) + + /** + * Returns `true` if a project targeting version `origVersion` can run with version `newVersion`. + */ + def isScalaBinaryCompatibleWith(newVersion: String, origVersion: String): Boolean = + CrossVersionUtil.isScalaBinaryCompatibleWith(newVersion, origVersion) } diff --git a/core/src/main/scala/sbt/librarymanagement/DependencyFilter.scala b/core/src/main/scala/sbt/librarymanagement/DependencyFilter.scala index 2f2adf76..3aa96f30 100644 --- a/core/src/main/scala/sbt/librarymanagement/DependencyFilter.scala +++ b/core/src/main/scala/sbt/librarymanagement/DependencyFilter.scala @@ -29,7 +29,9 @@ trait DependencyFilterExtra { ): ArtifactFilter = new ArtifactFilter { def apply(a: Artifact): Boolean = - name.accept(a.name) && `type`.accept(a.`type`) && extension.accept(a.extension) && classifier + name.accept(a.name) && `type`.accept(a.`type`) && extension.accept( + a.extension + ) && classifier .accept(a.classifier getOrElse "") } diff --git a/core/src/main/scala/sbt/librarymanagement/DependencyResolution.scala b/core/src/main/scala/sbt/librarymanagement/DependencyResolution.scala index 500f569e..1f2b37a2 100644 --- a/core/src/main/scala/sbt/librarymanagement/DependencyResolution.scala +++ b/core/src/main/scala/sbt/librarymanagement/DependencyResolution.scala @@ -189,10 +189,9 @@ class DependencyResolution private[sbt] (lmEngine: DependencyResolutionInterface ((sourceArtifactTypes.toIterable map (_ -> Artifact.SourceClassifier)) :: (docArtifactTypes.toIterable map (_ -> Artifact.DocClassifier)) :: Nil).flatten.toMap Right(r.substitute { (conf, mid, artFileSeq) => - artFileSeq map { - case (art, f) => - // Deduce the classifier from the type if no classifier is present already - art.withClassifier(art.classifier orElse typeClassifierMap.get(art.`type`)) -> f + artFileSeq map { case (art, f) => + // Deduce the classifier from the type if no classifier is present already + art.withClassifier(art.classifier orElse typeClassifierMap.get(art.`type`)) -> f } }) case Left(w) => Left(w) @@ -200,10 +199,9 @@ class DependencyResolution private[sbt] (lmEngine: DependencyResolutionInterface } protected def directDependenciesNames(module: ModuleDescriptor): String = - (module.directDependencies map { - case mID: ModuleID => - import mID._ - s"$organization % $name % $revision" + (module.directDependencies map { case mID: ModuleID => + import mID._ + s"$organization % $name % $revision" }).mkString(", ") } diff --git a/core/src/main/scala/sbt/librarymanagement/EvictionError.scala b/core/src/main/scala/sbt/librarymanagement/EvictionError.scala new file mode 100644 index 00000000..3e73e37c --- /dev/null +++ b/core/src/main/scala/sbt/librarymanagement/EvictionError.scala @@ -0,0 +1,186 @@ +package sbt +package librarymanagement + +import scala.collection.mutable +import sbt.internal.librarymanagement.VersionSchemes +import sbt.util.{ Level, ShowLines } +import EvictionWarningOptions.isNameScalaSuffixed + +object EvictionError { + def apply( + report: UpdateReport, + module: ModuleDescriptor, + schemes: Seq[ModuleID], + ): EvictionError = { + apply(report, module, schemes, "always", "always", Level.Debug) + } + + def apply( + report: UpdateReport, + module: ModuleDescriptor, + schemes: Seq[ModuleID], + assumedVersionScheme: String, + assumedVersionSchemeJava: String, + assumedEvictionErrorLevel: Level.Value, + ): EvictionError = { + val options = EvictionWarningOptions.full + val evictions = EvictionWarning.buildEvictions(options, report) + processEvictions( + module, + options, + evictions, + schemes, + assumedVersionScheme, + assumedVersionSchemeJava, + assumedEvictionErrorLevel, + ) + } + + private[sbt] def processEvictions( + module: ModuleDescriptor, + options: EvictionWarningOptions, + reports: Seq[OrganizationArtifactReport], + schemes: Seq[ModuleID], + assumedVersionScheme: String, + assumedVersionSchemeJava: String, + assumedEvictionErrorLevel: Level.Value, + ): EvictionError = { + val directDependencies = module.directDependencies + val pairs = reports map { detail => + val evicteds = detail.modules filter { _.evicted } + val winner = (detail.modules filterNot { _.evicted }).headOption + new EvictionPair( + detail.organization, + detail.name, + winner, + evicteds, + true, + options.showCallers + ) + } + val incompatibleEvictions: mutable.ListBuffer[(EvictionPair, String)] = mutable.ListBuffer() + val assumedIncompatEvictions: mutable.ListBuffer[(EvictionPair, String)] = mutable.ListBuffer() + val sbvOpt = module.scalaModuleInfo.map(_.scalaBinaryVersion) + val userDefinedSchemes: Map[(String, String), String] = Map(schemes flatMap { s => + val organization = s.organization + VersionSchemes.validateScheme(s.revision) + val versionScheme = s.revision + (s.crossVersion, sbvOpt) match { + case (_: Binary, Some("2.13")) => + List( + (s.organization, s"${s.name}_2.13") -> versionScheme, + (s.organization, s"${s.name}_3") -> versionScheme + ) + case (_: Binary, Some(sbv)) if sbv.startsWith("3.0") || sbv == "3" => + List( + (s.organization, s"${s.name}_$sbv") -> versionScheme, + (s.organization, s"${s.name}_2.13") -> versionScheme + ) + case (_: Binary, Some(sbv)) => + List((s.organization, s"${s.name}_$sbv") -> versionScheme) + case _ => + List((s.organization, s.name) -> versionScheme) + } + }: _*) + + pairs foreach { + // don't report on a transitive eviction that does not have a winner + // https://github.com/sbt/sbt/issues/4946 + case p if p.winner.isDefined => + val winner = p.winner.get + + def hasIncompatibleVersionForScheme(scheme: String) = { + val isCompat = VersionSchemes.evalFunc(scheme) + p.evicteds.exists { r => + !isCompat((r.module, Some(winner.module), module.scalaModuleInfo)) + } + } + + // from libraryDependencyScheme or defined in the pom using the `info.versionScheme` attribute + val userDefinedSchemeOrFromPom = { + def fromLibraryDependencySchemes(org: String = "*", mod: String = "*") = + userDefinedSchemes.get((org, mod)) + def fromWinnerPom = VersionSchemes.extractFromExtraAttributes( + winner.extraAttributes.toMap ++ winner.module.extraAttributes + ) + + fromLibraryDependencySchemes(p.organization, p.name) // by org and name + .orElse(fromLibraryDependencySchemes(p.organization)) // for whole org + .orElse(fromWinnerPom) // from pom + .orElse(fromLibraryDependencySchemes()) // global + } + + // We want the user to be able to suppress eviction errors for a specific library, + // which would result in an incompatible eviction based on the assumed version scheme. + // So, only fall back to the assumed scheme if there is no given scheme by the user or the pom. + userDefinedSchemeOrFromPom match { + case Some(givenScheme) => + if (hasIncompatibleVersionForScheme(givenScheme)) + incompatibleEvictions += (p -> givenScheme) + case None => + val assumedScheme = + if (isNameScalaSuffixed(p.name)) assumedVersionScheme + else assumedVersionSchemeJava + + if (hasIncompatibleVersionForScheme(assumedScheme)) + assumedIncompatEvictions += (p -> assumedScheme) + } + + case _ => () + } + + new EvictionError( + incompatibleEvictions.toList, + assumedIncompatEvictions.toList, + ) + } + + implicit val evictionErrorLines: ShowLines[EvictionError] = ShowLines { (a: EvictionError) => + a.toLines + } +} + +final class EvictionError private[sbt] ( + val incompatibleEvictions: Seq[(EvictionPair, String)], + val assumedIncompatibleEvictions: Seq[(EvictionPair, String)], +) { + def run(): Unit = + if (incompatibleEvictions.nonEmpty) { + sys.error(toLines.mkString("\n")) + } + + def toLines: List[String] = toLines(incompatibleEvictions, false) + + def toAssumedLines: List[String] = toLines(assumedIncompatibleEvictions, true) + + def toLines(evictions: Seq[(EvictionPair, String)], assumed: Boolean): List[String] = { + val out: mutable.ListBuffer[String] = mutable.ListBuffer() + out += "found version conflict(s) in library dependencies; some are suspected to be binary incompatible:" + out += "" + evictions.foreach({ case (a, scheme) => + val revs = a.evicteds map { _.module.revision } + val revsStr = + if (revs.size <= 1) revs.mkString else "{" + revs.distinct.mkString(", ") + "}" + val seen: mutable.Set[ModuleID] = mutable.Set() + val callers: List[String] = (a.evicteds.toList ::: a.winner.toList) flatMap { r => + val rev = r.module.revision + r.callers.toList flatMap { caller => + if (seen(caller.caller)) Nil + else { + seen += caller.caller + List(f"\t +- ${caller}%-50s (depends on $rev)") + } + } + } + val que = if (assumed) "?" else "" + val winnerRev = a.winner match { + case Some(r) => s":${r.module.revision} ($scheme$que) is selected over ${revsStr}" + case _ => " is evicted for all versions" + } + val title = s"\t* ${a.organization}:${a.name}$winnerRev" + val lines = title :: (if (a.showCallers) callers.reverse else Nil) ::: List("") + out ++= lines + }) + out.toList + } +} diff --git a/core/src/main/scala/sbt/librarymanagement/EvictionWarning.scala b/core/src/main/scala/sbt/librarymanagement/EvictionWarning.scala index e8dff4e6..df70eeff 100644 --- a/core/src/main/scala/sbt/librarymanagement/EvictionWarning.scala +++ b/core/src/main/scala/sbt/librarymanagement/EvictionWarning.scala @@ -98,12 +98,25 @@ object EvictionWarningOptions { lazy val defaultGuess: Function1[(ModuleID, Option[ModuleID], Option[ScalaModuleInfo]), Boolean] = guessSbtOne orElse guessSecondSegment orElse guessSemVer orElse guessFalse + private[sbt] def isNameScalaSuffixed(name: String): Boolean = + name.contains("_2.") || name.contains("_3") || name.contains("_4") + + /** A partial function that checks if given m2 is suffixed, and use pvp to evaluate. */ lazy val guessSecondSegment : PartialFunction[(ModuleID, Option[ModuleID], Option[ScalaModuleInfo]), Boolean] = { - case (m1, Some(m2), Some(scalaModuleInfo)) - if m2.name.endsWith("_" + scalaModuleInfo.scalaFullVersion) || m2.name.endsWith( - "_" + scalaModuleInfo.scalaBinaryVersion - ) => + case (m1, Some(m2), Some(_)) if isNameScalaSuffixed(m2.name) => + (m1.revision, m2.revision) match { + case (VersionNumber(ns1, ts1, es1), VersionNumber(ns2, ts2, es2)) => + VersionNumber.SecondSegment + .isCompatible(VersionNumber(ns1, ts1, es1), VersionNumber(ns2, ts2, es2)) + case _ => false + } + } + + /** A partial function that checks two versions match pvp. */ + private[sbt] lazy val evalPvp + : PartialFunction[(ModuleID, Option[ModuleID], Option[ScalaModuleInfo]), Boolean] = { + case (m1, Some(m2), _) => (m1.revision, m2.revision) match { case (VersionNumber(ns1, ts1, es1), VersionNumber(ns2, ts2, es2)) => VersionNumber.SecondSegment @@ -148,10 +161,26 @@ object EvictionWarningOptions { } } + lazy val guessStrict + : PartialFunction[(ModuleID, Option[ModuleID], Option[ScalaModuleInfo]), Boolean] = { + case (m1, Some(m2), _) => + (m1.revision, m2.revision) match { + case (VersionNumber(ns1, ts1, es1), VersionNumber(ns2, ts2, es2)) => + VersionNumber.Strict + .isCompatible(VersionNumber(ns1, ts1, es1), VersionNumber(ns2, ts2, es2)) + case _ => false + } + } + lazy val guessFalse : PartialFunction[(ModuleID, Option[ModuleID], Option[ScalaModuleInfo]), Boolean] = { case (_, _, _) => false } + + lazy val guessTrue + : PartialFunction[(ModuleID, Option[ModuleID], Option[ScalaModuleInfo]), Boolean] = { + case (_, _, _) => true + } } final class EvictionPair private[sbt] ( @@ -167,7 +196,7 @@ final class EvictionPair private[sbt] ( override def equals(o: Any): Boolean = o match { case o: EvictionPair => (this.organization == o.organization) && - (this.name == o.name) + (this.name == o.name) case _ => false } override def hashCode: Int = { @@ -179,7 +208,7 @@ final class EvictionPair private[sbt] ( } object EvictionPair { - implicit val evictionPairLines: ShowLines[EvictionPair] = ShowLines { a: EvictionPair => + implicit val evictionPairLines: ShowLines[EvictionPair] = ShowLines { (a: EvictionPair) => val revs = a.evicteds map { _.module.revision } val revsStr = if (revs.size <= 1) revs.mkString else "{" + revs.mkString(", ") + "}" val seen: mutable.Set[ModuleID] = mutable.Set() @@ -250,10 +279,12 @@ object EvictionWarning { } confs flatMap { confReport => confReport.details map { detail => - if ((detail.modules exists { _.evicted }) && - !(buffer exists { x => - (x.organization == detail.organization) && (x.name == detail.name) - })) { + if ( + (detail.modules exists { _.evicted }) && + !(buffer exists { x => + (x.organization == detail.organization) && (x.name == detail.name) + }) + ) { buffer += detail } } @@ -269,7 +300,7 @@ object EvictionWarning { module.scalaModuleInfo match { case Some(s) => organization == s.scalaOrganization && - (name == LibraryID) || (name == CompilerID) + (name == LibraryID) || (name == CompilerID) case _ => false } @@ -303,21 +334,25 @@ object EvictionWarning { def guessCompatible(p: EvictionPair): Boolean = p.evicteds forall { r => val winnerOpt = p.winner map { _.module } - val extraAttributes = (p.winner match { + val extraAttributes = ((p.winner match { case Some(r) => r.extraAttributes case _ => Map.empty - }) ++ (winnerOpt match { + }): collection.immutable.Map[String, String]) ++ (winnerOpt match { case Some(w) => w.extraAttributes case _ => Map.empty }) val schemeOpt = VersionSchemes.extractFromExtraAttributes(extraAttributes) val f = (winnerOpt, schemeOpt) match { + case (Some(_), Some(VersionSchemes.Always)) => + EvictionWarningOptions.guessTrue + case (Some(_), Some(VersionSchemes.Strict)) => + EvictionWarningOptions.guessStrict case (Some(_), Some(VersionSchemes.EarlySemVer)) => EvictionWarningOptions.guessEarlySemVer case (Some(_), Some(VersionSchemes.SemVerSpec)) => EvictionWarningOptions.guessSemVer case (Some(_), Some(VersionSchemes.PackVer)) => - EvictionWarningOptions.guessSecondSegment + EvictionWarningOptions.evalPvp case _ => options.guessCompatible(_) } f((r.module, winnerOpt, module.scalaModuleInfo)) diff --git a/core/src/main/scala/sbt/librarymanagement/Http.scala b/core/src/main/scala/sbt/librarymanagement/Http.scala index 2b54f814..5edf9a74 100644 --- a/core/src/main/scala/sbt/librarymanagement/Http.scala +++ b/core/src/main/scala/sbt/librarymanagement/Http.scala @@ -1,6 +1,6 @@ package sbt.librarymanagement -import gigahorse._, support.okhttp.Gigahorse +import gigahorse._, support.apachehttp.Gigahorse import scala.concurrent.duration.DurationInt object Http { diff --git a/core/src/main/scala/sbt/librarymanagement/LibraryManagementSyntax.scala b/core/src/main/scala/sbt/librarymanagement/LibraryManagementSyntax.scala index 8d177c83..1ab5629d 100644 --- a/core/src/main/scala/sbt/librarymanagement/LibraryManagementSyntax.scala +++ b/core/src/main/scala/sbt/librarymanagement/LibraryManagementSyntax.scala @@ -28,6 +28,7 @@ trait LibraryManagementSyntax final val Compile = C.Compile final val Test = C.Test final val Runtime = C.Runtime + @deprecated("Create a separate subproject for testing instead", "1.9.0") final val IntegrationTest = C.IntegrationTest final val Default = C.Default final val Provided = C.Provided diff --git a/core/src/main/scala/sbt/librarymanagement/License.scala b/core/src/main/scala/sbt/librarymanagement/License.scala new file mode 100644 index 00000000..a8ac3108 --- /dev/null +++ b/core/src/main/scala/sbt/librarymanagement/License.scala @@ -0,0 +1,25 @@ +package sbt.librarymanagement + +import java.net.URL +import java.net.URI + +/** + * Commonly used software licenses + * Names are SPDX ids: + * https://raw.githubusercontent.com/spdx/license-list-data/master/json/licenses.json + */ +object License { + lazy val Apache2: (String, URL) = + ("Apache-2.0", new URI("https://www.apache.org/licenses/LICENSE-2.0.txt").toURL) + + lazy val MIT: (String, URL) = + ("MIT", new URI("https://opensource.org/licenses/MIT").toURL) + + lazy val CC0: (String, URL) = + ("CC0-1.0", new URI("https://creativecommons.org/publicdomain/zero/1.0/legalcode").toURL) + + def PublicDomain: (String, URL) = CC0 + + lazy val GPL3_or_later: (String, URL) = + ("GPL-3.0-or-later", new URI("https://spdx.org/licenses/GPL-3.0-or-later.html").toURL) +} diff --git a/core/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala b/core/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala index 40db9def..e96eb85e 100644 --- a/core/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala @@ -3,7 +3,7 @@ */ package sbt.librarymanagement -import java.net.URL +import java.net.URI import sbt.internal.librarymanagement.mavenint.SbtPomExtraProperties import scala.collection.mutable.ListBuffer @@ -37,10 +37,10 @@ private[librarymanagement] abstract class ModuleIDExtra { protected def toStringImpl: String = s"""$organization:$name:$revision""" + (configurations match { case Some(s) => ":" + s; case None => "" }) + { - val attr = attributeString - if (attr == "") "" - else " " + attr - } + + val attr = attributeString + if (attr == "") "" + else " " + attr + } + (if (extraAttributes.isEmpty) "" else " " + extraString) protected def attributeString: String = { @@ -59,11 +59,11 @@ private[librarymanagement] abstract class ModuleIDExtra { /** String representation of the extra attributes, excluding any information only attributes. */ def extraString: String = - extraDependencyAttributes.map { case (k, v) => k + "=" + v } mkString ("(", ", ", ")") + extraDependencyAttributes.map { case (k, v) => k + "=" + v }.mkString("(", ", ", ")") /** Returns the extra attributes except for ones marked as information only (ones that typically would not be used for dependency resolution). */ def extraDependencyAttributes: Map[String, String] = - extraAttributes.filterKeys(!_.startsWith(SbtPomExtraProperties.POM_INFO_KEY_PREFIX)) + extraAttributes.filterKeys(!_.startsWith(SbtPomExtraProperties.POM_INFO_KEY_PREFIX)).toMap @deprecated( "Use `cross(CrossVersion)`, the variant accepting a CrossVersion value constructed by a member of the CrossVersion object instead.", @@ -71,14 +71,34 @@ private[librarymanagement] abstract class ModuleIDExtra { ) def cross(v: Boolean): ModuleID = cross(if (v) CrossVersion.binary else Disabled()) - /** Specifies the cross-version behavior for this module. See [CrossVersion] for details.*/ - def cross(v: CrossVersion): ModuleID = withCrossVersion(v) + /** + * Specifies the cross-version behavior for this module. See [CrossVersion] for details. + * Unlike `withCrossVersion(...)`, `cross(...)` will preserve the prefix and suffix + * values from the existing `crossVersion` value. + * + * {{{ + * ModuleID("com.example", "foo", "1.0") + * .cross(CrossVersion.binaryWith("sjs1_", "")) + * .cross(CrossVersion.for3Use2_13) + * }}} + * + * This allows `.cross(...)` to play well with `%%%` operator provided by sbt-platform-deps. + */ + def cross(v: CrossVersion): ModuleID = + withCrossVersion(CrossVersion.getPrefixSuffix(this.crossVersion) match { + case ("", "") => v + case (prefix, suffix) => + CrossVersion.getPrefixSuffix(v) match { + case ("", "") => CrossVersion.setPrefixSuffix(v, prefix, suffix) + case _ => v + } + }) // () required for chaining - /** Do not follow dependencies of this module. Synonym for `intransitive`.*/ + /** Do not follow dependencies of this module. Synonym for `intransitive`. */ def notTransitive(): ModuleID = intransitive() - /** Do not follow dependencies of this module. Synonym for `notTransitive`.*/ + /** Do not follow dependencies of this module. Synonym for `notTransitive`. */ def intransitive(): ModuleID = withIsTransitive(false) /** @@ -112,7 +132,7 @@ private[librarymanagement] abstract class ModuleIDExtra { * It is not included in published metadata. */ def from(url: String, allowInsecureProtocol: Boolean): ModuleID = - artifacts(Artifact(name, new URL(url), allowInsecureProtocol)) + artifacts(Artifact(name, new URI(url).toURL, allowInsecureProtocol)) /** Adds a dependency on the artifact for this module with classifier `c`. */ def classifier(c: String): ModuleID = 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 b5ae222b..ca980b7e 100644 --- a/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/ResolverExtra.scala @@ -5,9 +5,11 @@ package sbt.librarymanagement import java.io.{ IOException, File } import java.net.{ URI, URL } +import scala.annotation.nowarn import scala.xml.XML import org.xml.sax.SAXParseException import sbt.util.Logger +import java.net.URI final class RawRepository(val resolver: AnyRef, name: String) extends Resolver(name) { override def toString = "Raw(" + resolver.toString + ")" @@ -102,6 +104,9 @@ private[librarymanagement] abstract class ResolverFunctions { @deprecated("Renamed to SbtRepositoryRoot.", "1.0.0") val SbtPluginRepositoryRoot = SbtRepositoryRoot val SonatypeRepositoryRoot = "https://oss.sonatype.org/content/repositories" + val SonatypeS01RepositoryRoot = "https://s01.oss.sonatype.org/content/repositories" + val SonatypeReleasesRepository = + "https://oss.sonatype.org/service/local/repositories/releases/content/" val JavaNet2RepositoryName = "java.net Maven2 Repository" val JavaNet2RepositoryRoot = javanet2RepositoryRoot(useSecureResolvers) val JCenterRepositoryName = "jcenter" @@ -132,7 +137,7 @@ private[librarymanagement] abstract class ResolverFunctions { // obsolete: kept only for launcher compatibility private[sbt] val ScalaToolsReleasesName = "Sonatype OSS Releases" private[sbt] val ScalaToolsSnapshotsName = "Sonatype OSS Snapshots" - private[sbt] val ScalaToolsReleasesRoot = SonatypeRepositoryRoot + "/releases" + private[sbt] val ScalaToolsReleasesRoot = SonatypeReleasesRepository private[sbt] val ScalaToolsSnapshotsRoot = SonatypeRepositoryRoot + "/snapshots" private[sbt] val ScalaToolsReleases = MavenRepository(ScalaToolsReleasesName, ScalaToolsReleasesRoot) @@ -142,26 +147,51 @@ private[librarymanagement] abstract class ResolverFunctions { def typesafeRepo(status: String) = MavenRepository("typesafe-" + status, TypesafeRepositoryRoot + "/" + status) def typesafeIvyRepo(status: String) = - url("typesafe-ivy-" + status, new URL(TypesafeRepositoryRoot + "/ivy-" + status + "/"))( + url("typesafe-ivy-" + status, new URI(TypesafeRepositoryRoot + "/ivy-" + status + "/").toURL)( ivyStylePatterns ) def sbtIvyRepo(status: String) = - url(s"sbt-ivy-$status", new URL(s"$SbtRepositoryRoot/ivy-$status/"))(ivyStylePatterns) + url(s"sbt-ivy-$status", new URI(s"$SbtRepositoryRoot/ivy-$status/").toURL)(ivyStylePatterns) def sbtPluginRepo(status: String) = - url("sbt-plugin-" + status, new URL(SbtRepositoryRoot + "/sbt-plugin-" + status + "/"))( + url("sbt-plugin-" + status, new URI(SbtRepositoryRoot + "/sbt-plugin-" + status + "/").toURL)( ivyStylePatterns ) + @deprecated( + """Use sonatypeOssRepos instead e.g. `resolvers ++= Resolver.sonatypeOssRepos("snapshots")`""", + "1.7.0" + ) def sonatypeRepo(status: String) = - MavenRepository("sonatype-" + status, SonatypeRepositoryRoot + "/" + status) + MavenRepository( + "sonatype-" + status, + if (status == "releases") SonatypeReleasesRepository + else SonatypeRepositoryRoot + "/" + status + ) + private def sonatypeS01Repo(status: String) = + MavenRepository( + "sonatype-s01-" + status, + SonatypeS01RepositoryRoot + "/" + status + ) + def sonatypeOssRepos(status: String) = + Vector(sonatypeRepo(status): @nowarn("cat=deprecation"), sonatypeS01Repo(status)) def bintrayRepo(owner: String, repo: String) = MavenRepository(s"bintray-$owner-$repo", s"https://dl.bintray.com/$owner/$repo/") def bintrayIvyRepo(owner: String, repo: String) = - url(s"bintray-$owner-$repo", new URL(s"https://dl.bintray.com/$owner/$repo/"))( + url(s"bintray-$owner-$repo", new URI(s"https://dl.bintray.com/$owner/$repo/").toURL)( Resolver.ivyStylePatterns ) def jcenterRepo = JCenterRepository - /** Add the local and Maven Central repositories to the user repositories. */ + val ApacheMavenSnapshotsRepo = MavenRepository( + "apache-snapshots", + "https://repository.apache.org/content/repositories/snapshots/" + ) + + val ApacheMavenStagingRepo = MavenRepository( + "apache-staging", + "https://repository.apache.org/content/groups/staging/" + ) + + /** Add the local and Maven Central repositories to the user repositories. */ def combineDefaultResolvers(userResolvers: Vector[Resolver]): Vector[Resolver] = combineDefaultResolvers(userResolvers, mavenCentral = true) @@ -208,7 +238,10 @@ private[librarymanagement] abstract class ResolverFunctions { single(JCenterRepository, jcenter) ++ (xs.partition(_ == DefaultMavenRepository) match { case (_, xs) => - single(DefaultMavenRepository, mavenCentral) ++ xs // TODO - Do we need to filter out duplicates? + single( + DefaultMavenRepository, + mavenCentral + ) ++ xs // TODO - Do we need to filter out duplicates? }) }) } @@ -216,7 +249,7 @@ private[librarymanagement] abstract class ResolverFunctions { private def single[T](value: T, nonEmpty: Boolean): Vector[T] = if (nonEmpty) Vector(value) else Vector.empty - /** A base class for defining factories for interfaces to Ivy repositories that require a hostname , port, and patterns. */ + /** A base class for defining factories for interfaces to Ivy repositories that require a hostname , port, and patterns. */ sealed abstract class Define[RepositoryType <: SshBasedRepository] { /** Subclasses should implement this method to */ @@ -245,8 +278,8 @@ private[librarymanagement] abstract class ResolverFunctions { * patterns will be resolved. `basePatterns` are the initial patterns to use. * A ManagedProject has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns. */ - def apply(name: String, hostname: String, basePath: String)( - implicit basePatterns: Patterns + def apply(name: String, hostname: String, basePath: String)(implicit + basePatterns: Patterns ): RepositoryType = apply(name, Some(hostname), None, Some(basePath)) @@ -254,8 +287,8 @@ private[librarymanagement] abstract class ResolverFunctions { * Constructs this repository type with the given `name`, `hostname`, and `port`. `basePatterns` are the initial patterns to use. * A ManagedProject has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns. */ - def apply(name: String, hostname: String, port: Int)( - implicit basePatterns: Patterns + def apply(name: String, hostname: String, port: Int)(implicit + basePatterns: Patterns ): RepositoryType = apply(name, Some(hostname), Some(port), None) @@ -264,8 +297,8 @@ private[librarymanagement] abstract class ResolverFunctions { * patterns will be resolved. `basePatterns` are the initial patterns to use. * A ManagedProject has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns. */ - def apply(name: String, hostname: String, port: Int, basePath: String)( - implicit basePatterns: Patterns + def apply(name: String, hostname: String, port: Int, basePath: String)(implicit + basePatterns: Patterns ): RepositoryType = apply(name, Some(hostname), Some(port), Some(basePath)) @@ -280,13 +313,13 @@ private[librarymanagement] abstract class ResolverFunctions { construct(name, SshConnection(None, hostname, port), resolvePatterns(basePath, basePatterns)) } - /** A factory to construct an interface to an Ivy SSH resolver.*/ + /** A factory to construct an interface to an Ivy SSH resolver. */ object ssh extends Define[SshRepository] { protected def construct(name: String, connection: SshConnection, patterns: Patterns) = SshRepository(name, connection, patterns, None) } - /** A factory to construct an interface to an Ivy SFTP resolver.*/ + /** A factory to construct an interface to an Ivy SFTP resolver. */ object sftp extends Define[SftpRepository] { protected def construct(name: String, connection: SshConnection, patterns: Patterns) = SftpRepository(name, connection, patterns) @@ -324,8 +357,8 @@ private[librarymanagement] abstract class ResolverFunctions { def apply(name: String, baseURL: URL)(implicit basePatterns: Patterns): URLRepository = baseRepository(baseURL.toURI.normalize.toString)(URLRepository(name, _)) } - private def baseRepository[T](base: String)(construct: Patterns => T)( - implicit basePatterns: Patterns + private def baseRepository[T](base: String)(construct: Patterns => T)(implicit + basePatterns: Patterns ): T = construct(resolvePatterns(base, basePatterns)) @@ -357,7 +390,7 @@ private[librarymanagement] abstract class ResolverFunctions { } def defaultFileConfiguration = FileConfiguration(true, None) def mavenStylePatterns = Patterns().withArtifactPatterns(Vector(mavenStyleBasePattern)) - def ivyStylePatterns = defaultIvyPatterns //Patterns(Nil, Nil, false) + def ivyStylePatterns = defaultIvyPatterns // Patterns(Nil, Nil, false) def defaultPatterns = mavenStylePatterns def mavenStyleBasePattern = @@ -367,6 +400,20 @@ private[librarymanagement] abstract class ResolverFunctions { def defaultRetrievePattern = "[type]s/[organisation]/[module]/" + PluginPattern + "[artifact](-[revision])(-[classifier]).[ext]" final val PluginPattern = "(scala_[scalaVersion]/)(sbt_[sbtVersion]/)" + private[librarymanagement] def expandMavenSettings(str: String): String = { + // Aren't regular expressions beautifully clear and concise. + // This means "find all ${...}" blocks, with the first group of each being the text between curly brackets. + val findQuoted = "\\$\\{([^\\}]*)\\}".r + val env = "env\\.(.*)".r + + findQuoted.replaceAllIn( + str, + _.group(1) match { + case env(variable) => sys.env.getOrElse(variable, "") + case property => sys.props.getOrElse(property, "") + } + ) + } private[this] def mavenLocalDir: File = { def loadHomeFromSettings(f: () => File): Option[File] = try { @@ -375,7 +422,7 @@ private[librarymanagement] abstract class ResolverFunctions { else ((XML.loadFile(file) \ "localRepository").text match { case "" => None - case e @ _ => Some(new File(e)) + case e @ _ => Some(new File(expandMavenSettings(e))) }) } catch { // Occurs inside File constructor when property or environment variable does not exist @@ -386,8 +433,11 @@ private[librarymanagement] abstract class ResolverFunctions { System.err.println(s"WARNING: Problem parsing ${f().getAbsolutePath}, ${e.getMessage}"); None } - loadHomeFromSettings(() => new File(sbt.io.Path.userHome, ".m2/settings.xml")) orElse - loadHomeFromSettings(() => new File(new File(System.getenv("M2_HOME")), "conf/settings.xml")) getOrElse + sys.props.get("maven.repo.local").map(new File(_)) orElse + loadHomeFromSettings(() => new File(sbt.io.Path.userHome, ".m2/settings.xml")) orElse + loadHomeFromSettings(() => + new File(new File(System.getenv("M2_HOME")), "conf/settings.xml") + ) getOrElse new File(sbt.io.Path.userHome, ".m2/repository") } // TODO - should this just be the *exact* same as mavenLocal? probably... diff --git a/core/src/main/scala/sbt/librarymanagement/RichUpdateReport.scala b/core/src/main/scala/sbt/librarymanagement/RichUpdateReport.scala index f66440bb..9060f14b 100644 --- a/core/src/main/scala/sbt/librarymanagement/RichUpdateReport.scala +++ b/core/src/main/scala/sbt/librarymanagement/RichUpdateReport.scala @@ -12,16 +12,15 @@ final class RichUpdateReport(report: UpdateReport) { private[sbt] def recomputeStamps(): UpdateReport = { val files = report.cachedDescriptor +: allFiles val stamps = files - .map( - f => - ( - f, - // TODO: The list of files may also contain some odd files that do not actually exist like: - // "./target/ivyhome/resolution-cache/com.example/foo/0.4.0/resolved.xml.xml". - // IO.getModifiedTimeOrZero() will just return zero, but the list of files should not contain such - // files to begin with, in principle. - IO.getModifiedTimeOrZero(f) - ) + .map(f => + ( + f, + // TODO: The list of files may also contain some odd files that do not actually exist like: + // "./target/ivyhome/resolution-cache/com.example/foo/0.4.0/resolved.xml.xml". + // IO.getModifiedTimeOrZero() will just return zero, but the list of files should not contain such + // files to begin with, in principle. + IO.getModifiedTimeOrZero(f) + ) ) .toMap UpdateReport(report.cachedDescriptor, report.configurations, report.stats, stamps) @@ -65,13 +64,13 @@ final class RichUpdateReport(report: UpdateReport) { file } - /** Constructs a new report that only contains files matching the specified filter.*/ + /** Constructs a new report that only contains files matching the specified filter. */ def filter(f: DependencyFilter): UpdateReport = moduleReportMap { (configuration, modReport) => modReport .withArtifacts( - modReport.artifacts filter { - case (art, _) => f(configuration, modReport.module, art) + modReport.artifacts filter { case (art, _) => + f(configuration, modReport.module, art) } ) .withMissingArtifacts( diff --git a/core/src/main/scala/sbt/librarymanagement/ScalaArtifacts.scala b/core/src/main/scala/sbt/librarymanagement/ScalaArtifacts.scala index e0b1b6be..82c454e2 100644 --- a/core/src/main/scala/sbt/librarymanagement/ScalaArtifacts.scala +++ b/core/src/main/scala/sbt/librarymanagement/ScalaArtifacts.scala @@ -1,37 +1,104 @@ package sbt.librarymanagement object ScalaArtifacts { - val Organization = "org.scala-lang" - val LibraryID = "scala-library" - val CompilerID = "scala-compiler" - val ReflectID = "scala-reflect" - val ActorsID = "scala-actors" - val ScalapID = "scalap" - val Artifacts = Vector(LibraryID, CompilerID, ReflectID, ActorsID, ScalapID) - val DottyIDPrefix = "dotty" + final val Organization = "org.scala-lang" + final val LibraryID = "scala-library" + final val CompilerID = "scala-compiler" + final val ReflectID = "scala-reflect" + final val ActorsID = "scala-actors" + final val ScalapID = "scalap" + final val Artifacts = Vector(LibraryID, CompilerID, ReflectID, ActorsID, ScalapID) - def dottyID(binaryVersion: String): String = s"${DottyIDPrefix}_${binaryVersion}" + final val Scala3LibraryID = "scala3-library" + final val Scala3CompilerID = "scala3-compiler" + final val Scala3InterfacesID = "scala3-interfaces" + final val TastyCoreID = "tasty-core" + final val ScaladocID = "scaladoc" + final val Scala3DocID = "scala3doc" + final val Scala3TastyInspectorID = "scala3-tasty-inspector" - def libraryDependency(version: String): ModuleID = ModuleID(Organization, LibraryID, version) + private[sbt] final val Scala3LibraryPrefix = Scala3LibraryID + "_" + private[sbt] final val Scala3CompilerPrefix = Scala3CompilerID + "_" + private[sbt] final val TastyCorePrefix = TastyCoreID + "_" + private[sbt] final val ScaladocPrefix = ScaladocID + "_" + private[sbt] final val Scala3DocPrefix = Scala3DocID + "_" + private[sbt] final val Scala3TastyInspectorPrefix = Scala3TastyInspectorID + "_" + + def isScala2Artifact(name: String): Boolean = { + name == LibraryID || name == CompilerID || name == ReflectID || name == ActorsID || name == ScalapID + } + def isScala3Artifact(name: String): Boolean = { + name.startsWith(Scala3LibraryPrefix) || + name.startsWith(Scala3CompilerPrefix) || + name.startsWith(TastyCorePrefix) || + name == Scala3InterfacesID || + name.startsWith(ScaladocPrefix) || + name.startsWith(Scala3DocPrefix) || + name.startsWith(Scala3TastyInspectorPrefix) + } + + def isScala3(scalaVersion: String): Boolean = scalaVersion.startsWith("3.") + + private[sbt] def isScala3M123(scalaVersion: String): Boolean = + (scalaVersion == "3.0.0-M1") || + (scalaVersion == "3.0.0-M2") || + (scalaVersion == "3.0.0-M3") + + def libraryIds(version: String): Array[String] = { + if (isScala3(version)) + Array(Scala3LibraryID, LibraryID) + else Array(LibraryID) + } + + def compilerId(version: String): String = { + if (isScala3(version)) Scala3CompilerID + else CompilerID + } + + def libraryDependency(version: String): ModuleID = libraryDependency(Organization, version) + + def libraryDependency(org: String, version: String): ModuleID = { + if (isScala3(version)) + ModuleID(org, Scala3LibraryID, version).withCrossVersion(CrossVersion.binary) + else + ModuleID(org, LibraryID, version) + } + + private[sbt] def docToolDependencies( + org: String, + version: String + ): Seq[ModuleID] = + if (isScala3M123(version)) + Seq( + ModuleID(org, Scala3DocID, version) + .withConfigurations(Some(Configurations.ScalaDocTool.name + "->default(compile)")) + .withCrossVersion(CrossVersion.binary) + ) + else if (isScala3(version)) + Seq( + ModuleID(org, ScaladocID, version) + .withConfigurations(Some(Configurations.ScalaDocTool.name + "->default(compile)")) + .withCrossVersion(CrossVersion.binary) + ) + else Seq.empty private[sbt] def toolDependencies( org: String, - version: String, - isDotty: Boolean = false + version: String ): Seq[ModuleID] = - if (isDotty) + if (isScala3(version)) Seq( - ModuleID(org, DottyIDPrefix, version) + ModuleID(org, Scala3CompilerID, version) .withConfigurations(Some(Configurations.ScalaTool.name + "->default(compile)")) .withCrossVersion(CrossVersion.binary) ) else Seq( - scalaToolDependency(org, ScalaArtifacts.CompilerID, version), - scalaToolDependency(org, ScalaArtifacts.LibraryID, version) + scala2ToolDependency(org, CompilerID, version), + scala2ToolDependency(org, LibraryID, version) ) - private[this] def scalaToolDependency(org: String, id: String, version: String): ModuleID = + private[this] def scala2ToolDependency(org: String, id: String, version: String): ModuleID = ModuleID(org, id, version).withConfigurations( Some(Configurations.ScalaTool.name + "->default,optional(default)") ) diff --git a/core/src/main/scala/sbt/librarymanagement/UnresolvedWarning.scala b/core/src/main/scala/sbt/librarymanagement/UnresolvedWarning.scala index 99017ba8..6f4aa832 100644 --- a/core/src/main/scala/sbt/librarymanagement/UnresolvedWarning.scala +++ b/core/src/main/scala/sbt/librarymanagement/UnresolvedWarning.scala @@ -10,9 +10,13 @@ final class ResolveException( val failedPaths: Map[ModuleID, Seq[ModuleID]] ) extends RuntimeException(messages.mkString("\n")) { def this(messages: Seq[String], failed: Seq[ModuleID]) = - this(messages, failed, Map(failed map { m => - m -> Nil - }: _*)) + this( + messages, + failed, + Map(failed map { m => + m -> Nil + }: _*) + ) } /** @@ -30,15 +34,14 @@ object UnresolvedWarning { config: UnresolvedWarningConfiguration ): UnresolvedWarning = { def modulePosition(m0: ModuleID): Option[SourcePosition] = - config.modulePositions.find { - case (m, _) => - (m.organization == m0.organization) && - (m0.name startsWith m.name) && - (m.revision == m0.revision) - } map { - case (_, p) => p + config.modulePositions.find { case (m, _) => + (m.organization == m0.organization) && + (m0.name startsWith m.name) && + (m.revision == m0.revision) + } map { case (_, p) => + p } - val failedPaths = err.failed map { x: ModuleID => + val failedPaths = err.failed map { (x: ModuleID) => err.failedPaths(x).toList.reverse map { id => (id, modulePosition(id)) } @@ -67,9 +70,8 @@ object UnresolvedWarning { if (path.nonEmpty) { val head = path.head buffer += "\t\t" + head._1.toString + sourcePosStr(head._2) - path.tail foreach { - case (m, pos) => - buffer += "\t\t +- " + m.toString + sourcePosStr(pos) + path.tail foreach { case (m, pos) => + buffer += "\t\t +- " + m.toString + sourcePosStr(pos) } } } diff --git a/core/src/main/scala/sbt/librarymanagement/UpdateReportExtra.scala b/core/src/main/scala/sbt/librarymanagement/UpdateReportExtra.scala index 1ffba500..91082770 100644 --- a/core/src/main/scala/sbt/librarymanagement/UpdateReportExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/UpdateReportExtra.scala @@ -29,9 +29,13 @@ private[librarymanagement] abstract class ConfigurationReportExtra { } def retrieve(f: (ConfigRef, ModuleID, Artifact, File) => File): ConfigurationReport = - ConfigurationReport(configuration, modules map { - _.retrieve((mid, art, file) => f(configuration, mid, art, file)) - }, details) + ConfigurationReport( + configuration, + modules map { + _.retrieve((mid, art, file) => f(configuration, mid, art, file)) + }, + details + ) } private[librarymanagement] abstract class ModuleReportExtra { @@ -124,24 +128,23 @@ private[librarymanagement] abstract class UpdateReportExtra { /** All resolved modules in all configurations. */ def allModules: Vector[ModuleID] = { val key = (m: ModuleID) => (m.organization, m.name, m.revision) - configurations.flatMap(_.allModules).groupBy(key).toVector map { - case (_, v) => - v reduceLeft { (agg, x) => - agg.withConfigurations( - (agg.configurations, x.configurations) match { - case (None, _) => x.configurations - case (Some(ac), None) => Some(ac) - case (Some(ac), Some(xc)) => Some(s"$ac;$xc") - } - ) - } + configurations.flatMap(_.allModules).groupBy(key).toVector map { case (_, v) => + v reduceLeft { (agg, x) => + agg.withConfigurations( + (agg.configurations, x.configurations) match { + case (None, _) => x.configurations + case (Some(ac), None) => Some(ac) + case (Some(ac), Some(xc)) => Some(s"$ac;$xc") + } + ) + } } } def retrieve(f: (ConfigRef, ModuleID, Artifact, File) => File): UpdateReport = UpdateReport(cachedDescriptor, configurations map { _ retrieve f }, stats, stamps) - /** Gets the report for the given configuration, or `None` if the configuration was not resolved.*/ + /** Gets the report for the given configuration, or `None` if the configuration was not resolved. */ def configuration(s: ConfigRef) = configurations.find(_.configuration == s) /** Gets the names of all resolved configurations. This `UpdateReport` contains one `ConfigurationReport` for each configuration in this list. */ diff --git a/core/src/main/scala/sbt/librarymanagement/VersionNumber.scala b/core/src/main/scala/sbt/librarymanagement/VersionNumber.scala index c8bef483..1da91342 100644 --- a/core/src/main/scala/sbt/librarymanagement/VersionNumber.scala +++ b/core/src/main/scala/sbt/librarymanagement/VersionNumber.scala @@ -66,7 +66,7 @@ object VersionNumber { def splitDash(s: String) = splitOn(s, '-') def splitPlus(s: String) = splitOn(s, '+') map ("+" + _) - val TaggedVersion = """(\d{1,14})([\.\d{1,14}]*)((?:-\w+)*)((?:\+.+)*)""".r + val TaggedVersion = """(\d{1,14})([\.\d{1,14}]*)((?:-\w+(?:\.\w+)*)*)((?:\+.+)*)""".r val NonSpaceString = """(\S+)""".r s match { @@ -162,7 +162,8 @@ object VersionNumber { } } - /** A variant of SemVar that seems to be common among the Scala libraries. + /** + * A variant of SemVar that seems to be common among the Scala libraries. * The second segment (y in x.y.z) increments breaks the binary compatibility even when x > 0. * Also API compatibility is expected even when the first segment is zero. */ @@ -172,7 +173,8 @@ object VersionNumber { PackVer.isCompatible(v1, v2) } - /** A variant of SemVar that seems to be common among the Scala libraries. + /** + * A variant of SemVar that seems to be common among the Scala libraries. * The second segment (y in x.y.z) increments breaks the binary compatibility even when x > 0. * Also API compatibility is expected even when the first segment is zero. */ @@ -193,7 +195,8 @@ object VersionNumber { } } - /** A variant of SemVar that enforces API compatibility when the first segment is zero. + /** + * A variant of SemVar that enforces API compatibility when the first segment is zero. */ object EarlySemVer extends VersionNumberCompatibility { import SemVer._ diff --git a/core/src/test/scala/ConfigMacroSpec.scala b/core/src/test/scala/ConfigMacroSpec.scala index c35ab104..ea409efa 100644 --- a/core/src/test/scala/ConfigMacroSpec.scala +++ b/core/src/test/scala/ConfigMacroSpec.scala @@ -56,6 +56,6 @@ object ConfigMacroSpec extends Properties("ConfigMacroSpec") { s"Actual isPublic: ${c.isPublic}" |: (c.id == id) && (c.name == name) && - (c.isPublic == isPublic) + (c.isPublic == isPublic) } } diff --git a/core/src/test/scala/UpdateReportSpec.scala b/core/src/test/scala/UpdateReportSpec.scala index 12d7e70c..d12d7658 100644 --- a/core/src/test/scala/UpdateReportSpec.scala +++ b/core/src/test/scala/UpdateReportSpec.scala @@ -2,9 +2,10 @@ package sbt.librarymanagement import java.io.File -import org.scalatest._ +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers -class UpdateReportSpec extends FlatSpec with Matchers { +class UpdateReportSpec extends AnyFlatSpec with Matchers { "UpdateReport.toString" should "have a nice toString" in { assert(updateReport.toString === s""" |Update report: diff --git a/core/src/test/scala/example/tests/CrossVersionCompatTest.scala b/core/src/test/scala/example/tests/CrossVersionCompatTest.scala index 8aa136e8..ab5f4763 100644 --- a/core/src/test/scala/example/tests/CrossVersionCompatTest.scala +++ b/core/src/test/scala/example/tests/CrossVersionCompatTest.scala @@ -2,9 +2,9 @@ package example.tests import sbt.librarymanagement.{ CrossVersion, Disabled } import verify.BasicTestSuite -import com.github.ghik.silencer.silent +import scala.annotation.nowarn -@silent +@nowarn object CrossVersionCompatTest extends BasicTestSuite { test("CrossVersion.Disabled is typed to be Disabled") { assert(CrossVersion.Disabled match { diff --git a/core/src/test/scala/sbt/internal/librarymanagement/UnitSpec.scala b/core/src/test/scala/sbt/internal/librarymanagement/UnitSpec.scala index 238e018e..c656812d 100644 --- a/core/src/test/scala/sbt/internal/librarymanagement/UnitSpec.scala +++ b/core/src/test/scala/sbt/internal/librarymanagement/UnitSpec.scala @@ -2,6 +2,7 @@ package sbt package internal package librarymanagement -import org.scalatest._ +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers -abstract class UnitSpec extends FlatSpec with Matchers +abstract class UnitSpec extends AnyFlatSpec with Matchers diff --git a/core/src/test/scala/sbt/librarymanagement/ConfigMacroTest.scala b/core/src/test/scala/sbt/librarymanagement/ConfigMacroTest.scala index 85d798a2..1bb5d7a1 100644 --- a/core/src/test/scala/sbt/librarymanagement/ConfigMacroTest.scala +++ b/core/src/test/scala/sbt/librarymanagement/ConfigMacroTest.scala @@ -1,9 +1,10 @@ package sbt.librarymanagement import sbt.librarymanagement.Configurations.config -import org.scalatest._ +import org.scalatest.funspec.AnyFunSpec +import org.scalatest.matchers.should.Matchers -class ConfigMacroTest extends FunSpec with Matchers { +class ConfigMacroTest extends AnyFunSpec with Matchers { describe("Configurations.config") { it("should validate the ID in compile time") { """val A = config("a")""" should compile diff --git a/core/src/test/scala/sbt/librarymanagement/CrossVersionTest.scala b/core/src/test/scala/sbt/librarymanagement/CrossVersionTest.scala index 5ba8d8b7..96b3d164 100644 --- a/core/src/test/scala/sbt/librarymanagement/CrossVersionTest.scala +++ b/core/src/test/scala/sbt/librarymanagement/CrossVersionTest.scala @@ -138,6 +138,9 @@ class CrossVersionTest extends UnitSpec { it should "for 1.3.0-SNAPSHOT return 1.0" in { binarySbtVersion("1.3.0-SNAPSHOT") shouldBe "1.0" } + it should "for 1.3.0-A1-B1.1 return 1.0" in { + binarySbtVersion("1.3.0-A1-B1.1") shouldBe "1.0" + } it should "for 1.10.0 return 1.0" in { binarySbtVersion("1.10.0") shouldBe "1.0" } @@ -207,8 +210,53 @@ class CrossVersionTest extends UnitSpec { it should "for 2.20170314093845.0-87654321 return 2.20170314093845" in { binaryScalaVersion("2.20170314093845.0-87654321") shouldBe "2.20170314093845" } - it should "for Dotty 0.1.1 return 0.1" in { - binaryScalaVersion("0.1.1") shouldBe "0.1" + it should "for 3.0.0-M2 return 3.0.0-M2" in { + binaryScalaVersion("3.0.0-M2") shouldBe "3.0.0-M2" + } + it should "for 3.0.0-M3-bin-SNAPSHOT return 3.0.0-M3" in { + binaryScalaVersion("3.0.0-M3-bin-SNAPSHOT") shouldBe "3.0.0-M3" + } + it should "for 3.0.0-M3-bin-20201215-cbe50b3-NIGHTLY return 3.0.0-M3" in { + binaryScalaVersion("3.0.0-M3-bin-20201215-cbe50b3-NIGHTLY") shouldBe "3.0.0-M3" + } + it should "for 3.0.0-M3.5-bin-20201215-cbe50b3-NIGHTLY return 3.0.0-M3" in { + binaryScalaVersion("3.0.0-M3.5-bin-20201215-cbe50b3-NIGHTLY") shouldBe "3.0.0-M3.5" + } + it should "for 3.0.0-RC1 return 3.0.0-RC1" in { + binaryScalaVersion("3.0.0-RC1") shouldBe "3.0.0-RC1" + } + + // Not set in stone but 3 is the favorite candidate so far + // (see https://github.com/lampepfl/dotty/issues/10244) + it should "for 3.0.0 return 3" in { + binaryScalaVersion("3.0.0") shouldBe "3" + } + it should "for 3.1.0-M1 return 3" in { + binaryScalaVersion("3.1.0-M1") shouldBe "3" + } + it should "for 3.1.0-RC1-bin-SNAPSHOT return 3" in { + binaryScalaVersion("3.1.0-RC1-bin-SNAPSHOT") shouldBe "3" + } + it should "for 3.1.0-RC1 return 3" in { + binaryScalaVersion("3.1.0-RC1") shouldBe "3" + } + it should "for 3.1.0 return 3" in { + binaryScalaVersion("3.1.0") shouldBe "3" + } + it should "for 3.0.1-RC1 return 3" in { + binaryScalaVersion("3.0.1-RC1") shouldBe "3" + } + it should "for 3.0.1-M1 return 3" in { + binaryScalaVersion("3.0.1-M1") shouldBe "3" + } + it should "for 3.0.1-RC1-bin-SNAPSHOT return 3" in { + binaryScalaVersion("3.0.1-RC1-bin-SNAPSHOT") shouldBe "3" + } + it should "for 3.0.1-bin-nonbootstrapped return 3" in { + binaryScalaVersion("3.0.1-bin-SNAPSHOT") shouldBe "3" + } + it should "for 3.0.1-SNAPSHOT return 3" in { + binaryScalaVersion("3.0.1-SNAPSHOT") shouldBe "3" } private def patchVersion(fullVersion: String) = @@ -232,6 +280,58 @@ class CrossVersionTest extends UnitSpec { it should "for 2.11.8-RC1-bin-extra return 2.11.8-RC1" in { patchVersion("2.11.8-RC1-bin-extra") shouldBe Some("artefact_2.11.8-RC1") } + it should "for 2.11.8-X1.5-bin-extra return 2.11.8-X1.5" in { + patchVersion("2.11.8-X1.5-bin-extra") shouldBe Some("artefact_2.11.8-X1.5") + } + + "isScalaBinaryCompatibleWith" should "for (2.10.4, 2.10.5) return true" in { + isScalaBinaryCompatibleWith("2.10.4", "2.10.5") shouldBe true + } + it should "for (2.10.6, 2.10.5) return true" in { + isScalaBinaryCompatibleWith("2.10.6", "2.10.5") shouldBe true + } + it should "for (2.11.0, 2.10.5) return false" in { + isScalaBinaryCompatibleWith("2.11.0", "2.10.5") shouldBe false + } + it should "for (3.0.0, 2.10.5) return false" in { + isScalaBinaryCompatibleWith("3.0.0", "2.10.5") shouldBe false + } + it should "for (3.0.0, 3.1.0) return false" in { + isScalaBinaryCompatibleWith("3.0.0", "3.1.0") shouldBe false + } + it should "for (3.1.0, 3.0.0) return true" in { + isScalaBinaryCompatibleWith("3.1.0", "3.0.0") shouldBe true + } + it should "for (3.1.0, 3.1.1) return true" in { + isScalaBinaryCompatibleWith("3.1.0", "3.1.1") shouldBe true + } + it should "for (3.1.1, 3.1.0) return true" in { + isScalaBinaryCompatibleWith("3.1.1", "3.1.0") shouldBe true + } + it should "for (2.10.0-M1, 2.10.5) return false" in { + isScalaBinaryCompatibleWith("2.10.0-M1", "2.10.5") shouldBe false + } + it should "for (2.10.5, 2.10.0-M1) return false" in { + isScalaBinaryCompatibleWith("2.10.5", "2.10.0-M1") shouldBe false + } + it should "for (2.10.0-M1, 2.10.0-M2) return false" in { + isScalaBinaryCompatibleWith("2.10.0-M1", "2.10.0-M2") shouldBe false + } + it should "for (2.10.0-M1, 2.11.0-M1) return false" in { + isScalaBinaryCompatibleWith("2.10.0-M1", "2.11.0-M1") shouldBe false + } + it should "for (3.1.0-M1, 3.0.0) return true" in { + isScalaBinaryCompatibleWith("3.1.0-M1", "3.0.0") shouldBe true + } + it should "for (3.1.0-M1, 3.1.0) return false" in { + isScalaBinaryCompatibleWith("3.1.0-M1", "3.1.0") shouldBe false + } + it should "for (3.1.0-M1, 3.1.0-M2) return false" in { + isScalaBinaryCompatibleWith("3.1.0-M1", "3.1.0-M2") shouldBe false + } + it should "for (3.1.0-M2, 3.1.0-M1) return false" in { + isScalaBinaryCompatibleWith("3.1.0-M2", "3.1.0-M1") shouldBe false + } private def constantVersion(value: String) = CrossVersion(CrossVersion.constant(value), "dummy1", "dummy2") map (fn => fn("artefact")) @@ -252,4 +352,29 @@ class CrossVersionTest extends UnitSpec { "CrossVersion.constant" should "have structural equality" in { CrossVersion.constant("duck") shouldBe CrossVersion.constant("duck") } + + "CrossVersion.for3Use2_13" should "have structural equality" in { + CrossVersion.for3Use2_13 shouldBe CrossVersion.for3Use2_13 + CrossVersion.for3Use2_13With("_sjs1", "") shouldBe CrossVersion.for3Use2_13With("_sjs1", "") + } + it should "use the cross version 2.13 instead of 3" in { + CrossVersion(CrossVersion.for3Use2_13, "3.0.0", "3").map(_("artefact")) shouldBe Some( + "artefact_2.13" + ) + } + it should "use the cross version 2.13 instead of 3.0.0-M3" in { + CrossVersion(CrossVersion.for3Use2_13, "3.0.0-M3", "3.0.0-M3").map(_("artefact")) shouldBe Some( + "artefact_2.13" + ) + } + + "CrossVersion.for2_13Use3" should "have structural equality" in { + CrossVersion.for2_13Use3 shouldBe CrossVersion.for2_13Use3 + CrossVersion.for2_13Use3With("_sjs1", "") shouldBe CrossVersion.for2_13Use3With("_sjs1", "") + } + it should "use the cross version 3 instead of 2.13" in { + CrossVersion(CrossVersion.for2_13Use3, "2.13.4", "2.13").map(_("artefact")) shouldBe Some( + "artefact_3" + ) + } } diff --git a/core/src/test/scala/sbt/librarymanagement/ModuleIdTest.scala b/core/src/test/scala/sbt/librarymanagement/ModuleIdTest.scala index 1698f317..1c962aac 100644 --- a/core/src/test/scala/sbt/librarymanagement/ModuleIdTest.scala +++ b/core/src/test/scala/sbt/librarymanagement/ModuleIdTest.scala @@ -1,31 +1,49 @@ 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") +object ModuleIdTest extends verify.BasicTestSuite { + test("Module Id should return cross-disabled module id as equal to a copy") { + assert(ModuleID("com.acme", "foo", "1") == ModuleID("com.acme", "foo", "1")) } - it should "return cross-full module id as equal to a copy" in { - (ModuleID("com.acme", "foo", "1") cross CrossVersion.full) shouldBe - (ModuleID("com.acme", "foo", "1") cross CrossVersion.full) + + test("it should return cross-full module id as equal to a copy") { + assert( + ModuleID("com.acme", "foo", "1").cross(CrossVersion.full) == + ModuleID("com.acme", "foo", "1").cross(CrossVersion.full) + ) } - it should "return cross-binary module id as equal to a copy" in { - (ModuleID("com.acme", "foo", "1") cross CrossVersion.binary) shouldBe - (ModuleID("com.acme", "foo", "1") cross CrossVersion.binary) + + test("it should return cross-binary module id as equal to a copy") { + assert( + ModuleID("com.acme", "foo", "1").cross(CrossVersion.binary) == + ModuleID("com.acme", "foo", "1").cross(CrossVersion.binary) + ) } - it should "format itself into JSON" in { + + test("it should format itself into JSON") { import LibraryManagementCodec._ val json = Converter.toJson(ModuleID("com.acme", "foo", "1")).get assert(CompactPrinter(json) == expectedJson) } - it should "thaw back from JSON" in { + + test("it should thaw back from JSON") { import LibraryManagementCodec._ val json = Parser.parseUnsafe(expectedJson) val m = Converter.fromJsonUnsafe[ModuleID](json) assert(m == ModuleID("com.acme", "foo", "1")) } + + test("cross(...) should compose prefix with the existing value") { + assert( + ModuleID("com.acme", "foo", "1") + .cross(CrossVersion.binaryWith("sjs1_", "")) + .cross(CrossVersion.for3Use2_13) + == + ModuleID("com.acme", "foo", "1").cross(CrossVersion.for3Use2_13With("sjs1_", "")) + ) + } + + def expectedJson = + """{"organization":"com.acme","name":"foo","revision":"1","isChanging":false,"isTransitive":true,"isForce":false,"explicitArtifacts":[],"inclusions":[],"exclusions":[],"extraAttributes":{},"crossVersion":{"type":"Disabled"}}""" } diff --git a/core/src/test/scala/sbt/librarymanagement/ResolverExtraTest.scala b/core/src/test/scala/sbt/librarymanagement/ResolverExtraTest.scala new file mode 100644 index 00000000..10cad901 --- /dev/null +++ b/core/src/test/scala/sbt/librarymanagement/ResolverExtraTest.scala @@ -0,0 +1,43 @@ +package sbt.librarymanagement + +import verify.BasicTestSuite +import scala.annotation.nowarn + +@nowarn // Necessary because our test cases look like interpolated strings. +object ResolverExtraTest extends BasicTestSuite { + test("expandMavenSettings should expand existing environment variables") { + assertExpansion( + input = "User home: ${env.HOME}", + expected = s"User home: ${env("HOME")}" + ) + } + + test("expandMavenSettings should expand existing system properties") { + assertExpansion( + input = "User dir: ${user.dir}", + expected = s"User dir: ${prop("user.dir")}" + ) + } + + test("expandMavenSettings should expand unknown system properties to the empty string") { + assertExpansion( + input = "Unknown system property: ${IF_THIS_EXISTS_WE_NEED_TO_HAVE_A_CHAT}", + expected = s"Unknown system property: " + ) + } + + test("expandMavenSettings should expand unknown environment variables to the empty string") { + assertExpansion( + input = "Unknown environment variable: ${IF_THIS_EXISTS_I_WORRY_ABOUT_YOU}", + expected = s"Unknown environment variable: " + ) + } + + // - Helper functions ---------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------- + def assertExpansion(input: String, expected: String) = + assert(Resolver.expandMavenSettings(input) == s"$expected") + + def env(name: String) = sys.env.getOrElse(name, "") + def prop(name: String) = sys.props.getOrElse(name, "") +} diff --git a/core/src/test/scala/sbt/librarymanagement/ResolverTest.scala b/core/src/test/scala/sbt/librarymanagement/ResolverTest.scala index 70f7c19c..40016276 100644 --- a/core/src/test/scala/sbt/librarymanagement/ResolverTest.scala +++ b/core/src/test/scala/sbt/librarymanagement/ResolverTest.scala @@ -1,6 +1,6 @@ package sbt.librarymanagement -import java.net.URL +import java.net.URI import sbt.internal.librarymanagement.UnitSpec @@ -10,7 +10,7 @@ object ResolverTest extends UnitSpec { val pats = Vector("[orgPath]") val patsExpected = Vector("http://foo.com/test/[orgPath]") val patterns = Resolver - .url("test", new URL("http://foo.com/test"))( + .url("test", new URI("http://foo.com/test").toURL)( Patterns( pats, pats, diff --git a/core/src/test/scala/sbt/librarymanagement/SemanticSelectorSpec.scala b/core/src/test/scala/sbt/librarymanagement/SemanticSelectorSpec.scala index f7bf4f5b..cce9b4ff 100644 --- a/core/src/test/scala/sbt/librarymanagement/SemanticSelectorSpec.scala +++ b/core/src/test/scala/sbt/librarymanagement/SemanticSelectorSpec.scala @@ -1,8 +1,9 @@ package sbt.librarymanagement -import org.scalatest.{ FreeSpec, Matchers } +import org.scalatest.freespec.AnyFreeSpec +import org.scalatest.matchers.should.Matchers -class SemanticSelectorSpec extends FreeSpec with Matchers { +class SemanticSelectorSpec extends AnyFreeSpec with Matchers { semsel("<=1.2.3") { sel => assertMatches(sel, "1.2.3") assertMatches(sel, "1.2-beta") @@ -74,6 +75,7 @@ class SemanticSelectorSpec extends FreeSpec with Matchers { semsel(">=1.2.3") { sel => assertMatches(sel, "1.2.4-beta") + assertMatches(sel, "1.2.4-beta.1") assertMatches(sel, "1.2.3") assertMatches(sel, "1.3") assertMatches(sel, "2") @@ -305,6 +307,21 @@ class SemanticSelectorSpec extends FreeSpec with Matchers { assertNotMatches(sel, "1.2.2") } + semsel(">=1.2.3-beta.5") { sel => + assertMatches(sel, "1.3-alpha") + assertMatches(sel, "1.2.3") + assertMatches(sel, "1.2.3-beta.5") + assertMatches(sel, "1.2.3-beta.6-3") + assertMatches(sel, "1.2.3-beta.7") + assertMatches(sel, "1.2.3-beta.gamma") + assertMatches(sel, "1.2.4") + assertMatches(sel, "1.3") + assertNotMatches(sel, "1.2.3-alpha-3") + assertNotMatches(sel, "1.2.3-beta-1") + assertNotMatches(sel, "1.2.3-beta") + assertNotMatches(sel, "1.2.2") + } + Seq( // invalid operator "~1.2.3", @@ -338,7 +355,6 @@ class SemanticSelectorSpec extends FreeSpec with Matchers { "1.0.0 - 2.0.0 || - 2.0.0", "1.0.0- 2.0.0", "1.0.0 -2.0.0", - "1.0.0-2.0.0", "-", // minor and patch versions are required for pre-release version "1.2-alpha-beta", diff --git a/core/src/test/scala/sbt/librarymanagement/VersionNumberSpec.scala b/core/src/test/scala/sbt/librarymanagement/VersionNumberSpec.scala index 7a7038fb..bf3465cc 100644 --- a/core/src/test/scala/sbt/librarymanagement/VersionNumberSpec.scala +++ b/core/src/test/scala/sbt/librarymanagement/VersionNumberSpec.scala @@ -1,9 +1,11 @@ package sbt.librarymanagement -import org.scalatest.{ FreeSpec, Inside, Matchers } +import org.scalatest.Inside +import org.scalatest.freespec.AnyFreeSpec +import org.scalatest.matchers.should.Matchers // This is a specification to check VersionNumber and VersionNumberCompatibility. -class VersionNumberSpec extends FreeSpec with Matchers with Inside { +class VersionNumberSpec extends AnyFreeSpec with Matchers with Inside { import VersionNumber.{ EarlySemVer, SemVer, PackVer } version("1") { v => @@ -95,6 +97,13 @@ class VersionNumberSpec extends FreeSpec with Matchers with Inside { assertCascadesTo(v, Seq("0.1.0-MSERVER-1", "0.1.0", "0.1")) } + version("1.1.0-DLP-7923-presigned-download-url.5") { v => + assertParsesTo(v, Seq(1, 1, 0), Seq("DLP", "7923", "presigned", "download", "url.5"), Seq()) + assertCascadesTo(v, Seq("1.1.0-DLP-7923-presigned-download-url.5", "1.1.0", "1.1")) + assertIsCompatibleWith(v, "1.0.7", EarlySemVer) + assertIsNotCompatibleWith(v, "1.0.7", PackVer) + } + version("2.10.4-20140115-000117-b3a-sources") { v => assertParsesTo(v, Seq(2, 10, 4), Seq("20140115", "000117", "b3a", "sources"), Seq()) assertCascadesTo(v, Seq("2.10.4-20140115-000117-b3a-sources", "2.10.4", "2.10")) @@ -139,13 +148,12 @@ class VersionNumberSpec extends FreeSpec with Matchers with Inside { ts: Seq[String], es: Seq[String] ): Unit = - s"should parse to ($ns, $ts, $es)" in inside(v.value) { - case VersionNumber(ns1, ts1, es1) => - (ns1 shouldBe ns) - (ts1 shouldBe ts) - (es1 shouldBe es) - (VersionNumber(ns, ts, es).toString shouldBe v.value) - (VersionNumber(ns, ts, es) shouldBe VersionNumber(ns, ts, es)) + s"should parse to ($ns, $ts, $es)" in inside(v.value) { case VersionNumber(ns1, ts1, es1) => + (ns1 shouldBe ns) + (ts1 shouldBe ts) + (es1 shouldBe es) + (VersionNumber(ns, ts, es).toString shouldBe v.value) + (VersionNumber(ns, ts, es) shouldBe VersionNumber(ns, ts, es)) } private[this] def assertParsesToError(v: VersionString): Unit = diff --git a/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/ExternalIvyConfiguration.scala b/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/ExternalIvyConfiguration.scala index c5068c2a..d9905079 100644 --- a/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/ExternalIvyConfiguration.scala +++ b/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/ExternalIvyConfiguration.scala @@ -14,10 +14,10 @@ final class ExternalIvyConfiguration private ( private def this() = this(None, None, sbt.librarymanagement.ivy.UpdateOptions(), None, None, Vector()) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: ExternalIvyConfiguration => (this.lock == x.lock) && (this.log == x.log) && (this.updateOptions == x.updateOptions) && (this.baseDirectory == x.baseDirectory) && (this.uri == x.uri) && (this.extraResolvers == x.extraResolvers) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.ivy.ExternalIvyConfiguration".##) + lock.##) + log.##) + updateOptions.##) + baseDirectory.##) + uri.##) + extraResolvers.##) } diff --git a/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/InlineIvyConfiguration.scala b/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/InlineIvyConfiguration.scala index f528b84b..5455978f 100644 --- a/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/InlineIvyConfiguration.scala +++ b/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/InlineIvyConfiguration.scala @@ -18,10 +18,10 @@ final class InlineIvyConfiguration private ( private def this() = this(None, None, sbt.librarymanagement.ivy.UpdateOptions(), None, sbt.librarymanagement.Resolver.defaults, Vector.empty, Vector.empty, sbt.librarymanagement.ivy.IvyDefaults.defaultChecksums, false, None) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: InlineIvyConfiguration => (this.lock == x.lock) && (this.log == x.log) && (this.updateOptions == x.updateOptions) && (this.paths == x.paths) && (this.resolvers == x.resolvers) && (this.otherResolvers == x.otherResolvers) && (this.moduleConfigurations == x.moduleConfigurations) && (this.checksums == x.checksums) && (this.managedChecksums == x.managedChecksums) && (this.resolutionCacheDir == x.resolutionCacheDir) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.ivy.InlineIvyConfiguration".##) + lock.##) + log.##) + updateOptions.##) + paths.##) + resolvers.##) + otherResolvers.##) + moduleConfigurations.##) + checksums.##) + managedChecksums.##) + resolutionCacheDir.##) } diff --git a/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/IvyConfiguration.scala b/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/IvyConfiguration.scala index 8a1fd621..c515b374 100644 --- a/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/IvyConfiguration.scala +++ b/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/IvyConfiguration.scala @@ -12,10 +12,10 @@ abstract class IvyConfiguration( def this() = this(None, None, sbt.librarymanagement.ivy.UpdateOptions()) - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: IvyConfiguration => (this.lock == x.lock) && (this.log == x.log) && (this.updateOptions == x.updateOptions) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.ivy.IvyConfiguration".##) + lock.##) + log.##) + updateOptions.##) } diff --git a/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/IvyPaths.scala b/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/IvyPaths.scala index 866e5082..574369bb 100644 --- a/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/IvyPaths.scala +++ b/ivy/src/main/contraband-scala/sbt/librarymanagement/ivy/IvyPaths.scala @@ -10,10 +10,10 @@ final class IvyPaths private ( - override def equals(o: Any): Boolean = o match { + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { case x: IvyPaths => (this.baseDirectory == x.baseDirectory) && (this.ivyHome == x.ivyHome) case _ => false - } + }) override def hashCode: Int = { 37 * (37 * (37 * (17 + "sbt.librarymanagement.ivy.IvyPaths".##) + baseDirectory.##) + ivyHome.##) } diff --git a/ivy/src/main/java/internal/librarymanagement/JavaNetAuthenticator.java b/ivy/src/main/java/internal/librarymanagement/JavaNetAuthenticator.java deleted file mode 100644 index aa10461c..00000000 --- a/ivy/src/main/java/internal/librarymanagement/JavaNetAuthenticator.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2013 Square, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package sbt.internal.librarymanagement; - -import java.io.IOException; -import java.net.Authenticator.RequestorType; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.PasswordAuthentication; -import java.net.Proxy; -import java.util.List; -import okhttp3.Authenticator; -import okhttp3.Route; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.HttpUrl; -import okhttp3.Challenge; -import okhttp3.Credentials; - -/** - * Adapts java.net.Authenticator to Authenticator. Configure OkHttp to use - * java.net.Authenticator with OkHttpClient.Builder#authenticator or - * OkHttpClient.Builder#proxyAuthenticator(Authenticator). - */ -public final class JavaNetAuthenticator implements Authenticator { - @Override public Request authenticate(Route route, Response response) throws IOException { - List challenges = response.challenges(); - Request request = response.request(); - HttpUrl url = request.url(); - boolean proxyAuthorization = response.code() == 407; - Proxy proxy = null; - if (route != null) { - proxy = route.proxy(); - } - - for (int i = 0, size = challenges.size(); i < size; i++) { - Challenge challenge = challenges.get(i); - if (!"Basic".equalsIgnoreCase(challenge.scheme())) continue; - - PasswordAuthentication auth; - if (proxyAuthorization) { - InetSocketAddress proxyAddress = (InetSocketAddress) proxy.address(); - auth = java.net.Authenticator.requestPasswordAuthentication( - proxyAddress.getHostName(), getConnectToInetAddress(proxy, url), proxyAddress.getPort(), - url.scheme(), challenge.realm(), challenge.scheme(), url.url(), - RequestorType.PROXY); - } else { - auth = java.net.Authenticator.requestPasswordAuthentication( - url.host(), getConnectToInetAddress(proxy, url), url.port(), url.scheme(), - challenge.realm(), challenge.scheme(), url.url(), RequestorType.SERVER); - } - - if (auth != null) { - String credential = Credentials.basic(auth.getUserName(), new String(auth.getPassword())); - return request.newBuilder() - .header(proxyAuthorization ? "Proxy-Authorization" : "Authorization", credential) - .build(); - } - } - - return null; // No challenges were satisfied! - } - - private InetAddress getConnectToInetAddress(Proxy proxy, HttpUrl url) throws IOException { - return (proxy != null && proxy.type() != Proxy.Type.DIRECT) - ? ((InetSocketAddress) proxy.address()).getAddress() - : InetAddress.getByName(url.host()); - } -} diff --git a/ivy/src/main/scala/org/apache/ivy/plugins/parser/m2/ReplaceMavenConfigurationMappings.scala b/ivy/src/main/scala/org/apache/ivy/plugins/parser/m2/ReplaceMavenConfigurationMappings.scala index 410bdcfb..fb0b889d 100644 --- a/ivy/src/main/scala/org/apache/ivy/plugins/parser/m2/ReplaceMavenConfigurationMappings.scala +++ b/ivy/src/main/scala/org/apache/ivy/plugins/parser/m2/ReplaceMavenConfigurationMappings.scala @@ -21,8 +21,6 @@ import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; * * Also see: http://ant.apache.org/ivy/history/2.3.0/ivyfile/dependency.html * and: http://svn.apache.org/repos/asf/ant/ivy/core/tags/2.3.0/src/java/org/apache/ivy/plugins/parser/m2/PomModuleDescriptorBuilder.java - * - * */ object ReplaceMavenConfigurationMappings { diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/ComponentManager.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/ComponentManager.scala index ed42cd14..710c120d 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ComponentManager.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/ComponentManager.scala @@ -56,7 +56,7 @@ class ComponentManager( /** This is used to lock the local cache in project/boot/. By checking the local cache first, we can avoid grabbing a global lock. */ private def lockLocalCache[T](action: => T): T = lock(provider.lockFile)(action) - /** This is used to ensure atomic access to components in the global Ivy cache.*/ + /** This is used to ensure atomic access to components in the global Ivy cache. */ private def lockGlobalCache[T](action: => T): T = lock(ivyCache.lockFile)(action) private def lock[T](file: File)(action: => T): T = globalLock(file, new Callable[T] { def call = action }) diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala index e158c09d..1bd0d7aa 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala @@ -3,7 +3,7 @@ */ package sbt.internal.librarymanagement -import java.net.URL +import java.net.URI import java.util.Collections import org.apache.ivy.core.module.descriptor.DependencyDescriptor @@ -27,10 +27,16 @@ import org.apache.ivy.plugins.resolver.{ import org.apache.ivy.plugins.repository.url.{ URLRepository => URLRepo } import org.apache.ivy.plugins.repository.file.{ FileResource, FileRepository => FileRepo } import java.io.{ File, IOException } +import java.util.Date -import org.apache.ivy.util.{ ChecksumHelper, FileUtil, Message } import org.apache.ivy.core.module.descriptor.{ Artifact => IArtifact } +import org.apache.ivy.core.module.id.ModuleRevisionId +import org.apache.ivy.core.module.descriptor.DefaultArtifact import org.apache.ivy.core.report.DownloadReport +import org.apache.ivy.plugins.resolver.util.{ ResolvedResource, ResourceMDParser } +import org.apache.ivy.util.{ ChecksumHelper, FileUtil, Message } +import scala.collection.JavaConverters._ +import sbt.internal.librarymanagement.mavenint.PomExtraDependencyAttributes import sbt.io.IO import sbt.util.Logger import sbt.librarymanagement._ @@ -151,83 +157,115 @@ private[sbt] object ConvertResolver { (updateOptions.resolverConverter orElse defaultConvert)((r, settings, log)) /** The default implementation of converter. */ - lazy val defaultConvert: ResolverConverter = { - case (r, settings, log) => - val managedChecksums = Option(settings.getVariable(ManagedChecksums)) match { - case Some(x) => x.toBoolean - case _ => false - } - r match { - case repo: MavenRepository => { - val pattern = Collections.singletonList( - Resolver.resolvePattern(repo.root, Resolver.mavenStyleBasePattern) - ) - final class PluginCapableResolver - extends IBiblioResolver - with ChecksumFriendlyURLResolver - with DescriptorRequired { - override val managedChecksumsEnabled: Boolean = managedChecksums - override def getResource(resource: Resource, dest: File): Long = get(resource, dest) - def setPatterns(): Unit = { - // done this way for access to protected methods. - setArtifactPatterns(pattern) - setIvyPatterns(pattern) - } + lazy val defaultConvert: ResolverConverter = { case (r, settings, log) => + val managedChecksums = Option(settings.getVariable(ManagedChecksums)) match { + case Some(x) => x.toBoolean + case _ => false + } + r match { + case repo: MavenRepository => { + val pattern = Collections.singletonList( + Resolver.resolvePattern(repo.root, Resolver.mavenStyleBasePattern) + ) + final class PluginCapableResolver + extends IBiblioResolver + with ChecksumFriendlyURLResolver + with DescriptorRequired { + override val managedChecksumsEnabled: Boolean = managedChecksums + override def getResource(resource: Resource, dest: File): Long = get(resource, dest) + def setPatterns(): Unit = { + // done this way for access to protected methods. + setArtifactPatterns(pattern) + setIvyPatterns(pattern) } - val resolver = new PluginCapableResolver - if (repo.localIfFile) resolver.setRepository(new LocalIfFileRepo) - initializeMavenStyle(resolver, repo.name, repo.root) - resolver - .setPatterns() // has to be done after initializeMavenStyle, which calls methods that overwrite the patterns - resolver - } - case repo: SshRepository => { - val resolver = new SshResolver with DescriptorRequired with ThreadSafeSshBasedResolver { - override val managedChecksumsEnabled: Boolean = managedChecksums - override def getResource(resource: Resource, dest: File): Long = get(resource, dest) + override protected def findResourceUsingPattern( + mrid: ModuleRevisionId, + pattern: String, + artifact: IArtifact, + rmdparser: ResourceMDParser, + date: Date + ): ResolvedResource = { + val extraAttributes = + mrid.getExtraAttributes.asScala.toMap.asInstanceOf[Map[String, String]] + getSbtPluginCrossVersion(extraAttributes) match { + case Some(sbtCrossVersion) => + // if the module is an sbt plugin + // we first try to resolve the artifact with the sbt cross version suffix + // and we fallback to the one without the suffix + val newArtifact = DefaultArtifact.cloneWithAnotherName( + artifact, + artifact.getName + sbtCrossVersion + ) + val resolved = + super.findResourceUsingPattern(mrid, pattern, newArtifact, rmdparser, date) + if (resolved != null) resolved + else super.findResourceUsingPattern(mrid, pattern, artifact, rmdparser, date) + case None => + super.findResourceUsingPattern(mrid, pattern, artifact, rmdparser, date) + } } - initializeSSHResolver(resolver, repo, settings) - repo.publishPermissions.foreach(perm => resolver.setPublishPermissions(perm)) - resolver } - case repo: SftpRepository => { - val resolver = new SFTPResolver with ThreadSafeSshBasedResolver - initializeSSHResolver(resolver, repo, settings) - resolver + val resolver = new PluginCapableResolver + if (repo.localIfFile) resolver.setRepository(new LocalIfFileRepo) + initializeMavenStyle(resolver, repo.name, repo.root) + resolver + .setPatterns() // has to be done after initializeMavenStyle, which calls methods that overwrite the patterns + resolver + } + case repo: SshRepository => { + val resolver = new SshResolver with DescriptorRequired with ThreadSafeSshBasedResolver { + override val managedChecksumsEnabled: Boolean = managedChecksums + override def getResource(resource: Resource, dest: File): Long = get(resource, dest) } - case repo: FileRepository => { - val resolver = new FileSystemResolver with DescriptorRequired { - // Workaround for #1156 - // Temporarily in sbt 0.13.x we deprecate overwriting - // in local files for non-changing revisions. - // This will be fully enforced in sbt 1.0. - setRepository(new WarnOnOverwriteFileRepo()) - override val managedChecksumsEnabled: Boolean = managedChecksums - override def getResource(resource: Resource, dest: File): Long = get(resource, dest) - } - resolver.setName(repo.name) - initializePatterns(resolver, repo.patterns, settings) - import repo.configuration.{ isLocal, isTransactional } - resolver.setLocal(isLocal) - isTransactional.foreach(value => resolver.setTransactional(value.toString)) - resolver + initializeSSHResolver(resolver, repo, settings) + repo.publishPermissions.foreach(perm => resolver.setPublishPermissions(perm)) + resolver + } + case repo: SftpRepository => { + val resolver = new SFTPResolver with ThreadSafeSshBasedResolver + initializeSSHResolver(resolver, repo, settings) + resolver + } + case repo: FileRepository => { + val resolver = new FileSystemResolver with DescriptorRequired { + // Workaround for #1156 + // Temporarily in sbt 0.13.x we deprecate overwriting + // in local files for non-changing revisions. + // This will be fully enforced in sbt 1.0. + setRepository(new WarnOnOverwriteFileRepo()) + override val managedChecksumsEnabled: Boolean = managedChecksums + override def getResource(resource: Resource, dest: File): Long = get(resource, dest) } - case repo: URLRepository => { - val resolver = new URLResolver with ChecksumFriendlyURLResolver with DescriptorRequired { - override val managedChecksumsEnabled: Boolean = managedChecksums - override def getResource(resource: Resource, dest: File): Long = get(resource, dest) - } - resolver.setName(repo.name) - initializePatterns(resolver, repo.patterns, settings) - resolver + resolver.setName(repo.name) + initializePatterns(resolver, repo.patterns, settings) + import repo.configuration.{ isLocal, isTransactional } + resolver.setLocal(isLocal) + isTransactional.foreach(value => resolver.setTransactional(value.toString)) + resolver + } + case repo: URLRepository => { + val resolver = new URLResolver with ChecksumFriendlyURLResolver with DescriptorRequired { + override val managedChecksumsEnabled: Boolean = managedChecksums + override def getResource(resource: Resource, dest: File): Long = get(resource, dest) } - case repo: ChainedResolver => - IvySbt.resolverChain(repo.name, repo.resolvers, settings, log) - case repo: RawRepository => - repo.resolver match { - case r: DependencyResolver => r - } + resolver.setName(repo.name) + initializePatterns(resolver, repo.patterns, settings) + resolver } + case repo: ChainedResolver => + IvySbt.resolverChain(repo.name, repo.resolvers, settings, log) + case repo: RawRepository => + repo.resolver match { + case r: DependencyResolver => r + } + } + } + + private def getSbtPluginCrossVersion(extraAttributes: Map[String, String]): Option[String] = { + for { + sbtVersion <- extraAttributes.get(PomExtraDependencyAttributes.SbtVersionKey) + scalaVersion <- extraAttributes.get(PomExtraDependencyAttributes.ScalaVersionKey) + } yield s"_${scalaVersion}_$sbtVersion" } private sealed trait DescriptorRequired extends BasicResolver { @@ -290,8 +328,9 @@ private[sbt] object ConvertResolver { override def getDependency(dd: DependencyDescriptor, data: ResolveData) = { val prev = descriptorString(isAllownomd) setDescriptor(descriptorString(hasExplicitURL(dd))) - val t = try super.getDependency(dd, data) - finally setDescriptor(prev) + val t = + try super.getDependency(dd, data) + finally setDescriptor(prev) t } def descriptorString(optional: Boolean) = @@ -355,7 +394,7 @@ private[sbt] object ConvertResolver { private[this] val repo = new WarnOnOverwriteFileRepo() private[this] val progress = new RepositoryCopyProgressListener(this); override def getResource(source: String) = { - val url = new URL(source) + val url = new URI(source).toURL if (url.getProtocol == IO.FileScheme) new FileResource(repo, IO.toFile(url)) else @@ -363,7 +402,7 @@ private[sbt] object ConvertResolver { } override def put(source: File, destination: String, overwrite: Boolean): Unit = { - val url = new URL(destination) + val url = new URI(destination).toURL try { if (url.getProtocol != IO.FileScheme) super.put(source, destination, overwrite) else { @@ -403,7 +442,7 @@ private[sbt] object ConvertResolver { | publishConfiguration := publishConfiguration.value.withOverwrite(true) | publishLocalConfiguration := publishLocalConfiguration.value.withOverwrite(true) | - |If you have a remote cache respoitory, you can enable overwriting as follows: + |If you have a remote cache repository, you can enable overwriting as follows: | pushRemoteCacheConfiguration := pushRemoteCacheConfiguration.value.withOverwrite(true) |""".stripMargin, ex diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/CustomHttp.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/CustomHttp.scala deleted file mode 100644 index 9454affc..00000000 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/CustomHttp.scala +++ /dev/null @@ -1,21 +0,0 @@ -package sbt.internal.librarymanagement - -import gigahorse.HttpClient -import okhttp3.{ JavaNetAuthenticator => _, _ } -import sbt.librarymanagement.Http - -object CustomHttp { - private[this] def http0: HttpClient = Http.http - - private[sbt] def defaultHttpClientBuilder: OkHttpClient.Builder = { - http0 - .underlying[OkHttpClient] - .newBuilder() - .authenticator(new sbt.internal.librarymanagement.JavaNetAuthenticator) - .followRedirects(true) - .followSslRedirects(true) - } - - private[sbt] lazy val defaultHttpClient: OkHttpClient = - defaultHttpClientBuilder.build -} diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/CustomPomParser.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/CustomPomParser.scala index 591e3e88..eb937888 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/CustomPomParser.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/CustomPomParser.scala @@ -64,15 +64,42 @@ object CustomPomParser { // Evil hackery to override the default maven pom mappings. ReplaceMavenConfigurationMappings.init() - /** The key prefix that indicates that this is used only to store extra information and is not intended for dependency resolution.*/ + /** The key prefix that indicates that this is used only to store extra information and is not intended for dependency resolution. */ val InfoKeyPrefix = SbtPomExtraProperties.POM_INFO_KEY_PREFIX val ApiURLKey = SbtPomExtraProperties.POM_API_KEY + val VersionSchemeKey = SbtPomExtraProperties.VERSION_SCHEME_KEY val SbtVersionKey = PomExtraDependencyAttributes.SbtVersionKey val ScalaVersionKey = PomExtraDependencyAttributes.ScalaVersionKey val ExtraAttributesKey = PomExtraDependencyAttributes.ExtraAttributesKey private[this] val unqualifiedKeys = - Set(SbtVersionKey, ScalaVersionKey, ExtraAttributesKey, ApiURLKey) + Set(SbtVersionKey, ScalaVersionKey, ExtraAttributesKey, ApiURLKey, VersionSchemeKey) + + /** + * In the new POM format of sbt plugins, the dependency to an sbt plugin + * contains the sbt cross-version _2.12_1.0. The reason is we want Maven to be able + * to resolve the dependency using the pattern: + * /_2.12_1.0//_2.12_1.0-.pom + * In sbt 1.x we use extra-attributes to resolve sbt plugins, so here we must remove + * the sbt cross-version and keep the extra-attributes. + * Parsing a dependency found in the new POM format produces the same module as + * if it is found in the old POM format. It used not to contain the sbt cross-version + * suffix, but that was invalid. + * Hence we can resolve conflicts between new and old POM formats. + * + * To compare the two formats you can look at the POMs in: + * https://repo1.maven.org/maven2/ch/epfl/scala/sbt-plugin-example-diamond_2.12_1.0/0.5.0/ + */ + private def removeSbtCrossVersion( + properties: Map[String, String], + moduleName: String + ): String = { + val sbtCrossVersion = for { + sbtVersion <- properties.get(s"e:$SbtVersionKey") + scalaVersion <- properties.get(s"e:$ScalaVersionKey") + } yield s"_${scalaVersion}_$sbtVersion" + sbtCrossVersion.map(moduleName.stripSuffix).getOrElse(moduleName) + } // packagings that should be jars, but that Ivy doesn't handle as jars // TODO - move this elsewhere. @@ -108,7 +135,9 @@ object CustomPomParser { val MyHash = MakeTransformHash(md) // sbt 0.13.1 used "sbtTransformHash" instead of "e:sbtTransformHash" until #1192 so read both Option(extraInfo).isDefined && - ((Option(extraInfo get TransformedHashKey) orElse Option(extraInfo get oldTransformedHashKey)) match { + ((Option(extraInfo get TransformedHashKey) orElse Option( + extraInfo get oldTransformedHashKey + )) match { case Some(MyHash) => true case _ => false }) @@ -153,7 +182,7 @@ object CustomPomParser { (propertyAttributes - ExtraAttributesKey) map { case (k, v) => ("e:" + k, v) } private[this] def shouldBeUnqualified(m: Map[String, String]): Map[String, String] = - m.filterKeys(unqualifiedKeys) + m.filterKeys(unqualifiedKeys).toMap private[this] def addExtra( properties: Map[String, String], @@ -162,9 +191,12 @@ object CustomPomParser { import collection.JavaConverters._ val oldExtra = qualifiedExtra(id) val newExtra = (oldExtra ++ properties).asJava + // remove the sbt plugin cross version from the resolved ModuleRevisionId + // sbt-plugin-example_2.12_1.0 => sbt-plugin-example + val nameWithoutCrossVersion = removeSbtCrossVersion(properties, id.getName) ModuleRevisionId.newInstance( id.getOrganisation, - id.getName, + nameWithoutCrossVersion, id.getBranch, id.getRevision, newExtra @@ -181,7 +213,7 @@ object CustomPomParser { def filterCustomExtra(item: ExtendableItem, include: Boolean): Map[String, String] = (qualifiedExtra(item) filterKeys { k => qualifiedIsExtra(k) == include - }) + }).toMap def writeDependencyExtra(s: Seq[DependencyDescriptor]): Seq[String] = PomExtraDependencyAttributes.writeDependencyExtra(s) @@ -268,17 +300,23 @@ object CustomPomParser { for (l <- md.getLicenses) dmd.addLicense(l) for ((key, value) <- md.getExtraInfo.asInstanceOf[java.util.Map[String, String]].asScala) dmd.addExtraInfo(key, value) - dmd.addExtraInfo(TransformedHashKey, MakeTransformHash(md)) // mark as transformed by this version, so we don't need to do it again - for ((key, value) <- md.getExtraAttributesNamespaces - .asInstanceOf[java.util.Map[String, String]] - .asScala) dmd.addExtraAttributeNamespace(key, value) + dmd.addExtraInfo( + TransformedHashKey, + MakeTransformHash(md) + ) // mark as transformed by this version, so we don't need to do it again + for ( + (key, value) <- md.getExtraAttributesNamespaces + .asInstanceOf[java.util.Map[String, String]] + .asScala + ) dmd.addExtraAttributeNamespace(key, value) IvySbt.addExtraNamespace(dmd) val withExtra = md.getDependencies map { dd => addExtra(dd, dependencyExtra) } val withVersionRangeMod: Seq[DependencyDescriptor] = - if (LMSysProp.modifyVersionRange) 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/CustomXmlParser.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/CustomXmlParser.scala index 0498828b..a72a6533 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/CustomXmlParser.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/CustomXmlParser.scala @@ -15,7 +15,7 @@ import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser import org.apache.ivy.plugins.repository.Resource import org.apache.ivy.plugins.repository.url.URLResource -/** Subclasses the default Ivy file parser in order to provide access to protected methods.*/ +/** Subclasses the default Ivy file parser in order to provide access to protected methods. */ private[sbt] object CustomXmlParser extends XmlModuleDescriptorParser { import XmlModuleDescriptorParser.Parser class CustomParser(settings: IvySettings, defaultConfig: Option[String]) @@ -26,7 +26,7 @@ private[sbt] object CustomXmlParser extends XmlModuleDescriptorParser { } def setInput(bytes: Array[Byte]): Unit = setInput(new ByteArrayInputStream(bytes)) - /** Overridden because the super implementation overwrites the module descriptor.*/ + /** Overridden because the super implementation overwrites the module descriptor. */ override def setResource(res: Resource): Unit = () override def setMd(md: DefaultModuleDescriptor) = { super.setMd(md) diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/FakeResolver.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/FakeResolver.scala index 794fff9e..2d6ef89d 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/FakeResolver.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/FakeResolver.scala @@ -1,7 +1,7 @@ package sbt import java.io.File -import java.net.URL +import java.net.URI import org.apache.ivy.core.cache.ArtifactOrigin import org.apache.ivy.core.cache.{ DefaultRepositoryCacheManager, RepositoryCacheManager } @@ -69,7 +69,7 @@ private[sbt] class FakeResolver(private var name: String, cacheDir: File, module ): ArtifactDownloadReport = { val report = new ArtifactDownloadReport(artifact.getArtifact) - val path = new URL(artifact.getLocation).toURI.getPath + val path = new URI(artifact.getLocation).toURL.toURI.getPath val localFile = new File(path) if (path.nonEmpty && localFile.exists) { @@ -178,8 +178,8 @@ private[sbt] class FakeResolver(private var name: String, cacheDir: File, module val artifact = for { artifacts <- modules get ((moduleOrganisation, moduleName, moduleRevision)) - artifact <- artifacts find ( - a => a.name == art.getName && a.tpe == art.getType && a.ext == art.getExt + artifact <- artifacts find (a => + a.name == art.getName && a.tpe == art.getType && a.ext == art.getExt ) } yield new ArtifactOrigin(art, /* isLocal = */ true, artifact.file.toURI.toURL.toString) diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/Ivy.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/Ivy.scala index cc381573..4fbdbce4 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/Ivy.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/Ivy.scala @@ -7,7 +7,6 @@ import java.io.File import java.net.URI import java.util.concurrent.Callable -import okhttp3.OkHttpClient import org.apache.ivy.Ivy import org.apache.ivy.core.IvyPatternHelper import org.apache.ivy.core.cache.{ CacheMetadataOptions, DefaultRepositoryCacheManager } @@ -50,17 +49,13 @@ import ivyint.{ CachedResolutionResolveEngine, ParallelResolveEngine, SbtDefaultDependencyDescriptor, - GigahorseUrlHandler } import sjsonnew.JsonFormat import sjsonnew.support.murmurhash.Hasher final class IvySbt( val configuration: IvyConfiguration, - val http: OkHttpClient ) { self => - def this(configuration: IvyConfiguration) = this(configuration, CustomHttp.defaultHttpClient) - /* * ========== Configuration/Setup ============ * This part configures the Ivy instance by first creating the logger interface to ivy, then IvySettings, and then the Ivy instance. @@ -90,7 +85,6 @@ final class IvySbt( } private lazy val basicUrlHandler: URLHandler = new BasicURLHandler - private lazy val gigahorseUrlHandler: URLHandler = new GigahorseUrlHandler(http) private lazy val settings: IvySettings = { val dispatcher: URLHandlerDispatcher = URLHandlerRegistry.getDefault match { @@ -106,8 +100,8 @@ final class IvySbt( disp } - val urlHandler: URLHandler = - if (configuration.updateOptions.gigahorse) gigahorseUrlHandler else basicUrlHandler + // Ignore configuration.updateOptions.gigahorse due to sbt/sbt#6912 + val urlHandler: URLHandler = basicUrlHandler // Only set the urlHandler for the http/https protocols so we do not conflict with any other plugins // that might register other protocol handlers. @@ -141,7 +135,8 @@ final class IvySbt( is } - /** Defines a parallel [[CachedResolutionResolveEngine]]. + /** + * Defines a parallel [[CachedResolutionResolveEngine]]. * * This is defined here because it needs access to [[mkIvy]]. */ @@ -160,8 +155,10 @@ final class IvySbt( } } - /** Provides a default ivy implementation that decides which resolution - * engine to use depending on the passed ivy configuration options. */ + /** + * Provides a default ivy implementation that decides which resolution + * engine to use depending on the passed ivy configuration options. + */ private class IvyImplementation extends Ivy { private val loggerEngine = new SbtMessageLoggerEngine override def getLoggerEngine: SbtMessageLoggerEngine = loggerEngine @@ -201,7 +198,7 @@ final class IvySbt( // ========== End Configuration/Setup ============ - /** Uses the configured Ivy instance within a safe context.*/ + /** Uses the configured Ivy instance within a safe context. */ def withIvy[T](log: Logger)(f: Ivy => T): T = withIvy(new IvyLoggerInterface(log))(f) @@ -225,9 +222,28 @@ final class IvySbt( else IvySbt.cachedResolutionResolveCache.clean() } - final class Module(rawModuleSettings: ModuleSettings) + /** + * In the new POM format of sbt plugins, we append the sbt-cross version _2.12_1.0 to + * the module artifactId, and the artifactIds of its dependencies that are sbt plugins. + * + * The goal is to produce a valid Maven POM, a POM that Maven can resolve: + * Maven will try and succeed to resolve the POM of pattern: + * /_2.12_1.0//_2.12_1.0-.pom + */ + final class Module(rawModuleSettings: ModuleSettings, appendSbtCrossVersion: Boolean) extends sbt.librarymanagement.ModuleDescriptor { self => - val moduleSettings: ModuleSettings = IvySbt.substituteCross(rawModuleSettings) + + def this(rawModuleSettings: ModuleSettings) = + this(rawModuleSettings, appendSbtCrossVersion = false) + + val moduleSettings: ModuleSettings = + rawModuleSettings match { + case ic: InlineConfiguration => + val icWithCross = IvySbt.substituteCross(ic) + if (appendSbtCrossVersion) IvySbt.appendSbtCrossVersion(icWithCross) + else icWithCross + case m => m + } def directDependencies: Vector[ModuleID] = moduleSettings match { @@ -320,7 +336,7 @@ final class IvySbt( mod } - /** Parses the Maven pom 'pomFile' from the given `PomConfiguration`.*/ + /** Parses the Maven pom 'pomFile' from the given `PomConfiguration`. */ private def configurePom(pc: PomConfiguration) = { val md = CustomPomParser.default.parseDescriptor(settings, toURL(pc.file), pc.validate) val dmd = IvySbt.toDefaultModuleDescriptor(md) @@ -334,7 +350,7 @@ final class IvySbt( (dmd, defaultConf) } - /** Parses the Ivy file 'ivyFile' from the given `IvyFileConfiguration`.*/ + /** Parses the Ivy file 'ivyFile' from the given `IvyFileConfiguration`. */ private def configureIvyFile(ifc: IvyFileConfiguration) = { val parser = new CustomXmlParser.CustomParser(settings, None) parser.setValidate(ifc.validate) @@ -433,11 +449,11 @@ final class IvySbt( unionFormat2[IvyConfiguration, InlineIvyConfiguration, ExternalIvyConfiguration] object NullLogger extends sbt.internal.util.BasicLogger { - override def control(event: sbt.util.ControlEvent.Value, message: ⇒ String): Unit = () - override def log(level: Level.Value, message: ⇒ String): Unit = () + override def control(event: sbt.util.ControlEvent.Value, message: => String): Unit = () + override def log(level: Level.Value, message: => String): Unit = () override def logAll(events: Seq[sbt.util.LogEvent]): Unit = () - override def success(message: ⇒ String): Unit = () - override def trace(t: ⇒ Throwable): Unit = () + override def success(message: => String): Unit = () + override def trace(t: => Throwable): Unit = () } } @@ -690,7 +706,7 @@ private[sbt] object IvySbt { moduleID.addConflictManager(mid, matcher, manager) } - /** Converts the given sbt module id into an Ivy ModuleRevisionId.*/ + /** Converts the given sbt module id into an Ivy ModuleRevisionId. */ def toID(m: ModuleID) = { import m._ ModuleRevisionId.newInstance( @@ -702,32 +718,44 @@ private[sbt] object IvySbt { ) } - private def substituteCross(m: ModuleSettings): ModuleSettings = { - m.scalaModuleInfo match { - case None => m - case Some(is) => substituteCross(m, is.scalaFullVersion, is.scalaBinaryVersion) + private def substituteCross(ic: InlineConfiguration): InlineConfiguration = { + ic.scalaModuleInfo match { + case None => ic + case Some(is) => substituteCross(ic, is.scalaFullVersion, is.scalaBinaryVersion) } } private def substituteCross( - m: ModuleSettings, + ic: InlineConfiguration, scalaFullVersion: String, scalaBinaryVersion: String - ): ModuleSettings = { - m match { - case ic: InlineConfiguration => - val applyCross = CrossVersion(scalaFullVersion, scalaBinaryVersion) - def propagateCrossVersion(moduleID: ModuleID): ModuleID = { - val crossExclusions: Vector[ExclusionRule] = - moduleID.exclusions.map(CrossVersion.substituteCross(_, ic.scalaModuleInfo)) - applyCross(moduleID) - .withExclusions(crossExclusions) - } - ic.withModule(applyCross(ic.module)) - .withDependencies(ic.dependencies.map(propagateCrossVersion)) - .withOverrides(ic.overrides map applyCross) - case _ => m + ): InlineConfiguration = { + val applyCross = CrossVersion(scalaFullVersion, scalaBinaryVersion) + def propagateCrossVersion(moduleID: ModuleID): ModuleID = { + val crossExclusions: Vector[ExclusionRule] = + moduleID.exclusions.map(CrossVersion.substituteCross(_, ic.scalaModuleInfo)) + applyCross(moduleID) + .withExclusions(crossExclusions) } + ic.withModule(applyCross(ic.module)) + .withDependencies(ic.dependencies.map(propagateCrossVersion)) + .withOverrides(ic.overrides map applyCross) + } + + private def appendSbtCrossVersion(ic: InlineConfiguration): InlineConfiguration = + ic.withModule(appendSbtCrossVersion(ic.module)) + .withDependencies(ic.dependencies.map(appendSbtCrossVersion)) + .withOverrides(ic.overrides.map(appendSbtCrossVersion)) + + private def appendSbtCrossVersion(mid: ModuleID): ModuleID = { + val crossVersion = for { + scalaVersion <- mid.extraAttributes.get("e:scalaVersion") + sbtVersion <- mid.extraAttributes.get("e:sbtVersion") + } yield s"_${scalaVersion}_$sbtVersion" + crossVersion + .filter(!mid.name.endsWith(_)) + .map(cv => mid.withName(mid.name + cv)) + .getOrElse(mid) } private def toIvyArtifact( @@ -758,7 +786,8 @@ private[sbt] object IvySbt { } private[sbt] def javaMap(m: Map[String, String], unqualify: Boolean = false) = { import scala.collection.JavaConverters._ - val map = if (unqualify) m map { case (k, v) => (k.stripPrefix("e:"), v) } else m + val map = if (unqualify) m map { case (k, v) => (k.stripPrefix("e:"), v) } + else m if (map.isEmpty) null else map.asJava } @@ -789,8 +818,8 @@ private[sbt] object IvySbt { elem: scala.xml.Elem, extra: Map[String, String] ): scala.xml.Elem = - extra.foldLeft(elem) { - case (e, (key, value)) => e % new scala.xml.UnprefixedAttribute(key, value, scala.xml.Null) + extra.foldLeft(elem) { case (e, (key, value)) => + e % new scala.xml.UnprefixedAttribute(key, value, scala.xml.Null) } private def hasInfo(module: ModuleID, x: scala.xml.NodeSeq) = { val info = {x} \ "info" @@ -918,7 +947,7 @@ private[sbt] object IvySbt { } } - /** Transforms an sbt ModuleID into an Ivy DefaultDependencyDescriptor.*/ + /** Transforms an sbt ModuleID into an Ivy DefaultDependencyDescriptor. */ def convertDependency( moduleID: DefaultModuleDescriptor, dependency: ModuleID, @@ -936,7 +965,9 @@ private[sbt] object IvySbt { dependency.configurations match { case None => // The configuration for this dependency was not explicitly specified, so use the default parser.parseDepsConfs(parser.getDefaultConf, dependencyDescriptor) - case Some(confs) => // The configuration mapping (looks like: test->default) was specified for this dependency + case Some( + confs + ) => // The configuration mapping (looks like: test->default) was specified for this dependency parser.parseDepsConfs(confs, dependencyDescriptor) } for (artifact <- dependency.explicitArtifacts) { diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/IvyActions.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/IvyActions.scala index 09e8b1e6..42a0eed7 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/IvyActions.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/IvyActions.scala @@ -29,7 +29,7 @@ import sbt.internal.librarymanagement.IvyUtil.TransientNetworkException object IvyActions { - /** Installs the dependencies of the given 'module' from the resolver named 'from' to the resolver named 'to'.*/ + /** Installs the dependencies of the given 'module' from the resolver named 'from' to the resolver named 'to'. */ def install(module: IvySbt#Module, from: String, to: String, log: Logger): Unit = { module.withModule(log) { (ivy, md, _) => for (dependency <- md.getDependencies) { @@ -57,7 +57,7 @@ object IvyActions { module.owner.cleanCachedResolutionCache() } - /** Creates a Maven pom from the given Ivy configuration*/ + /** Creates a Maven pom from the given Ivy configuration */ def makePomFile(module: IvySbt#Module, configuration: MakePomConfiguration, log: Logger): File = { import configuration.{ allRepositories, @@ -91,13 +91,12 @@ object IvyActions { val deliverIvyPattern = configuration.deliverIvyPattern .getOrElse(sys.error("deliverIvyPattern must be specified.")) val status = getDeliverStatus(configuration.status) - module.withModule(log) { - case (ivy, md, _) => - val revID = md.getModuleRevisionId - val options = DeliverOptions.newInstance(ivy.getSettings).setStatus(status) - options.setConfs(getConfigurations(md, configuration.configurations)) - ivy.deliver(revID, revID.getRevision, deliverIvyPattern, options) - deliveredFile(ivy, deliverIvyPattern, md) + module.withModule(log) { case (ivy, md, _) => + val revID = md.getModuleRevisionId + val options = DeliverOptions.newInstance(ivy.getSettings).setStatus(status) + options.setConfs(getConfigurations(md, configuration.configurations)) + ivy.deliver(revID, revID.getRevision, deliverIvyPattern, options) + deliveredFile(ivy, deliverIvyPattern, md) } } @@ -130,18 +129,17 @@ object IvyActions { val artifacts = Map(configuration.artifacts: _*) val checksums = configuration.checksums - module.withModule(log) { - case (ivy, md, _) => - val resolver = ivy.getSettings.getResolver(resolverName) - if (resolver eq null) sys.error("Undefined resolver '" + resolverName + "'") - val ivyArtifact = ivyFile map { file => - (MDArtifact.newIvyArtifact(md), file) - } - val cross = crossVersionMap(module.moduleSettings) - val as = mapArtifacts(md, cross, artifacts) ++ ivyArtifact.toList - withChecksums(resolver, checksums) { - publish(md, as, resolver, overwrite = configuration.overwrite) - } + module.withModule(log) { case (ivy, md, _) => + val resolver = ivy.getSettings.getResolver(resolverName) + if (resolver eq null) sys.error("Undefined resolver '" + resolverName + "'") + val ivyArtifact = ivyFile map { file => + (MDArtifact.newIvyArtifact(md), file) + } + val cross = crossVersionMap(module.moduleSettings) + val as = mapArtifacts(md, cross, artifacts) ++ ivyArtifact.toList + withChecksums(resolver, checksums) { + publish(md, as, resolver, overwrite = configuration.overwrite) + } } } private[this] def withChecksums[T](resolver: DependencyResolver, checksums: Vector[String])( @@ -193,35 +191,36 @@ object IvyActions { uwconfig: UnresolvedWarningConfiguration, log: Logger ): Either[UnresolvedWarning, UpdateReport] = { - module.withModule(log) { - case (ivy, moduleDescriptor, _) => - // Warn about duplicated and inconsistent dependencies - val iw = IvySbt.inconsistentDuplicateWarning(moduleDescriptor) - iw.foreach(log.warn(_)) - - val metadataDirectory = configuration.metadataDirectory - - // Create inputs, resolve and retrieve the module descriptor - val inputs = ResolutionInputs(ivy, moduleDescriptor, configuration, log) - val resolutionResult: Either[ResolveException, UpdateReport] = { - if (module.owner.configuration.updateOptions.cachedResolution && metadataDirectory.isDefined) { - val cache = - metadataDirectory.getOrElse(sys.error("Missing directory for cached resolution.")) - cachedResolveAndRetrieve(inputs, cache) - } else resolveAndRetrieve(inputs) - } + module.withModule(log) { case (ivy, moduleDescriptor, _) => + // Warn about duplicated and inconsistent dependencies + val iw = IvySbt.inconsistentDuplicateWarning(moduleDescriptor) + iw.foreach(log.warn(_)) + + val metadataDirectory = configuration.metadataDirectory + + // Create inputs, resolve and retrieve the module descriptor + val inputs = ResolutionInputs(ivy, moduleDescriptor, configuration, log) + val resolutionResult: Either[ResolveException, UpdateReport] = { + if ( + module.owner.configuration.updateOptions.cachedResolution && metadataDirectory.isDefined + ) { + val cache = + metadataDirectory.getOrElse(sys.error("Missing directory for cached resolution.")) + cachedResolveAndRetrieve(inputs, cache) + } else resolveAndRetrieve(inputs) + } - // Convert to unresolved warning or retrieve update report - resolutionResult.fold( - exception => Left(UnresolvedWarning(exception, uwconfig)), - ur0 => { - val ur = configuration.retrieveManaged match { - case Some(retrieveConf) => retrieve(log, ivy, ur0, retrieveConf) - case _ => ur0 - } - Right(ur) + // Convert to unresolved warning or retrieve update report + resolutionResult.fold( + exception => Left(UnresolvedWarning(exception, uwconfig)), + ur0 => { + val ur = configuration.retrieveManaged match { + case Some(retrieveConf) => retrieve(log, ivy, ur0, retrieveConf) + case _ => ur0 } - ) + Right(ur) + } + ) } } @@ -237,7 +236,7 @@ object IvyActions { }.toMap def grouped[T](grouping: ModuleID => T)(mods: Seq[ModuleID]): Map[T, Set[String]] = - mods groupBy (grouping) mapValues (_.map(_.revision).toSet) + mods.groupBy(grouping).mapValues(_.map(_.revision).toSet).toMap def addExcluded( report: UpdateReport, @@ -252,11 +251,10 @@ object IvyActions { exclude.getOrElse(restrictedCopy(id, false), Set.empty[String]) def extractExcludes(report: UpdateReport): Map[ModuleID, Set[String]] = - report.allMissing flatMap { - case (_, mod, art) => - art.classifier.map { c => - (restrictedCopy(mod, false), c) - } + report.allMissing flatMap { case (_, mod, art) => + art.classifier.map { c => + (restrictedCopy(mod, false), c) + } } groupBy (_._1) map { case (mod, pairs) => (mod, pairs.map(_._2).toSet) } /** @@ -275,8 +273,8 @@ object IvyActions { ) implicit def toIvyFilter(f: ArtifactTypeFilter): IvyFilter = new IvyFilter { - override def accept(o: Object): Boolean = Option(o) exists { - case a: IArtifact => applyFilter(a) + override def accept(o: Object): Boolean = Option(o) exists { case a: IArtifact => + applyFilter(a) } def applyFilter(a: IArtifact): Boolean = @@ -396,7 +394,7 @@ object IvyActions { val toRetrieve: Option[Vector[ConfigRef]] = config.configurationsToRetrieve val base = getRetrieveDirectory(config.retrieveDirectory) val pattern = getRetrievePattern(config.outputPattern) - val existingFiles = PathFinder(base).allPaths.get filterNot { _.isDirectory } + val existingFiles = PathFinder(base).allPaths.get() filterNot { _.isDirectory } val toCopy = new collection.mutable.HashSet[(File, File)] val retReport = report retrieve { (conf: ConfigRef, mid, art, cached) => toRetrieve match { @@ -498,13 +496,12 @@ object IvyActions { checkFilesPresent(artifacts) try { resolver.beginPublishTransaction(module.getModuleRevisionId(), overwrite); - artifacts.foreach { - case (artifact, file) => - IvyUtil.retryWithBackoff( - resolver.publish(artifact, file, overwrite), - TransientNetworkException.apply, - maxAttempts = LMSysProp.maxPublishAttempts - ) + artifacts.foreach { case (artifact, file) => + IvyUtil.retryWithBackoff( + resolver.publish(artifact, file, overwrite), + TransientNetworkException.apply, + maxAttempts = LMSysProp.maxPublishAttempts + ) } resolver.commitPublishTransaction() } catch { diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/IvyCache.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/IvyCache.scala index 397f2e8d..756fb068 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/IvyCache.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/IvyCache.scala @@ -31,11 +31,11 @@ private object NotInCache { } } -/** Provides methods for working at the level of a single jar file with the default Ivy cache.*/ +/** Provides methods for working at the level of a single jar file with the default Ivy cache. */ class IvyCache(val ivyHome: Option[File]) { def lockFile = new File(ivyHome getOrElse Path.userHome, ".sbt.cache.lock") - /** Caches the given 'file' with the given ID. It may be retrieved or cleared using this ID.*/ + /** Caches the given 'file' with the given ID. It may be retrieved or cleared using this ID. */ def cacheJar( moduleID: ModuleID, file: File, @@ -52,7 +52,7 @@ class IvyCache(val ivyHome: Option[File]) { } } - /** Clears the cache of the jar for the given ID.*/ + /** Clears the cache of the jar for the given ID. */ def clearCachedJar(id: ModuleID, lock: Option[xsbti.GlobalLock], log: Logger): Unit = { try { withCachedJar(id, lock, log)(_.delete); () @@ -61,7 +61,7 @@ class IvyCache(val ivyHome: Option[File]) { } } - /** Copies the cached jar for the given ID to the directory 'toDirectory'. If the jar is not in the cache, NotInCache is thrown.*/ + /** Copies the cached jar for the given ID to the directory 'toDirectory'. If the jar is not in the cache, NotInCache is thrown. */ def retrieveCachedJar( id: ModuleID, toDirectory: File, @@ -74,7 +74,7 @@ class IvyCache(val ivyHome: Option[File]) { copyTo } - /** Get the location of the cached jar for the given ID in the Ivy cache. If the jar is not in the cache, NotInCache is thrown .*/ + /** Get the location of the cached jar for the given ID in the Ivy cache. If the jar is not in the cache, NotInCache is thrown . */ def withCachedJar[T](id: ModuleID, lock: Option[xsbti.GlobalLock], log: Logger)( f: File => T ): T = { @@ -89,7 +89,7 @@ class IvyCache(val ivyHome: Option[File]) { if (cachedFile.exists) f(cachedFile) else throw new NotInCache(id) } - /** Calls the given function with the default Ivy cache.*/ + /** Calls the given function with the default Ivy cache. */ def withDefaultCache[T](lock: Option[xsbti.GlobalLock], log: Logger)( f: DefaultRepositoryCacheManager => T ): T = { @@ -103,7 +103,7 @@ class IvyCache(val ivyHome: Option[File]) { } private def unknownOrigin(artifact: IvyArtifact) = ArtifactOrigin.unkwnown(artifact) - /** A minimal Ivy setup with only a local resolver and the current directory as the base directory.*/ + /** A minimal Ivy setup with only a local resolver and the current directory as the base directory. */ private def basicLocalIvy(lock: Option[xsbti.GlobalLock], log: Logger) = { val local = Resolver.defaultLocal val paths = IvyPaths(new File("."), ivyHome) @@ -112,15 +112,15 @@ class IvyCache(val ivyHome: Option[File]) { .withResolvers(Vector(local)) .withLock(lock) .withLog(log) - (new IvySbt(conf, CustomHttp.defaultHttpClient), local) + (new IvySbt(conf), local) } - /** Creates a default jar artifact based on the given ID.*/ + /** Creates a default jar artifact based on the given ID. */ private def defaultArtifact(moduleID: ModuleID): IvyArtifact = new DefaultArtifact(IvySbt.toID(moduleID), null, moduleID.name, "jar", "jar") } -/** Required by Ivy for copying to the cache.*/ +/** Required by Ivy for copying to the cache. */ private class FileDownloader extends ResourceDownloader { def download(artifact: IvyArtifact, resource: Resource, dest: File): Unit = { if (dest.exists()) dest.delete() diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/IvyLogger.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/IvyLogger.scala index 29f61222..dd041639 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/IvyLogger.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/IvyLogger.scala @@ -19,7 +19,7 @@ private[sbt] final class IvyLoggerInterface(logger: Logger) extends MessageLogge case MSG_ERR => error(msg) } } - //DEBUG level messages are very verbose and rarely useful to users. + // DEBUG level messages are very verbose and rarely useful to users. // TODO: provide access to this information some other way def debug(msg: String): Unit = () def verbose(msg: String): Unit = logger.verbose(msg) diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/IvyRetrieve.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/IvyRetrieve.scala index 67ebaa52..3e1d5f32 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/IvyRetrieve.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/IvyRetrieve.scala @@ -54,14 +54,18 @@ object IvyRetrieve { private[sbt] def organizationArtifactReports( confReport: ConfigurationResolveReport ): Vector[OrganizationArtifactReport] = { - val moduleIds = confReport.getModuleIds.toArray.toVector collect { - case mId: IvyModuleId => mId + val moduleIds = confReport.getModuleIds.toArray.toVector collect { case mId: IvyModuleId => + mId } def organizationArtifact(mid: IvyModuleId): OrganizationArtifactReport = { val deps = confReport.getNodes(mid).toArray.toVector collect { case node: IvyNode => node } - OrganizationArtifactReport(mid.getOrganisation, mid.getName, deps map { - moduleRevisionDetail(confReport, _) - }) + OrganizationArtifactReport( + mid.getOrganisation, + mid.getName, + deps map { + moduleRevisionDetail(confReport, _) + } + ) } moduleIds map { organizationArtifact } } @@ -141,9 +145,13 @@ object IvyRetrieve { val edOpt = Option(dep.getEvictedData(confReport.getConfiguration)) edOpt match { case Some(ed) => - (true, nonEmptyString(Option(ed.getConflictManager) map { _.toString } getOrElse { - "transitive" - }), nonEmptyString(ed.getDetail)) + ( + true, + nonEmptyString(Option(ed.getConflictManager) map { _.toString } getOrElse { + "transitive" + }), + nonEmptyString(ed.getDetail) + ) case None => (true, None, None) } case _ => (false, None, None) @@ -231,7 +239,7 @@ object IvyRetrieve { reports(report) map configurationReport, updateStats(report), Map.empty - ) recomputeStamps () + ).recomputeStamps() def updateStats(report: ResolveReport): UpdateStats = UpdateStats(report.getResolveTime, report.getDownloadTime, report.getDownloadSize, false) def configurationReport(confReport: ConfigurationResolveReport): ConfigurationReport = diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/IvyScalaUtil.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/IvyScalaUtil.scala index e318eb6c..bb270181 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/IvyScalaUtil.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/IvyScalaUtil.scala @@ -12,7 +12,7 @@ import org.apache.ivy.plugins.matcher.ExactPatternMatcher import org.apache.ivy.plugins.namespace.NamespaceTransformer import sbt.util.Logger import sbt.librarymanagement.ScalaArtifacts._ -import sbt.librarymanagement.{ ScalaModuleInfo, CrossVersion, Configuration } +import sbt.librarymanagement.{ Configuration, CrossVersion, ScalaModuleInfo } object IvyScalaUtil { @@ -48,38 +48,45 @@ object IvyScalaUtil { scalaVersionConfigs0: Vector[String] ) extends DependencyDescriptorMediator { private[this] val scalaVersionConfigs = scalaVersionConfigs0.toSet + private val binaryVersion = CrossVersion.binaryScalaVersion(scalaVersion) def mediate(dd: DependencyDescriptor): DependencyDescriptor = { // Mediate only for the dependencies in scalaVersion configurations. https://github.com/sbt/sbt/issues/2786 def configQualifies: Boolean = - (dd.getModuleConfigurations exists { scalaVersionConfigs }) + dd.getModuleConfigurations exists { scalaVersionConfigs } // Do not rewrite the dependencies of Scala dependencies themselves, this prevents bootstrapping // a Scala compiler using another Scala compiler. def dependeeQualifies: Boolean = - dd.getParentRevisionId == null || ( - dd.getParentRevisionId.getName match { - case _ @(CompilerID | LibraryID | ReflectID | ActorsID | ScalapID) => - false - case _ => - true - } - ) + dd.getParentRevisionId == null || + !isScala2Artifact(dd.getParentRevisionId.getName) || + !isScala3Artifact(dd.getParentRevisionId.getName) + + def matchBinaryVersion(version: String): Boolean = + CrossVersion.binaryScalaVersion(version) == binaryVersion + val transformer = new NamespaceTransformer { def transform(mrid: ModuleRevisionId): ModuleRevisionId = { if (mrid == null) mrid - else - mrid.getName match { - case name @ (CompilerID | LibraryID | ReflectID | ActorsID | ScalapID) - if configQualifies && dependeeQualifies => - ModuleRevisionId.newInstance( - scalaOrganization, - name, - mrid.getBranch, - scalaVersion, - mrid.getQualifiedExtraAttributes - ) - case _ => mrid - } + else if ( + (isScala2Artifact(mrid.getName) || isScala3Artifact(mrid.getName)) && + configQualifies && + dependeeQualifies + ) { + // do not override the binary incompatible Scala version because: + // - the artifacts compiled with Scala 3 depends on the Scala 2.13 scala-library + // - the Scala 2 TASTy reader can consume the Scala 3 artifacts + val newScalaVersion = + if (matchBinaryVersion(mrid.getRevision)) scalaVersion + else mrid.getRevision + + ModuleRevisionId.newInstance( + scalaOrganization, + mrid.getName, + mrid.getBranch, + newScalaVersion, + mrid.getQualifiedExtraAttributes + ) + } else mrid } def isIdentity: Boolean = false @@ -139,9 +146,16 @@ object IvyScalaUtil { val depBinaryVersion = CrossVersion.binaryScalaVersion(id.getRevision) def isScalaLangOrg = id.getOrganisation == scalaOrganization def isScalaArtifact = scalaArtifacts.contains[String](id.getName) - def hasBinVerMismatch = depBinaryVersion != scalaBinaryVersion + + def hasBinVerMismatch = + depBinaryVersion != scalaBinaryVersion && + // scala 2.13 is compatible with scala 3.x + !Seq(depBinaryVersion, scalaBinaryVersion) + .forall(bv => bv.startsWith("3") || bv.startsWith("2.13")) + def matchesOneOfTheConfigs = dep.getModuleConfigurations exists { scalaVersionConfigs } - val mismatched = isScalaLangOrg && isScalaArtifact && hasBinVerMismatch && matchesOneOfTheConfigs + val mismatched = + isScalaLangOrg && isScalaArtifact && hasBinVerMismatch && matchesOneOfTheConfigs if (mismatched) Some( "Binary version (" + depBinaryVersion + ") for dependency " + id + diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/IvyUtil.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/IvyUtil.scala index c3437b59..04b31ada 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/IvyUtil.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/IvyUtil.scala @@ -8,7 +8,7 @@ import scala.util.{ Failure, Success, Try } private[sbt] object IvyUtil { def separate[A, B](l: Seq[Either[A, B]]): (Seq[A], Seq[B]) = - (l.flatMap(_.left.toOption), l.flatMap(_.right.toOption)) + (l.flatMap(_.left.toOption), l.flatMap(_.toOption)) @tailrec final def retryWithBackoff[T]( diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/MakePom.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/MakePom.scala index 4f172ce9..a030a277 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/MakePom.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/MakePom.scala @@ -504,7 +504,7 @@ class MakePom(val log: Logger) { s.toArray.map(_.asInstanceOf[DependencyResolver]) def toID(name: String) = checkID(name.filter(isValidIDCharacter).mkString, name) - def isValidIDCharacter(c: Char) = c.isLetterOrDigit + def isValidIDCharacter(c: Char) = !"""\/:"<>|?*""".contains(c) private def checkID(id: String, name: String) = if (id.isEmpty) sys.error("Could not convert '" + name + "' to an ID") else id def mavenRepository(repo: MavenRepository): XNode = diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/ResolutionCache.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/ResolutionCache.scala index c6d3da44..5c381913 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ResolutionCache.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/ResolutionCache.scala @@ -102,5 +102,6 @@ private[sbt] object ResolutionCache { private val Name = "sbt-resolution-cache" // use sbt-specific extra attributes so that resolved xml files do not get overwritten when using different Scala/sbt versions - private val ResolvedPattern = "[organisation]/[module]/" + Resolver.PluginPattern + "([branch]/)[revision]/[artifact].[ext]" + private val ResolvedPattern = + "[organisation]/[module]/" + Resolver.PluginPattern + "([branch]/)[revision]/[artifact].[ext]" } diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/CachedResolutionResolveEngine.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/CachedResolutionResolveEngine.scala index d9cadfd8..7dc600e1 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/CachedResolutionResolveEngine.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/CachedResolutionResolveEngine.scala @@ -61,7 +61,7 @@ private[sbt] class CachedResolutionResolveCache { val maxConflictCacheSize: Int = 1024 val maxUpdateReportCacheSize: Int = 1024 - def clean(): Unit = updateReportCache.clear + def clean(): Unit = updateReportCache.clear() def directDependencies(md0: ModuleDescriptor): Vector[DependencyDescriptor] = md0.getDependencies.toVector @@ -105,7 +105,7 @@ private[sbt] class CachedResolutionResolveCache { s"""Include(${rule.getId},${rule.getConfigurations.mkString(",")},${rule.getMatcher})""" def artifactString(dad: DependencyArtifactDescriptor): String = s"""Artifact(${dad.getName},${dad.getType},${dad.getExt},${dad.getUrl},${dad.getConfigurations - .mkString(",")},${dad.getExtraAttributes})""" + .mkString(",")},${dad.getExtraAttributes})""" val mrid = dd.getDependencyRevisionId val confMap = (dd.getModuleConfigurations map { conf => conf + "->(" + dd.getDependencyConfigurations(conf).mkString(",") + ")" @@ -127,9 +127,13 @@ private[sbt] class CachedResolutionResolveCache { val mesStr = (mes map excludeRuleString).mkString(",") val os = extractOverrides(parent) val moduleLevel = s"""dependencyOverrides=${os.mkString(",")};moduleExclusions=$mesStr""" - val depsString = s"""$mrid;${confMap.mkString(",")};isForce=${dd.isForce};isChanging=${dd.isChanging};isTransitive=${dd.isTransitive};""" + - s"""exclusions=${exclusions.mkString(",")};inclusions=${inclusions.mkString(",")};explicitArtifacts=${explicitArtifacts - .mkString(",")};$moduleLevel;""" + val depsString = s"""$mrid;${confMap.mkString( + "," + )};isForce=${dd.isForce};isChanging=${dd.isChanging};isTransitive=${dd.isTransitive};""" + + s"""exclusions=${exclusions.mkString(",")};inclusions=${inclusions.mkString( + "," + )};explicitArtifacts=${explicitArtifacts + .mkString(",")};$moduleLevel;""" val sha1 = Hash.toHex( Hash(s"""graphVersion=${CachedResolutionResolveCache.graphVersion};$depsString""") ) @@ -158,15 +162,14 @@ private[sbt] class CachedResolutionResolveCache { md0.getAllDependencyDescriptorMediators.getAllRules.asScala.toSeq.toVector sortBy { case (k, _) => k.toString - } collect { - case (k: MapMatcher, v: OverrideDependencyDescriptorMediator) => - val attr: Map[Any, Any] = k.getAttributes.asScala.toMap - val module = IvyModuleId.newInstance( - attr(IvyPatternHelper.ORGANISATION_KEY).toString, - attr(IvyPatternHelper.MODULE_KEY).toString - ) - val pm = k.getPatternMatcher - IvyOverride(module, pm, v) + } collect { case (k: MapMatcher, v: OverrideDependencyDescriptorMediator) => + val attr: Map[Any, Any] = k.getAttributes.asScala.toMap + val module = IvyModuleId.newInstance( + attr(IvyPatternHelper.ORGANISATION_KEY).toString, + attr(IvyPatternHelper.MODULE_KEY).toString + ) + val pm = k.getPatternMatcher + IvyOverride(module, pm, v) } } def getOrElseUpdateMiniGraph( @@ -200,8 +203,10 @@ private[sbt] class CachedResolutionResolveCache { } val staticGraphDirectory = miniGraphPath / "static" val dynamicGraphDirectory = miniGraphPath / "dynamic" - val staticGraphPath = staticGraphDirectory / pathScalaVersion / pathSbtVersion / pathOrg / pathName / pathRevision / "graphs" / "graph.json" - val dynamicGraphPath = dynamicGraphDirectory / todayStr / logicalClock.toString / pathScalaVersion / pathSbtVersion / pathOrg / pathName / pathRevision / "graphs" / "graph.json" + val staticGraphPath = + staticGraphDirectory / pathScalaVersion / pathSbtVersion / pathOrg / pathName / pathRevision / "graphs" / "graph.json" + val dynamicGraphPath = + dynamicGraphDirectory / todayStr / logicalClock.toString / pathScalaVersion / pathSbtVersion / pathOrg / pathName / pathRevision / "graphs" / "graph.json" def cleanDynamicGraph(): Unit = { val list = IO.listFiles(dynamicGraphDirectory, DirectoryFilter).toList list filterNot { d => @@ -282,9 +287,12 @@ private[sbt] class CachedResolutionResolveCache { val moduleIdMap = Map(conflicts map { x => x.module -> x }: _*) - (surviving map moduleIdMap, evicted map moduleIdMap map { - _.withEvicted(true).withEvictedReason(Some(mgr.toString)) - }) + ( + surviving map moduleIdMap, + evicted map moduleIdMap map { + _.withEvicted(true).withEvictedReason(Some(mgr.toString)) + } + ) } (conflictCache get ((cf0, cf1))) match { case Some((surviving, evicted, mgr)) => reconstructReports(surviving, evicted, mgr) @@ -410,59 +418,58 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { Left(new ResolveException(messages, failed, failedPaths)) } } - val (internal, external) = mds.partition { - case (_, _, dd) => cache.internalDependency(dd, projectResolver).isDefined + val (internal, external) = mds.partition { case (_, _, dd) => + cache.internalDependency(dd, projectResolver).isDefined } - val internalResults = internal map { - case (md, changing, dd) => - cache.getOrElseUpdateMiniGraph( - md, - changing, - logicalClock, - miniGraphPath, - cachedDescriptor, - log - ) { - doWork(md, dd) - } + val internalResults = internal map { case (md, changing, dd) => + cache.getOrElseUpdateMiniGraph( + md, + changing, + logicalClock, + miniGraphPath, + cachedDescriptor, + log + ) { + doWork(md, dd) + } } - val externalResults = external map { - case (md0, changing, dd) => - val configurationsInInternal = internalResults flatMap { - case Right(ur) => - ur.allModules.flatMap { - case md => - val sameName = md.name == dd.getDependencyId.getName - val sameOrg = md.organization == dd.getDependencyId.getOrganisation - if (sameName && sameOrg) md.configurations - else None - } - case _ => Nil - } + val externalResults = external map { case (md0, changing, dd) => + val configurationsInInternal = internalResults flatMap { + case Right(ur) => + ur.allModules.flatMap { case md => + val sameName = md.name == dd.getDependencyId.getName + val sameOrg = md.organization == dd.getDependencyId.getOrganisation + if (sameName && sameOrg) md.configurations + else None + } + case _ => Nil + } - dd match { - case d: DefaultDependencyDescriptor => - configurationsInInternal foreach { c => - val configurations = c.split(";").map(_.split("->")) - configurations foreach { conf => - try d.addDependencyConfiguration(conf(0), conf(1)) - catch { case _: Throwable => () } // An exception will be thrown if `conf(0)` doesn't exist. - } + dd match { + case d: DefaultDependencyDescriptor => + configurationsInInternal foreach { c => + val configurations = c.split(";").map(_.split("->")) + configurations foreach { conf => + try d.addDependencyConfiguration(conf(0), conf(1)) + catch { + case _: Throwable => () + } // An exception will be thrown if `conf(0)` doesn't exist. } + } - case _ => () - } + case _ => () + } - cache.getOrElseUpdateMiniGraph( - md0, - changing, - logicalClock, - miniGraphPath, - cachedDescriptor, - log - ) { - doWork(md0, dd) - } + cache.getOrElseUpdateMiniGraph( + md0, + changing, + logicalClock, + miniGraphPath, + cachedDescriptor, + log + ) { + doWork(md0, dd) + } } val results = internalResults ++ externalResults val uReport = @@ -485,21 +492,20 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { log: Logger ): Either[ResolveException, UpdateReport] = if (!missingOk && (results exists { _.isLeft })) - Left(mergeErrors(md0, results collect { case Left(re) => re })) + Left(mergeErrors(md0, results collect { case Left(re) => re })) else Right(mergeReports(md0, results collect { case Right(ur) => ur }, resolveTime, os, log)) def mergeErrors(md0: ModuleDescriptor, errors: Vector[ResolveException]): ResolveException = { val messages = errors flatMap { _.messages } val failed = errors flatMap { _.failed } val failedPaths = errors flatMap { - _.failedPaths.toList map { - case (failed, paths) => - if (paths.isEmpty) (failed, paths) - else - ( - failed, - List(IvyRetrieve.toModuleID(md0.getResolvedModuleRevisionId)) ::: paths.toList.tail - ) + _.failedPaths.toList map { case (failed, paths) => + if (paths.isEmpty) (failed, paths) + else + ( + failed, + List(IvyRetrieve.toModuleID(md0.getResolvedModuleRevisionId)) ::: paths.toList.tail + ) } } new ResolveException(messages, failed, ListMap(failedPaths: _*)) @@ -579,12 +585,11 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { // this might take up some memory, but it's limited to a single val reports1 = reports0 flatMap { filterReports } val allModules0: Map[(String, String), Vector[OrganizationArtifactReport]] = - Map(orgNamePairs map { - case (organization, name) => - val xs = reports1 filter { oar => - oar.organization == organization && oar.name == name - } - ((organization, name), xs) + Map(orgNamePairs map { case (organization, name) => + val xs = reports1 filter { oar => + oar.organization == organization && oar.name == name + } + ((organization, name), xs) }: _*) // this returns a List of Lists of (org, name). should be deterministic def detectLoops( @@ -699,11 +704,11 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { ) } (if (n > guard) { - warnCircular + warnCircular() result0 } else if (called.isEmpty) result0 else if (notCalled.isEmpty) { - warnCircular + warnCircular() sortModules(cs.tail, acc, extra :+ cs.head, n + 1, guard) } else sortModules(called, acc ++ notCalled, extra, 0, called.size * called.size + 1)) } @@ -766,8 +771,8 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { val completelyEvicted = xs forall { _.evicted } val allCallers = xs flatMap { _.callers } // Caller info is often repeated across the subprojects. We only need ModuleID info for later, so xs.head is ok. - val distinctByModuleId = allCallers.groupBy({ _.caller }).toVector map { - case (_, xs) => xs.head + val distinctByModuleId = allCallers.groupBy({ _.caller }).toVector map { case (_, xs) => + xs.head } val allArtifacts = (xs flatMap { _.artifacts }).distinct xs.head @@ -777,10 +782,9 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { } val merged = (modules groupBy { m => (m.module.organization, m.module.name, m.module.revision) - }).toSeq.toVector flatMap { - case (_, xs) => - if (xs.size < 2) xs - else Vector(mergeModuleReports(xs)) + }).toSeq.toVector flatMap { case (_, xs) => + if (xs.size < 2) xs + else Vector(mergeModuleReports(xs)) } val conflicts = merged filter { m => !m.evicted && m.problem.isEmpty @@ -789,9 +793,12 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { else resolveConflict(rootModuleConf, conflicts, os, log) match { case (survivor, evicted) => - (survivor ++ (merged filter { m => - m.evicted || m.problem.isDefined - }), evicted) + ( + survivor ++ (merged filter { m => + m.evicted || m.problem.isDefined + }), + evicted + ) } } @@ -869,9 +876,13 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { }) match { case Some(m) => log.debug(s"- directly forced dependency: $m ${m.callers}") - (Vector(m), conflicts filterNot { _ == m } map { - _.withEvicted(true).withEvictedReason(Some("direct-force")) - }, "direct-force") + ( + Vector(m), + conflicts filterNot { _ == m } map { + _.withEvicted(true).withEvictedReason(Some("direct-force")) + }, + "direct-force" + ) case None => (conflicts find { m => m.callers.exists { _.isForceDependency } @@ -879,18 +890,26 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { // Ivy translates pom.xml dependencies to forced="true", so transitive force is broken. case Some(m) if !ignoreTransitiveForce => log.debug(s"- transitively forced dependency: $m ${m.callers}") - (Vector(m), conflicts filterNot { _ == m } map { - _.withEvicted(true).withEvictedReason(Some("transitive-force")) - }, "transitive-force") + ( + Vector(m), + conflicts filterNot { _ == m } map { + _.withEvicted(true).withEvictedReason(Some("transitive-force")) + }, + "transitive-force" + ) case _ => val strategy = lcm.getStrategy val infos = conflicts map { ModuleReportArtifactInfo(_) } log.debug(s"- Using $strategy with $infos") Option(strategy.findLatest(infos.toArray, None.orNull)) match { case Some(ModuleReportArtifactInfo(m)) => - (Vector(m), conflicts filterNot { _ == m } map { - _.withEvicted(true).withEvictedReason(Some(lcm.toString)) - }, lcm.toString) + ( + Vector(m), + conflicts filterNot { _ == m } map { + _.withEvicted(true).withEvictedReason(Some(lcm.toString)) + }, + lcm.toString + ) case _ => (conflicts, Vector(), lcm.toString) } } @@ -905,9 +924,13 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { mr.module.revision == ovrVersion } match { case Some(m) => - (Vector(m), conflicts filterNot { _ == m } map { - _.withEvicted(true).withEvictedReason(Some("override")) - }, "override") + ( + Vector(m), + conflicts filterNot { _ == m } map { + _.withEvicted(true).withEvictedReason(Some("override")) + }, + "override" + ) case None => sys.error( s"override dependency specifies $ovrVersion but no candidates were found: " + (conflicts map { @@ -925,7 +948,7 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { }).mkString("(", ", ", ")")) ) case lcm: LatestConflictManager => useLatest(lcm) - case conflictManager => sys.error(s"Unsupported conflict manager $conflictManager") + case conflictManager => sys.error(s"Unsupported conflict manager $conflictManager") } } if (conflicts.size == 2 && os.isEmpty) { 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 2ba03b74..478462e8 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/ErrorMessageAuthenticator.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/ErrorMessageAuthenticator.scala @@ -64,10 +64,14 @@ object ErrorMessageAuthenticator { ivyOriginalField.set(ivy, newOriginal) } - try Option(ivyOriginalField.get(ivy).asInstanceOf[Authenticator]) match { - case Some(_: ErrorMessageAuthenticator) => // We're already installed, no need to do the work again. - case originalOpt => installIntoIvyImpl(originalOpt) - } catch { + try + Option(ivyOriginalField.get(ivy).asInstanceOf[Authenticator]) match { + case Some( + _: ErrorMessageAuthenticator + ) => // We're already installed, no need to do the work again. + case originalOpt => installIntoIvyImpl(originalOpt) + } + catch { case t: Throwable => Message.debug( "Error occurred while trying to install debug messages into Ivy Authentication" + t.getMessage @@ -135,16 +139,17 @@ private[sbt] final class ErrorMessageAuthenticator(original: Option[Authenticato // Grabs the authentication that would have been provided had we not been installed... def originalAuthentication: Option[PasswordAuthentication] = { Authenticator.setDefault(original.orNull) - try Option( - Authenticator.requestPasswordAuthentication( - getRequestingHost, - getRequestingSite, - getRequestingPort, - getRequestingProtocol, - getRequestingPrompt, - getRequestingScheme + try + Option( + Authenticator.requestPasswordAuthentication( + getRequestingHost, + getRequestingSite, + getRequestingPort, + getRequestingProtocol, + getRequestingPrompt, + getRequestingScheme + ) ) - ) finally Authenticator.setDefault(this) } originalAuthentication.orNull diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/GigahorseUrlHandler.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/GigahorseUrlHandler.scala deleted file mode 100644 index 87ed352b..00000000 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/GigahorseUrlHandler.scala +++ /dev/null @@ -1,339 +0,0 @@ -package sbt.internal.librarymanagement -package ivyint - -import java.net.{ URL, UnknownHostException } -import java.io._ - -import scala.util.control.NonFatal - -import okhttp3.{ MediaType, Request, RequestBody } -import okhttp3.internal.http.HttpDate - -import okhttp3.{ JavaNetAuthenticator => _, _ } -import okio._ - -import org.apache.ivy.util.{ CopyProgressEvent, CopyProgressListener, Message } -import org.apache.ivy.util.url.{ AbstractURLHandler, BasicURLHandler, IvyAuthenticator, URLHandler } -import org.apache.ivy.util.url.URLHandler._ -import sbt.io.IO - -// Copied from Ivy's BasicURLHandler. -class GigahorseUrlHandler(http: OkHttpClient) extends AbstractURLHandler { - - import GigahorseUrlHandler._ - - /** - * Returns the URLInfo of the given url or a #UNAVAILABLE instance, - * if the url is not reachable. - */ - def getURLInfo(url: URL): URLInfo = getURLInfo(url, 0) - - /** - * Returns the URLInfo of the given url or a #UNAVAILABLE instance, - * if the url is not reachable. - */ - def getURLInfo(url0: URL, timeout: Int): URLInfo = { - // Install the ErrorMessageAuthenticator - if ("http" == url0.getProtocol || "https" == url0.getProtocol) { - IvyAuthenticator.install() - ErrorMessageAuthenticator.install() - } - - val url = normalizeToURL(url0) - val request = new Request.Builder() - .url(url) - - if (getRequestMethod == URLHandler.REQUEST_METHOD_HEAD) request.head() else request.get() - - val response = http.newCall(request.build()).execute() - try { - val infoOption = try { - - if (checkStatusCode(url, response)) { - val bodyCharset = - BasicURLHandler.getCharSetFromContentType( - Option(response.body().contentType()).map(_.toString).orNull - ) - Some( - new SbtUrlInfo( - true, - response.body().contentLength(), - lastModifiedTimestamp(response), - bodyCharset - ) - ) - } else None - // - // Commented out for now - can potentially be used for non HTTP urls - // - // val contentLength: Long = con.getContentLengthLong - // if (contentLength <= 0) None - // else { - // // TODO: not HTTP... maybe we *don't* want to default to ISO-8559-1 here? - // val bodyCharset = BasicURLHandler.getCharSetFromContentType(con.getContentType) - // Some(new SbtUrlInfo(true, contentLength, con.getLastModified(), bodyCharset)) - // } - - } catch { - case e: UnknownHostException => - Message.warn("Host " + e.getMessage + " not found. url=" + url) - Message.info( - "You probably access the destination server through " - + "a proxy server that is not well configured." - ) - None - case e: IOException => - Message.error("Server access Error: " + e.getMessage + " url=" + url) - None - } - infoOption.getOrElse(UNAVAILABLE) - } finally { - response.close() - } - } - - //The caller of this *MUST* call Response.close() - private def getUrl(url0: URL): okhttp3.Response = { - // Install the ErrorMessageAuthenticator - if ("http" == url0.getProtocol || "https" == url0.getProtocol) { - IvyAuthenticator.install() - ErrorMessageAuthenticator.install() - } - - val url = normalizeToURL(url0) - val request = new Request.Builder() - .url(url) - .get() - .build() - - val response = http.newCall(request).execute() - try { - if (!checkStatusCode(url, response)) { - throw new IOException( - "The HTTP response code for " + url + " did not indicate a success." - + " See log for more detail." - ) - } - response - } catch { - case NonFatal(e) => - //ensure the response gets closed if there's an error - response.close() - throw e - } - - } - - def openStream(url: URL): InputStream = { - //It's assumed that the caller of this will call close() on the supplied inputstream, - // thus closing the OkHTTP request - getUrl(url).body().byteStream() - } - - def download(url: URL, dest: File, l: CopyProgressListener): Unit = { - - val response = getUrl(url) - try { - - if (l != null) { - l.start(new CopyProgressEvent()) - } - val sink = Okio.buffer(Okio.sink(dest)) - try { - sink.writeAll(response.body().source()) - sink.flush() - } finally { - sink.close() - } - - val contentLength = response.body().contentLength() - if (contentLength != -1 && dest.length != contentLength) { - IO.delete(dest) - throw new IOException( - "Downloaded file size doesn't match expected Content Length for " + url - + ". Please retry." - ) - } - - val lastModified = lastModifiedTimestamp(response) - if (lastModified > 0) { - IO.setModifiedTimeOrFalse(dest, lastModified) - } - - if (l != null) { - l.end(new CopyProgressEvent(EmptyBuffer, contentLength)) - } - - } finally { - response.close() - } - } - - def upload(source: File, dest0: URL, l: CopyProgressListener): Unit = { - - if (("http" != dest0.getProtocol) && ("https" != dest0.getProtocol)) { - throw new UnsupportedOperationException("URL repository only support HTTP PUT at the moment") - } - - IvyAuthenticator.install() - ErrorMessageAuthenticator.install() - - val dest = normalizeToURL(dest0) - - val body = RequestBody.create(MediaType.parse("application/octet-stream"), source) - - val request = new Request.Builder() - .url(dest) - .put(body) - .build() - - if (l != null) { - l.start(new CopyProgressEvent()) - } - val response = http.newCall(request).execute() - try { - if (l != null) { - l.end(new CopyProgressEvent(EmptyBuffer, source.length())) - } - validatePutStatusCode(dest, response) - } finally { - response.close() - } - } - - private val ErrorBodyTruncateLen = 512 // in case some bad service returns files rather than messages in error bodies - private val DefaultErrorCharset = java.nio.charset.StandardCharsets.UTF_8 - - // neurotic resource managemement... - // we could use this elsewhere in the class too - private def borrow[S <: AutoCloseable, T](rsrc: => S)(op: S => T): T = { - val r = rsrc - val out = { - try { - op(r) - } catch { - case NonFatal(t) => { - try { - r.close() - } catch { - case NonFatal(ct) => t.addSuppressed(ct) - } - throw t - } - } - } - r.close() - out - } - - // this is perhaps overly cautious, but oh well - private def readTruncated(byteStream: InputStream): Option[(Array[Byte], Boolean)] = { - borrow(byteStream) { is => - borrow(new ByteArrayOutputStream(ErrorBodyTruncateLen)) { os => - var count = 0 - var b = is.read() - var truncated = false - while (!truncated && b >= 0) { - if (count >= ErrorBodyTruncateLen) { - truncated = true - } else { - os.write(b) - count += 1 - b = is.read() - } - } - if (count > 0) { - Some((os.toByteArray, truncated)) - } else { - None - } - } - } - } - - /* - * Supplements the IOException emitted on a bad status code by our inherited validatePutStatusCode(...) - * method with any message that might be present in an error response body. - * - * after calling this method, the object given as the response parameter must be reliably closed. - */ - private def validatePutStatusCode(dest: URL, response: Response): Unit = { - try { - validatePutStatusCode(dest, response.code(), response.message()) - } catch { - case ioe: IOException => { - val mbBodyMessage = { - for { - body <- Option(response.body()) - is <- Option(body.byteStream) - (bytes, truncated) <- readTruncated(is) - charset <- Option(body.contentType()).map(_.charset(DefaultErrorCharset)) orElse Some( - DefaultErrorCharset - ) - } yield { - val raw = new String(bytes, charset) - if (truncated) raw + "..." else raw - } - } - - mbBodyMessage match { - case Some(bodyMessage) => { // reconstruct the IOException - val newMessage = ioe.getMessage() + s"; Response Body: ${bodyMessage}" - val reconstructed = new IOException(newMessage, ioe.getCause()) - reconstructed.setStackTrace(ioe.getStackTrace()) - throw reconstructed - } - case None => { - throw ioe - } - } - } - } - } -} - -object GigahorseUrlHandler { - // This is requires to access the constructor of URLInfo. - private[sbt] class SbtUrlInfo( - available: Boolean, - contentLength: Long, - lastModified: Long, - bodyCharset: String - ) extends URLInfo(available, contentLength, lastModified, bodyCharset) { - def this(available: Boolean, contentLength: Long, lastModified: Long) = { - this(available, contentLength, lastModified, null) - } - } - - private val EmptyBuffer: Array[Byte] = new Array[Byte](0) - - private def checkStatusCode(url: URL, response: Response): Boolean = - response.code() match { - case 200 => true - case 204 if "HEAD" == response.request().method() => true - case status => - Message.debug("HTTP response status: " + status + " url=" + url) - if (status == 407 /* PROXY_AUTHENTICATION_REQUIRED */ ) { - Message.warn("Your proxy requires authentication.") - } else if (status == 401) { - Message.warn( - "CLIENT ERROR: 401 Unauthorized. Check your resolvers username and password." - ) - } else if (String.valueOf(status).startsWith("4")) { - Message.verbose("CLIENT ERROR: " + response.message() + " url=" + url) - } else if (String.valueOf(status).startsWith("5")) { - Message.error("SERVER ERROR: " + response.message() + " url=" + url) - } - false - } - - private def lastModifiedTimestamp(response: Response): Long = { - val lastModifiedDate = - Option(response.headers().get("Last-Modified")).flatMap { headerValue => - Option(HttpDate.parse(headerValue)) - } - - lastModifiedDate.map(_.getTime).getOrElse(0) - } - -} diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/IvyCredentialsLookup.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/IvyCredentialsLookup.scala index e2e11912..9d814832 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/IvyCredentialsLookup.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/IvyCredentialsLookup.scala @@ -47,20 +47,20 @@ private[sbt] object IvyCredentialsLookup { val map = credKeyringField.get(null).asInstanceOf[java.util.HashMap[String, Any]] // make a clone of the set... (map.keySet.asScala.map { - case KeySplit(realm, host) => Realm(host, realm) - case host => Host(host) - })(collection.breakOut) + case KeySplit(realm, host) => (Realm(host, realm): CredentialKey) + case host => (Host(host): CredentialKey) + }).toSet } /** * A mapping of host -> realms in the ivy credentials store. */ def realmsForHost: Map[String, Set[String]] = - keyringKeys collect { - case x: Realm => x + (keyringKeys collect { case x: Realm => + x } groupBy { realm => realm.host } mapValues { realms => realms map (_.realm) - } + }).toMap } diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/MergeDescriptors.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/MergeDescriptors.scala index 1c9f2e7d..765360d9 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/MergeDescriptors.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/MergeDescriptors.scala @@ -13,14 +13,14 @@ private[sbt] object MergeDescriptors { a.isTransitive == b.isTransitive && a.getParentRevisionId == b.getParentRevisionId && a.getNamespace == b.getNamespace && { - val amrid = a.getDependencyRevisionId - val bmrid = b.getDependencyRevisionId - amrid == bmrid - } && { - val adyn = a.getDynamicConstraintDependencyRevisionId - val bdyn = b.getDynamicConstraintDependencyRevisionId - adyn == bdyn - } + val amrid = a.getDependencyRevisionId + val bmrid = b.getDependencyRevisionId + amrid == bmrid + } && { + val adyn = a.getDynamicConstraintDependencyRevisionId + val bdyn = b.getDynamicConstraintDependencyRevisionId + adyn == bdyn + } def apply(a: DependencyDescriptor, b: DependencyDescriptor): DependencyDescriptor = { assert(mergeable(a, b)) diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/ParallelResolveEngine.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/ParallelResolveEngine.scala index 9af7ef6c..711e0322 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/ParallelResolveEngine.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/ParallelResolveEngine.scala @@ -48,17 +48,18 @@ private[sbt] class ParallelResolveEngine( } // Farm out the dependencies for parallel download implicit val ec = ParallelResolveEngine.resolveExecutionContext - val allDownloadsFuture = Future.traverse(report.getDependencies.asScala) { - case dep: IvyNode => - Future { - if (!(dep.isCompletelyEvicted || dep.hasProblem) && - dep.getModuleRevision != null) { - Some(downloadNodeArtifacts(dep, artifactFilter, options)) - } else None - } + val allDownloadsFuture = Future.traverse(report.getDependencies.asScala) { case dep: IvyNode => + Future { + if ( + !(dep.isCompletelyEvicted || dep.hasProblem) && + dep.getModuleRevision != null + ) { + Some(downloadNodeArtifacts(dep, artifactFilter, options)) + } else None + } } val allDownloads = Await.result(allDownloadsFuture, Duration.Inf) - //compute total downloaded size + // compute total downloaded size val totalSize = allDownloads.foldLeft(0L) { case (size, Some(download)) => val dependency = download.dep @@ -67,8 +68,10 @@ private[sbt] class ParallelResolveEngine( val configurationReport = report.getConfigurationReport(configuration) // Take into account artifacts required by the given configuration - if (dependency.isEvicted(configuration) || - dependency.isBlacklisted(configuration)) { + if ( + dependency.isEvicted(configuration) || + dependency.isBlacklisted(configuration) + ) { configurationReport.addDependency(dependency) } else configurationReport.addDependency(dependency, download.report) } diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/SbtChainResolver.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/SbtChainResolver.scala index 2314838e..9dfd3b83 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/SbtChainResolver.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/SbtChainResolver.scala @@ -37,9 +37,9 @@ private[sbt] case class SbtChainResolver( override def equals(o: Any): Boolean = o match { case o: SbtChainResolver => this.name == o.name && - this.resolvers == o.resolvers && - this.settings == o.settings && - this.updateOptions == o.updateOptions + this.resolvers == o.resolvers && + this.settings == o.settings && + this.updateOptions == o.updateOptions case _ => false } @@ -124,7 +124,8 @@ private[sbt] case class SbtChainResolver( /** If None, module was not found. Otherwise, hit. */ type TriedResolution = Option[(ResolvedModuleRevision, DependencyResolver)] - /** Attempts to resolve the artifact from each of the resolvers in the chain. + /** + * Attempts to resolve the artifact from each of the resolvers in the chain. * * Contract: * 1. It doesn't resolve anything when there is a resolved module, `isReturnFirst` is @@ -155,8 +156,8 @@ private[sbt] case class SbtChainResolver( currentlyResolved = Option(resolver.getDependency(descriptor, data)) if (currentlyResolved eq previouslyResolved) None else if (useLatest) { - currentlyResolved.map( - x => (reparseModuleDescriptor(descriptor, data, resolver, x), resolver) + currentlyResolved.map(x => + (reparseModuleDescriptor(descriptor, data, resolver, x), resolver) ) } else currentlyResolved.map(x => (forcedRevision(x), resolver)) } @@ -174,7 +175,8 @@ private[sbt] case class SbtChainResolver( val oldLatest: Option[LatestStrategy] = setLatestIfRequired(resolver, Option(getLatestStrategy)) try Right(performResolution(resolver)) - catch { case NonFatal(t) => reportError(t, resolver); Left(t) } finally { + catch { case NonFatal(t) => reportError(t, resolver); Left(t) } + finally { oldLatest.foreach(_ => doSetLatestStrategy(resolver, oldLatest)) checkInterrupted() } @@ -189,34 +191,33 @@ private[sbt] case class SbtChainResolver( data: ResolveData ): Option[ResolvedModuleRevision] = { - val sortedRevisions = foundRevisions.sortBy { - case (rmr, resolver) => - val publicationDate = rmr.getPublicationDate - val descriptorDate = rmr.getDescriptor.getPublicationDate - Message.warn(s"Sorting results from $rmr, using $publicationDate and $descriptorDate.") - // Just issue warning about issues with publication date, and fake one on it for now - val chosenPublicationDate = Option(publicationDate).orElse(Option(descriptorDate)) - chosenPublicationDate match { - case Some(date) => date.getTime - case None => - val id = rmr.getId - val resolvedResource = (resolver.findIvyFileRef(descriptor, data), rmr.getDescriptor) - resolvedResource match { - case (res: ResolvedResource, dmd: DefaultModuleDescriptor) => - val resolvedPublicationDate = new java.util.Date(res.getLastModified) - Message.debug(s"No publication date from resolver $resolver for $id.") - Message.debug(s"Setting publication date to: $resolvedPublicationDate.") - dmd.setPublicationDate(resolvedPublicationDate) - res.getLastModified - case (ivf, dmd) => - // The dependency is specified by a direct URL or some sort of non-ivy file - if (ivf == null && descriptor.isChanging) - Message.warn(s"$prefix: changing dependency $id with no ivy/pom file!") - if (dmd == null) - Message.warn(s"$prefix: no publication date from resolver $resolver for $id") - 0L - } - } + val sortedRevisions = foundRevisions.sortBy { case (rmr, resolver) => + val publicationDate = rmr.getPublicationDate + val descriptorDate = rmr.getDescriptor.getPublicationDate + Message.warn(s"Sorting results from $rmr, using $publicationDate and $descriptorDate.") + // Just issue warning about issues with publication date, and fake one on it for now + val chosenPublicationDate = Option(publicationDate).orElse(Option(descriptorDate)) + chosenPublicationDate match { + case Some(date) => date.getTime + case None => + val id = rmr.getId + val resolvedResource = (resolver.findIvyFileRef(descriptor, data), rmr.getDescriptor) + resolvedResource match { + case (res: ResolvedResource, dmd: DefaultModuleDescriptor) => + val resolvedPublicationDate = new java.util.Date(res.getLastModified) + Message.debug(s"No publication date from resolver $resolver for $id.") + Message.debug(s"Setting publication date to: $resolvedPublicationDate.") + dmd.setPublicationDate(resolvedPublicationDate) + res.getLastModified + case (ivf, dmd) => + // The dependency is specified by a direct URL or some sort of non-ivy file + if (ivf == null && descriptor.isChanging) + Message.warn(s"$prefix: changing dependency $id with no ivy/pom file!") + if (dmd == null) + Message.warn(s"$prefix: no publication date from resolver $resolver for $id") + 0L + } + } } val firstHit = sortedRevisions.reverse.headOption @@ -233,7 +234,7 @@ private[sbt] case class SbtChainResolver( val (module, resolver) = h Message.info( s"Out of ${sortedRevisions.size} candidates we found for ${module.getId} in ${resolvers - .mkString(" and ")}, we are choosing ${resolver}." + .mkString(" and ")}, we are choosing ${resolver}." ) }) } else { @@ -277,12 +278,11 @@ private[sbt] case class SbtChainResolver( } /** Cleans unnecessary module id information not provided by [[IvyRetrieve.toModuleID()]]. */ - private final val moduleResolvers = updateOptions.moduleResolvers.map { - case (key, value) => - val cleanKey = ModuleID(key.organization, key.name, key.revision) - .withExtraAttributes(key.extraAttributes) - .withBranchName(key.branchName) - cleanKey -> value + private final val moduleResolvers = updateOptions.moduleResolvers.map { case (key, value) => + val cleanKey = ModuleID(key.organization, key.name, key.revision) + .withExtraAttributes(key.extraAttributes) + .withBranchName(key.branchName) + cleanKey -> value } /** @@ -309,7 +309,8 @@ private[sbt] case class SbtChainResolver( def findInterProjectResolver(resolvers: Seq[DependencyResolver]): Option[DependencyResolver] = resolvers.find(_.getName == ProjectResolver.InterProject) - /** Gets the dependency for a given descriptor with the pertinent resolve data. + /** + * Gets the dependency for a given descriptor with the pertinent resolve data. * * This is a custom sbt chain operation that produces better error output and deals with * cases that the conventional ivy resolver does not. It accumulates the resolution of diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/mavenint/PomExtraDependencyAttributes.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/mavenint/PomExtraDependencyAttributes.scala index c198f046..25ab896b 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/mavenint/PomExtraDependencyAttributes.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/mavenint/PomExtraDependencyAttributes.scala @@ -80,7 +80,7 @@ object PomExtraDependencyAttributes { def filterCustomExtra(item: ExtendableItem, include: Boolean): Map[String, String] = (qualifiedExtra(item) filterKeys { k => qualifiedIsExtra(k) == include - }) + }).toMap def qualifiedIsExtra(k: String): Boolean = k.endsWith(ScalaVersionKey) || k.endsWith(SbtVersionKey) diff --git a/ivy/src/main/scala/sbt/librarymanagement/ivy/Credentials.scala b/ivy/src/main/scala/sbt/librarymanagement/ivy/Credentials.scala index 7ebc4521..6d65f72f 100644 --- a/ivy/src/main/scala/sbt/librarymanagement/ivy/Credentials.scala +++ b/ivy/src/main/scala/sbt/librarymanagement/ivy/Credentials.scala @@ -16,11 +16,11 @@ object Credentials { def apply(file: File): Credentials = new FileCredentials(file) - /** Add the provided credentials to Ivy's credentials cache.*/ + /** Add the provided credentials to Ivy's credentials cache. */ def add(realm: String, host: String, userName: String, passwd: String): Unit = CredentialsStore.INSTANCE.addCredentials(realm, host, userName, passwd) - /** Load credentials from the given file into Ivy's credentials cache.*/ + /** Load credentials from the given file into Ivy's credentials cache. */ def add(path: File, log: Logger): Unit = loadCredentials(path) match { case Left(err) => log.warn(err) @@ -47,9 +47,13 @@ object Credentials { .headOption .toRight(keys.head + " not specified in credentials file: " + path) - IvyUtil.separate(List(RealmKeys, HostKeys, UserKeys, PasswordKeys).map(get)) match { - case (Nil, List(realm, host, user, pass)) => - Right(new DirectCredentials(realm, host, user, pass)) + IvyUtil.separate(List(HostKeys, UserKeys, PasswordKeys).map(get)) match { + case (Nil, List(host, user, pass)) => + IvyUtil.separate(List(RealmKeys).map(get)) match { + case (_, List(realm)) => Right(new DirectCredentials(realm, host, user, pass)) + case _ => Right(new DirectCredentials(null, host, user, pass)) + } + case (errors, _) => Left(errors.mkString("\n")) } } else @@ -84,5 +88,11 @@ final class DirectCredentials( val userName: String, val passwd: String ) extends Credentials { - override def toString = s"""DirectCredentials("$realm", "$host", "$userName", ****)""" + override def toString = { + val dq = '"' + val r = + if (realm == null) "null" + else s"$dq$realm$dq" + s"""DirectCredentials($r, "$host", "$userName", ****)""" + } } diff --git a/ivy/src/main/scala/sbt/librarymanagement/ivy/IvyDependencyResolution.scala b/ivy/src/main/scala/sbt/librarymanagement/ivy/IvyDependencyResolution.scala index bc72f4bc..3f5aedac 100644 --- a/ivy/src/main/scala/sbt/librarymanagement/ivy/IvyDependencyResolution.scala +++ b/ivy/src/main/scala/sbt/librarymanagement/ivy/IvyDependencyResolution.scala @@ -2,7 +2,6 @@ package sbt package librarymanagement package ivy -import okhttp3.OkHttpClient import sbt.internal.librarymanagement._ import sbt.util.Logger @@ -30,8 +29,5 @@ class IvyDependencyResolution private[sbt] (val ivySbt: IvySbt) object IvyDependencyResolution { def apply(ivyConfiguration: IvyConfiguration): DependencyResolution = - apply(ivyConfiguration, CustomHttp.defaultHttpClient) - - def apply(ivyConfiguration: IvyConfiguration, http: OkHttpClient): DependencyResolution = - DependencyResolution(new IvyDependencyResolution(new IvySbt(ivyConfiguration, http))) + DependencyResolution(new IvyDependencyResolution(new IvySbt(ivyConfiguration))) } diff --git a/ivy/src/main/scala/sbt/librarymanagement/ivy/IvyPublisher.scala b/ivy/src/main/scala/sbt/librarymanagement/ivy/IvyPublisher.scala index dc15ba7a..78439874 100644 --- a/ivy/src/main/scala/sbt/librarymanagement/ivy/IvyPublisher.scala +++ b/ivy/src/main/scala/sbt/librarymanagement/ivy/IvyPublisher.scala @@ -2,7 +2,6 @@ package sbt package librarymanagement package ivy -import okhttp3.OkHttpClient import sbt.internal.librarymanagement._ import sbt.util.Logger import java.io.File @@ -36,8 +35,5 @@ class IvyPublisher private[sbt] (val ivySbt: IvySbt) extends PublisherInterface object IvyPublisher { def apply(ivyConfiguration: IvyConfiguration): Publisher = - apply(ivyConfiguration, CustomHttp.defaultHttpClient) - - def apply(ivyConfiguration: IvyConfiguration, http: OkHttpClient): Publisher = - Publisher(new IvyPublisher(new IvySbt(ivyConfiguration, http))) + Publisher(new IvyPublisher(new IvySbt(ivyConfiguration))) } diff --git a/ivy/src/main/scala/sbt/librarymanagement/ivy/UpdateOptions.scala b/ivy/src/main/scala/sbt/librarymanagement/ivy/UpdateOptions.scala index 0a41509b..1fa856d0 100644 --- a/ivy/src/main/scala/sbt/librarymanagement/ivy/UpdateOptions.scala +++ b/ivy/src/main/scala/sbt/librarymanagement/ivy/UpdateOptions.scala @@ -79,12 +79,12 @@ final class UpdateOptions private[sbt] ( override def equals(o: Any): Boolean = o match { case o: UpdateOptions => this.circularDependencyLevel == o.circularDependencyLevel && - this.interProjectFirst == o.interProjectFirst && - this.latestSnapshots == o.latestSnapshots && - this.cachedResolution == o.cachedResolution && - this.gigahorse == o.gigahorse && - this.resolverConverter == o.resolverConverter && - this.moduleResolvers == o.moduleResolvers + this.interProjectFirst == o.interProjectFirst && + this.latestSnapshots == o.latestSnapshots && + this.cachedResolution == o.cachedResolution && + this.gigahorse == o.gigahorse && + this.resolverConverter == o.resolverConverter && + this.moduleResolvers == o.moduleResolvers case _ => false } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/BaseIvySpecification.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/BaseIvySpecification.scala index 30441206..a1bd6d31 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/BaseIvySpecification.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/BaseIvySpecification.scala @@ -37,7 +37,8 @@ trait BaseIvySpecification extends AbstractEngineSpec { deps: Vector[ModuleID], scalaFullVersion: Option[String], uo: UpdateOptions = UpdateOptions(), - overrideScalaVersion: Boolean = true + overrideScalaVersion: Boolean = true, + appendSbtCrossVersion: Boolean = false ): IvySbt#Module = { val scalaModuleInfo = scalaFullVersion map { fv => ScalaModuleInfo( @@ -55,7 +56,7 @@ trait BaseIvySpecification extends AbstractEngineSpec { .withConfigurations(configurations) .withScalaModuleInfo(scalaModuleInfo) val ivySbt = new IvySbt(mkIvyConfiguration(uo)) - new ivySbt.Module(moduleSetting) + new ivySbt.Module(moduleSetting, appendSbtCrossVersion) } def resolvers: Vector[Resolver] = Vector(Resolver.mavenCentral) @@ -102,7 +103,7 @@ trait BaseIvySpecification extends AbstractEngineSpec { } } - def cleanCache: Unit = cleanIvyCache() + def cleanCache(): Unit = cleanIvyCache() def cleanIvyCache(): Unit = IO.delete(currentTarget / "cache") override def cleanCachedResolutionCache(module: ModuleDescriptor): Unit = { diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/ComponentManagerTest.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/ComponentManagerTest.scala index dc2947e2..15a68f70 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/ComponentManagerTest.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/ComponentManagerTest.scala @@ -121,7 +121,7 @@ object ComponentManagerTest extends BasicTestSuite { TestLogger { logger => withTemporaryDirectory { temp => // The actual classes we'll use at runtime. - //val mgr = new ComponentManager(xsbt.boot.Locks, new xsbt.boot.ComponentProvider(temp, true), Some(ivyHome), logger) + // val mgr = new ComponentManager(xsbt.boot.Locks, new xsbt.boot.ComponentProvider(temp, true), Some(ivyHome), logger) // A stub component manager object provider extends ComponentProvider { diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/ConflictWarningSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/ConflictWarningSpec.scala new file mode 100644 index 00000000..bc3f05eb --- /dev/null +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/ConflictWarningSpec.scala @@ -0,0 +1,40 @@ +package sbt.internal.librarymanagement + +import sbt.librarymanagement._ +import sbt.librarymanagement.syntax._ + +object ConflictWarningSpec extends BaseIvySpecification { + + test("it should print out message about the cross-Scala conflict") { + var found = false + val deps = Vector( + `scala2.13.6`, + `cats-effect3.1.1`, + `cats-core2.6.1`.cross(CrossVersion.for3Use2_13), + ) + val m = module(defaultModuleId, deps, Some("3.0.1-RC2")) + val report = ivyUpdate(m) + val w = ConflictWarning.default("foo") + + try { + ConflictWarning(w, report, log) + } catch { + case e: Throwable => + found = true + assert( + e.getMessage.linesIterator.toList.head + .startsWith("Conflicting cross-version suffixes in") + ) + } + if (!found) { + sys.error("conflict warning was expected, but didn't happen sbt/sbt#6578") + } + } + + lazy val `scala2.13.6` = + ModuleID("org.scala-lang", "scala-library", "2.13.6").withConfigurations(Some("compile")) + lazy val `cats-effect3.1.1` = + ("org.typelevel" %% "cats-effect" % "3.1.1").withConfigurations(Some("compile")) + lazy val `cats-core2.6.1` = + ("org.typelevel" %% "cats-core" % "2.6.1").withConfigurations(Some("compile")) +} diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/CredentialsSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/CredentialsSpec.scala new file mode 100644 index 00000000..13189de5 --- /dev/null +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/CredentialsSpec.scala @@ -0,0 +1,50 @@ +package sbt.internal.librarymanagement + +import sbt.librarymanagement.ivy.Credentials + +import java.io.File +import java.nio.file.Files + +import org.scalatest.funsuite.AnyFunSuite + +class CredentialsSpec extends AnyFunSuite { + + test("load credential file without authentication") { + val credentialsFile = File.createTempFile("credentials", "tmp") + + val content = + """|host=example.org + |user=username + |password=password""".stripMargin + + Files.write(credentialsFile.toPath(), content.getBytes()) + + val Right(credentials) = Credentials.loadCredentials(credentialsFile) + + assert(credentials.realm == null) + + credentialsFile.delete() + } + + test("DirectCredentials.toString") { + assert( + Credentials( + realm = null, + host = "example.org", + userName = "username", + passwd = "password" + ).toString == + """DirectCredentials(null, "example.org", "username", ****)""" + ) + + assert( + Credentials( + realm = "realm", + host = "example.org", + userName = "username", + passwd = "password" + ).toString == + """DirectCredentials("realm", "example.org", "username", ****)""" + ) + } +} diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/DMSerializationSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/DMSerializationSpec.scala index 8ffd3ed1..33b591b6 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/DMSerializationSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/DMSerializationSpec.scala @@ -1,6 +1,6 @@ package sbt.internal.librarymanagement -import java.net.URL +import java.net.URI import java.io.File import sbt.librarymanagement._ @@ -18,6 +18,14 @@ object DMSerializationSpec extends BasicTestSuite { roundtripStr(CrossVersion.binary: CrossVersion) } + test("CrossVersion.for3Use2_13 should roundtrip") { + roundtripStr(CrossVersion.for3Use2_13: CrossVersion) + } + + test("CrossVersion.for2_13Use3 with prefix should roundtrip") { + roundtripStr(CrossVersion.for2_13Use3With("_sjs1", ""): CrossVersion) + } + test("CrossVersion.Disabled should roundtrip") { roundtrip(Disabled(): CrossVersion) } @@ -35,7 +43,7 @@ object DMSerializationSpec extends BasicTestSuite { } test("""Artifact("foo", url("http://example.com/")) should roundtrip""") { - roundtrip(Artifact("foo", new URL("http://example.com/"))) + roundtrip(Artifact("foo", new URI("http://example.com/").toURL)) } test("""Artifact("foo").extra(("key", "value")) should roundtrip""") { diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/EvictionErrorSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/EvictionErrorSpec.scala new file mode 100644 index 00000000..2d02e289 --- /dev/null +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/EvictionErrorSpec.scala @@ -0,0 +1,169 @@ +package sbt.internal.librarymanagement + +import sbt.librarymanagement._ +import sbt.internal.librarymanagement.cross.CrossVersionUtil +import sbt.librarymanagement.syntax._ +import sbt.util.Level + +object EvictionErrorSpec extends BaseIvySpecification { + // This is a specification to check the eviction errors + + import sbt.util.ShowLines._ + + test("Eviction error should detect binary incompatible Scala libraries") { + val deps = Vector(`scala2.10.4`, `akkaActor2.1.4`, `akkaActor2.3.0`) + val m = module(defaultModuleId, deps, Some("2.10.4")) + val report = ivyUpdate(m) + assert(EvictionError(report, m, oldAkkaPvp).incompatibleEvictions.size == 1) + } + + test("it should print out message about the eviction") { + val deps = Vector(`scala2.10.4`, `akkaActor2.1.4`, `akkaActor2.3.0`) + val m = module(defaultModuleId, deps, Some("2.10.4")) + val report = ivyUpdate(m) + assert( + EvictionError(report, m, oldAkkaPvp).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.0 (pvp) is selected over 2.1.4", + "\t +- com.example:foo:0.1.0 (depends on 2.1.4)", + "" + ) + ) + } + + test("it should print out message including the transitive dependencies") { + val deps = Vector(`scala2.10.4`, `bananaSesame0.4`, `akkaRemote2.3.4`) + val m = module(defaultModuleId, deps, Some("2.10.4")) + val report = ivyUpdate(m) + assert( + EvictionError(report, m, oldAkkaPvp).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 (pvp) 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 be able to emulate eviction warnings") { + val deps = Vector(`scala2.10.4`, `bananaSesame0.4`, `akkaRemote2.3.4`) + val m = module(defaultModuleId, deps, Some("2.10.4")) + val report = ivyUpdate(m) + assert( + EvictionError(report, m, Nil, "pvp", "early-semver", Level.Warn).toAssumedLines == + 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 (pvp?) 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 detect Semantic Versioning violations") { + val deps = Vector(`scala2.13.3`, `http4s0.21.11`, `cats-effect3.0.0-M4`) + val m = module(defaultModuleId, deps, Some("2.13.3")) + val report = ivyUpdate(m) + assert( + EvictionError(report, m, Nil).lines == + List( + "found version conflict(s) in library dependencies; some are suspected to be binary incompatible:", + "", + "\t* org.typelevel:cats-effect_2.13:3.0.0-M4 (early-semver) is selected over {2.0.0, 2.2.0}", + "\t +- com.example:foo:0.1.0 (depends on 3.0.0-M4)", + "\t +- co.fs2:fs2-core_2.13:2.4.5 (depends on 2.2.0)", + "\t +- org.http4s:http4s-core_2.13:0.21.11 (depends on 2.2.0)", + "\t +- io.chrisdavenport:vault_2.13:2.0.0 (depends on 2.0.0)", + "\t +- io.chrisdavenport:unique_2.13:2.0.0 (depends on 2.0.0)", + "" + ) + ) + } + + test("it should selectively allow opt-out from the error") { + val deps = Vector(`scala2.13.3`, `http4s0.21.11`, `cats-effect3.0.0-M4`) + val m = module(defaultModuleId, deps, Some("2.13.3")) + val report = ivyUpdate(m) + val overrideRules = List("org.typelevel" %% "cats-effect" % "always") + assert(EvictionError(report, m, overrideRules).incompatibleEvictions.isEmpty) + } + + test("it should selectively allow opt-out from the error despite assumed scheme") { + val deps = Vector(`scala2.12.17`, `akkaActor2.6.0`, `swagger-akka-http1.4.0`) + val m = module(defaultModuleId, deps, Some("2.12.17")) + val report = ivyUpdate(m) + val overrideRules = List("org.scala-lang.modules" %% "scala-java8-compat" % "always") + assert( + EvictionError( + report = report, + module = m, + schemes = overrideRules, + assumedVersionScheme = "early-semver", + assumedVersionSchemeJava = "always", + assumedEvictionErrorLevel = Level.Error, + ).assumedIncompatibleEvictions.isEmpty + ) + } + + // older Akka was on pvp + def oldAkkaPvp = List("com.typesafe.akka" % "*" % "pvp") + + lazy val `akkaActor2.1.4` = + ModuleID("com.typesafe.akka", "akka-actor", "2.1.4").withConfigurations( + Some("compile") + ) cross CrossVersion.binary + lazy val `akkaActor2.3.0` = + ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations( + Some("compile") + ) cross CrossVersion.binary + lazy val `akkaActor2.6.0` = + ModuleID("com.typesafe.akka", "akka-actor", "2.6.0").withConfigurations( + Some("compile") + ) cross CrossVersion.binary + lazy val `scala2.10.4` = + ModuleID("org.scala-lang", "scala-library", "2.10.4").withConfigurations(Some("compile")) + lazy val `scala2.12.17` = + ModuleID("org.scala-lang", "scala-library", "2.12.17").withConfigurations(Some("compile")) + lazy val `scala2.13.3` = + ModuleID("org.scala-lang", "scala-library", "2.13.3").withConfigurations(Some("compile")) + lazy val `bananaSesame0.4` = + ModuleID("org.w3", "banana-sesame", "0.4").withConfigurations( + Some("compile") + ) cross CrossVersion.binary // uses akka-actor 2.1.4 + lazy val `akkaRemote2.3.4` = + ModuleID("com.typesafe.akka", "akka-remote", "2.3.4").withConfigurations( + Some("compile") + ) cross CrossVersion.binary // uses akka-actor 2.3.4 + lazy val `http4s0.21.11` = + ("org.http4s" %% "http4s-blaze-server" % "0.21.11").withConfigurations(Some("compile")) + // https://repo1.maven.org/maven2/org/typelevel/cats-effect_2.13/3.0.0-M4/cats-effect_2.13-3.0.0-M4.pom + // is published with early-semver + lazy val `cats-effect3.0.0-M4` = + ("org.typelevel" %% "cats-effect" % "3.0.0-M4").withConfigurations(Some("compile")) + lazy val `cats-parse0.1.0` = + ("org.typelevel" %% "cats-parse" % "0.1.0").withConfigurations(Some("compile")) + lazy val `cats-parse0.2.0` = + ("org.typelevel" %% "cats-parse" % "0.2.0").withConfigurations(Some("compile")) + lazy val `swagger-akka-http1.4.0` = + ("com.github.swagger-akka-http" %% "swagger-akka-http" % "1.4.0") + .withConfigurations(Some("compile")) + + def dummyScalaModuleInfo(v: String): ScalaModuleInfo = + ScalaModuleInfo( + scalaFullVersion = v, + scalaBinaryVersion = CrossVersionUtil.binaryScalaVersion(v), + configurations = Vector.empty, + checkExplicit = true, + filterImplicit = false, + overrideScalaVersion = true + ) +} diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/EvictionWarningSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/EvictionWarningSpec.scala index 925bdb59..4f8ded23 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/EvictionWarningSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/EvictionWarningSpec.scala @@ -20,7 +20,11 @@ object EvictionWarningSpec extends BaseIvySpecification { 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 + EvictionWarning( + m, + fullOptions.withWarnScalaVersionEviction(false), + report + ).scalaEvictions.size == 0 ) } @@ -79,7 +83,11 @@ object EvictionWarningSpec extends BaseIvySpecification { val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2")) val report = ivyUpdate(m) assert( - EvictionWarning(m, fullOptions.withWarnScalaVersionEviction(false), report).scalaEvictions.size == 0 + EvictionWarning( + m, + fullOptions.withWarnScalaVersionEviction(false), + report + ).scalaEvictions.size == 0 ) } @@ -283,12 +291,36 @@ object EvictionWarningSpec extends BaseIvySpecification { ) } + test("Comparing 2.13 libraries with pvp under Scala 3.0.0-M3 should work") { + val m1 = "org.scodec" % "scodec-bits_2.13" % "1.1.21" + val m2 = "org.scodec" % "scodec-bits_2.13" % "1.1.22" + assert( + EvictionWarningOptions + .evalPvp((m1, Option(m2), Option(dummyScalaModuleInfo("3.0.0-M3")))) + ) + } + + test("Comparing 2.13 libraries with guessSecondSegment under Scala 3.0.0-M3 should work") { + val m1 = "org.scodec" % "scodec-bits_2.13" % "1.1.21" + val m2 = "org.scodec" % "scodec-bits_2.13" % "1.1.22" + assert( + EvictionWarningOptions + .guessSecondSegment((m1, Option(m2), Option(dummyScalaModuleInfo("3.0.0-M3")))) + ) + } + def akkaActor214 = - ModuleID("com.typesafe.akka", "akka-actor", "2.1.4").withConfigurations(Some("compile")) cross CrossVersion.binary + ModuleID("com.typesafe.akka", "akka-actor", "2.1.4").withConfigurations( + Some("compile") + ) cross CrossVersion.binary def akkaActor230 = - ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("compile")) cross CrossVersion.binary + ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations( + Some("compile") + ) cross CrossVersion.binary def akkaActor234 = - ModuleID("com.typesafe.akka", "akka-actor", "2.3.4").withConfigurations(Some("compile")) cross CrossVersion.binary + ModuleID("com.typesafe.akka", "akka-actor", "2.3.4").withConfigurations( + Some("compile") + ) cross CrossVersion.binary def scala2102 = ModuleID("org.scala-lang", "scala-library", "2.10.2").withConfigurations(Some("compile")) def scala2103 = @@ -299,13 +331,21 @@ object EvictionWarningSpec extends BaseIvySpecification { def commonsIo14 = ModuleID("commons-io", "commons-io", "1.4").withConfigurations(Some("compile")) def commonsIo24 = ModuleID("commons-io", "commons-io", "2.4").withConfigurations(Some("compile")) def bnfparser10 = - ModuleID("ca.gobits.bnf", "bnfparser", "1.0").withConfigurations(Some("compile")) // uses commons-io 2.4 + ModuleID("ca.gobits.bnf", "bnfparser", "1.0").withConfigurations( + Some("compile") + ) // uses commons-io 2.4 def unfilteredUploads080 = - ModuleID("net.databinder", "unfiltered-uploads", "0.8.0").withConfigurations(Some("compile")) cross CrossVersion.binary // uses commons-io 1.4 + ModuleID("net.databinder", "unfiltered-uploads", "0.8.0").withConfigurations( + Some("compile") + ) cross CrossVersion.binary // uses commons-io 1.4 def bananaSesame04 = - ModuleID("org.w3", "banana-sesame", "0.4").withConfigurations(Some("compile")) cross CrossVersion.binary // uses akka-actor 2.1.4 + ModuleID("org.w3", "banana-sesame", "0.4").withConfigurations( + Some("compile") + ) cross CrossVersion.binary // uses akka-actor 2.1.4 def akkaRemote234 = - ModuleID("com.typesafe.akka", "akka-remote", "2.3.4").withConfigurations(Some("compile")) cross CrossVersion.binary // uses akka-actor 2.3.4 + 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 def javaLibDirectDeps = Vector(commonsIo14, commonsIo24) diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/InconsistentDuplicateSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/InconsistentDuplicateSpec.scala index db934407..46e830c0 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/InconsistentDuplicateSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/InconsistentDuplicateSpec.scala @@ -24,9 +24,15 @@ object InconsistentDuplicateSpec extends BasicTestSuite { } def akkaActor214 = - ModuleID("com.typesafe.akka", "akka-actor", "2.1.4").withConfigurations(Some("compile")) cross CrossVersion.binary + ModuleID("com.typesafe.akka", "akka-actor", "2.1.4").withConfigurations( + Some("compile") + ) cross CrossVersion.binary def akkaActor230 = - ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("compile")) cross CrossVersion.binary + ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations( + Some("compile") + ) cross CrossVersion.binary def akkaActor230Test = - ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("test")) cross CrossVersion.binary + ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations( + Some("test") + ) cross CrossVersion.binary } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/IvyModuleSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/IvyModuleSpec.scala new file mode 100644 index 00000000..ac947491 --- /dev/null +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/IvyModuleSpec.scala @@ -0,0 +1,38 @@ +package sbt.internal.librarymanagement + +import sbt.internal.librarymanagement.mavenint.PomExtraDependencyAttributes.{ + SbtVersionKey, + ScalaVersionKey +} +import sbt.librarymanagement.{ CrossVersion, ModuleDescriptorConfiguration } + +object IvyModuleSpec extends BaseIvySpecification { + + test("The Scala binary version of a Scala module should be appended to its name") { + val m = module( + defaultModuleId.withCrossVersion(CrossVersion.Binary()), + Vector.empty, + Some("2.13.10") + ) + m.moduleSettings match { + case configuration: ModuleDescriptorConfiguration => + assert(configuration.module.name == "foo_2.13") + case _ => fail() + } + } + + test("The sbt cross-version should be appended to the name of an sbt plugin") { + val m = module( + defaultModuleId.extra(SbtVersionKey -> "1.0", ScalaVersionKey -> "2.12"), + Vector.empty, + Some("2.12.17"), + appendSbtCrossVersion = true + ) + m.moduleSettings match { + case configuration: ModuleDescriptorConfiguration => + assert(configuration.module.name == "foo_2.12_1.0") + case _ => fail() + } + } + +} diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala index 97515d9e..c3235b93 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala @@ -17,7 +17,7 @@ object IvyRepoSpec extends BaseIvySpecification { module( ourModuleID, Vector(dep), - None //, UpdateOptions().withCachedResolution(true) + None // , UpdateOptions().withCachedResolution(true) ) } @@ -31,13 +31,11 @@ object IvyRepoSpec extends BaseIvySpecification { val report = ivyUpdate(m) import Inside._ - inside(report.configuration(ConfigRef("compile")).map(_.modules)) { - case Some(Seq(mr)) => - inside(mr.artifacts) { - case Seq((ar, _)) => - assert(ar.`type` == "jar") - assert(ar.extension == "jar") - } + inside(report.configuration(ConfigRef("compile")).map(_.modules)) { case Some(Seq(mr)) => + inside(mr.artifacts) { case Seq((ar, _)) => + assert(ar.`type` == "jar") + assert(ar.extension == "jar") + } } } @@ -90,14 +88,12 @@ object IvyRepoSpec extends BaseIvySpecification { .get import Inside._ - inside(report2.configuration(ConfigRef("compile")).map(_.modules)) { - case Some(Seq(mr)) => - inside(mr.artifacts) { - case Seq((ar, _)) => - assert(ar.name == "libmodule-source") - assert(ar.`type` == "src") - assert(ar.extension == "jar") - } + inside(report2.configuration(ConfigRef("compile")).map(_.modules)) { case Some(Seq(mr)) => + inside(mr.artifacts) { case Seq((ar, _)) => + assert(ar.name == "libmodule-source") + assert(ar.`type` == "src") + assert(ar.extension == "jar") + } } } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/IvyUtilSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/IvyUtilSpec.scala index 6924d739..7b000ae4 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/IvyUtilSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/IvyUtilSpec.scala @@ -2,10 +2,10 @@ package sbt.internal.librarymanagement import java.io.IOException -import org.scalatest.FunSuite +import org.scalatest.funsuite.AnyFunSuite import sbt.internal.librarymanagement.IvyUtil._ -class IvyUtilSpec extends FunSuite { +class IvyUtilSpec extends AnyFunSuite { test("503 should be a TransientNetworkException") { val statusCode503Exception = new IOException("Server returned HTTP response code: 503 for URL:") diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/MakePomSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/MakePomSpec.scala index 30c36e09..6b3aafd1 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/MakePomSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/MakePomSpec.scala @@ -1,6 +1,7 @@ package sbt.internal.librarymanagement import sbt.internal.util.ConsoleLogger +import sbt.librarymanagement.MavenRepository import verify.BasicTestSuite // http://ant.apache.org/ivy/history/2.3.0/ivyfile/dependency.html @@ -74,6 +75,18 @@ object MakePomSpec extends BasicTestSuite { beParsedAsError("foo+") } + test("repository id should not contain maven illegal repo id characters") { + val repository = mp.mavenRepository( + MavenRepository( + """repository-id-\with-/illegal:"<-chars>|?*-others~!@#$%^&`';{}[]=+_,.""", + "uri" + ) + ) + assert( + (repository \ "id").text == "repository-id-with-illegal-chars-others~!@#$%^&`';{}[]=+_,." + ) + } + val mp = new MakePom(ConsoleLogger()) def convertTo(s: String, expected: String): Unit = { assert(MakePom.makeDependencyVersion(s) == expected) diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/ManagedChecksumsSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/ManagedChecksumsSpec.scala index e9e133d4..b49c34b7 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/ManagedChecksumsSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/ManagedChecksumsSpec.scala @@ -1,7 +1,5 @@ package sbt.internal.librarymanagement -import java.io.File - import org.apache.ivy.util.Message import sbt.librarymanagement._ import sbt.librarymanagement.ivy._ diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/MergeDescriptorSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/MergeDescriptorSpec.scala index 89840222..78061309 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/MergeDescriptorSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/MergeDescriptorSpec.scala @@ -14,20 +14,19 @@ object MergeDescriptorSpec extends BaseIvySpecification { None, UpdateOptions() ) - m.withModule(log) { - case (_, md, _) => - val deps = md.getDependencies - assert(deps.size == 1) - deps.headOption.getOrElse(sys.error("Dependencies not found")) match { - case dd @ MergedDescriptors(_, _) => - val arts = dd.getAllDependencyArtifacts - val a0: DependencyArtifactDescriptor = arts.toList(0) - val a1: DependencyArtifactDescriptor = arts.toList(1) - val configs0 = a0.getConfigurations.toList - val configs1 = a1.getConfigurations.toList - assert(configs0 == List("compile")) - assert(configs1 == List("test")) - } + m.withModule(log) { case (_, md, _) => + val deps = md.getDependencies + assert(deps.size == 1) + deps.headOption.getOrElse(sys.error("Dependencies not found")) match { + case dd @ MergedDescriptors(_, _) => + val arts = dd.getAllDependencyArtifacts + val a0: DependencyArtifactDescriptor = arts.toList(0) + val a1: DependencyArtifactDescriptor = arts.toList(1) + val configs0 = a0.getConfigurations.toList + val configs1 = a1.getConfigurations.toList + assert(configs0 == List("compile")) + assert(configs1 == List("test")) + } } } def guavaTest = diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/ResolverSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/ResolverSpec.scala index 92cb9fa3..6e7816ae 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/ResolverSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/ResolverSpec.scala @@ -1,13 +1,13 @@ package sbttest -import java.net.URL +import java.net.URI import sbt.librarymanagement._ import sbt.librarymanagement.syntax._ import verify.BasicTestSuite class ResolverSpec extends BasicTestSuite { test("Resolver.url") { - Resolver.url("Test Repo", new URL("http://example.com/"))(Resolver.ivyStylePatterns) + Resolver.url("Test Repo", new URI("http://example.com/").toURL)(Resolver.ivyStylePatterns) () } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/ScalaOverrideTest.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/ScalaOverrideTest.scala index d9ed46cf..37a82432 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/ScalaOverrideTest.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/ScalaOverrideTest.scala @@ -11,10 +11,13 @@ import verify.BasicTestSuite object ScalaOverrideTest extends BasicTestSuite { val OtherOrgID = "other.org" - def check(org0: String, version0: String)(org1: String, name1: String, version1: String) = { - val scalaConfigs = Configurations.default.toVector filter { Configurations.underScalaVersion } map { - _.name - } + private val scalaConfigs = + Configurations.default.filter(Configurations.underScalaVersion).map(_.name) + + def checkOrgAndVersion( + org0: String, + version0: String + )(org1: String, name1: String, version1: String): Unit = { val osm = new OverrideScalaMediator(org0, version0, scalaConfigs) val mrid = ModuleRevisionId.newInstance(org1, name1, version1) @@ -25,8 +28,36 @@ object ScalaOverrideTest extends BasicTestSuite { assert(res.getDependencyRevisionId == ModuleRevisionId.newInstance(org0, name1, version0)) } - test("""OverrideScalaMediator should override compiler version""") { - check(Organization, "2.11.8")( + def checkOnlyOrg( + org0: String, + version0: String + )(org1: String, name1: String, version1: String): Unit = { + val osm = new OverrideScalaMediator(org0, version0, scalaConfigs) + + val mrid = ModuleRevisionId.newInstance(org1, name1, version1) + val dd = new DefaultDependencyDescriptor(mrid, false) + dd.addDependencyConfiguration("compile", "compile") + + val res = osm.mediate(dd) + assert(res.getDependencyRevisionId == ModuleRevisionId.newInstance(org0, name1, version1)) + } + + def checkNoOverride( + org0: String, + version0: String + )(org1: String, name1: String, version1: String): Unit = { + val osm = new OverrideScalaMediator(org0, version0, scalaConfigs) + + val mrid = ModuleRevisionId.newInstance(org1, name1, version1) + val dd = new DefaultDependencyDescriptor(mrid, false) + dd.addDependencyConfiguration("compile", "compile") + + val res = osm.mediate(dd) + assert(res.getDependencyRevisionId == mrid) + } + + test("OverrideScalaMediator should override compiler version") { + checkOrgAndVersion(Organization, "2.11.8")( Organization, CompilerID, "2.11.9" @@ -34,7 +65,7 @@ object ScalaOverrideTest extends BasicTestSuite { } test("it should override library version") { - check(Organization, "2.11.8")( + checkOrgAndVersion(Organization, "2.11.8")( Organization, LibraryID, "2.11.8" @@ -42,7 +73,7 @@ object ScalaOverrideTest extends BasicTestSuite { } test("it should override reflect version") { - check(Organization, "2.11.8")( + checkOrgAndVersion(Organization, "2.11.8")( Organization, ReflectID, "2.11.7" @@ -50,7 +81,7 @@ object ScalaOverrideTest extends BasicTestSuite { } test("it should override actors version") { - check(Organization, "2.11.8")( + checkOrgAndVersion(Organization, "2.11.8")( Organization, ActorsID, "2.11.6" @@ -58,7 +89,7 @@ object ScalaOverrideTest extends BasicTestSuite { } test("it should override scalap version") { - check(Organization, "2.11.8")( + checkOrgAndVersion(Organization, "2.11.8")( Organization, ScalapID, "2.11.5" @@ -66,7 +97,7 @@ object ScalaOverrideTest extends BasicTestSuite { } test("it should override default compiler organization") { - check(OtherOrgID, "2.11.8")( + checkOrgAndVersion(OtherOrgID, "2.11.8")( Organization, CompilerID, "2.11.9" @@ -74,7 +105,7 @@ object ScalaOverrideTest extends BasicTestSuite { } test("it should override default library organization") { - check(OtherOrgID, "2.11.8")( + checkOrgAndVersion(OtherOrgID, "2.11.8")( Organization, LibraryID, "2.11.8" @@ -82,7 +113,7 @@ object ScalaOverrideTest extends BasicTestSuite { } test("it should override default reflect organization") { - check(OtherOrgID, "2.11.8")( + checkOrgAndVersion(OtherOrgID, "2.11.8")( Organization, ReflectID, "2.11.7" @@ -90,7 +121,7 @@ object ScalaOverrideTest extends BasicTestSuite { } test("it should override default actors organization") { - check(OtherOrgID, "2.11.8")( + checkOrgAndVersion(OtherOrgID, "2.11.8")( Organization, ActorsID, "2.11.6" @@ -98,7 +129,7 @@ object ScalaOverrideTest extends BasicTestSuite { } test("it should override default scalap organization") { - check(OtherOrgID, "2.11.8")( + checkOrgAndVersion(OtherOrgID, "2.11.8")( Organization, ScalapID, "2.11.5" @@ -106,7 +137,7 @@ object ScalaOverrideTest extends BasicTestSuite { } test("it should override custom compiler organization") { - check(Organization, "2.11.8")( + checkOrgAndVersion(Organization, "2.11.8")( OtherOrgID, CompilerID, "2.11.9" @@ -114,7 +145,7 @@ object ScalaOverrideTest extends BasicTestSuite { } test("it should override custom library organization") { - check(Organization, "2.11.8")( + checkOrgAndVersion(Organization, "2.11.8")( OtherOrgID, LibraryID, "2.11.8" @@ -122,7 +153,7 @@ object ScalaOverrideTest extends BasicTestSuite { } test("it should override custom reflect organization") { - check(Organization, "2.11.8")( + checkOrgAndVersion(Organization, "2.11.8")( OtherOrgID, ReflectID, "2.11.7" @@ -130,7 +161,7 @@ object ScalaOverrideTest extends BasicTestSuite { } test("it should override custom actors organization") { - check(Organization, "2.11.8")( + checkOrgAndVersion(Organization, "2.11.8")( OtherOrgID, ActorsID, "2.11.6" @@ -138,10 +169,106 @@ object ScalaOverrideTest extends BasicTestSuite { } test("it should override custom scalap organization") { - check(Organization, "2.11.8")( + checkOrgAndVersion(Organization, "2.11.8")( OtherOrgID, ScalapID, "2.11.5" ) } + + test("it should override Scala 3 compiler version") { + checkOrgAndVersion(Organization, "3.1.0")( + Organization, + Scala3CompilerPrefix + "3", + "3.0.0" + ) + } + + test("it should override Scala 3 library version") { + checkOrgAndVersion(Organization, "3.1.0")( + Organization, + Scala3LibraryPrefix + "3", + "3.0.0" + ) + } + + test("it should override Scala 3 interfaces version") { + checkOrgAndVersion(Organization, "3.1.0")( + Organization, + Scala3InterfacesID, + "3.0.0" + ) + } + + test("it should override TASTy core version") { + checkOrgAndVersion(Organization, "3.1.0")( + Organization, + TastyCorePrefix + "3", + "3.0.0" + ) + } + + test("it should not override Scala 2 library version when using Scala 3") { + checkNoOverride(Organization, "3.1.0")( + Organization, + LibraryID, + "2.13.4" + ) + } + + test("it should not override TASTy core version when using Scala 2") { + checkNoOverride(Organization, "2.13.4")( + Organization, + TastyCorePrefix + "3", + "3.0.0" + ) + } + + test("it should override default Scala 3 compiler organization") { + checkOrgAndVersion(OtherOrgID, "3.1.0")( + Organization, + Scala3CompilerPrefix + "3", + "3.0.0" + ) + } + + test("it should override default Scala 3 library organization") { + checkOrgAndVersion(OtherOrgID, "3.1.0")( + Organization, + Scala3LibraryPrefix + "3", + "3.0.0" + ) + } + + test("it should override default Scala 3 interfaces organization") { + checkOrgAndVersion(OtherOrgID, "3.1.0")( + Organization, + Scala3InterfacesID, + "3.0.0" + ) + } + + test("it should override default Scala 3 TASTy core organization") { + checkOrgAndVersion(OtherOrgID, "3.1.0")( + Organization, + TastyCorePrefix + "3", + "3.0.0" + ) + } + + test("it should override default Scala 2 library organization when in Scala 3") { + checkOnlyOrg(OtherOrgID, "3.1.0")( + Organization, + LibraryID, + "2.13.4" + ) + } + + test("it should override default TASTy core organization when in Scala 2") { + checkOnlyOrg(OtherOrgID, "2.13.4")( + Organization, + TastyCorePrefix + "3", + "3.0.0" + ) + } } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/SftpRepoSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/SftpRepoSpec.scala index 2bf13668..c131e290 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/SftpRepoSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/SftpRepoSpec.scala @@ -13,7 +13,7 @@ import java.nio.file.Paths 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 + // a dependency which depends on another in the repo def org(repo: String) = s"com.${repo}" def module(org: String) = org % "some-lib" % "version" diff --git a/project/DatatypeConfig.scala b/project/DatatypeConfig.scala index e8749260..38807b39 100644 --- a/project/DatatypeConfig.scala +++ b/project/DatatypeConfig.scala @@ -49,9 +49,15 @@ object DatatypeConfig { "sbt.librarymanagement.ConstantFormats" :: "sbt.librarymanagement.PatchFormats" :: "sbt.librarymanagement.FullFormats" :: + "sbt.librarymanagement.For3Use2_13Formats" :: + "sbt.librarymanagement.For2_13Use3Formats" :: Nil } + case "sbt.librarymanagement.ConfigRef" => { _ => + "sbt.librarymanagement.ConfigRefFormats" :: Nil + } + // TODO: These are handled by BasicJsonProtocol, and sbt-datatype should handle them by default, imo case "Option" | "Set" | "scala.Vector" => { tpe => getFormats(oneArg(tpe)) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index f4dc77eb..f4418802 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -3,13 +3,14 @@ import Keys._ import sbt.contraband.ContrabandPlugin.autoImport._ object Dependencies { - val scala212 = "2.12.10" + val scala212 = "2.12.18" + val scala213 = "2.13.10" def nightlyVersion: Option[String] = sys.env.get("BUILD_VERSION") orElse sys.props.get("sbt.build.version") - private val ioVersion = nightlyVersion.getOrElse("1.4.0") - private val utilVersion = nightlyVersion.getOrElse("1.4.0") + private val ioVersion = nightlyVersion.getOrElse("1.9.1") + private val utilVersion = nightlyVersion.getOrElse("1.9.1") private val sbtIO = "org.scala-sbt" %% "io" % ioVersion @@ -42,7 +43,7 @@ object Dependencies { def addSbtUtilCache(p: Project): Project = addSbtModule(p, sbtUtilPath, "utilCache", utilCache) val launcherInterface = "org.scala-sbt" % "launcher-interface" % "1.0.0" - val ivy = "org.scala-sbt.ivy" % "ivy" % "2.3.0-sbt-839fad1cdc07cf6fc81364d74c323867230432ad" + val ivy = "org.scala-sbt.ivy" % "ivy" % "2.3.0-sbt-396a783bba347016e7fe30dacc60d355be607fe2" val sbtV = "1.0" val scalaV = "2.12" @@ -50,9 +51,9 @@ object Dependencies { val jsch = "com.jcraft" % "jsch" % "0.1.54" intransitive () val scalaReflect = Def.setting { "org.scala-lang" % "scala-reflect" % scalaVersion.value } 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 scalaXml = "org.scala-lang.modules" %% "scala-xml" % "2.1.0" + val scalaTest = "org.scalatest" %% "scalatest" % "3.2.0" + val scalaVerify = "com.eed3si9n.verify" %% "verify" % "1.0.0" val scalaCheck = "org.scalacheck" %% "scalacheck" % "1.14.0" val sjsonnew = Def.setting { "com.eed3si9n" %% "sjson-new-core" % contrabandSjsonNewVersion.value @@ -60,7 +61,5 @@ object Dependencies { val sjsonnewScalaJson = Def.setting { "com.eed3si9n" %% "sjson-new-scalajson" % contrabandSjsonNewVersion.value } - 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" + val gigahorseApacheHttp = "com.eed3si9n" %% "gigahorse-apache-http" % "0.7.0" } diff --git a/project/HouseRulesPlugin.scala b/project/HouseRulesPlugin.scala index f204ee31..3d29c00d 100644 --- a/project/HouseRulesPlugin.scala +++ b/project/HouseRulesPlugin.scala @@ -2,24 +2,14 @@ package lmbuild import sbt._ import Keys._ -import bintray.BintrayPlugin -import bintray.BintrayPlugin.autoImport._ object HouseRulesPlugin extends AutoPlugin { - override def requires = plugins.JvmPlugin && BintrayPlugin + override def requires = plugins.JvmPlugin override def trigger = allRequirements - override def buildSettings: Seq[Def.Setting[_]] = baseBuildSettings override def projectSettings: Seq[Def.Setting[_]] = baseSettings - lazy val baseBuildSettings: Seq[Def.Setting[_]] = Seq( - bintrayOrganization := Some("sbt"), - bintrayRepository := sys.env.get("BINTRAY_REPOSITORY").getOrElse("maven-releases"), - ) - lazy val baseSettings: Seq[Def.Setting[_]] = Seq( - bintrayPackage := (ThisBuild / bintrayPackage).value, - bintrayRepository := (ThisBuild / bintrayRepository).value, scalacOptions ++= Seq("-encoding", "utf8"), scalacOptions ++= Seq("-deprecation", "-feature", "-unchecked", "-Xlint"), scalacOptions += "-language:higherKinds", @@ -41,8 +31,8 @@ object HouseRulesPlugin extends AutoPlugin { scalacOptions += "-Ywarn-numeric-widen", scalacOptions += "-Ywarn-value-discard", scalacOptions ++= "-Ywarn-unused-import".ifScala(v => 11 <= v && v <= 12).value.toList - ) ++ Seq(Compile, Test).flatMap( - c => scalacOptions in (c, console) --= Seq("-Ywarn-unused-import", "-Xlint") + ) ++ Seq(Compile, Test).flatMap(c => + (c / console / scalacOptions) --= Seq("-Ywarn-unused-import", "-Xlint") ) private def scalaPartV = Def setting (CrossVersion partialVersion scalaVersion.value) diff --git a/project/Util.scala b/project/Util.scala index 172b3642..88517e66 100644 --- a/project/Util.scala +++ b/project/Util.scala @@ -30,7 +30,9 @@ object Util { val f = dir / "xsbt.version.properties" // TODO: replace lastModified() with sbt.io.IO.getModifiedTimeOrZero(), once the build // has been upgraded to a version of sbt that includes that call. - if (!f.exists || f.lastModified < lastCompilationTime(analysis) || !containsVersion(f, version)) { + if ( + !f.exists || f.lastModified < lastCompilationTime(analysis) || !containsVersion(f, version) + ) { s.log.info("Writing version information to " + f + " :\n" + content) IO.write(f, content) } diff --git a/project/build.properties b/project/build.properties index c19c768d..52413ab7 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.4.2 +sbt.version=1.9.3 diff --git a/project/plugins.sbt b/project/plugins.sbt index f2c5eaec..279b64f1 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,9 +1,7 @@ addSbtPlugin("com.dwijnand" % "sbt-dynver" % "4.0.0") -addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.6") -addSbtPlugin("com.jsuereth" % "sbt-pgp" % "2.0.1") -addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.6.1") +addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2") +addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.8.1") addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.0.2") -addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.5.0") -addSbtPlugin("com.lightbend" % "sbt-whitesource" % "0.1.14") +addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.5.1") scalacOptions += "-language:postfixOps"