diff --git a/ivy/src/main/scala/sbt/MakePom.scala b/ivy/src/main/scala/sbt/MakePom.scala index ee238371c..e05221b43 100644 --- a/ivy/src/main/scala/sbt/MakePom.scala +++ b/ivy/src/main/scala/sbt/MakePom.scala @@ -196,6 +196,7 @@ class MakePom(val log: Logger) { } + /** Converts Ivy revision ranges to that of Maven POM */ def makeDependencyVersion(revision: String): String = { def plusRange(s: String, shift: Int = 0) = { def pow(i: Int): Int = if (i > 0) 10 * pow(i - 1) else 1 @@ -209,20 +210,26 @@ class MakePom(val log: Logger) { } val startSym = Set(']', '[', '(') val stopSym = Set(']', '[', ')') + val DotPlusPattern = """(.+)\.\+""".r + val DotNumPlusPattern = """(.+)\.(\d+)\+""".r + val NumPlusPattern = """(\d+)\+""".r + val maxDigit = 5 try { - if (revision endsWith ".+") { - plusRange(revision.substring(0, revision.length - 2)) - } else if (revision endsWith "+") { - val base = revision.take(revision.length - 1) + revision match { + case "+" => "[0,)" + case DotPlusPattern(base) => plusRange(base) // This is a heuristic. Maven just doesn't support Ivy's notions of 1+, so // we assume version ranges never go beyond 5 siginificant digits. - (0 to 5).map(plusRange(base, _)).mkString(",") - } else if (startSym(revision(0)) && stopSym(revision(revision.length - 1))) { - val start = revision(0) - val stop = revision(revision.length - 1) - val mid = revision.substring(1, revision.length - 1) - (if (start == ']') "(" else start) + mid + (if (stop == '[') ")" else stop) - } else revision + case NumPlusPattern(tail) => (0 until maxDigit).map(plusRange(tail, _)).mkString(",") + case DotNumPlusPattern(base, tail) => (0 until maxDigit).map(plusRange(base + "." + tail, _)).mkString(",") + case rev if rev endsWith "+" => sys.error(s"dynamic revision '$rev' cannot be translated to POM") + case rev if startSym(rev(0)) && stopSym(rev(rev.length - 1)) => + 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) + case _ => revision + } } catch { case e: NumberFormatException => // TODO - if the version doesn't meet our expectations, maybe we just issue a hard diff --git a/ivy/src/test/scala/MakePomSpec.scala b/ivy/src/test/scala/MakePomSpec.scala new file mode 100644 index 000000000..3310ed62b --- /dev/null +++ b/ivy/src/test/scala/MakePomSpec.scala @@ -0,0 +1,73 @@ +package sbt + +import java.io.File +import org.specs2._ + +// http://ant.apache.org/ivy/history/2.3.0/ivyfile/dependency.html +// http://maven.apache.org/enforcer/enforcer-rules/versionRanges.html +class MakePomSpec extends Specification { + def is = s2""" + + This is a specification to check the Ivy revision number conversion to pom. + + 1.0 should + ${convertTo("1.0", "1.0")} + + [1.0,2.0] should + ${convertTo("[1.0,2.0]", "[1.0,2.0]")} + + [1.0,2.0[ should + ${convertTo("[1.0,2.0[", "[1.0,2.0)")} + + ]1.0,2.0] should + ${convertTo("]1.0,2.0]", "(1.0,2.0]")} + + ]1.0,2.0[ should + ${convertTo("]1.0,2.0[", "(1.0,2.0)")} + + [1.0,) should + ${convertTo("[1.0,)", "[1.0,)")} + + ]1.0,) should + ${convertTo("]1.0,)", "(1.0,)")} + + (,2.0] should + ${convertTo("(,2.0]", "(,2.0]")} + + (,2.0[ should + ${convertTo("(,2.0[", "(,2.0)")} + + 1.+ should + ${convertTo("1.+", "[1,2)")} + + 1.2.3.4.+ should + ${convertTo("1.2.3.4.+", "[1.2.3.4,1.2.3.5)")} + + 12.31.42.+ should + ${convertTo("12.31.42.+", "[12.31.42,12.31.43)")} + + 1.1+ should + ${convertTo("1.1+", "[1.1,1.2),[1.10,1.20),[1.100,1.200),[1.1000,1.2000),[1.10000,1.20000)")} + + 1+ should + ${convertTo("1+", "[1,2),[10,20),[100,200),[1000,2000),[10000,20000)")} + + + should + ${convertTo("+", "[0,)")} + + foo+ should + ${beParsedAsError("foo+")} + """ + + val mp = new MakePom(ConsoleLogger()) + def convertTo(s: String, expected: String) = + mp.makeDependencyVersion(s) must_== expected + def beParsedAsError(s: String) = + try { + mp.makeDependencyVersion(s) + failure + } catch { + case e: Throwable => success + } +} + diff --git a/ivy/src/test/scala/MakePomTest.scala b/ivy/src/test/scala/MakePomTest.scala deleted file mode 100644 index c96d2102e..000000000 --- a/ivy/src/test/scala/MakePomTest.scala +++ /dev/null @@ -1,28 +0,0 @@ -package sbt - -import java.io.File -import org.specs2._ -import mutable.Specification - -object MakePomTest extends Specification { - val mp = new MakePom(ConsoleLogger()) - import mp.{ makeDependencyVersion => v } - "MakePom makeDependencyVersion" should { - "Handle .+ in versions" in { - v("1.+") must_== "[1,2)" - v("1.2.3.4.+") must_== "[1.2.3.4,1.2.3.5)" - v("12.31.42.+") must_== "[12.31.42,12.31.43)" - } - /* TODO - do we care about this case? - * 1+ --> [1,2),[10,20),[100,200),[1000,2000),[10000,20000),[100000,200000) - */ - "Handle ]* bracket in version ranges" in { - v("]1,3]") must_== "(1,3]" - v("]1.1,1.3]") must_== "(1.1,1.3]" - } - "Handle *[ bracket in version ranges" in { - v("[1,3[") must_== "[1,3)" - v("[1.1,1.3[") must_== "[1.1,1.3)" - } - } -}