diff --git a/.travis.yml b/.travis.yml index 20ffdf8b7..3856d1e3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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: diff --git a/build.sbt b/build.sbt index 9fbe4fa00..2b2b4bd16 100644 --- a/build.sbt +++ b/build.sbt @@ -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( diff --git a/core/src/main/contraband-scala/sbt/librarymanagement/OrganizationArtifactReport.scala b/core/src/main/contraband-scala/sbt/librarymanagement/OrganizationArtifactReport.scala index 3b62b191a..112c4708b 100644 --- a/core/src/main/contraband-scala/sbt/librarymanagement/OrganizationArtifactReport.scala +++ b/core/src/main/contraband-scala/sbt/librarymanagement/OrganizationArtifactReport.scala @@ -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) diff --git a/core/src/main/contraband/librarymanagement.json b/core/src/main/contraband/librarymanagement.json index fa7506f95..c7a04ede8 100644 --- a/core/src/main/contraband/librarymanagement.json +++ b/core/src/main/contraband/librarymanagement.json @@ -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\"" ] }, { diff --git a/core/src/main/scala/sbt/internal/librarymanagement/cross/CrossVersionUtil.scala b/core/src/main/scala/sbt/internal/librarymanagement/cross/CrossVersionUtil.scala index b9d4cc2dd..b9e784a51 100644 --- a/core/src/main/scala/sbt/internal/librarymanagement/cross/CrossVersionUtil.scala +++ b/core/src/main/scala/sbt/internal/librarymanagement/cross/CrossVersionUtil.scala @@ -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) = { diff --git a/core/src/main/scala/sbt/internal/librarymanagement/formats/GlobalLockFormat.scala b/core/src/main/scala/sbt/internal/librarymanagement/formats/GlobalLockFormat.scala index 2f4342d24..fffd9b6a8 100644 --- a/core/src/main/scala/sbt/internal/librarymanagement/formats/GlobalLockFormat.scala +++ b/core/src/main/scala/sbt/internal/librarymanagement/formats/GlobalLockFormat.scala @@ -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(_ => "", _ => 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() + } } diff --git a/core/src/main/scala/sbt/internal/librarymanagement/formats/LoggerFormat.scala b/core/src/main/scala/sbt/internal/librarymanagement/formats/LoggerFormat.scala index b751672bd..954b48127 100644 --- a/core/src/main/scala/sbt/internal/librarymanagement/formats/LoggerFormat.scala +++ b/core/src/main/scala/sbt/internal/librarymanagement/formats/LoggerFormat.scala @@ -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(_ => "", _ => Null) + + implicit lazy val LoggerFormat: JsonFormat[Logger] = implicitly } diff --git a/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala b/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala index 93c28a199..a57a9f4f3 100644 --- a/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala +++ b/core/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala @@ -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 diff --git a/core/src/main/scala/sbt/librarymanagement/Http.scala b/core/src/main/scala/sbt/librarymanagement/Http.scala index 3fee33b82..9870d9b0f 100644 --- a/core/src/main/scala/sbt/librarymanagement/Http.scala +++ b/core/src/main/scala/sbt/librarymanagement/Http.scala @@ -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) } diff --git a/core/src/main/scala/sbt/librarymanagement/LibraryManagementInterface.scala b/core/src/main/scala/sbt/librarymanagement/LibraryManagementInterface.scala index 6afc27e2d..33c72c55f 100644 --- a/core/src/main/scala/sbt/librarymanagement/LibraryManagementInterface.scala +++ b/core/src/main/scala/sbt/librarymanagement/LibraryManagementInterface.scala @@ -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 } diff --git a/core/src/test/scala/UpdateReportSpec.scala b/core/src/test/scala/UpdateReportSpec.scala new file mode 100644 index 000000000..cc7dfd7fd --- /dev/null +++ b/core/src/test/scala/UpdateReportSpec.scala @@ -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)) + +} diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala index f31d223d3..a90399b8b 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala @@ -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) } } diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/Ivy.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/Ivy.scala index 86c1ef5f2..dcf5f3327 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/Ivy.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/Ivy.scala @@ -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 + } + } } } diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/IvyLogger.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/IvyLogger.scala index f178a95f0..29f61222a 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/IvyLogger.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/IvyLogger.scala @@ -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) } diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/GigahorseUrlHandler.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/GigahorseUrlHandler.scala index 6603919b5..69ab22cf7 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/GigahorseUrlHandler.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/GigahorseUrlHandler.scala @@ -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) +} diff --git a/ivy/src/test/scala/CrossVersionTest.scala b/ivy/src/test/scala/CrossVersionTest.scala index b2c52a732..5ba8d8b72 100644 --- a/ivy/src/test/scala/CrossVersionTest.scala +++ b/ivy/src/test/scala/CrossVersionTest.scala @@ -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" } diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 57048034a..9f92915e6 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -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 diff --git a/project/build.properties b/project/build.properties index cd66fd542..12c38d389 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.0.0-M6 +sbt.version=1.0.0-RC3 diff --git a/project/plugins.sbt b/project/plugins.sbt index e5b186e6d..7ddf08986 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -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"