From 2b1806ae2511015a89539aacb0c4afc2d2064a04 Mon Sep 17 00:00:00 2001 From: Adrien Piquerez Date: Fri, 8 Jan 2021 18:06:49 +0100 Subject: [PATCH] Add for3Use2_13 and for2_13Use3 --- .../LibraryManagementCodec.scala | 2 + .../sbt/librarymanagement/CrossVersion.scala | 140 +++++++++++++++++- .../librarymanagement/CrossVersionExtra.scala | 40 +++++ .../librarymanagement/CrossVersionTest.scala | 25 ++++ .../DMSerializationSpec.scala | 8 + project/DatatypeConfig.scala | 2 + 6 files changed, 214 insertions(+), 3 deletions(-) diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/LibraryManagementCodec.scala b/core/src/main/contraband-scala/sbt/librarymanagement/LibraryManagementCodec.scala index 06f3bfa22..fc918b42b 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/LibraryManagementCodec.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/LibraryManagementCodec.scala @@ -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/scala/sbt/librarymanagement/CrossVersion.scala b/core/src/main/scala/sbt/librarymanagement/CrossVersion.scala index 4ab1b6446..e447cb6a7 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 43a46073f..6e8ff00d6 100644 --- a/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala @@ -17,10 +17,14 @@ private[librarymanagement] abstract class CrossVersionFunctions { final val Constant = sbt.librarymanagement.Constant final val Full = sbt.librarymanagement.Full final val Patch = sbt.librarymanagement.Patch + final val For3Use2_13 = sbt.librarymanagement.For3Use2_13 + final val For2_13Use3 = sbt.librarymanagement.For2_13Use3 type Binary = sbt.librarymanagement.Binary type Constant = sbt.librarymanagement.Constant type Full = sbt.librarymanagement.Full type Patch = sbt.librarymanagement.Patch + type For3Use2_13 = sbt.librarymanagement.For3Use2_13 + type For2_13Use3 = sbt.librarymanagement.For2_13Use3 /** The first `major.minor` Scala version that the Scala binary version should be used for cross-versioning instead of the full version. */ val TransitionScalaVersion = CrossVersionUtil.TransitionScalaVersion @@ -57,6 +61,32 @@ 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 patchFun(fullVersion: String): String = { val BinCompatV = """(\d+)\.(\d+)\.(\d+)(-\w+)??-bin(-.*)?""".r fullVersion match { @@ -83,6 +113,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. */ diff --git a/core/src/test/scala/sbt/librarymanagement/CrossVersionTest.scala b/core/src/test/scala/sbt/librarymanagement/CrossVersionTest.scala index 5864a4012..8f8f0e5b1 100644 --- a/core/src/test/scala/sbt/librarymanagement/CrossVersionTest.scala +++ b/core/src/test/scala/sbt/librarymanagement/CrossVersionTest.scala @@ -279,4 +279,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/ivy/src/test/scala/sbt/internal/librarymanagement/DMSerializationSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/DMSerializationSpec.scala index 8ffd3ed1f..86cf43322 100644 --- a/ivy/src/test/scala/sbt/internal/librarymanagement/DMSerializationSpec.scala +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/DMSerializationSpec.scala @@ -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) } diff --git a/project/DatatypeConfig.scala b/project/DatatypeConfig.scala index e87492601..dbd1ba8ce 100644 --- a/project/DatatypeConfig.scala +++ b/project/DatatypeConfig.scala @@ -49,6 +49,8 @@ object DatatypeConfig { "sbt.librarymanagement.ConstantFormats" :: "sbt.librarymanagement.PatchFormats" :: "sbt.librarymanagement.FullFormats" :: + "sbt.librarymanagement.For3Use2_13Formats" :: + "sbt.librarymanagement.For2_13Use3Formats" :: Nil }