Merge branch '1.0.0' into merge-1.0.0

* 1.0.0:
  IO 1.0.0, Util 1.0.0
  Upgrade to sbt 1.0.0-RC3
  Bump mimaPreviousArtifacts to 1.0.0-RC3
  IO 1.0.0-RC3, Util 1.0.0-RC3
  Contraband 0.3.0
  Make sure UpdateReport has a nice toString
  Upgrade to Scala 2.12.3
  Fix MiMa failures
  Name the reverse missing methods
  Exclude ReversedMissingMethodProblem sbt.internal.librarymanagement.formats.*
  Let `ModuleDescriptor` declare cache inputs
  Implement better fake formats than ???
  Upgrade to mima 0.1.15 & add exclusions
  Change overwrite warning
  Filter out ":: loading settings"
  Use IvyAuthenticator and JavaNetAuthenticator
  Fixes sbtApiVersion logic
  Add, configure & enable MiMa
  Add Constant aliases to CrossVersion
This commit is contained in:
Dale Wijnand 2017-08-10 09:18:32 +01:00
commit 60ae1dc1ee
No known key found for this signature in database
GPG Key ID: 4F256E3D151DF5EF
19 changed files with 252 additions and 45 deletions

View File

@ -3,10 +3,12 @@ jdk: oraclejdk8
scala:
- 2.11.11
- 2.12.2
- 2.12.3
script:
- sbt -Dfile.encoding=UTF8 -J-XX:ReservedCodeCacheSize=256M ";++$TRAVIS_SCALA_VERSION test;scalafmt::test;test:scalafmt::test"
# drop scalafmt to dogfood latest 1.0.0-RC before there is an sbt 1.0 release of new-sbt-scalafmt
# - sbt -Dfile.encoding=UTF8 -J-XX:ReservedCodeCacheSize=256M ";++$TRAVIS_SCALA_VERSION;mimaReportBinaryIssues;test;scalafmt::test;test:scalafmt::test"
- sbt -Dfile.encoding=UTF8 -J-XX:ReservedCodeCacheSize=256M ";++$TRAVIS_SCALA_VERSION;mimaReportBinaryIssues;test"
cache:
directories:

View File

@ -1,7 +1,6 @@
import Dependencies._
import Path._
// import com.typesafe.tools.mima.core._, ProblemFilters._
//import com.typesafe.tools.mima.core._, ProblemFilters._
def baseVersion = "1.0.0-SNAPSHOT"
@ -24,12 +23,15 @@ def commonSettings: Seq[Setting[_]] = Seq(
case _ => old ++ List("-Ywarn-unused", "-Ywarn-unused-import", "-YdisableFlatCpCaching")
}
},
// mimaPreviousArtifacts := Set(), // Some(organization.value %% moduleName.value % "1.0.0"),
publishArtifact in Compile := true,
publishArtifact in Test := false,
parallelExecution in Test := false
)
val mimaSettings = Def settings (
mimaPreviousArtifacts := Set(organization.value %% moduleName.value % "1.0.0-RC3")
)
lazy val lmRoot = (project in file("."))
.aggregate(lmCore, lmIvy)
.settings(
@ -41,9 +43,9 @@ lazy val lmRoot = (project in file("."))
url("https://github.com/sbt/librarymanagement"), "git@github.com:sbt/librarymanagement.git"
)),
bintrayPackage := "librarymanagement",
scalafmtOnCompile := true,
// scalafmtOnCompile := true,
// scalafmtVersion 1.0.0-RC3 has regression
scalafmtVersion := "0.6.8",
// scalafmtVersion := "0.6.8",
git.baseVersion := baseVersion,
version := {
val v = version.value
@ -80,7 +82,6 @@ lazy val lmCore = (project in file("core"))
version.value, resourceManaged.value, streams.value, (compile in Compile).value
)
).taskValue,
// mimaBinaryIssueFilters ++= Seq(),
managedSourceDirectories in Compile +=
baseDirectory.value / "src" / "main" / "contraband-scala",
sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala",
@ -91,7 +92,8 @@ lazy val lmCore = (project in file("core"))
val sdirs = (managedSourceDirectories in Compile).value
val base = baseDirectory.value
(((srcs --- sdirs --- base) pair (relativeTo(sdirs) | relativeTo(base) | flat)) toSeq)
}
},
mimaSettings,
)
.configure(addSbtIO, addSbtUtilLogging, addSbtUtilPosition, addSbtUtilCache)
@ -107,6 +109,7 @@ lazy val lmIvy = (project in file("ivy"))
sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala",
contrabandFormatsForType in generateContrabands in Compile := DatatypeConfig.getFormats,
scalacOptions in (Compile, console) --= Vector("-Ywarn-unused-import", "-Ywarn-unused", "-Xlint"),
mimaSettings,
)
def customCommands: Seq[Setting[_]] = Seq(

View File

@ -30,7 +30,8 @@ final class OrganizationArtifactReport private (
37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.OrganizationArtifactReport".##) + organization.##) + name.##) + modules.##)
}
override def toString: String = {
"OrganizationArtifactReport(" + organization + ", " + name + ", " + modules + ")"
val details = modules map { _.detailReport }
s"\t$organization:$name\n${details.mkString}\n"
}
protected[this] def copy(organization: String = organization, name: String = name, modules: Vector[sbt.librarymanagement.ModuleReport] = modules): OrganizationArtifactReport = {
new OrganizationArtifactReport(organization, name, modules)

View File

@ -596,6 +596,10 @@
{ "name": "organization", "type": "String" },
{ "name": "name", "type": "String" },
{ "name": "modules", "type": "sbt.librarymanagement.ModuleReport*" }
],
"toString": [
"val details = modules map { _.detailReport }",
"s\"\\t$organization:$name\\n${details.mkString}\\n\""
]
},
{

View File

@ -36,10 +36,13 @@ object CrossVersionUtil {
* Compatible versions include 0.12.0-1 and 0.12.0-RC1 for Some(0, 12).
*/
private[sbt] def sbtApiVersion(v: String): Option[(Long, Long)] = v match {
case ReleaseV(x, y, _, _) => Some(sbtApiVersion(x.toLong, y.toLong))
case CandidateV(x, y, _, _) => Some(sbtApiVersion(x.toLong, y.toLong))
case NonReleaseV_n(x, y, z, _) if z.toInt > 0 => Some(sbtApiVersion(x.toLong, y.toLong))
case _ => None
case ReleaseV(x, y, _, _) => Some(sbtApiVersion(x.toLong, y.toLong))
case CandidateV(x, y, _, _) => Some(sbtApiVersion(x.toLong, y.toLong))
case NonReleaseV_n(x, y, z, _) if x.toLong == 0 && z.toLong > 0 =>
Some(sbtApiVersion(x.toLong, y.toLong))
case NonReleaseV_n(x, y, z, _) if x.toLong > 0 && (y.toLong > 0 || z.toLong > 0) =>
Some(sbtApiVersion(x.toLong, y.toLong))
case _ => None
}
private def sbtApiVersion(x: Long, y: Long) = {

View File

@ -2,7 +2,24 @@ package sbt.internal.librarymanagement.formats
import sjsonnew._
import xsbti._
import java.io.File
import java.util.concurrent.Callable
/**
* A fake JsonFormat for xsbti.GlobalLock.
* This is mostly for making IvyConfiguration serializable to JSON.
*/
trait GlobalLockFormat { self: BasicJsonProtocol =>
implicit lazy val GlobalLockFormat: JsonFormat[GlobalLock] = ???
import GlobalLockFormats._
implicit lazy val globalLockIsoString: IsoString[GlobalLock] =
IsoString.iso(_ => "<lock>", _ => NoGlobalLock)
implicit lazy val GlobalLockFormat: JsonFormat[GlobalLock] = implicitly
}
private[sbt] object GlobalLockFormats {
object NoGlobalLock extends GlobalLock {
def apply[T](lockFile: File, run: Callable[T]) = run.call()
}
}

View File

@ -2,7 +2,15 @@ package sbt.internal.librarymanagement.formats
import sjsonnew._
import xsbti._
import sbt.util.Logger.Null
/**
* A fake JsonFormat for xsbti.Logger.
* This is mostly for making IvyConfiguration serializable to JSON.
*/
trait LoggerFormat { self: BasicJsonProtocol =>
implicit lazy val LoggerFormat: JsonFormat[Logger] = ???
implicit lazy val xsbtiLoggerIsoString: IsoString[Logger] =
IsoString.iso(_ => "<logger>", _ => Null)
implicit lazy val LoggerFormat: JsonFormat[Logger] = implicitly
}

View File

@ -10,9 +10,11 @@ abstract class CrossVersionFunctions {
/** Compatibility with 0.13 */
final val Disabled = sbt.librarymanagement.Disabled
final val Binary = sbt.librarymanagement.Binary
final val Constant = sbt.librarymanagement.Constant
final val Full = sbt.librarymanagement.Full
final val Patch = sbt.librarymanagement.Patch
type Binary = sbt.librarymanagement.Binary
type Constant = sbt.librarymanagement.Constant
type Full = sbt.librarymanagement.Full
type Patch = sbt.librarymanagement.Patch

View File

@ -1,13 +1,7 @@
package sbt.librarymanagement
import gigahorse._, support.okhttp.Gigahorse
import okhttp3.{ OkUrlFactory, OkHttpClient }
import java.net.{ URL, HttpURLConnection }
object Http {
lazy val http: HttpClient = Gigahorse.http(Gigahorse.config)
private[sbt] lazy val urlFactory = new OkUrlFactory(http.underlying[OkHttpClient])
private[sbt] def open(url: URL): HttpURLConnection =
urlFactory.open(url)
}

View File

@ -81,4 +81,14 @@ trait ModuleDescriptor {
* if any.
*/
def scalaModuleInfo: Option[ScalaModuleInfo]
/**
* The input parameters used to construct the `ModuleSettings`.
*/
def moduleSettings: ModuleSettings
/**
* Hash for extra parameter that were not captured as `moduleSettings`.
*/
def extraInputHash: Long
}

View File

@ -0,0 +1,41 @@
package sbt.librarymanagement
import java.io.File
import org.scalatest._
class UpdateReportSpec extends FlatSpec with Matchers {
"UpdateReport.toString" should "have a nice toString" in {
assert(updateReport.toString === s"""
|Update report:
| Resolve time: 0 ms, Download time: 0 ms, Download size: 0 bytes
| compile:
| org:name
| - 1.0
| evicted: false
|
|""".stripMargin.drop(1))
}
lazy val updateReport =
UpdateReport(
new File("cachedDescriptor.data"),
Vector(configurationReport),
UpdateStats(0, 0, 0, false),
Map.empty
)
lazy val configurationReport =
ConfigurationReport(
ConfigRef("compile"),
Vector(moduleReport),
Vector(organizationArtifactReport)
)
lazy val moduleReport =
ModuleReport(ModuleID("org", "name", "1.0"), Vector.empty, Vector.empty)
lazy val organizationArtifactReport =
OrganizationArtifactReport("org", "name", Vector(moduleReport))
}

View File

@ -400,10 +400,11 @@ private[sbt] object ConvertResolver {
try super.put(source, destination, overwrite)
catch {
case e: java.io.IOException if e.getMessage.contains("destination already exists") =>
val overwriteWarning =
if (destination contains "-SNAPSHOT") s"Attempting to overwrite $destination"
else "Attempting to overwrite $destination (non-SNAPSHOT)\n\tYou need to remove it from the cache manually to take effect."
import org.apache.ivy.util.Message
Message.warn(
s"Attempting to overwrite $destination\n\tThis usage is deprecated and will be removed in sbt 1.0."
)
Message.warn(overwriteWarning)
super.put(source, destination, true)
}
}

View File

@ -36,10 +36,12 @@ import org.apache.ivy.util.extendable.ExtendableItem
import org.apache.ivy.util.url._
import scala.xml.NodeSeq
import scala.collection.mutable
import sbt.util.Logger
import scala.util.{ Success, Failure }
import sbt.util._
import sbt.librarymanagement.{ ModuleDescriptorConfiguration => InlineConfiguration, _ }
import sbt.librarymanagement.ivy._
import sbt.librarymanagement.syntax._
import IvyInternalDefaults._
import Resolver.PluginPattern
import ivyint.{
@ -49,6 +51,8 @@ import ivyint.{
SbtDefaultDependencyDescriptor,
GigahorseUrlHandler
}
import sjsonnew.JsonFormat
import sjsonnew.support.murmurhash.Hasher
final class IvySbt(val configuration: IvyConfiguration) { self =>
/*
@ -336,6 +340,73 @@ final class IvySbt(val configuration: IvyConfiguration) { self =>
)
}
private def toURL(file: File) = file.toURI.toURL
// Todo: We just need writing side of this codec. We can clean up the reads.
private[sbt] object AltLibraryManagementCodec extends IvyLibraryManagementCodec {
import sbt.io.Hash
type InlineIvyHL = (Option[IvyPaths], Vector[Resolver], Vector[Resolver], Vector[
ModuleConfiguration], Vector[String], Boolean)
def inlineIvyToHL(i: InlineIvyConfiguration): InlineIvyHL =
(i.paths, i.resolvers, i.otherResolvers, i.moduleConfigurations,
i.checksums, i.managedChecksums)
type ExternalIvyHL = (Option[PlainFileInfo], Array[Byte])
def externalIvyToHL(e: ExternalIvyConfiguration): ExternalIvyHL =
(e.baseDirectory.map(FileInfo.exists.apply),
e.uri.map(Hash.contentsIfLocal).getOrElse(Array.empty))
// Redefine to use a subset of properties, that are serialisable
override implicit lazy val InlineIvyConfigurationFormat: JsonFormat[InlineIvyConfiguration] = {
def hlToInlineIvy(i: InlineIvyHL): InlineIvyConfiguration = {
val (paths, resolvers, otherResolvers, moduleConfigurations, checksums, managedChecksums) = i
InlineIvyConfiguration()
.withPaths(paths)
.withResolvers(resolvers)
.withOtherResolvers(otherResolvers)
.withModuleConfigurations(moduleConfigurations)
.withManagedChecksums(managedChecksums)
.withChecksums(checksums)
}
projectFormat[InlineIvyConfiguration, InlineIvyHL](inlineIvyToHL, hlToInlineIvy)
}
// Redefine to use a subset of properties, that are serialisable
override implicit lazy val ExternalIvyConfigurationFormat
: JsonFormat[ExternalIvyConfiguration] = {
def hlToExternalIvy(e: ExternalIvyHL): ExternalIvyConfiguration = {
val (baseDirectory, _) = e
ExternalIvyConfiguration(
None,
Some(NullLogger),
UpdateOptions(),
baseDirectory.map(_.file),
None /* the original uri is destroyed.. */,
Vector.empty
)
}
projectFormat[ExternalIvyConfiguration, ExternalIvyHL](externalIvyToHL, hlToExternalIvy)
}
// Redefine to switch to unionFormat
override implicit lazy val IvyConfigurationFormat: JsonFormat[IvyConfiguration] =
unionFormat2[IvyConfiguration, InlineIvyConfiguration, ExternalIvyConfiguration]
object NullLogger extends sbt.internal.util.BasicLogger {
override def control(event: sbt.util.ControlEvent.Value, message: String): Unit = ()
override def log(level: Level.Value, message: String): Unit = ()
override def logAll(events: Seq[sbt.util.LogEvent]): Unit = ()
override def success(message: String): Unit = ()
override def trace(t: Throwable): Unit = ()
}
}
def extraInputHash: Long = {
import AltLibraryManagementCodec._
Hasher.hash(owner.configuration) match {
case Success(keyHash) => keyHash.toLong
case Failure(_) => 0L
}
}
}
}

View File

@ -7,7 +7,7 @@ import org.apache.ivy.util.{ Message, MessageLogger, MessageLoggerEngine }
import sbt.util.Logger
/** Interface to Ivy logging. */
private final class IvyLoggerInterface(logger: Logger) extends MessageLogger {
private[sbt] final class IvyLoggerInterface(logger: Logger) extends MessageLogger {
def rawlog(msg: String, level: Int): Unit = log(msg, level)
def log(msg: String, level: Int): Unit = {
import Message.{ MSG_DEBUG, MSG_VERBOSE, MSG_INFO, MSG_WARN, MSG_ERR }
@ -24,7 +24,7 @@ private final class IvyLoggerInterface(logger: Logger) extends MessageLogger {
def debug(msg: String): Unit = ()
def verbose(msg: String): Unit = logger.verbose(msg)
def deprecated(msg: String): Unit = warn(msg)
def info(msg: String): Unit = logger.info(msg)
def info(msg: String): Unit = if (SbtIvyLogger.acceptInfo(msg)) logger.info(msg)
def rawinfo(msg: String): Unit = info(msg)
def warn(msg: String): Unit = logger.warn(msg)
def error(msg: String): Unit = if (SbtIvyLogger.acceptError(msg)) logger.error(msg)
@ -43,13 +43,16 @@ private final class IvyLoggerInterface(logger: Logger) extends MessageLogger {
def isShowProgress = false
def setShowProgress(progress: Boolean): Unit = ()
}
private final class SbtMessageLoggerEngine extends MessageLoggerEngine {
private[sbt] final class SbtMessageLoggerEngine extends MessageLoggerEngine {
/** This is a hack to filter error messages about 'unknown resolver ...'. */
override def error(msg: String): Unit = if (SbtIvyLogger.acceptError(msg)) super.error(msg)
override def sumupProblems(): Unit = clearProblems()
}
private object SbtIvyLogger {
val UnknownResolver = "unknown resolver"
def acceptError(msg: String) = (msg ne null) && !msg.startsWith(UnknownResolver)
private[sbt] object SbtIvyLogger {
final val unknownResolver = "unknown resolver"
def acceptError(msg: String) = (msg ne null) && !msg.startsWith(unknownResolver)
final val loadingSettings = ":: loading settings"
def acceptInfo(msg: String) = (msg ne null) && !msg.startsWith(loadingSettings)
}

View File

@ -4,9 +4,8 @@ package ivyint
import java.net.{ URL, UnknownHostException, HttpURLConnection }
import java.io.{ File, IOException, InputStream, ByteArrayOutputStream, ByteArrayInputStream }
import org.apache.ivy.util.{ CopyProgressListener, Message, FileUtil }
import org.apache.ivy.util.url.{ URLHandler, AbstractURLHandler, BasicURLHandler }
import org.apache.ivy.util.url.{ URLHandler, AbstractURLHandler, BasicURLHandler, IvyAuthenticator }
import org.apache.ivy.util.url.URLHandler._
import sbt.librarymanagement.Http
import sbt.io.{ IO, Using }
// Copied from Ivy's BasicURLHandler.
@ -24,8 +23,14 @@ class GigahorseUrlHandler extends AbstractURLHandler {
* if the url is not reachable.
*/
def getURLInfo(url0: URL, timeout: Int): URLInfo = {
// Install the ErrorMessageAuthenticator
if ("http" == url0.getProtocol() || "https" == url0.getProtocol()) {
IvyAuthenticator.install()
ErrorMessageAuthenticator.install()
}
val url = normalizeToURL(url0)
val con = Http.open(url)
val con = GigahorseUrlHandler.open(url)
val infoOption = try {
con match {
case httpCon: HttpURLConnection =>
@ -65,8 +70,14 @@ class GigahorseUrlHandler extends AbstractURLHandler {
}
def openStream(url0: URL): InputStream = {
// Install the ErrorMessageAuthenticator
if ("http" == url0.getProtocol() || "https" == url0.getProtocol()) {
IvyAuthenticator.install()
ErrorMessageAuthenticator.install()
}
val url = normalizeToURL(url0)
val conn = Http.open(url)
val conn = GigahorseUrlHandler.open(url)
conn.setRequestProperty("Accept-Encoding", "gzip,deflate")
conn match {
case httpCon: HttpURLConnection =>
@ -91,8 +102,14 @@ class GigahorseUrlHandler extends AbstractURLHandler {
}
def download(src0: URL, dest: File, l: CopyProgressListener): Unit = {
// Install the ErrorMessageAuthenticator
if ("http" == src0.getProtocol() || "https" == src0.getProtocol()) {
IvyAuthenticator.install()
ErrorMessageAuthenticator.install()
}
val src = normalizeToURL(src0)
val srcConn = Http.open(src)
val srcConn = GigahorseUrlHandler.open(src)
srcConn.setRequestProperty("Accept-Encoding", "gzip,deflate")
srcConn match {
case httpCon: HttpURLConnection =>
@ -126,8 +143,16 @@ class GigahorseUrlHandler extends AbstractURLHandler {
}
def upload(source: File, dest0: URL, l: CopyProgressListener): Unit = {
if( ("http" != dest0.getProtocol()) && ("https" != dest0.getProtocol())) {
throw new UnsupportedOperationException(
"URL repository only support HTTP PUT at the moment")
}
IvyAuthenticator.install()
ErrorMessageAuthenticator.install()
val dest = normalizeToURL(dest0)
val conn = Http.open(dest) match {
val conn = GigahorseUrlHandler.open(dest) match {
case c: HttpURLConnection => c
}
conn.setDoOutput(true)
@ -169,3 +194,21 @@ class GigahorseUrlHandler extends AbstractURLHandler {
}
}
}
object GigahorseUrlHandler {
import gigahorse._, support.okhttp.Gigahorse
import okhttp3.{ OkUrlFactory, OkHttpClient, JavaNetAuthenticator }
lazy val http: HttpClient = Gigahorse.http(Gigahorse.config)
private[sbt] def urlFactory = {
val client0 = http.underlying[OkHttpClient]
val client = client0.newBuilder()
.authenticator(new JavaNetAuthenticator)
.build
new OkUrlFactory(client)
}
private[sbt] def open(url: URL): HttpURLConnection =
urlFactory.open(url)
}

View File

@ -135,6 +135,9 @@ class CrossVersionTest extends UnitSpec {
it should "for 1.3.0 return 1.0" in {
binarySbtVersion("1.3.0") shouldBe "1.0"
}
it should "for 1.3.0-SNAPSHOT return 1.0" in {
binarySbtVersion("1.3.0-SNAPSHOT") shouldBe "1.0"
}
it should "for 1.10.0 return 1.0" in {
binarySbtVersion("1.10.0") shouldBe "1.0"
}

View File

@ -4,10 +4,10 @@ import sbt.contraband.ContrabandPlugin.autoImport._
object Dependencies {
val scala211 = "2.11.11"
val scala212 = "2.12.2"
val scala212 = "2.12.3"
private val ioVersion = "1.0.0-M13"
private val utilVersion = "1.0.0-M27"
private val ioVersion = "1.0.0"
private val utilVersion = "1.0.0"
private val sbtIO = "org.scala-sbt" %% "io" % ioVersion

View File

@ -1 +1 @@
sbt.version=1.0.0-M6
sbt.version=1.0.0-RC3

View File

@ -1,6 +1,7 @@
addSbtPlugin("org.scala-sbt" % "sbt-houserules" % "0.3.3")
addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.3.0-M9")
addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.4.0")
addSbtPlugin("com.lucidchart" % "sbt-scalafmt" % "1.3")
addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.3.0")
// addSbtPlugin("com.lucidchart" % "sbt-scalafmt" % "1.3")
addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.17")
scalacOptions += "-language:postfixOps"