mirror of https://github.com/sbt/sbt.git
Temporary workaround
Until we bump the coursier version again
This commit is contained in:
parent
75ac7b6ca1
commit
6185d646af
|
|
@ -38,7 +38,7 @@ final case class ResolutionParams(
|
|||
.toMap
|
||||
|
||||
Seq(
|
||||
InMemoryRepository(map)
|
||||
TemporaryInMemoryRepository(map, cache)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,216 @@
|
|||
package lmcoursier.internal
|
||||
|
||||
import java.io.{File, FileNotFoundException, IOException}
|
||||
import java.net.{HttpURLConnection, URL, URLConnection}
|
||||
|
||||
import coursier.cache.{CacheUrl, FileCache}
|
||||
import coursier.core._
|
||||
import coursier.util.{EitherT, Monad}
|
||||
|
||||
import scala.util.Try
|
||||
|
||||
object TemporaryInMemoryRepository {
|
||||
|
||||
def closeConn(conn: URLConnection): Unit = {
|
||||
Try(conn.getInputStream).toOption.filter(_ != null).foreach(_.close())
|
||||
conn match {
|
||||
case conn0: HttpURLConnection =>
|
||||
Try(conn0.getErrorStream).toOption.filter(_ != null).foreach(_.close())
|
||||
conn0.disconnect()
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
|
||||
def exists(
|
||||
url: URL,
|
||||
localArtifactsShouldBeCached: Boolean
|
||||
): Boolean =
|
||||
exists(url, localArtifactsShouldBeCached, None)
|
||||
|
||||
def exists(
|
||||
url: URL,
|
||||
localArtifactsShouldBeCached: Boolean,
|
||||
cacheOpt: Option[FileCache[Nothing]]
|
||||
): Boolean = {
|
||||
|
||||
// Sometimes HEAD attempts fail even though standard GETs are fine.
|
||||
// E.g. https://github.com/NetLogo/NetLogo/releases/download/5.3.1/NetLogo.jar
|
||||
// returning 403s. Hence the second attempt below.
|
||||
|
||||
val protocolSpecificAttemptOpt = {
|
||||
|
||||
def ifFile: Option[Boolean] = {
|
||||
if (localArtifactsShouldBeCached && !new File(url.toURI).exists()) {
|
||||
val cachePath = coursier.cache.CacheDefaults.location
|
||||
// 'file' here stands for the protocol (e.g. it's https instead for https:// URLs)
|
||||
Some(new File(cachePath, s"file/${url.getPath}").exists())
|
||||
} else {
|
||||
Some(new File(url.toURI).exists()) // FIXME Escaping / de-escaping needed here?
|
||||
}
|
||||
}
|
||||
|
||||
def ifHttp: Option[Boolean] = {
|
||||
// HEAD request attempt, adapted from http://stackoverflow.com/questions/22541629/android-how-can-i-make-an-http-head-request/22545275#22545275
|
||||
|
||||
var conn: URLConnection = null
|
||||
try {
|
||||
conn = CacheUrl.urlConnection(
|
||||
url.toString,
|
||||
None,
|
||||
followHttpToHttpsRedirections = cacheOpt.fold(false)(_.followHttpToHttpsRedirections),
|
||||
followHttpsToHttpRedirections = cacheOpt.fold(false)(_.followHttpsToHttpRedirections),
|
||||
sslSocketFactoryOpt = cacheOpt.flatMap(_.sslSocketFactoryOpt),
|
||||
hostnameVerifierOpt = cacheOpt.flatMap(_.hostnameVerifierOpt),
|
||||
method = "HEAD",
|
||||
maxRedirectionsOpt = cacheOpt.flatMap(_.maxRedirections)
|
||||
)
|
||||
// Even though the finally clause handles this too, this has to be run here, so that we return Some(true)
|
||||
// iff this doesn't throw.
|
||||
conn.getInputStream.close()
|
||||
Some(true)
|
||||
}
|
||||
catch {
|
||||
case _: FileNotFoundException => Some(false)
|
||||
case _: IOException => None // error other than not found
|
||||
}
|
||||
finally {
|
||||
if (conn != null)
|
||||
closeConn(conn)
|
||||
}
|
||||
}
|
||||
|
||||
url.getProtocol match {
|
||||
case "file" => ifFile
|
||||
case "http" | "https" => ifHttp
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
def genericAttempt: Boolean = {
|
||||
var conn: URLConnection = null
|
||||
try {
|
||||
conn = url.openConnection()
|
||||
// NOT setting request type to HEAD here.
|
||||
conn.getInputStream.close()
|
||||
true
|
||||
}
|
||||
catch {
|
||||
case _: IOException => false
|
||||
}
|
||||
finally {
|
||||
if (conn != null)
|
||||
closeConn(conn)
|
||||
}
|
||||
}
|
||||
|
||||
protocolSpecificAttemptOpt
|
||||
.getOrElse(genericAttempt)
|
||||
}
|
||||
|
||||
def apply(
|
||||
fallbacks: Map[(Module, String), (URL, Boolean)]
|
||||
): TemporaryInMemoryRepository =
|
||||
new TemporaryInMemoryRepository(fallbacks, localArtifactsShouldBeCached = false, None)
|
||||
|
||||
def apply(
|
||||
fallbacks: Map[(Module, String), (URL, Boolean)],
|
||||
localArtifactsShouldBeCached: Boolean
|
||||
): TemporaryInMemoryRepository =
|
||||
new TemporaryInMemoryRepository(fallbacks, localArtifactsShouldBeCached, None)
|
||||
|
||||
def apply[F[_]](
|
||||
fallbacks: Map[(Module, String), (URL, Boolean)],
|
||||
cache: FileCache[F]
|
||||
): TemporaryInMemoryRepository =
|
||||
new TemporaryInMemoryRepository(
|
||||
fallbacks,
|
||||
localArtifactsShouldBeCached = cache.localArtifactsShouldBeCached,
|
||||
Some(cache.asInstanceOf[FileCache[Nothing]])
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
final class TemporaryInMemoryRepository private(
|
||||
val fallbacks: Map[(Module, String), (URL, Boolean)],
|
||||
val localArtifactsShouldBeCached: Boolean,
|
||||
val cacheOpt: Option[FileCache[Nothing]]
|
||||
) extends Repository {
|
||||
|
||||
def find[F[_]](
|
||||
module: Module,
|
||||
version: String,
|
||||
fetch: Repository.Fetch[F]
|
||||
)(implicit
|
||||
F: Monad[F]
|
||||
): EitherT[F, String, (Artifact.Source, Project)] = {
|
||||
|
||||
def res = fallbacks
|
||||
.get((module, version))
|
||||
.fold[Either[String, (Artifact.Source, Project)]](Left("No fallback URL found")) {
|
||||
case (url, _) =>
|
||||
|
||||
println(s"($module, $version) -> $url")
|
||||
|
||||
val urlStr = url.toExternalForm
|
||||
val idx = urlStr.lastIndexOf('/')
|
||||
|
||||
if (idx < 0 || urlStr.endsWith("/"))
|
||||
Left(s"$url doesn't point to a file")
|
||||
else {
|
||||
val (dirUrlStr, fileName) = urlStr.splitAt(idx + 1)
|
||||
|
||||
if (TemporaryInMemoryRepository.exists(url, localArtifactsShouldBeCached, cacheOpt)) {
|
||||
println("returning proj")
|
||||
val proj = Project(
|
||||
module,
|
||||
version,
|
||||
Nil,
|
||||
Map.empty,
|
||||
None,
|
||||
Nil,
|
||||
Nil,
|
||||
Nil,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
relocated = false,
|
||||
None,
|
||||
Nil,
|
||||
Info.empty
|
||||
)
|
||||
|
||||
Right((this, proj))
|
||||
} else
|
||||
Left(s"$fileName not found under $dirUrlStr")
|
||||
}
|
||||
}
|
||||
|
||||
// EitherT(F.bind(F.point(()))(_ => F.point(res)))
|
||||
EitherT(F.map(F.point(()))(_ => res))
|
||||
}
|
||||
|
||||
def artifacts(
|
||||
dependency: Dependency,
|
||||
project: Project,
|
||||
overrideClassifiers: Option[Seq[Classifier]]
|
||||
): Seq[(Publication, Artifact)] = {
|
||||
println(s"artifacts($dependency)")
|
||||
fallbacks
|
||||
.get(dependency.moduleVersion)
|
||||
.toSeq
|
||||
.map {
|
||||
case (url, changing) =>
|
||||
println(s"$url, $changing")
|
||||
val url0 = url.toString
|
||||
val ext = url0.substring(url0.lastIndexOf('.') + 1)
|
||||
val pub = Publication(
|
||||
dependency.module.name.value, // ???
|
||||
Type(ext),
|
||||
Extension(ext),
|
||||
Classifier.empty
|
||||
)
|
||||
(pub, Artifact(url0, Map.empty, Map.empty, changing, optional = false, None))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue