diff --git a/build.sbt b/build.sbt index 9a1e8b923..ec5065942 100644 --- a/build.sbt +++ b/build.sbt @@ -9,7 +9,7 @@ def buildLevelSettings: Seq[Setting[_]] = inThisBuild( Seq( organization := "org.scala-sbt", - version := "1.0.3-SNAPSHOT", + version := "1.1.0-SNAPSHOT", description := "sbt is an interactive build tool", bintrayOrganization := Some("sbt"), bintrayRepository := { diff --git a/main-actions/src/main/scala/sbt/compiler/Eval.scala b/main-actions/src/main/scala/sbt/compiler/Eval.scala index 3bd69b09a..a075f61a8 100644 --- a/main-actions/src/main/scala/sbt/compiler/Eval.scala +++ b/main-actions/src/main/scala/sbt/compiler/Eval.scala @@ -485,7 +485,11 @@ private[sbt] object Eval { def filesModifiedBytes(fs: Array[File]): Array[Byte] = if (fs eq null) filesModifiedBytes(Array[File]()) else seqBytes(fs)(fileModifiedBytes) def fileModifiedBytes(f: File): Array[Byte] = - (if (f.isDirectory) filesModifiedBytes(f listFiles classDirFilter) else bytes(f.lastModified)) ++ + (if (f.isDirectory) filesModifiedBytes(f listFiles classDirFilter) + else + bytes( + try IO.getModifiedTime(f) + catch { case _: java.io.FileNotFoundException => 0L })) ++ bytes(f.getAbsolutePath) def fileExistsBytes(f: File): Array[Byte] = bytes(f.exists) ++ diff --git a/main-command/src/main/java/sbt/internal/NGUnixDomainSocket.java b/main-command/src/main/java/sbt/internal/NGUnixDomainSocket.java index 1a9942ad9..b70bef611 100644 --- a/main-command/src/main/java/sbt/internal/NGUnixDomainSocket.java +++ b/main-command/src/main/java/sbt/internal/NGUnixDomainSocket.java @@ -29,6 +29,8 @@ import java.nio.ByteBuffer; import java.net.Socket; +import java.util.concurrent.atomic.AtomicInteger; + /** * Implements a {@link Socket} backed by a native Unix domain socket. * @@ -41,6 +43,25 @@ public class NGUnixDomainSocket extends Socket { private final InputStream is; private final OutputStream os; + public NGUnixDomainSocket(String path) throws IOException { + try { + AtomicInteger fd = new AtomicInteger( + NGUnixDomainSocketLibrary.socket( + NGUnixDomainSocketLibrary.PF_LOCAL, + NGUnixDomainSocketLibrary.SOCK_STREAM, + 0)); + NGUnixDomainSocketLibrary.SockaddrUn address = + new NGUnixDomainSocketLibrary.SockaddrUn(path); + int socketFd = fd.get(); + NGUnixDomainSocketLibrary.connect(socketFd, address, address.size()); + this.fd = new ReferenceCountedFileDescriptor(socketFd); + this.is = new NGUnixDomainSocketInputStream(); + this.os = new NGUnixDomainSocketOutputStream(); + } catch (LastErrorException e) { + throw new IOException(e); + } + } + /** * Creates a Unix domain socket backed by a native file descriptor. */ diff --git a/main-command/src/main/java/sbt/internal/NGUnixDomainSocketLibrary.java b/main-command/src/main/java/sbt/internal/NGUnixDomainSocketLibrary.java index 7e760d37a..4d781b6b6 100644 --- a/main-command/src/main/java/sbt/internal/NGUnixDomainSocketLibrary.java +++ b/main-command/src/main/java/sbt/internal/NGUnixDomainSocketLibrary.java @@ -131,6 +131,8 @@ public class NGUnixDomainSocketLibrary { public static native int listen(int fd, int backlog) throws LastErrorException; public static native int accept(int fd, SockaddrUn address, IntByReference addressLen) throws LastErrorException; + public static native int connect(int fd, SockaddrUn address, int addressLen) + throws LastErrorException; public static native int read(int fd, ByteBuffer buffer, int count) throws LastErrorException; public static native int write(int fd, ByteBuffer buffer, int count) diff --git a/main-command/src/main/scala/sbt/BasicKeys.scala b/main-command/src/main/scala/sbt/BasicKeys.scala index 42b68daa4..86dd9343f 100644 --- a/main-command/src/main/scala/sbt/BasicKeys.scala +++ b/main-command/src/main/scala/sbt/BasicKeys.scala @@ -11,6 +11,7 @@ import java.io.File import sbt.internal.util.AttributeKey import sbt.internal.inc.classpath.ClassLoaderCache import sbt.librarymanagement.ModuleID +import sbt.util.Level object BasicKeys { val historyPath = AttributeKey[Option[File]]( @@ -38,6 +39,14 @@ object BasicKeys { "The wire protocol for the server command.", 10000) + // Unlike other BasicKeys, this is not used directly as a setting key, + // and severLog / logLevel is used instead. + private[sbt] val serverLogLevel = + AttributeKey[Level.Value]("serverLogLevel", "The log level for the server.", 10000) + + private[sbt] val logLevel = + AttributeKey[Level.Value]("logLevel", "The amount of logging sent to the screen.", 10) + private[sbt] val interactive = AttributeKey[Boolean]( "interactive", "True if commands are currently being entered from an interactive environment.", diff --git a/main-command/src/main/scala/sbt/internal/server/Server.scala b/main-command/src/main/scala/sbt/internal/server/Server.scala index c4d3b542c..4fb8a7cb4 100644 --- a/main-command/src/main/scala/sbt/internal/server/Server.scala +++ b/main-command/src/main/scala/sbt/internal/server/Server.scala @@ -9,7 +9,7 @@ package sbt package internal package server -import java.io.File +import java.io.{ File, IOException } import java.net.{ SocketTimeoutException, InetAddress, ServerSocket, Socket } import java.util.concurrent.atomic.AtomicBoolean import java.nio.file.attribute.{ UserPrincipal, AclEntry, AclEntryPermission, AclEntryType } @@ -54,15 +54,17 @@ private[sbt] object Server { val serverThread = new Thread("sbt-socket-server") { override def run(): Unit = { Try { - ErrorHandling.translate(s"server failed to start on ${connection.shortName}. ") { - connection.connectionType match { - case ConnectionType.Local if isWindows => - new NGWin32NamedPipeServerSocket(pipeName) - case ConnectionType.Local => - prepareSocketfile() - new NGUnixDomainServerSocket(socketfile.getAbsolutePath) - case ConnectionType.Tcp => new ServerSocket(port, 50, InetAddress.getByName(host)) - } + connection.connectionType match { + case ConnectionType.Local if isWindows => + // Named pipe already has an exclusive lock. + addServerError(new NGWin32NamedPipeServerSocket(pipeName)) + case ConnectionType.Local => + tryClient(new NGUnixDomainSocket(socketfile.getAbsolutePath)) + prepareSocketfile() + addServerError(new NGUnixDomainServerSocket(socketfile.getAbsolutePath)) + case ConnectionType.Tcp => + tryClient(new Socket(InetAddress.getByName(host), port)) + addServerError(new ServerSocket(port, 50, InetAddress.getByName(host))) } } match { case Failure(e) => p.failure(e) @@ -87,6 +89,24 @@ private[sbt] object Server { } serverThread.start() + // Try the socket as a client to make sure that the server is not already up. + // f tries to connect to the server, and flip the result. + def tryClient(f: => Socket): Unit = { + if (portfile.exists) { + Try { f } match { + case Failure(e) => () + case Success(socket) => + socket.close() + throw new IOException("sbt server is already running.") + } + } else () + } + + def addServerError(f: => ServerSocket): ServerSocket = + ErrorHandling.translate(s"server failed to start on ${connection.shortName}. ") { + f + } + override def authenticate(challenge: String): Boolean = synchronized { if (token == challenge) { token = nextToken @@ -154,7 +174,7 @@ private[sbt] object Server { auth match { case _ if auth(ServerAuthentication.Token) => writeTokenfile() - PortFile(uri, Option(tokenfile.toString), Option(tokenfile.toURI.toString)) + PortFile(uri, Option(tokenfile.toString), Option(IO.toURI(tokenfile).toString)) case _ => PortFile(uri, None, None) } diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 912cd2a50..4b6e245fe 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -2316,7 +2316,7 @@ object Classpaths { case Some(period) => val fullUpdateOutput = cacheDirectory / "out" val now = System.currentTimeMillis - val diff = now - fullUpdateOutput.lastModified() + val diff = now - IO.getModifiedTime(fullUpdateOutput) val elapsedDuration = new FiniteDuration(diff, TimeUnit.MILLISECONDS) fullUpdateOutput.exists() && elapsedDuration > period } diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 3df25679d..bfcb3139e 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -94,7 +94,7 @@ object Keys { val TraceValues = "-1 to disable, 0 for up to the first sbt frame, or a positive number to set the maximum number of frames shown." // logging - val logLevel = settingKey[Level.Value]("The amount of logging sent to the screen.").withRank(ASetting) + val logLevel = SettingKey(BasicKeys.logLevel).withRank(ASetting) val persistLogLevel = settingKey[Level.Value]("The amount of logging sent to a file for persistence.").withRank(CSetting) val traceLevel = settingKey[Int]("The amount of a stack trace displayed. " + TraceValues).withRank(ASetting) val persistTraceLevel = settingKey[Int]("The amount of stack trace persisted.").withRank(CSetting) @@ -105,6 +105,7 @@ object Keys { val logManager = settingKey[LogManager]("The log manager, which creates Loggers for different contexts.").withRank(DSetting) val logBuffered = settingKey[Boolean]("True if logging should be buffered until work completes.").withRank(CSetting) val sLog = settingKey[Logger]("Logger usable by settings during project loading.").withRank(CSetting) + val serverLog = taskKey[Unit]("A dummy task to set server log level using Global / serverLog / logLevel.").withRank(CTask) // Project keys val autoGeneratedProject = settingKey[Boolean]("If it exists, represents that the project (and name) were automatically created, rather than user specified.").withRank(DSetting) diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 09d668c4b..6c605056e 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -103,7 +103,7 @@ object StandardMain { private[sbt] lazy val exchange = new CommandExchange() import scalacache._ import scalacache.caffeine._ - private[sbt] val cache: Cache[Any] = CaffeineCache[Any] + private[sbt] lazy val cache: Cache[Any] = CaffeineCache[Any] def runManaged(s: State): xsbti.MainResult = { val previous = TrapExit.installManager() @@ -135,9 +135,6 @@ object StandardMain { Exec(x, None) } val initAttrs = BuiltinCommands.initialAttributes - import scalacache.modes.scalaFuture._ - import scala.concurrent.ExecutionContext.Implicits.global - cache.removeAll() val s = State( configuration, initialDefinitions, diff --git a/main/src/main/scala/sbt/Project.scala b/main/src/main/scala/sbt/Project.scala index 680bba811..fd175f6c6 100755 --- a/main/src/main/scala/sbt/Project.scala +++ b/main/src/main/scala/sbt/Project.scala @@ -11,6 +11,7 @@ import java.io.File import java.net.URI import java.util.Locale import Project._ +import BasicKeys.serverLogLevel import Keys.{ stateBuildStructure, commands, @@ -21,9 +22,11 @@ import Keys.{ shellPrompt, templateResolverInfos, serverHost, + serverLog, serverPort, serverAuthentication, serverConnectionType, + logLevel, watch } import Scope.{ Global, ThisScope } @@ -41,7 +44,7 @@ import sbt.internal.util.{ AttributeKey, AttributeMap, Dag, Relation, Settings, import sbt.internal.util.Types.{ const, idFun } import sbt.internal.util.complete.DefaultParsers import sbt.librarymanagement.Configuration -import sbt.util.Show +import sbt.util.{ Show, Level } import sjsonnew.JsonFormat import language.experimental.macros @@ -463,6 +466,7 @@ object Project extends ProjectExtra { val port: Option[Int] = get(serverPort) val authentication: Option[Set[ServerAuthentication]] = get(serverAuthentication) val connectionType: Option[ConnectionType] = get(serverConnectionType) + val srvLogLevel: Option[Level.Value] = (logLevel in (ref, serverLog)).get(structure.data) val commandDefs = allCommands.distinct.flatten[Command].map(_ tag (projectCommand, true)) val newDefinedCommands = commandDefs ++ BasicCommands.removeTagged(s.definedCommands, projectCommand) @@ -477,6 +481,7 @@ object Project extends ProjectExtra { .put(historyPath.key, history) .put(templateResolverInfos.key, trs) .setCond(shellPrompt.key, prompt) + .setCond(serverLogLevel, srvLogLevel) s.copy( attributes = newAttrs, definedCommands = newDefinedCommands diff --git a/main/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala index 7bbb2c38b..39259ee28 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -13,7 +13,14 @@ import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.atomic.AtomicInteger import scala.collection.mutable.ListBuffer import scala.annotation.tailrec -import BasicKeys.{ serverHost, serverPort, serverAuthentication, serverConnectionType } +import BasicKeys.{ + serverHost, + serverPort, + serverAuthentication, + serverConnectionType, + serverLogLevel, + logLevel +} import java.net.Socket import sjsonnew.JsonFormat import sjsonnew.shaded.scalajson.ast.unsafe._ @@ -21,7 +28,7 @@ import scala.concurrent.Await import scala.concurrent.duration.Duration import scala.util.{ Success, Failure } import sbt.io.syntax._ -import sbt.io.Hash +import sbt.io.{ Hash, IO } import sbt.internal.server._ import sbt.internal.langserver.{ LogMessageParams, MessageType } import sbt.internal.util.{ StringEvent, ObjectEvent, MainAppender } @@ -106,7 +113,10 @@ private[sbt] final class CommandExchange { case Some(x) => x case None => ConnectionType.Tcp } - val serverLogLevel: Level.Value = Level.Debug + lazy val level: Level.Value = (s get serverLogLevel) + .orElse(s get logLevel) + .getOrElse(Level.Warn) + def onIncomingSocket(socket: Socket, instance: ServerInstance): Unit = { val name = newNetworkName s.log.info(s"new client connected: $name") @@ -114,7 +124,7 @@ private[sbt] final class CommandExchange { val log = LogExchange.logger(name, None, None) LogExchange.unbindLoggerAppenders(name) val appender = MainAppender.defaultScreen(s.globalLogging.console) - LogExchange.bindLoggerAppenders(name, List(appender -> serverLogLevel)) + LogExchange.bindLoggerAppenders(name, List(appender -> level)) log } val channel = @@ -125,7 +135,7 @@ private[sbt] final class CommandExchange { case Some(_) => // do nothing case _ => val portfile = (new File(".")).getAbsoluteFile / "project" / "target" / "active.json" - val h = Hash.halfHashString(portfile.toURI.toString) + val h = Hash.halfHashString(IO.toURI(portfile).toString) val tokenfile = BuildPaths.getGlobalBase(s) / "server" / h / "token.json" val socketfile = BuildPaths.getGlobalBase(s) / "server" / h / "sock" val pipeName = "sbt-server-" + h @@ -142,11 +152,13 @@ private[sbt] final class CommandExchange { Await.ready(x.ready, Duration("10s")) x.ready.value match { case Some(Success(_)) => + // rememeber to shutdown only when the server comes up + server = Some(x) case Some(Failure(e)) => s.log.error(e.toString) + server = None case None => // this won't happen because we awaited } - server = Some(x) } s } diff --git a/main/src/main/scala/sbt/internal/LibraryManagement.scala b/main/src/main/scala/sbt/internal/LibraryManagement.scala index a245344dc..fc832ffff 100644 --- a/main/src/main/scala/sbt/internal/LibraryManagement.scala +++ b/main/src/main/scala/sbt/internal/LibraryManagement.scala @@ -13,6 +13,7 @@ import sbt.internal.librarymanagement._ import sbt.librarymanagement._ import sbt.librarymanagement.syntax._ import sbt.util.{ CacheStore, CacheStoreFactory, Logger, Tracked } +import sbt.io.IO private[sbt] object LibraryManagement { @@ -126,7 +127,7 @@ private[sbt] object LibraryManagement { } private[this] def fileUptodate(file: File, stamps: Map[File, Long]): Boolean = - stamps.get(file).forall(_ == file.lastModified) + stamps.get(file).forall(_ == IO.getModifiedTime(file)) private[sbt] def transitiveScratch( lm: DependencyResolution, diff --git a/main/src/main/scala/sbt/internal/parser/SbtParser.scala b/main/src/main/scala/sbt/internal/parser/SbtParser.scala index 6e89cdf28..18dfa2b5e 100644 --- a/main/src/main/scala/sbt/internal/parser/SbtParser.scala +++ b/main/src/main/scala/sbt/internal/parser/SbtParser.scala @@ -116,9 +116,7 @@ private[sbt] object SbtParser { scalacGlobalInitReporter = Some(new ConsoleReporter(settings)) // Mix Positions, otherwise global ignores -Yrangepos - val global = new Global(settings, globalReporter) with Positions { - override protected def synchronizeNames = true // https://github.com/scala/bug/issues/10605 - } + val global = new Global(settings, globalReporter) with Positions val run = new global.Run // Add required dummy unit for initialization... val initFile = new BatchSourceFile("", "") @@ -151,7 +149,9 @@ private[sbt] object SbtParser { val wrapperFile = new BatchSourceFile(reporterId, code) val unit = new CompilationUnit(wrapperFile) val parser = new syntaxAnalyzer.UnitParser(unit) - val parsedTrees = parser.templateStats() + val parsedTrees = SbtParser.synchronized { // see https://github.com/scala/bug/issues/10605 + parser.templateStats() + } parser.accept(scala.tools.nsc.ast.parser.Tokens.EOF) globalReporter.throwParserErrorsIfAny(reporter, filePath) parsedTrees -> reporterId diff --git a/main/src/main/scala/sbt/internal/server/Definition.scala b/main/src/main/scala/sbt/internal/server/Definition.scala index 4459861db..0c39d15cd 100644 --- a/main/src/main/scala/sbt/internal/server/Definition.scala +++ b/main/src/main/scala/sbt/internal/server/Definition.scala @@ -9,6 +9,7 @@ package sbt package internal package server +import sbt.io.IO import sbt.internal.inc.MixedAnalyzingCompiler import sbt.internal.langserver.ErrorCodes import sbt.util.Logger @@ -297,7 +298,7 @@ private[sbt] object Definition { textProcessor.markPosition(classFile, sym).collect { case (file, line, from, to) => import sbt.internal.langserver.{ Location, Position, Range } - Location(file.toURI.toURL.toString, + Location(IO.toURI(file).toString, Range(Position(line, from), Position(line, to))) } } diff --git a/main/src/main/scala/sbt/internal/server/LanguageServerReporter.scala b/main/src/main/scala/sbt/internal/server/LanguageServerReporter.scala index 90d947a3d..28551be7c 100644 --- a/main/src/main/scala/sbt/internal/server/LanguageServerReporter.scala +++ b/main/src/main/scala/sbt/internal/server/LanguageServerReporter.scala @@ -24,6 +24,7 @@ import sbt.internal.langserver.{ import sbt.internal.inc.JavaInterfaceUtil._ import scala.collection.mutable import scala.collection.JavaConverters._ +import sbt.io.IO /** * Defines a compiler reporter that uses event logging provided by a [[ManagedLogger]]. @@ -82,7 +83,7 @@ class LanguageServerReporter( import sbt.internal.langserver.codec.JsonProtocol._ val files = analysis.readSourceInfos.getAllSourceInfos.keySet.asScala files foreach { f => - val params = PublishDiagnosticsParams(f.toURI.toString, Vector()) + val params = PublishDiagnosticsParams(IO.toURI(f).toString, Vector()) exchange.notifyEvent("textDocument/publishDiagnostics", params) } } @@ -94,7 +95,7 @@ class LanguageServerReporter( problemsByFile.get(sourceFile) match { case Some(xs: List[Problem]) => val ds = toDiagnostics(xs) - val params = PublishDiagnosticsParams(sourceFile.toURI.toString, ds) + val params = PublishDiagnosticsParams(IO.toURI(sourceFile).toString, ds) exchange.notifyEvent("textDocument/publishDiagnostics", params) case _ => } diff --git a/notes/1.1.0.markdown b/notes/1.1.0.markdown index 8bbfa3805..07d8a4a4a 100644 --- a/notes/1.1.0.markdown +++ b/notes/1.1.0.markdown @@ -1,3 +1,13 @@ +### Changes since RC-1 + +- Fixes Java compilation causing `NullPointerException` by making PositionImpl thread-safe. [zinc#465](https://github.com/sbt/zinc/pull/465) by [@eed3si9n][@eed3si9n] +- Restores Scala 2.13.0-M1 support. #461 by @dwijnand +- Fixes `PollingWatchService` by preventing concurrent modification of `keysWithEvents` map. [io#90](https://github.com/sbt/io/pull/90) by [@mechkg][@mechkg], which fixes `~` related issues [#3687](https://github.com/sbt/sbt/issues/3687), [#3695](https://github.com/sbt/sbt/issues/3695), and [#3775](https://github.com/sbt/sbt/issues/3775). +- Fixed server spewing out debug level logs. [#3791](https://github.com/sbt/sbt/pull/3791) by [@eed3si9n][@eed3si9n] +- Fixes the encoding of Unix-like file path to use `file:///`. [#3805](https://github.com/sbt/sbt/pull/3805) by [@eed3si9n][@eed3si9n] +- Fixes Log4J2 initialization error during startup. [#3814](https://github.com/sbt/sbt/pull/3814) by [@dwijnand][@dwijnand] +- Provides workaround for `File#lastModified()` losing millisecond-precision by using native code when possible. [io#92](https://github.com/sbt/io/pull/92) by [@cunei][@cunei] + ### Features, fixes, changes with compatibility implications - sbt server feature is reworked in sbt 1.1.0. See below. @@ -112,7 +122,7 @@ Currently this extension is able to: - Run `compile` at the root project when `*.scala` files are saved. [#3524][3524] by [@eed3si9n][@eed3si9n] - Display compiler errors. - Display log messages. [#3740][3740] by [@laughedelic][@laughedelic] -- Jump to class definitions. [#3660][3660] +- Jump to class definitions. [#3660][3660] by [@wpopielarski][@wpopielarski] ### Filtering scripted tests using `project/build.properties` @@ -122,6 +132,7 @@ This allows you to define scripted tests that track the minimum supported sbt ve [@eed3si9n]: https://github.com/eed3si9n [@dwijnand]: http://github.com/dwijnand + [@cunei]: https://github.com/cunei [@jvican]: https://github.com/jvican [@Duhemm]: https://github.com/Duhemm [@jonas]: https://github.com/jonas @@ -136,6 +147,7 @@ This allows you to define scripted tests that track the minimum supported sbt ve [@romanowski]: https://github.com/romanowski [@raboof]: https://github.com/raboof [@jilen]: https://github.com/jilen + [@mechkg]: https://github.com/mechkg [vscode-sbt-scala]: https://marketplace.visualstudio.com/items?itemName=lightbend.vscode-sbt-scala [1812]: https://github.com/sbt/sbt/issues/1812 [3524]: https://github.com/sbt/sbt/pull/3524 diff --git a/project/Dependencies.scala b/project/Dependencies.scala index a628f6aaf..f8e14429f 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -12,10 +12,10 @@ object Dependencies { val baseScalaVersion = scala212 // sbt modules - private val ioVersion = "1.1.1" - private val utilVersion = "1.1.0" - private val lmVersion = "1.1.0" - private val zincVersion = "1.1.0-RC1" + private val ioVersion = "1.1.2" + private val utilVersion = "1.1.1" + private val lmVersion = "1.1.1" + private val zincVersion = "1.1.0-RC3" private val sbtIO = "org.scala-sbt" %% "io" % ioVersion diff --git a/project/SiteMap.scala b/project/SiteMap.scala index ed1f5239e..2cfb5d8ea 100644 --- a/project/SiteMap.scala +++ b/project/SiteMap.scala @@ -68,6 +68,8 @@ object SiteMap { // generates a string suitable for a sitemap file representing the last modified time of the given File private[this] def lastModifiedString(f: File): String = { val formatter = new java.text.SimpleDateFormat("yyyy-MM-dd") + // TODO: replace lastModified() with sbt.io.Milli.getModifiedTime(), once the build + // has been upgraded to a version of sbt that includes sbt.io.Milli. formatter.format(new java.util.Date(f.lastModified)) } // writes the provided XML node to `output` and then gzips it to `gzipped` if `gzip` is true diff --git a/project/Util.scala b/project/Util.scala index 89556cd2e..0b87b02db 100644 --- a/project/Util.scala +++ b/project/Util.scala @@ -105,6 +105,8 @@ object Util { val timestamp = formatter.format(new Date) val content = versionLine(version) + "\ntimestamp=" + timestamp val f = dir / "xsbt.version.properties" + // TODO: replace lastModified() with sbt.io.Milli.getModifiedTime(), once the build + // has been upgraded to a version of sbt that includes sbt.io.Milli. if (!f.exists || f.lastModified < lastCompilationTime(analysis) || !containsVersion(f, version)) { s.log.info("Writing version information to " + f + " :\n" + content) IO.write(f, content) diff --git a/project/plugins.sbt b/project/plugins.sbt index 4cfe0e774..66097a8b9 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,15 +1,8 @@ scalaVersion := "2.12.3" scalacOptions ++= Seq("-feature", "-language:postfixOps") -addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.17") -// addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.6.0") -// addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "0.9.2") -// addSbtPlugin("com.typesafe.sbt" % "sbt-javaversioncheck" % "0.1.0") -// addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.2.0") - -addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.1") -addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.3.1") -addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.0-M1") +addSbtPlugin("org.scala-sbt" % "sbt-houserules" % "0.3.4") +addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.3.2") addSbtPlugin("com.lucidchart" % "sbt-scalafmt" % "1.14") addSbtPlugin("de.heikoseeberger" % "sbt-header" % "3.0.2") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.7.0") diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/ClientCapabilities.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/ClientCapabilities.scala index 7bbfe152a..8e046ede9 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/langserver/ClientCapabilities.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/ClientCapabilities.scala @@ -9,7 +9,7 @@ final class ClientCapabilities private () extends Serializable { override def equals(o: Any): Boolean = o match { - case x: ClientCapabilities => true + case _: ClientCapabilities => true case _ => false } override def hashCode: Int = { diff --git a/protocol/src/main/contraband-scala/sbt/protocol/CommandMessage.scala b/protocol/src/main/contraband-scala/sbt/protocol/CommandMessage.scala index 9292dbd16..79b15d024 100644 --- a/protocol/src/main/contraband-scala/sbt/protocol/CommandMessage.scala +++ b/protocol/src/main/contraband-scala/sbt/protocol/CommandMessage.scala @@ -11,7 +11,7 @@ abstract class CommandMessage() extends Serializable { override def equals(o: Any): Boolean = o match { - case x: CommandMessage => true + case _: CommandMessage => true case _ => false } override def hashCode: Int = { diff --git a/protocol/src/main/contraband-scala/sbt/protocol/EventMessage.scala b/protocol/src/main/contraband-scala/sbt/protocol/EventMessage.scala index 6e934413e..9e4435096 100644 --- a/protocol/src/main/contraband-scala/sbt/protocol/EventMessage.scala +++ b/protocol/src/main/contraband-scala/sbt/protocol/EventMessage.scala @@ -11,7 +11,7 @@ abstract class EventMessage() extends Serializable { override def equals(o: Any): Boolean = o match { - case x: EventMessage => true + case _: EventMessage => true case _ => false } override def hashCode: Int = { diff --git a/protocol/src/main/contraband-scala/sbt/protocol/SettingQueryResponse.scala b/protocol/src/main/contraband-scala/sbt/protocol/SettingQueryResponse.scala index a63a99897..f8fe40388 100644 --- a/protocol/src/main/contraband-scala/sbt/protocol/SettingQueryResponse.scala +++ b/protocol/src/main/contraband-scala/sbt/protocol/SettingQueryResponse.scala @@ -10,7 +10,7 @@ abstract class SettingQueryResponse() extends sbt.protocol.EventMessage() with S override def equals(o: Any): Boolean = o match { - case x: SettingQueryResponse => true + case _: SettingQueryResponse => true case _ => false } override def hashCode: Int = { diff --git a/sbt/src/sbt-test/project/cross-plugins-defaults/build.sbt b/sbt/src/sbt-test/project/cross-plugins-defaults/build.sbt index b1d361b5a..55b3bac97 100644 --- a/sbt/src/sbt-test/project/cross-plugins-defaults/build.sbt +++ b/sbt/src/sbt-test/project/cross-plugins-defaults/build.sbt @@ -1,4 +1,4 @@ -val baseSbt = "1.0" +val baseSbt = "1." val buildCrossList = List("2.10.6", "2.11.11", "2.12.2") scalaVersion in ThisBuild := "2.12.2" @@ -10,20 +10,20 @@ lazy val root = (project in file(".")) .settings( sbtPlugin := true, - TaskKey[Unit]("check") := mkCheck("2.12", "1.0").value, - TaskKey[Unit]("check2") := mkCheck("2.10", "0.13").value + TaskKey[Unit]("check") := mkCheck("2.12", "1.0", "1.").value, + TaskKey[Unit]("check2") := mkCheck("2.10", "0.13", "0.13").value ) lazy val app = (project in file("app")) -def mkCheck(scalaBinV: String, sbtBinVer: String) = Def task { +def mkCheck(scalaBinV: String, sbtBinVer: String, sbtVerPrefix: String) = Def task { val crossV = (sbtVersion in pluginCrossBuild).value val crossBinV = (sbtBinaryVersion in pluginCrossBuild).value val sv = projectID.value.extraAttributes("e:scalaVersion") assert(sbtVersion.value startsWith baseSbt, s"Wrong sbt version: ${sbtVersion.value}") assert(sv == scalaBinV, s"Wrong e:scalaVersion: $sv") assert(scalaBinaryVersion.value == scalaBinV, s"Wrong Scala binary version: ${scalaBinaryVersion.value}") - assert(crossV startsWith sbtBinVer, s"Wrong `sbtVersion in pluginCrossBuild`: $crossV") + assert(crossV startsWith sbtVerPrefix, s"Wrong `sbtVersion in pluginCrossBuild`: $crossV") val ur = update.value val cr = ur.configuration(Compile).get @@ -31,7 +31,7 @@ def mkCheck(scalaBinV: String, sbtBinVer: String) = Def task { val plugSv = mr.module.extraAttributes("scalaVersion") val plugSbtV = mr.module.extraAttributes("sbtVersion") assert(plugSv == scalaBinV, s"Wrong plugin scalaVersion: $plugSv") - assert(plugSbtV == sbtBinVer, s"Wrong plugin scalaVersion: $sbtBinVer") + assert(plugSbtV == sbtBinVer, s"Wrong plugin sbtVersion: $plugSbtV") // crossScalaVersions in app should not be affected, per se or after ^^ val appCrossScalaVersions = (crossScalaVersions in app).value.toList diff --git a/sbt/src/sbt-test/run/error/test b/sbt/src/sbt-test/run/error/test index a603016e6..d3599f40d 100644 --- a/sbt/src/sbt-test/run/error/test +++ b/sbt/src/sbt-test/run/error/test @@ -13,7 +13,6 @@ $ copy-file changes/ThreadRunError.scala src/main/scala/Run.scala $ copy-file changes/RunExplicitSuccess.scala src/main/scala/Run.scala > run -# https://github.com/sbt/sbt/issues/3543 -# # explicitly calling System.exit(1) should fail the 'run' task -# $ copy-file changes/RunExplicitFailure.scala src/main/scala/Run.scala -# -> run +# explicitly calling System.exit(1) should fail the 'run' task +$ copy-file changes/RunExplicitFailure.scala src/main/scala/Run.scala +-> run \ No newline at end of file diff --git a/testing/src/main/contraband-scala/sbt/protocol/testing/TestInitEvent.scala b/testing/src/main/contraband-scala/sbt/protocol/testing/TestInitEvent.scala index 978524687..b6178c40f 100644 --- a/testing/src/main/contraband-scala/sbt/protocol/testing/TestInitEvent.scala +++ b/testing/src/main/contraband-scala/sbt/protocol/testing/TestInitEvent.scala @@ -10,7 +10,7 @@ final class TestInitEvent private () extends sbt.protocol.testing.TestMessage() override def equals(o: Any): Boolean = o match { - case x: TestInitEvent => true + case _: TestInitEvent => true case _ => false } override def hashCode: Int = { diff --git a/testing/src/main/contraband-scala/sbt/protocol/testing/TestMessage.scala b/testing/src/main/contraband-scala/sbt/protocol/testing/TestMessage.scala index 406807c6f..3ef0f0a76 100644 --- a/testing/src/main/contraband-scala/sbt/protocol/testing/TestMessage.scala +++ b/testing/src/main/contraband-scala/sbt/protocol/testing/TestMessage.scala @@ -11,7 +11,7 @@ abstract class TestMessage() extends Serializable { override def equals(o: Any): Boolean = o match { - case x: TestMessage => true + case _: TestMessage => true case _ => false } override def hashCode: Int = {