Merge pull request #592 from coursier/topic/fix

Small fixes
This commit is contained in:
Alexandre Archambault 2017-06-24 17:24:38 +02:00 committed by GitHub
commit 4df11cfaa4
13 changed files with 282 additions and 173 deletions

View File

@ -230,7 +230,7 @@ lazy val `sbt-launcher` = project
libs ++= {
if (scalaBinaryVersion.value == "2.11")
Seq(
Deps.caseApp,
Deps.caseApp12,
Deps.sbtLauncherInterface,
Deps.typesafeConfig
)

View File

@ -0,0 +1,9 @@
package coursier
import java.net.URLConnection
import coursier.core.Authentication
trait AuthenticatedURLConnection extends URLConnection {
def authenticate(authentication: Authentication): Unit
}

View File

@ -25,10 +25,6 @@ import scala.concurrent.duration.{ Duration, DurationInt }
import scala.util.Try
import scala.util.control.NonFatal
trait AuthenticatedURLConnection extends URLConnection {
def authenticate(authentication: Authentication): Unit
}
object Cache {
private[coursier] def closeConn(conn: URLConnection): Unit = {
@ -190,7 +186,11 @@ object Cache {
// TODO If Cache is made an (instantiated) class at some point, allow to log that exception.
None
case NonFatal(e) =>
Some(-\/(FileError.DownloadError(s"Caught $e${Option(e.getMessage).fold("")(" (" + _ + ")")}")))
Some(-\/(
FileError.DownloadError(
s"Caught $e${Option(e.getMessage).fold("")(" (" + _ + ")")} while downloading $url"
)
))
}
resOpt match {

View File

@ -6,56 +6,9 @@ import java.util.concurrent._
import java.util.concurrent.atomic.AtomicBoolean
import scala.collection.mutable.ArrayBuffer
import scala.util.Try
object Terminal {
// Cut-n-pasted and adapted from
// https://github.com/lihaoyi/Ammonite/blob/10854e3b8b454a74198058ba258734a17af32023/terminal/src/main/scala/ammonite/terminal/Utils.scala
private lazy val pathedTput = if (new File("/usr/bin/tput").exists()) "/usr/bin/tput" else "tput"
def consoleDim(s: String): Option[Int] =
if (new File("/dev/tty").exists()) {
import sys.process._
val nullLog = new ProcessLogger {
def out(s: => String): Unit = {}
def err(s: => String): Unit = {}
def buffer[T](f: => T): T = f
}
Try(Process(Seq("bash", "-c", s"$pathedTput $s 2> /dev/tty")).!!(nullLog).trim.toInt).toOption
} else
None
implicit class Ansi(val output: Writer) extends AnyVal {
private def control(n: Int, c: Char) = output.write(s"\033[" + n + c)
/**
* Move up `n` squares
*/
def up(n: Int): Unit = if (n > 0) control(n, 'A')
/**
* Move down `n` squares
*/
def down(n: Int): Unit = if (n > 0) control(n, 'B')
/**
* Move left `n` squares
*/
def left(n: Int): Unit = if (n > 0) control(n, 'D')
/**
* Clear the current line
*
* n=0: clear from cursor to end of line
* n=1: clear from cursor to start of line
* n=2: clear entire line
*/
def clearLine(n: Int): Unit = control(n, 'K')
}
}
object TermDisplay {
def defaultFallbackMode: Boolean = {
val env0 = sys.env.get("COURSIER_PROGRESS").map(_.toLowerCase).collect {
case "true" | "enable" | "1" => true
@ -265,7 +218,7 @@ object TermDisplay {
else
s"(${pctOpt.map(pct => f"$pct%.2f %%, ").mkString}${downloadInfo.downloaded}${downloadInfo.length.map(" / " + _).mkString})"
case updateInfo: CheckUpdateInfo =>
case _: CheckUpdateInfo =>
"Checking for updates"
}

View File

@ -0,0 +1,52 @@
package coursier
import java.io.{File, Writer}
import scala.util.Try
object Terminal {
// Cut-n-pasted and adapted from
// https://github.com/lihaoyi/Ammonite/blob/10854e3b8b454a74198058ba258734a17af32023/terminal/src/main/scala/ammonite/terminal/Utils.scala
private lazy val pathedTput = if (new File("/usr/bin/tput").exists()) "/usr/bin/tput" else "tput"
def consoleDim(s: String): Option[Int] =
if (new File("/dev/tty").exists()) {
import sys.process._
val nullLog = new ProcessLogger {
def out(s: => String): Unit = {}
def err(s: => String): Unit = {}
def buffer[T](f: => T): T = f
}
Try(Process(Seq("bash", "-c", s"$pathedTput $s 2> /dev/tty")).!!(nullLog).trim.toInt).toOption
} else
None
implicit class Ansi(val output: Writer) extends AnyVal {
private def control(n: Int, c: Char) = output.write(s"\033[" + n + c)
/**
* Move up `n` squares
*/
def up(n: Int): Unit = if (n > 0) control(n, 'A')
/**
* Move down `n` squares
*/
def down(n: Int): Unit = if (n > 0) control(n, 'B')
/**
* Move left `n` squares
*/
def left(n: Int): Unit = if (n > 0) control(n, 'D')
/**
* Clear the current line
*
* n=0: clear from cursor to end of line
* n=1: clear from cursor to start of line
* n=2: clear entire line
*/
def clearLine(n: Int): Unit = control(n, 'K')
}
}

View File

@ -64,6 +64,22 @@ final case class Missing(
cont: Resolution => ResolutionProcess
) extends ResolutionProcess {
def uniqueModules: Missing = {
// only try to fetch a single version of a given module in a same iteration, so that resolutions for different
// versions don't try to download the same URL in the same iteration, which the coursier.Cache.Logger API doesn't
// allow
val missing0 = missing.groupBy(_._1).toSeq.map(_._2).map {
case Seq(v) => v
case Seq() => sys.error("Cannot happen")
case v =>
v.maxBy { case (_, v0) => Version(v0) }
}
copy(missing = missing0)
}
def next(results: Fetch.MD): ResolutionProcess = {
val errors = results.collect {
@ -96,7 +112,7 @@ final case class Missing(
else {
val min = map.map(_._2.size).min // should be 0
val (toAdd, remaining) = map.partition {
case (k, v) => v.size == min
case (_, v) => v.size == min
}
val acc0 = toAdd.keys.foldLeft(acc)(_.::(_))
val remainingKeys = remaining.keySet.map(_._1)
@ -120,7 +136,7 @@ final case class Missing(
Continue(res0, cont)
} else
Missing(depMgmtMissing.toSeq, res, cont0)
Missing(depMgmtMissing.toSeq, res, cont0).uniqueModules
}
val current0 = current.copyWithCache(
@ -158,7 +174,7 @@ object ResolutionProcess {
if (resolution0.isDone)
Done(resolution0)
else
Missing(resolution0.missingFromCache.toSeq, resolution0, apply)
Missing(resolution0.missingFromCache.toSeq, resolution0, apply).uniqueModules
}
}

View File

@ -12,7 +12,7 @@ object MavenRepository {
val SnapshotTimestamp = "(.*-)?[0-9]{8}\\.[0-9]{6}-[0-9]+".r
def isSnapshot(version: String): Boolean =
version.endsWith("SNAPSHOT") || SnapshotTimestamp.findFirstIn(version).nonEmpty
version.endsWith("SNAPSHOT") || SnapshotTimestamp.pattern.matcher(version).matches()
def toBaseVersion(version: String): String = version match {
case SnapshotTimestamp(null) => "SNAPSHOT"

View File

@ -21,6 +21,7 @@ object CoursierPlugin extends AutoPlugin {
val coursierVerbosity = Keys.coursierVerbosity
val mavenProfiles = Keys.mavenProfiles
val coursierResolvers = Keys.coursierResolvers
val coursierReorderResolvers = Keys.coursierReorderResolvers
val coursierRecursiveResolvers = Keys.coursierRecursiveResolvers
val coursierSbtResolvers = Keys.coursierSbtResolvers
val coursierUseSbtCredentials = Keys.coursierUseSbtCredentials
@ -160,7 +161,7 @@ object CoursierPlugin extends AutoPlugin {
}
)
override def buildSettings = super.buildSettings ++ Seq(
override lazy val buildSettings = super.buildSettings ++ Seq(
coursierParallelDownloads := 6,
coursierMaxIterations := 50,
coursierChecksums := Seq(Some("SHA-1"), None),
@ -171,7 +172,8 @@ object CoursierPlugin extends AutoPlugin {
mavenProfiles := Set.empty,
coursierUseSbtCredentials := true,
coursierCredentials := Map.empty,
coursierCache := Cache.default
coursierCache := Cache.default,
coursierReorderResolvers := true
)
override lazy val projectSettings = coursierSettings(None, Seq(Compile, Test).map(c => c -> c.name)) ++

View File

@ -23,6 +23,10 @@ object Keys {
val mavenProfiles = SettingKey[Set[String]]("maven-profiles")
val coursierReorderResolvers = SettingKey[Boolean](
"coursier-reorder-resolvers",
"Whether resolvers should be re-ordered so that typically slow ones are given a lower priority"
)
val coursierResolvers = TaskKey[Seq[Resolver]]("coursier-resolvers")
val coursierRecursiveResolvers = TaskKey[Seq[Resolver]]("coursier-recursive-resolvers", "Resolvers of the current project, plus those of all from its inter-dependency projects")
val coursierSbtResolvers = TaskKey[Seq[Resolver]]("coursier-sbt-resolvers")

View File

@ -44,15 +44,44 @@ object Tasks {
structure(state).allProjectRefs.filter(p => deps(p.project))
}
private val slowReposBase = Seq(
"https://repo.typesafe.com/",
"https://repo.scala-sbt.org/",
"http://repo.typesafe.com/",
"http://repo.scala-sbt.org/"
)
private val fastReposBase = Seq(
"http://repo1.maven.org/",
"https://repo1.maven.org/"
)
def coursierResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] = Def.task {
def url(res: Resolver): Option[String] =
res match {
case m: SbtCompatibility.MavenRepository =>
Some(m.root)
case u: sbt.URLRepository =>
u.patterns.artifactPatterns.headOption
.orElse(u.patterns.ivyPatterns.headOption)
case _ =>
None
}
def fastRepo(res: Resolver): Boolean =
url(res).exists(u => fastReposBase.exists(u.startsWith))
def slowRepo(res: Resolver): Boolean =
url(res).exists(u => slowReposBase.exists(u.startsWith))
val extRes = externalResolvers.value
val isSbtPlugin = sbtPlugin.value
val sbtRes = sbtResolver.value
val bootResOpt = bootResolvers.value
val overrideFlag = overrideBuildResolvers.value
val reorderResolvers = coursierReorderResolvers.value
bootResOpt.filter(_ => overrideFlag).getOrElse {
val result = bootResOpt.filter(_ => overrideFlag).getOrElse {
var resolvers = extRes
if (isSbtPlugin)
resolvers = Seq(
@ -61,6 +90,12 @@ object Tasks {
) ++ resolvers
resolvers
}
if (reorderResolvers && result.exists(fastRepo) && result.exists(slowRepo)) {
val (slow, other) = result.partition(slowRepo)
other ++ slow
} else
result
}
def coursierRecursiveResolversTask: Def.Initialize[sbt.Task[Seq[Resolver]]] =

View File

@ -6,105 +6,157 @@ import java.nio.file.Files
import caseapp._
import com.typesafe.config.ConfigFactory
import coursier.Dependency
import coursier.util.Properties
import coursier.{Dependency, Module}
final case class MainApp(
final case class MainOptions(
@ExtraName("org")
organization: String,
name: String,
version: String,
scalaVersion: String,
sbtVersion: String,
mainClass: String,
mainComponents: List[String],
classpathExtra: List[String],
extra: List[String]
) extends App {
organization: String = "",
name: String = "",
version: String = "",
scalaVersion: String = "",
sbtVersion: String = "",
mainClass: String = "",
mainComponents: List[String] = Nil,
classpathExtra: List[String] = Nil,
extra: List[String] = Nil,
addCoursier: Boolean = true
)
val sbtPropFile = new File(sys.props("user.dir") + "/sbt.properties")
val buildPropFile = new File(sys.props("user.dir") + "/project/build.properties")
object MainApp extends CaseApp[MainOptions] {
val propFileOpt = Some(sbtPropFile).filter(_.exists())
.orElse(Some(buildPropFile).filter(_.exists()))
val debug = sys.props.contains("coursier.sbt-launcher.debug") || sys.env.contains("COURSIER_SBT_LAUNCHER_DEBUG")
val (org0, name0, ver0, scalaVer0, extraDeps0, mainClass0, sbtVersion0) =
propFileOpt match {
case Some(propFile) =>
// can't get ConfigFactory.parseFile to work fine here
val conf = ConfigFactory.parseString(new String(Files.readAllBytes(propFile.toPath), StandardCharsets.UTF_8))
.withFallback(ConfigFactory.defaultReference(Thread.currentThread().getContextClassLoader))
.resolve()
val sbtConfig = SbtConfig.fromConfig(conf)
def log(msg: String): Unit =
if (debug)
Console.err.println(msg)
(sbtConfig.organization, sbtConfig.moduleName, sbtConfig.version, sbtConfig.scalaVersion, sbtConfig.dependencies, sbtConfig.mainClass, sbtConfig.version)
case None =>
require(scalaVersion.nonEmpty, "No scala version specified")
(organization, name, version, scalaVersion, Nil, mainClass, sbtVersion)
def run(options: MainOptions, remainingArgs: RemainingArgs): Unit = {
val sbtPropFile = new File(sys.props("user.dir") + "/sbt.properties")
val buildPropFile = new File(sys.props("user.dir") + "/project/build.properties")
val propFileOpt = Some(sbtPropFile).filter(_.exists())
.orElse(Some(buildPropFile).filter(_.exists()))
val (org0, name0, ver0, scalaVer0, extraDeps0, mainClass0, sbtVersion0) =
propFileOpt match {
case Some(propFile) =>
log(s"Parsing $propFile")
// can't get ConfigFactory.parseFile to work fine here
val conf = ConfigFactory.parseString(new String(Files.readAllBytes(propFile.toPath), StandardCharsets.UTF_8))
.withFallback(ConfigFactory.defaultReference(Thread.currentThread().getContextClassLoader))
.resolve()
val sbtConfig = SbtConfig.fromConfig(conf)
(sbtConfig.organization, sbtConfig.moduleName, sbtConfig.version, sbtConfig.scalaVersion, sbtConfig.dependencies, sbtConfig.mainClass, sbtConfig.version)
case None =>
require(options.scalaVersion.nonEmpty, "No scala version specified")
(
options.organization,
options.name,
options.version,
options.scalaVersion,
Nil,
options.mainClass,
options.sbtVersion
)
}
val (extraParseErrors, extraModuleVersions) =
coursier.util.Parse.moduleVersions(options.extra, options.scalaVersion)
if (extraParseErrors.nonEmpty) {
???
}
val (extraParseErrors, extraModuleVersions) = coursier.util.Parse.moduleVersions(extra, scalaVersion)
if (extraParseErrors.nonEmpty) {
???
}
val extraDeps = extraModuleVersions.map {
case (mod, ver) =>
Dependency(mod, ver)
}
val launcher = new Launcher(
scalaVer0,
// FIXME Add org & moduleName in this path
new File(s"${sys.props("user.dir")}/target/sbt-components/components_scala$scalaVer0${if (sbtVersion0.isEmpty) "" else "_sbt" + sbtVersion0}"),
new File(s"${sys.props("user.dir")}/target/ivy2")
)
launcher.registerScalaComponents()
if (sbtVersion0.nonEmpty)
launcher.registerSbtInterfaceComponents(sbtVersion0)
val appId = ApplicationID(
org0,
name0,
ver0,
mainClass0,
mainComponents.toArray,
crossVersioned = false,
xsbti.CrossValue.Disabled,
classpathExtra.map(new File(_)).toArray
)
val appProvider = launcher.app(appId, extraDeps0 ++ extraDeps: _*)
val appMain = appProvider.newMain()
val appConfig = AppConfiguration(
remainingArgs.toArray,
new File(sys.props("user.dir")),
appProvider
)
val thread = Thread.currentThread()
val previousLoader = thread.getContextClassLoader
val result =
try {
thread.setContextClassLoader(appProvider.loader())
appMain.run(appConfig)
} finally {
thread.setContextClassLoader(previousLoader)
val extraDeps = extraModuleVersions.map {
case (mod, ver) =>
Dependency(mod, ver)
}
result match {
case _: xsbti.Continue =>
case e: xsbti.Exit =>
sys.exit(e.code())
case _: xsbti.Reboot =>
sys.error("Not able to reboot yet")
val coursierDeps =
if (options.addCoursier && sbtVersion0.nonEmpty)
Seq(
Dependency(
Module(
"io.get-coursier",
"sbt-coursier",
attributes = Map(
"scalaVersion" -> scalaVer0.split('.').take(2).mkString("."),
"sbtVersion" -> sbtVersion0.split('.').take(2).mkString(".")
)
),
Properties.version
)
)
else
Nil
log("Creating launcher")
val launcher = new Launcher(
scalaVer0,
// FIXME Add org & moduleName in this path
new File(s"${sys.props("user.dir")}/target/sbt-components/components_scala$scalaVer0${if (sbtVersion0.isEmpty) "" else "_sbt" + sbtVersion0}"),
new File(s"${sys.props("user.dir")}/target/ivy2")
)
log("Registering scala components")
launcher.registerScalaComponents()
if (sbtVersion0.nonEmpty) {
log("Registering sbt interface components")
launcher.registerSbtInterfaceComponents(sbtVersion0)
}
val appId = ApplicationID(
org0,
name0,
ver0,
mainClass0,
options.mainComponents.toArray,
crossVersioned = false,
xsbti.CrossValue.Disabled,
options.classpathExtra.map(new File(_)).toArray
)
log("Getting app provider")
val appProvider = launcher.app(appId, extraDeps0 ++ extraDeps ++ coursierDeps: _*)
log("Creating main")
val appMain = appProvider.newMain()
val appConfig = AppConfiguration(
remainingArgs.args.toArray,
new File(sys.props("user.dir")),
appProvider
)
val thread = Thread.currentThread()
val previousLoader = thread.getContextClassLoader
val result =
try {
thread.setContextClassLoader(appProvider.loader())
appMain.run(appConfig)
} finally {
thread.setContextClassLoader(previousLoader)
}
log("Done")
result match {
case _: xsbti.Continue =>
case e: xsbti.Exit =>
sys.exit(e.code())
case _: xsbti.Reboot =>
sys.error("Not able to reboot yet")
}
}
}
object Main extends AppOf[MainApp]

View File

@ -4,7 +4,7 @@ import java.io.File
import coursier.ivy.IvyXml.{mappings => ivyXmlMappings}
import sbt.Keys._
import sbt.{AutoPlugin, Compile, Configuration, TaskKey, inConfig}
import sbt.{AutoPlugin, Compile, Configuration, SettingKey, TaskKey, inConfig}
import SbtCompatibility._
@ -21,10 +21,10 @@ object ShadingPlugin extends AutoPlugin {
val Shaded = Configuration("shaded", "", isPublic = true, Vector(), transitive = true)
// make that a setting?
val shadingNamespace = TaskKey[String]("shading-namespace")
val shadingNamespace = SettingKey[String]("shading-namespace")
// make that a setting?
val shadeNamespaces = TaskKey[Set[String]]("shade-namespaces")
val shadeNamespaces = SettingKey[Set[String]]("shade-namespaces")
val toShadeJars = TaskKey[Seq[File]]("to-shade-jars")
val toShadeClasses = TaskKey[Seq[String]]("to-shade-classes")
@ -61,6 +61,10 @@ object ShadingPlugin extends AutoPlugin {
import CoursierPlugin.autoImport._
override lazy val buildSettings = super.buildSettings ++ Seq(
shadeNamespaces := Set()
)
override lazy val projectSettings =
Seq(
coursierConfigurations := Tasks.coursierConfigurationsTask(
@ -72,8 +76,7 @@ object ShadingPlugin extends AutoPlugin {
conf.extend(Shaded)
else
conf
},
shadeNamespaces := Set()
}
) ++
inConfig(Shading)(
sbt.Defaults.configSettings ++

View File

@ -1,17 +0,0 @@
sbt.version=0.13.8
plugins = [
"io.get-coursier:sbt-coursier:1.0.0-M15-5"
"io.get-coursier:sbt-shading:1.0.0-M15-5"
"org.xerial.sbt:sbt-pack:0.8.2"
"org.scala-js:sbt-scalajs:0.6.14"
"com.jsuereth:sbt-pgp:1.0.0"
"org.scoverage:sbt-scoverage:1.4.0"
"org.tpolecat:tut-plugin:0.4.8"
"com.typesafe.sbt:sbt-proguard:0.2.2"
"com.typesafe:sbt-mima-plugin:0.1.13"
]
dependencies = [
"org.scala-sbt:scripted-plugin:"${sbt.version}
]