Add support for HTTP authentication in SBT plugin

This commit is contained in:
Alexandre Archambault 2016-05-06 13:54:17 +02:00
parent 265d79b156
commit 0ccabd0820
No known key found for this signature in database
GPG Key ID: 14640A6839C263A9
14 changed files with 138 additions and 9 deletions

View File

@ -19,6 +19,7 @@ object CoursierPlugin extends AutoPlugin {
val coursierSourceRepositories = Keys.coursierSourceRepositories
val coursierResolvers = Keys.coursierResolvers
val coursierSbtResolvers = Keys.coursierSbtResolvers
val coursierCredentials = Keys.coursierCredentials
val coursierFallbackDependencies = Keys.coursierFallbackDependencies
val coursierCache = Keys.coursierCache
val coursierProject = Keys.coursierProject
@ -61,6 +62,7 @@ object CoursierPlugin extends AutoPlugin {
coursierSourceRepositories := Nil,
coursierResolvers <<= Tasks.coursierResolversTask,
coursierSbtResolvers <<= externalResolvers in updateSbtClassifiers,
coursierCredentials := Map.empty,
coursierFallbackDependencies <<= Tasks.coursierFallbackDependenciesTask,
coursierCache := Cache.default,
update <<= Tasks.updateTask(withClassifiers = false),

View File

@ -0,0 +1,57 @@
package coursier
import java.io.{File, FileInputStream}
import java.util.Properties
import coursier.core.Authentication
sealed abstract class Credentials extends Product with Serializable {
def user: String
def password: String
def authentication: Authentication =
Authentication(user, password)
}
object Credentials {
case class Direct(user: String, password: String) extends Credentials {
override def toString = s"Direct($user, ******)"
}
case class FromFile(file: File) extends Credentials {
private lazy val props = {
val p = new Properties()
p.load(new FileInputStream(file))
p
}
private def findKey(keys: Seq[String]) = keys
.iterator
.map(props.getProperty)
.filter(_ != null)
.toStream
.headOption
.getOrElse {
throw new NoSuchElementException(s"${keys.head} key in $file")
}
lazy val user: String = findKey(FromFile.fileUserKeys)
lazy val password: String = findKey(FromFile.filePasswordKeys)
}
object FromFile {
// from sbt.Credentials
private val fileUserKeys = Seq("user", "user.name", "username")
private val filePasswordKeys = Seq("password", "pwd", "pass", "passwd")
}
def apply(user: String, password: String): Credentials =
Direct(user, password)
def apply(file: File): Credentials =
FromFile(file)
}

View File

@ -4,6 +4,7 @@ import coursier.ivy.{ IvyXml, IvyRepository }
import java.net.{ MalformedURLException, URL }
import coursier.core.Authentication
import sbt.{ Resolver, CrossVersion, ModuleID }
import sbt.mavenint.SbtPomExtraProperties
@ -145,11 +146,21 @@ object FromSbt {
} else
None
private def mavenRepositoryOpt(root: String, log: sbt.Logger): Option[MavenRepository] =
private def mavenRepositoryOpt(
root: String,
log: sbt.Logger,
authentication: Option[Authentication]
): Option[MavenRepository] =
try {
Cache.url(root) // ensure root is a URL whose protocol can be handled here
val root0 = if (root.endsWith("/")) root else root + "/"
Some(MavenRepository(root0, sbtAttrStub = true))
Some(
MavenRepository(
root0,
sbtAttrStub = true,
authentication = authentication
)
)
} catch {
case e: MalformedURLException =>
log.warn(
@ -165,11 +176,12 @@ object FromSbt {
def repository(
resolver: Resolver,
ivyProperties: Map[String, String],
log: sbt.Logger
log: sbt.Logger,
authentication: Option[Authentication]
): Option[Repository] =
resolver match {
case sbt.MavenRepository(_, root) =>
mavenRepositoryOpt(root, log)
mavenRepositoryOpt(root, log, authentication)
case sbt.FileRepository(_, _, patterns)
if patterns.ivyPatterns.lengthCompare(1) == 0 &&
@ -184,10 +196,11 @@ object FromSbt {
metadataPatternOpt = Some("file://" + patterns.ivyPatterns.head),
changing = Some(true),
properties = ivyProperties,
dropInfoAttributes = true
dropInfoAttributes = true,
authentication = authentication
))
case Some(mavenCompatibleBase) =>
mavenRepositoryOpt("file://" + mavenCompatibleBase, log)
mavenRepositoryOpt("file://" + mavenCompatibleBase, log, authentication)
}
case sbt.URLRepository(_, patterns)
@ -203,10 +216,11 @@ object FromSbt {
metadataPatternOpt = Some(patterns.ivyPatterns.head),
changing = None,
properties = ivyProperties,
dropInfoAttributes = true
dropInfoAttributes = true,
authentication = authentication
))
case Some(mavenCompatibleBase) =>
mavenRepositoryOpt(mavenCompatibleBase, log)
mavenRepositoryOpt(mavenCompatibleBase, log, authentication)
}
case other =>

View File

@ -18,6 +18,7 @@ object Keys {
val coursierSourceRepositories = SettingKey[Seq[File]]("coursier-source-repositories")
val coursierResolvers = TaskKey[Seq[Resolver]]("coursier-resolvers")
val coursierSbtResolvers = TaskKey[Seq[Resolver]]("coursier-sbt-resolvers")
val coursierCredentials = TaskKey[Map[String, Credentials]]("coursier-credentials")
val coursierCache = SettingKey[File]("coursier-cache")

View File

@ -371,6 +371,8 @@ object Tasks {
"ivy.home" -> (new File(sys.props("user.home")).toURI.getPath + ".ivy2")
) ++ sys.props
val credentials = coursierCredentials.value
val sourceRepositories0 = sourceRepositories.map {
base =>
MavenRepository(base.toURI.toString, changing = Some(true))
@ -393,7 +395,14 @@ object Tasks {
val repositories =
Seq(globalPluginsRepo, interProjectRepo) ++
sourceRepositories0 ++
resolvers.flatMap(FromSbt.repository(_, ivyProperties, log)) ++
resolvers.flatMap { resolver =>
FromSbt.repository(
resolver,
ivyProperties,
log,
credentials.get(resolver.name).map(_.authentication)
)
} ++
fallbackDependenciesRepositories
def resolution = {

View File

@ -0,0 +1,9 @@
scalaVersion := "2.11.8"
resolvers += "authenticated" at "http://localhost:8080"
coursierCredentials += "authenticated" -> coursier.Credentials(file("credentials"))
coursierCachePolicies := Seq(coursier.CachePolicy.ForceDownload)
libraryDependencies += "com.abc" % "test" % "0.1"

View File

@ -0,0 +1,2 @@
user=user
password=pass

View File

@ -0,0 +1,11 @@
{
val pluginVersion = sys.props.getOrElse(
"plugin.version",
throw new RuntimeException(
"""|The system property 'plugin.version' is not defined.
|Specify this property using the scriptedLaunchOpts -D.""".stripMargin
)
)
addSbtPlugin("io.get-coursier" % "sbt-coursier" % pluginVersion)
}

View File

@ -0,0 +1 @@
object Main extends App

View File

@ -0,0 +1 @@
> coursierResolution

View File

@ -0,0 +1,9 @@
scalaVersion := "2.11.8"
resolvers += "authenticated" at "http://localhost:8080"
coursierCredentials += "authenticated" -> coursier.Credentials("user", "pass")
coursierCachePolicies := Seq(coursier.CachePolicy.ForceDownload)
libraryDependencies += "com.abc" % "test" % "0.1"

View File

@ -0,0 +1,11 @@
{
val pluginVersion = sys.props.getOrElse(
"plugin.version",
throw new RuntimeException(
"""|The system property 'plugin.version' is not defined.
|Specify this property using the scriptedLaunchOpts -D.""".stripMargin
)
)
addSbtPlugin("io.get-coursier" % "sbt-coursier" % pluginVersion)
}

View File

@ -0,0 +1 @@
object Main extends App

View File

@ -0,0 +1 @@
> coursierResolution