diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 000000000..a0d3292f1 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,23 @@ +build: off + +init: + - git config --global core.autocrlf input + +install: + - cinst jdk8 -params 'installdir=C:\\jdk8' + - SET JAVA_HOME=C:\jdk8 + - SET PATH=C:\jdk8\bin;%PATH% + + - ps: | + Add-Type -AssemblyName System.IO.Compression.FileSystem + if (!(Test-Path -Path "C:\sbt" )) { + (new-object System.Net.WebClient).DownloadFile( + 'https://github.com/sbt/sbt/releases/download/v1.0.4/sbt-1.0.4.zip', + 'C:\sbt-bin.zip' + ) + [System.IO.Compression.ZipFile]::ExtractToDirectory("C:\sbt-bin.zip", "C:\sbt") + } + - SET PATH=C:\sbt\sbt\bin;%PATH% + - SET SBT_OPTS=-XX:MaxPermSize=2g -Xmx4g -Dfile.encoding=UTF8 +test_script: + - sbt "scripted actions/* server/*" diff --git a/build.sbt b/build.sbt index f9fe5937b..8a8643f45 100644 --- a/build.sbt +++ b/build.sbt @@ -34,6 +34,7 @@ def buildLevelSettings: Seq[Setting[_]] = scmInfo := Some(ScmInfo(url("https://github.com/sbt/sbt"), "git@github.com:sbt/sbt.git")), resolvers += Resolver.mavenLocal, scalafmtOnCompile := true, + scalafmtOnCompile in Sbt := false, scalafmtVersion := "1.3.0", )) @@ -328,8 +329,7 @@ lazy val commandProj = (project in file("main-command")) .settings( testedBaseSettings, name := "Command", - libraryDependencies ++= Seq(launcherInterface, sjsonNewScalaJson.value, templateResolverApi, - jna, jnaPlatform), + libraryDependencies ++= Seq(launcherInterface, sjsonNewScalaJson.value, templateResolverApi), managedSourceDirectories in Compile += baseDirectory.value / "src" / "main" / "contraband-scala", sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala", @@ -481,10 +481,9 @@ lazy val sbtIgnoredProblems = { } def runNpm(command: String, base: File, log: sbt.internal.util.ManagedLogger) = { - val npm = if (sbt.internal.util.Util.isWindows) "npm.cmd" else "npm" import scala.sys.process._ try { - val exitCode = Process(s"$npm $command", Option(base)) ! log + val exitCode = Process(s"npm $command", Option(base)) ! log if (exitCode != 0) throw new Exception("Process returned exit code: " + exitCode) } catch { case e: java.io.IOException => log.warn("failed to run npm " + e.getMessage) diff --git a/main-actions/src/main/scala/sbt/compiler/Eval.scala b/main-actions/src/main/scala/sbt/compiler/Eval.scala index a075f61a8..a9d97246a 100644 --- a/main-actions/src/main/scala/sbt/compiler/Eval.scala +++ b/main-actions/src/main/scala/sbt/compiler/Eval.scala @@ -485,12 +485,10 @@ 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) + (if (f.isDirectory) + filesModifiedBytes(f listFiles classDirFilter) else - bytes( - try IO.getModifiedTime(f) - catch { case _: java.io.FileNotFoundException => 0L })) ++ - bytes(f.getAbsolutePath) + bytes(IO.getModifiedTimeOrZero(f))) ++ bytes(f.getAbsolutePath) def fileExistsBytes(f: File): Array[Byte] = bytes(f.exists) ++ bytes(f.getAbsolutePath) diff --git a/main-command/src/main/java/sbt/internal/NGWin32NamedPipeLibrary.java b/main-command/src/main/java/sbt/internal/NGWin32NamedPipeLibrary.java index ba535691f..dd4d8f15a 100644 --- a/main-command/src/main/java/sbt/internal/NGWin32NamedPipeLibrary.java +++ b/main-command/src/main/java/sbt/internal/NGWin32NamedPipeLibrary.java @@ -29,7 +29,7 @@ import com.sun.jna.ptr.IntByReference; import com.sun.jna.win32.W32APIOptions; -public interface NGWin32NamedPipeLibrary extends WinNT { +public interface NGWin32NamedPipeLibrary extends Library, WinNT { int PIPE_ACCESS_DUPLEX = 3; int PIPE_UNLIMITED_INSTANCES = 255; int FILE_FLAG_FIRST_PIPE_INSTANCE = 524288; 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 4fb8a7cb4..521c8d399 100644 --- a/main-command/src/main/scala/sbt/internal/server/Server.scala +++ b/main-command/src/main/scala/sbt/internal/server/Server.scala @@ -97,7 +97,7 @@ private[sbt] object Server { case Failure(e) => () case Success(socket) => socket.close() - throw new IOException("sbt server is already running.") + throw new AlreadyRunningException() } } else () } @@ -210,3 +210,5 @@ private[sbt] case class ServerConnection( } } } + +private[sbt] class AlreadyRunningException extends IOException("sbt server is already running.") diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 9471fa8c9..0b82ce8ea 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -2318,7 +2318,7 @@ object Classpaths { case Some(period) => val fullUpdateOutput = cacheDirectory / "out" val now = System.currentTimeMillis - val diff = now - IO.getModifiedTime(fullUpdateOutput) + val diff = now - IO.getModifiedTimeOrZero(fullUpdateOutput) val elapsedDuration = new FiniteDuration(diff, TimeUnit.MILLISECONDS) fullUpdateOutput.exists() && elapsedDuration > period } diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 7732d2323..75401eacd 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -128,6 +128,9 @@ object StandardMain { def initialState(configuration: xsbti.AppConfiguration, initialDefinitions: Seq[Command], preCommands: Seq[String]): State = { + // This is to workaround https://github.com/sbt/io/issues/110 + sys.props.put("jna.nosys", "true") + import BasicCommandStrings.isEarlyCommand val userCommands = configuration.arguments.map(_.trim) val (earlyCommands, normalCommands) = (preCommands ++ userCommands).partition(isEarlyCommand) diff --git a/main/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala index 443c9642c..33fbfa986 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -10,7 +10,7 @@ package internal import java.io.IOException import java.util.concurrent.ConcurrentLinkedQueue -import java.util.concurrent.atomic.AtomicInteger +import java.util.concurrent.atomic._ import scala.collection.mutable.ListBuffer import scala.annotation.tailrec import BasicKeys.{ @@ -26,7 +26,7 @@ import sjsonnew.JsonFormat import sjsonnew.shaded.scalajson.ast.unsafe._ import scala.concurrent.Await import scala.concurrent.duration.Duration -import scala.util.{ Success, Failure } +import scala.util.{ Success, Failure, Try } import sbt.io.syntax._ import sbt.io.{ Hash, IO } import sbt.internal.server._ @@ -48,6 +48,7 @@ private[sbt] final class CommandExchange { private val lock = new AnyRef {} private var server: Option[ServerInstance] = None + private val firstInstance: AtomicBoolean = new AtomicBoolean(true) private var consoleChannel: Option[ConsoleChannel] = None private val commandQueue: ConcurrentLinkedQueue[Exec] = new ConcurrentLinkedQueue() private val channelBuffer: ListBuffer[CommandChannel] = new ListBuffer() @@ -131,7 +132,8 @@ private[sbt] final class CommandExchange { subscribe(channel) } server match { - case Some(_) => // do nothing + case Some(_) => // do nothing + case None if !firstInstance.get => // there's another server case _ => val portfile = (new File(".")).getAbsoluteFile / "project" / "target" / "active.json" val h = Hash.halfHashString(IO.toURI(portfile).toString) @@ -148,15 +150,27 @@ private[sbt] final class CommandExchange { socketfile, pipeName) val x = Server.start(connection, onIncomingSocket, s.log) - Await.ready(x.ready, Duration("10s")) + + // don't throw exception when it times out + val d = "10s" + Try(Await.ready(x.ready, Duration(d))) x.ready.value match { case Some(Success(_)) => // rememeber to shutdown only when the server comes up server = Some(x) + case Some(Failure(e: AlreadyRunningException)) => + s.log.warn( + "sbt server could not start because there's another instance of sbt running on this build.") + s.log.warn("Running multiple instances is unsupported") + server = None + firstInstance.set(false) case Some(Failure(e)) => s.log.error(e.toString) server = None - case None => // this won't happen because we awaited + case None => + s.log.warn(s"sbt server could not start in $d") + server = None + firstInstance.set(false) } } s @@ -190,6 +204,7 @@ private[sbt] final class CommandExchange { case xs => lock.synchronized { channelBuffer --= xs + () } } } @@ -228,6 +243,7 @@ private[sbt] final class CommandExchange { case xs => lock.synchronized { channelBuffer --= xs + () } } } @@ -269,6 +285,7 @@ private[sbt] final class CommandExchange { case xs => lock.synchronized { channelBuffer --= xs + () } } } @@ -310,6 +327,7 @@ private[sbt] final class CommandExchange { case xs => lock.synchronized { channelBuffer --= xs + () } } } diff --git a/main/src/main/scala/sbt/internal/LibraryManagement.scala b/main/src/main/scala/sbt/internal/LibraryManagement.scala index 66fa494c1..28a40c5c7 100644 --- a/main/src/main/scala/sbt/internal/LibraryManagement.scala +++ b/main/src/main/scala/sbt/internal/LibraryManagement.scala @@ -121,7 +121,7 @@ private[sbt] object LibraryManagement { } private[this] def fileUptodate(file: File, stamps: Map[File, Long]): Boolean = - stamps.get(file).forall(_ == IO.getModifiedTime(file)) + stamps.get(file).forall(_ == IO.getModifiedTimeOrZero(file)) private[sbt] def transitiveScratch( lm: DependencyResolution, diff --git a/notes/1.1.0.markdown b/notes/1.1.0.markdown index 07d8a4a4a..29ed283f7 100644 --- a/notes/1.1.0.markdown +++ b/notes/1.1.0.markdown @@ -1,12 +1,19 @@ +### Changes since RC-2 + +- Provides workaround for `File#lastModified()` losing millisecond-precision by using native code when possible. [io#92](https://github.com/sbt/io/pull/92)/[io#106](https://github.com/sbt/io/pull/106) by [@cunei][@cunei] +- Fixes `IO.relativize` not working with relative path. [io#108](https://github.com/sbt/io/pull/108) by [@dwijnand][@dwijnand] +- Fixes `ClasspathFilter` that was causing `Class.forName` to not work in `run`. [zinc#473](https://github.com/sbt/zinc/pull/473) / [#3736](https://github.com/sbt/sbt/issues/3736) / [#3733](https://github.com/sbt/sbt/issues/3733) / [#3647](https://github.com/sbt/sbt/issues/3647) / [#3608](https://github.com/sbt/sbt/issues/3608) by [@ravwojdyla][@ravwojdyla] +- Fixes JNA version mixup. [#3837](https://github.com/sbt/sbt/pull/3837) by [@eed3si9n][@eed3si9n] +- Fixes warning message when multiple instances are detected. [#3828](https://github.com/sbt/sbt/pull/3828) by [@eed3si9n][@eed3si9n] + ### 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 +- Restores Scala 2.13.0-M1 support. #461 by [@dwijnand][@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 @@ -148,6 +155,7 @@ This allows you to define scripted tests that track the minimum supported sbt ve [@raboof]: https://github.com/raboof [@jilen]: https://github.com/jilen [@mechkg]: https://github.com/mechkg + [@ravwojdyla]: https://github.com/ravwojdyla [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 f8e14429f..f8d470ccd 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.2" - private val utilVersion = "1.1.1" - private val lmVersion = "1.1.1" - private val zincVersion = "1.1.0-RC3" + private val ioVersion = "1.1.3" + private val utilVersion = "1.1.2" + private val lmVersion = "1.1.2" + private val zincVersion = "1.1.0" private val sbtIO = "org.scala-sbt" %% "io" % ioVersion @@ -106,8 +106,6 @@ object Dependencies { val specs2 = "org.specs2" %% "specs2-junit" % "4.0.1" val junit = "junit" % "junit" % "4.11" val templateResolverApi = "org.scala-sbt" % "template-resolver" % "0.1" - val jna = "net.java.dev.jna" % "jna" % "4.1.0" - val jnaPlatform = "net.java.dev.jna" % "jna-platform" % "4.1.0" private def scala211Module(name: String, moduleVersion: String) = Def setting ( scalaBinaryVersion.value match { diff --git a/project/Scripted.scala b/project/Scripted.scala index 932d55a0f..788f1d60e 100644 --- a/project/Scripted.scala +++ b/project/Scripted.scala @@ -37,6 +37,9 @@ trait ScriptedKeys { } object Scripted { + // This is to workaround https://github.com/sbt/io/issues/110 + sys.props.put("jna.nosys", "true") + lazy val MavenResolverPluginTest = config("mavenResolverPluginTest") extend Compile lazy val RepoOverrideTest = config("repoOverrideTest") extend Compile diff --git a/project/SiteMap.scala b/project/SiteMap.scala index 2cfb5d8ea..95e038eab 100644 --- a/project/SiteMap.scala +++ b/project/SiteMap.scala @@ -68,8 +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. + // TODO: replace lastModified() with sbt.io.IO.getModifiedTimeOrZero(), once the build + // has been upgraded to a version of sbt that includes that call. 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 4cdb02029..74ecb1c9f 100644 --- a/project/Util.scala +++ b/project/Util.scala @@ -106,8 +106,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. + // TODO: replace lastModified() with sbt.io.IO.getModifiedTimeOrZero(), once the build + // has been upgraded to a version of sbt that includes that call. 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/build.properties b/project/build.properties index 94005e587..394cb75cf 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.0.0 +sbt.version=1.0.4 diff --git a/project/plugins.sbt b/project/plugins.sbt index 4503fc161..7ea70f8ea 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,8 +1,7 @@ scalaVersion := "2.12.4" scalacOptions ++= Seq("-feature", "-language:postfixOps") -addSbtPlugin("org.scala-sbt" % "sbt-houserules" % "0.3.4") +addSbtPlugin("org.scala-sbt" % "sbt-houserules" % "0.3.5") 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/sbt/src/sbt-test/tests/fork-parallel/test b/sbt/src/sbt-test/tests/fork-parallel/test index 9d76b41e6..662328f42 100644 --- a/sbt/src/sbt-test/tests/fork-parallel/test +++ b/sbt/src/sbt-test/tests/fork-parallel/test @@ -1,8 +1,19 @@ -# https://github.com/sbt/sbt/issues/3545 +# The tests/fork-parallel test will currently always +# report success when run on less than four cores, +# rather than failing in one of the two cases as expected. +# TODO: Adjust this scripted test so that it works as +# intended on less than four cores as well. + +# To debug, it is possible to limit the number of cores +# reported to sbt, and run the test, by using: +# taskset 0x00000003 sbt 'scripted tests/fork-parallel' +# See: https://github.com/sbt/sbt/issues/3545 + +# This bit won't currently work when using less than four cores. # > test # -> check > clean > set testForkedParallel := true > test -> check \ No newline at end of file +> check diff --git a/src/main/conscript/scalas/launchconfig b/src/main/conscript/scalas/launchconfig index 497187233..98febc38c 100644 --- a/src/main/conscript/scalas/launchconfig +++ b/src/main/conscript/scalas/launchconfig @@ -4,7 +4,7 @@ [app] org: ${sbt.organization-org.scala-sbt} name: sbt - version: ${sbt.version-read(sbt.version)[1.0.0]} + version: ${sbt.version-read(sbt.version)[1.1.0]} class: sbt.ScriptMain components: xsbti,extra cross-versioned: ${sbt.cross.versioned-false} diff --git a/src/main/conscript/screpl/launchconfig b/src/main/conscript/screpl/launchconfig index 4701c697e..17a32efb0 100644 --- a/src/main/conscript/screpl/launchconfig +++ b/src/main/conscript/screpl/launchconfig @@ -4,7 +4,7 @@ [app] org: ${sbt.organization-org.scala-sbt} name: sbt - version: ${sbt.version-read(sbt.version)[1.0.0]} + version: ${sbt.version-read(sbt.version)[1.1.0]} class: sbt.ConsoleMain components: xsbti,extra cross-versioned: ${sbt.cross.versioned-false} diff --git a/src/main/conscript/xsbt/launchconfig b/src/main/conscript/xsbt/launchconfig index e47a59083..79ddd5ef7 100644 --- a/src/main/conscript/xsbt/launchconfig +++ b/src/main/conscript/xsbt/launchconfig @@ -4,7 +4,7 @@ [app] org: ${sbt.organization-org.scala-sbt} name: sbt - version: ${sbt.version-read(sbt.version)[1.0.0]} + version: ${sbt.version-read(sbt.version)[1.1.0]} class: sbt.xMain components: xsbti,extra cross-versioned: ${sbt.cross.versioned-false}