mirror of https://github.com/sbt/sbt.git
Add support for version ranges for sbt plugins from Maven repositories
These seem to lack some maven-metadata.xml files, so require specific handling
This commit is contained in:
parent
b7e361fe5d
commit
f57977dcd4
|
|
@ -76,14 +76,11 @@ final case class MavenRepository(
|
||||||
val root0 = if (root.endsWith("/")) root else root + "/"
|
val root0 = if (root.endsWith("/")) root else root + "/"
|
||||||
val source = MavenSource(root0, changing, sbtAttrStub, authentication)
|
val source = MavenSource(root0, changing, sbtAttrStub, authentication)
|
||||||
|
|
||||||
private def modulePath(
|
private def modulePath(module: Module): Seq[String] =
|
||||||
module: Module,
|
module.organization.split('.').toSeq :+ dirModuleName(module, sbtAttrStub)
|
||||||
version: String
|
|
||||||
): Seq[String] =
|
private def moduleVersionPath(module: Module, version: String): Seq[String] =
|
||||||
module.organization.split('.').toSeq ++ Seq(
|
modulePath(module) :+ version
|
||||||
dirModuleName(module, sbtAttrStub),
|
|
||||||
version
|
|
||||||
)
|
|
||||||
|
|
||||||
private def urlFor(path: Seq[String]): String =
|
private def urlFor(path: Seq[String]): String =
|
||||||
root0 + path.map(encodeURIComponent).mkString("/")
|
root0 + path.map(encodeURIComponent).mkString("/")
|
||||||
|
|
@ -94,7 +91,7 @@ final case class MavenRepository(
|
||||||
versioningValue: Option[String]
|
versioningValue: Option[String]
|
||||||
): Artifact = {
|
): Artifact = {
|
||||||
|
|
||||||
val path = modulePath(module, version) :+
|
val path = moduleVersionPath(module, version) :+
|
||||||
s"${module.name}-${versioningValue getOrElse version}.pom"
|
s"${module.name}-${versioningValue getOrElse version}.pom"
|
||||||
|
|
||||||
Artifact(
|
Artifact(
|
||||||
|
|
@ -136,7 +133,7 @@ final case class MavenRepository(
|
||||||
version: String
|
version: String
|
||||||
): Option[Artifact] = {
|
): Option[Artifact] = {
|
||||||
|
|
||||||
val path = modulePath(module, version) :+ "maven-metadata.xml"
|
val path = moduleVersionPath(module, version) :+ "maven-metadata.xml"
|
||||||
|
|
||||||
val artifact =
|
val artifact =
|
||||||
Artifact(
|
Artifact(
|
||||||
|
|
@ -153,6 +150,52 @@ final case class MavenRepository(
|
||||||
Some(artifact)
|
Some(artifact)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def versionsFromListing[F[_]](
|
||||||
|
module: Module,
|
||||||
|
fetch: Fetch.Content[F]
|
||||||
|
)(implicit
|
||||||
|
F: Monad[F]
|
||||||
|
): EitherT[F, String, Versions] = {
|
||||||
|
|
||||||
|
val listingUrl = urlFor(modulePath(module)) + "/"
|
||||||
|
|
||||||
|
// version listing -> changing (changes as new versions are released)
|
||||||
|
val listingArtifact = artifactFor(listingUrl, changing = true)
|
||||||
|
|
||||||
|
fetch(listingArtifact).flatMap { listing =>
|
||||||
|
|
||||||
|
val files = WebPage.listFiles(listingUrl, listing)
|
||||||
|
val rawVersions = WebPage.listDirectories(listingUrl, listing)
|
||||||
|
|
||||||
|
val res =
|
||||||
|
if (files.contains("maven-metadata.xml"))
|
||||||
|
-\/("maven-metadata.xml found, not listing version from directory listing")
|
||||||
|
else if (rawVersions.isEmpty)
|
||||||
|
-\/(s"No versions found at $listingUrl")
|
||||||
|
else {
|
||||||
|
val parsedVersions = rawVersions.map(Version(_))
|
||||||
|
val nonPreVersions = parsedVersions.filter(_.items.forall {
|
||||||
|
case q: Version.Qualifier => q.level >= 0
|
||||||
|
case _ => true
|
||||||
|
})
|
||||||
|
|
||||||
|
if (nonPreVersions.isEmpty)
|
||||||
|
-\/(s"Found only pre-versions at $listingUrl")
|
||||||
|
else {
|
||||||
|
val latest = nonPreVersions.max
|
||||||
|
\/-(Versions(
|
||||||
|
latest.repr,
|
||||||
|
latest.repr,
|
||||||
|
nonPreVersions.map(_.repr).toList,
|
||||||
|
None
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EitherT(F.point(res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def versions[F[_]](
|
def versions[F[_]](
|
||||||
module: Module,
|
module: Module,
|
||||||
fetch: Fetch.Content[F]
|
fetch: Fetch.Content[F]
|
||||||
|
|
@ -239,6 +282,16 @@ final case class MavenRepository(
|
||||||
F.map(res)(_.map(proj => proj.copy(actualVersionOpt = Some(version))))
|
F.map(res)(_.map(proj => proj.copy(actualVersionOpt = Some(version))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def artifactFor(url: String, changing: Boolean) =
|
||||||
|
Artifact(
|
||||||
|
url,
|
||||||
|
Map.empty,
|
||||||
|
Map.empty,
|
||||||
|
Attributes("", ""),
|
||||||
|
changing = changing,
|
||||||
|
authentication
|
||||||
|
)
|
||||||
|
|
||||||
def findVersioning[F[_]](
|
def findVersioning[F[_]](
|
||||||
module: Module,
|
module: Module,
|
||||||
version: String,
|
version: String,
|
||||||
|
|
@ -255,16 +308,6 @@ final case class MavenRepository(
|
||||||
proj <- Pom.project(xml, relocationAsDependency = true)
|
proj <- Pom.project(xml, relocationAsDependency = true)
|
||||||
} yield proj
|
} yield proj
|
||||||
|
|
||||||
def artifactFor(url: String) =
|
|
||||||
Artifact(
|
|
||||||
url,
|
|
||||||
Map.empty,
|
|
||||||
Map.empty,
|
|
||||||
Attributes("", ""),
|
|
||||||
changing = changing.getOrElse(version.contains("-SNAPSHOT")),
|
|
||||||
authentication
|
|
||||||
)
|
|
||||||
|
|
||||||
def isArtifact(fileName: String, prefix: String): Option[(String, String)] =
|
def isArtifact(fileName: String, prefix: String): Option[(String, String)] =
|
||||||
// TODO There should be a regex for that...
|
// TODO There should be a regex for that...
|
||||||
if (fileName.startsWith(prefix)) {
|
if (fileName.startsWith(prefix)) {
|
||||||
|
|
@ -287,7 +330,7 @@ final case class MavenRepository(
|
||||||
|
|
||||||
val projectArtifact0 = projectArtifact(module, version, versioningValue)
|
val projectArtifact0 = projectArtifact(module, version, versioningValue)
|
||||||
|
|
||||||
val listFilesUrl = urlFor(modulePath(module, version)) + "/"
|
val listFilesUrl = urlFor(moduleVersionPath(module, version)) + "/"
|
||||||
|
|
||||||
val listFilesArtifact =
|
val listFilesArtifact =
|
||||||
Artifact(
|
Artifact(
|
||||||
|
|
@ -313,7 +356,7 @@ final case class MavenRepository(
|
||||||
|
|
||||||
for {
|
for {
|
||||||
str <- fetch(requiringDirListingProjectArtifact)
|
str <- fetch(requiringDirListingProjectArtifact)
|
||||||
rawListFilesPageOpt <- EitherT(F.map(fetch(artifactFor(listFilesUrl)).run) {
|
rawListFilesPageOpt <- EitherT(F.map(fetch(artifactFor(listFilesUrl, changing.getOrElse(version.contains("-SNAPSHOT")))).run) {
|
||||||
e => \/-(e.toOption): String \/ Option[String]
|
e => \/-(e.toOption): String \/ Option[String]
|
||||||
})
|
})
|
||||||
proj0 <- EitherT(F.point[String \/ Project](parseRawPom(str)))
|
proj0 <- EitherT(F.point[String \/ Project](parseRawPom(str)))
|
||||||
|
|
@ -383,7 +426,14 @@ final case class MavenRepository(
|
||||||
case None =>
|
case None =>
|
||||||
findNoInterval(module, version, fetch).map((source, _))
|
findNoInterval(module, version, fetch).map((source, _))
|
||||||
case Some(itv) =>
|
case Some(itv) =>
|
||||||
versions(module, fetch).flatMap { versions0 =>
|
def v = versions(module, fetch)
|
||||||
|
val v0 =
|
||||||
|
if (changing.forall(!_) && module.attributes.contains("scalaVersion") && module.attributes.contains("sbtVersion"))
|
||||||
|
versionsFromListing(module, fetch).orElse(v)
|
||||||
|
else
|
||||||
|
v
|
||||||
|
|
||||||
|
v0.flatMap { versions0 =>
|
||||||
val eitherVersion = {
|
val eitherVersion = {
|
||||||
val release = Version(versions0.release)
|
val release = Version(versions0.release)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,4 +48,7 @@ package object compatibility {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def tryCreate(path: String, content: String): Unit = {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package coursier.test
|
package coursier.test
|
||||||
|
|
||||||
import java.io.{FileNotFoundException, InputStream}
|
import java.nio.charset.StandardCharsets
|
||||||
import java.nio.file.{Files, Paths}
|
import java.nio.file.{Files, Paths}
|
||||||
|
|
||||||
import coursier.util.TestEscape
|
import coursier.util.TestEscape
|
||||||
|
|
@ -71,4 +71,17 @@ package object compatibility {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private lazy val baseResources = {
|
||||||
|
val dir = Paths.get("tests/shared/src/test/resources")
|
||||||
|
assert(Files.isDirectory(dir))
|
||||||
|
dir
|
||||||
|
}
|
||||||
|
|
||||||
|
def tryCreate(path: String, content: String): Unit =
|
||||||
|
if (fillChunks) {
|
||||||
|
val path0 = baseResources.resolve(path)
|
||||||
|
Files.createDirectories(path0.getParent)
|
||||||
|
Files.write(path0, content.getBytes(StandardCharsets.UTF_8))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit f932032f9cf013a6d7fe205b2a8d53229c926162
|
Subproject commit 1c030359018e600bc4d33c562a4ab616b6570c63
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
org.ensime:sbt-ensime;sbtVersion=0.13;scalaVersion=2.10:1.12.12:compile
|
||||||
|
org.jsoup:jsoup:1.10.2:compile
|
||||||
|
org.scala-lang:scala-library:2.10.6:compile
|
||||||
|
org.scala-lang:scala-reflect:2.10.4:compile
|
||||||
|
org.scalamacros:quasiquotes_2.10:2.1.0:compile
|
||||||
|
org.scalariform:scalariform_2.10:0.1.4:compile
|
||||||
|
org.scalaz:scalaz-concurrent_2.10:7.2.12:compile
|
||||||
|
org.scalaz:scalaz-core_2.10:7.2.12:compile
|
||||||
|
org.scalaz:scalaz-effect_2.10:7.2.12:compile
|
||||||
|
|
@ -69,27 +69,25 @@ abstract class CentralTests extends TestSuite {
|
||||||
case (k, v) => k + "_" + v
|
case (k, v) => k + "_" + v
|
||||||
}.mkString("_")
|
}.mkString("_")
|
||||||
|
|
||||||
val expected =
|
val path = Seq(
|
||||||
await(
|
"resolutions",
|
||||||
textResource(
|
module.organization,
|
||||||
Seq(
|
module.name,
|
||||||
"resolutions",
|
attrPathPart,
|
||||||
module.organization,
|
version + (
|
||||||
module.name,
|
if (configuration.isEmpty)
|
||||||
attrPathPart,
|
""
|
||||||
version + (
|
else
|
||||||
if (configuration.isEmpty)
|
"_" + configuration.replace('(', '_').replace(')', '_')
|
||||||
""
|
)
|
||||||
else
|
).filter(_.nonEmpty).mkString("/")
|
||||||
"_" + configuration.replace('(', '_').replace(')', '_')
|
|
||||||
)
|
def tryRead = textResource(path)
|
||||||
).filter(_.nonEmpty).mkString("/")
|
|
||||||
)
|
|
||||||
).split('\n').toSeq
|
|
||||||
|
|
||||||
val dep = Dependency(module, version, configuration = configuration)
|
val dep = Dependency(module, version, configuration = configuration)
|
||||||
val res = await(resolve(Set(dep), extraRepo = extraRepo, profiles = profiles))
|
val res = await(resolve(Set(dep), extraRepo = extraRepo, profiles = profiles))
|
||||||
|
|
||||||
|
// making that lazy makes scalac crash in 2.10 with scalajs
|
||||||
val result = res
|
val result = res
|
||||||
.minDependencies
|
.minDependencies
|
||||||
.toVector
|
.toVector
|
||||||
|
|
@ -109,6 +107,15 @@ abstract class CentralTests extends TestSuite {
|
||||||
Seq(org, name, ver, cfg).mkString(":")
|
Seq(org, name, ver, cfg).mkString(":")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val expected =
|
||||||
|
await(
|
||||||
|
tryRead.recoverWith {
|
||||||
|
case _: Exception =>
|
||||||
|
tryCreate(path, result.mkString("\n"))
|
||||||
|
tryRead
|
||||||
|
}
|
||||||
|
).split('\n').toSeq
|
||||||
|
|
||||||
for (((e, r), idx) <- expected.zip(result).zipWithIndex if e != r)
|
for (((e, r), idx) <- expected.zip(result).zipWithIndex if e != r)
|
||||||
println(s"Line ${idx + 1}:\n expected: $e\n got: $r")
|
println(s"Line ${idx + 1}:\n expected: $e\n got: $r")
|
||||||
|
|
||||||
|
|
@ -723,6 +730,16 @@ abstract class CentralTests extends TestSuite {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
'sbtPluginVersionRange - {
|
||||||
|
val mod = Module("org.ensime", "sbt-ensime", attributes = Map("scalaVersion" -> "2.10", "sbtVersion" -> "0.13"))
|
||||||
|
val ver = "1.12.+"
|
||||||
|
|
||||||
|
* - {
|
||||||
|
if (isActualCentral) // doesn't work via proxies, which don't list all the upstream available versions
|
||||||
|
resolutionCheck(mod, ver)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue