diff --git a/build.sc b/build.sc index 2cb79cfa1..1f1d8c267 100644 --- a/build.sc +++ b/build.sc @@ -11,6 +11,7 @@ import $file.project.settings, settings.{ AlmondRepositories, AlmondSimpleModule, AlmondTestModule, + AlmondUnpublishedModule, BootstrapLauncher, DependencyListResource, ExternalSources, @@ -389,6 +390,7 @@ trait CoursierLogger extends Cross.Module[String] with AlmondModule { shared.logger() ) def ivyDeps = super.ivyDeps() ++ Agg( + Deps.collectionCompat, Deps.coursierApi, Deps.scalatags.applyBinaryVersion213_3(scalaVersion()) ) @@ -536,7 +538,7 @@ object scala extends Module { trait Examples extends SbtModule { private def examplesScalaVersion = "2.12.18" - private def baseRepoRoot = os.rel / "out" / "repo" + private def baseRepoRoot = os.sub / "out" / "repo" def scalaVersion = ScalaVersions.scala3Latest object test extends SbtModuleTests { def testFramework = "munit.Framework" @@ -578,11 +580,13 @@ trait TestKit extends Cross.Module[String] with CrossSbtModule with Bloop.Module def ivyDeps = super.ivyDeps() ++ Agg( Deps.expecty, Deps.osLib, - Deps.pprint + Deps.pprint, + Deps.testUtil ) } -trait TestDefinitions extends Cross.Module[String] with CrossSbtModule with Bloop.Module { +trait TestDefinitions extends Cross.Module[String] with AlmondUnpublishedModule with Bloop.Module { + def supports3 = true def crossScalaVersion = crossValue def skipBloop = !ScalaVersions.binaries.contains(crossScalaVersion) @@ -646,7 +650,8 @@ trait Integration extends SbtModule { def ivyDeps = super.ivyDeps() ++ Agg( Deps.munit, Deps.osLib, - Deps.pprint + Deps.pprint, + Deps.testUtil ) object test extends SbtModuleTests with TestCommand { diff --git a/modules/scala/coursier-logger/src/main/scala/almond/cslogger/NotebookCacheLogger.scala b/modules/scala/coursier-logger/src/main/scala/almond/cslogger/NotebookCacheLogger.scala index bbb6619b2..ebe5c5d7c 100644 --- a/modules/scala/coursier-logger/src/main/scala/almond/cslogger/NotebookCacheLogger.scala +++ b/modules/scala/coursier-logger/src/main/scala/almond/cslogger/NotebookCacheLogger.scala @@ -7,7 +7,7 @@ import java.lang.{Long => JLong} import java.util.UUID import java.util.concurrent.ConcurrentHashMap -import scala.collection.JavaConverters._ +import scala.jdk.CollectionConverters._ class NotebookCacheLogger( publish: OutputHandler, diff --git a/modules/scala/integration/src/main/scala/almond/integration/KernelLauncher.scala b/modules/scala/integration/src/main/scala/almond/integration/KernelLauncher.scala index 66480d4f3..586c5e2f6 100644 --- a/modules/scala/integration/src/main/scala/almond/integration/KernelLauncher.scala +++ b/modules/scala/integration/src/main/scala/almond/integration/KernelLauncher.scala @@ -9,6 +9,7 @@ import cats.effect.IO import cats.effect.unsafe.IORuntime import com.github.plokhotnyuk.jsoniter_scala.core.{readFromArray, writeToArray} import fs2.concurrent.SignallingRef +import io.github.alexarchambault.testutil.{TestOutput, TestUtil} import org.zeromq.ZMQ import java.io.{File, IOException} @@ -25,6 +26,10 @@ import scala.util.Properties object KernelLauncher { + def enableOutputFrame = System.getenv("CI") == null + def enableSilentOutput = true + def printOutputOnError = true + lazy val testScalaVersion = sys.props.getOrElse( "almond.test.scala-version", sys.error("almond.test.scala-version Java property not set") @@ -125,7 +130,7 @@ class KernelLauncher( def isTwoStepStartup = launcherType.isTwoStepStartup - private def generateLauncher(extraOptions: Seq[String] = Nil): os.Path = { + private def generateLauncher(output: TestOutput, extraOptions: Seq[String] = Nil): os.Path = { val perms: os.PermSet = if (Properties.isWin) null else "rwx------" val tmpDir = os.temp.dir(prefix = "almond-tests", perms = perms) val (jarDest, extraOpts) = @@ -170,7 +175,12 @@ class KernelLauncher( launcherArgs, extraOptions ) - .call(stdin = os.Inherit, stdout = os.Inherit, check = false) + .call( + stdin = os.Inherit, + stdout = output.processOutput, + stderr = output.processOutput, + check = false + ) if (res.exitCode != 0) sys.error( s"""Error generating an Almond $almondVersion launcher for Scala $defaultScalaVersion @@ -187,7 +197,16 @@ class KernelLauncher( jarDest } - private lazy val jarLauncher = generateLauncher() + private var jarLauncher0: os.Path = null + private def jarLauncher(output: TestOutput) = { + if (jarLauncher0 == null) + synchronized { + if (jarLauncher0 == null) + jarLauncher0 = generateLauncher(output) + } + + jarLauncher0 + } private lazy val threads = ZeromqThreads.create("almond-tests") @@ -195,13 +214,13 @@ class KernelLauncher( // creates a deadlock (on the CI, at least) private def perTestZeroMqContext = !Properties.isWin - private def stackTracePrinterThread(): Thread = + private def stackTracePrinterThread(output: TestOutput): Thread = new Thread("stack-trace-printer") { - import scala.collection.JavaConverters._ + import scala.jdk.CollectionConverters._ setDaemon(true) override def run(): Unit = try { - System.err.println("stack-trace-printer thread starting") + output.printStream.println("stack-trace-printer thread starting") while (true) { Thread.sleep(1.minute.toMillis) Thread.getAllStackTraces @@ -211,22 +230,22 @@ class KernelLauncher( .sortBy(_._1.getId) .foreach { case (t, stack) => - System.err.println(s"Thread $t (${t.getState}, ${t.getId})") + output.printStream.println(s"Thread $t (${t.getState}, ${t.getId})") for (e <- stack) - System.err.println(s" $e") - System.err.println() + output.printStream.println(s" $e") + output.printStream.println() } } } catch { case _: InterruptedException => - System.err.println("stack-trace-printer thread interrupted") + output.printStream.println("stack-trace-printer thread interrupted") } finally - System.err.println("stack-trace-printer thread exiting") + output.printStream.println("stack-trace-printer thread exiting") } - def session(conn: Connection, ctx: ZMQ.Context): Session with AutoCloseable = + def session(conn: Connection, ctx: ZMQ.Context, output: TestOutput): Session with AutoCloseable = new Session with AutoCloseable { def run(streams: ClientStreams): Unit = { @@ -261,17 +280,17 @@ class KernelLauncher( } if (perTestZeroMqContext) { - val t = stackTracePrinterThread() + val t = stackTracePrinterThread(output) try { t.start() - System.err.println("Closing test ZeroMQ context") + output.printStream.println("Closing test ZeroMQ context") IO(ctx.close()) .evalOn(threads.pollingEc) .unsafeRunTimed(2.minutes)(IORuntime.global) .getOrElse { sys.error("Timeout when closing ZeroMQ context") } - System.err.println("Test ZeroMQ context closed") + output.printStream.println("Test ZeroMQ context closed") } finally t.interrupt() @@ -279,9 +298,11 @@ class KernelLauncher( } } - def runner(): Runner with AutoCloseable = + private def runner(output0: TestOutput): Runner with AutoCloseable = new Runner with AutoCloseable { + def output: Option[TestOutput] = Some(output0) + override def differedStartUp = isTwoStepStartup var proc: os.SubProcess = null @@ -291,7 +312,8 @@ class KernelLauncher( private def setupJupyterDir[T]( options: Seq[String], launcherOptions: Seq[String], - extraClassPath: Seq[String] + extraClassPath: Seq[String], + output: TestOutput ): (os.Path => os.Shellable, Map[String, String]) = { val kernelId = "almond-it" @@ -300,9 +322,9 @@ class KernelLauncher( case LauncherType.Legacy => val jarLauncher0 = if (launcherOptions.isEmpty) - jarLauncher + jarLauncher(output) else - generateLauncher(launcherOptions) + generateLauncher(output, launcherOptions) val baseCp = (extraClassPath :+ jarLauncher0.toString) .filter(_.nonEmpty) .mkString(File.pathSeparator) @@ -318,7 +340,7 @@ class KernelLauncher( "java", "-Xmx1g", "-cp", - jarLauncher, + jarLauncher(output), "coursier.bootstrap.launcher.Launcher" ) } @@ -349,7 +371,7 @@ class KernelLauncher( twoStepStartupOpts, options ) - proc0.call(stdin = os.Inherit, stdout = os.Inherit) + proc0.call(stdin = os.Inherit, stdout = output.processOutput, stderr = output.processOutput) val specFile = dir / kernelId / "kernel.json" val spec = readFromArray(os.read.bytes(specFile))(KernelSpec.codec) @@ -374,62 +396,59 @@ class KernelLauncher( )(implicit sessionId: SessionId): T = withRunnerSession(options, launcherOptions, Nil)(f) - def apply(options: String*): Session = - runnerSession(options, Nil, Nil) - def withExtraClassPath(extraClassPath: String*)(options: String*): Session = - runnerSession(options, Nil, extraClassPath) - def withLauncherOptions(launcherOptions: String*)(options: String*): Session = - runnerSession(options, launcherOptions, Nil) - def withRunnerSession[T]( options: Seq[String], launcherOptions: Seq[String], extraClassPath: Seq[String] - )(f: Session => T)(implicit sessionId: SessionId): T = { - implicit val sess = runnerSession(options, launcherOptions, extraClassPath) - var running = true - - val currentThread = Thread.currentThread() - - val t: Thread = - new Thread("watch-kernel-proc") { - setDaemon(true) - override def run(): Unit = { - var done = false - while (running && !done) - done = proc.waitFor(100L) - if (running && done) { - val retCode = proc.exitCode() - System.err.println(s"Kernel process exited with code $retCode, interrupting test") - currentThread.interrupt() + )(f: Session => T)(implicit sessionId: SessionId): T = + TestUtil.runWithTimeout(Some(3.minutes)) { + implicit val sess = runnerSession(options, launcherOptions, extraClassPath, output0) + var running = true + + val currentThread = Thread.currentThread() + + val t: Thread = + new Thread("watch-kernel-proc") { + setDaemon(true) + override def run(): Unit = { + var done = false + while (running && !done) + done = proc.waitFor(100L) + if (running && done) { + val retCode = proc.exitCode() + output0.printStream.println( + s"Kernel process exited with code $retCode, interrupting test" + ) + currentThread.interrupt() + } } } - } - t.start() - try { - val t = f(sess) - if (Properties.isWin) - // On Windows, exit the kernel manually from the inside, so that all involved processes - // exit cleanly. A call to Process#destroy would only destroy the first kernel process, - // not any of its sub-processes (which would stay around, and such processes would end up - // filling up memory on Windows). - exit() - t - } - finally { - running = false - close() + t.start() + try { + val t0 = f(sess) + if (Properties.isWin) + // On Windows, exit the kernel manually from the inside, so that all involved processes + // exit cleanly. A call to Process#destroy would only destroy the first kernel process, + // not any of its sub-processes (which would stay around, and such processes would end up + // filling up memory on Windows). + exit() + t0 + } + finally { + running = false + close(Some(output0)) + } } - } private def runnerSession( options: Seq[String], launcherOptions: Seq[String], - extraClassPath: Seq[String] + extraClassPath: Seq[String], + output: TestOutput ): Session = { - close() + close(Some(output)) val dir = TmpDir.tmpDir() val connFile = dir / "connection.json" @@ -440,11 +459,11 @@ class KernelLauncher( os.write(connFile, writeToArray(connDetails)) val (command, specExtraEnv) = { - val (f, env0) = setupJupyterDir(options, launcherOptions, extraClassPath) + val (f, env0) = setupJupyterDir(options, launcherOptions, extraClassPath, output) (f(connFile), env0) } - System.err.println(s"Running ${command.value.mkString(" ")}") + output.printStream.println(s"Running ${command.value.mkString(" ")}") val extraEnv = if (isTwoStepStartup) { val baseRepos = sys.env.getOrElse( @@ -463,14 +482,15 @@ class KernelLauncher( cwd = dir, env = extraEnv ++ specExtraEnv, stdin = os.Inherit, - stdout = os.Inherit + stdout = output.processOutput, + stderr = output.processOutput ) if (System.getenv("CI") != null) { val delay = 4.seconds - System.err.println(s"Waiting $delay for the kernel to start") + output.printStream.println(s"Waiting $delay for the kernel to start") Thread.sleep(delay.toMillis) - System.err.println("Done waiting") + output.printStream.println("Done waiting") } val ctx = @@ -480,7 +500,7 @@ class KernelLauncher( bind = false, threads.copy(context = ctx), lingerPeriod = Some(Duration.Inf), - logCtx = TestLogging.logCtx, + logCtx = TestLogging.logCtxForOutput(output), identityOpt = Some(UUID.randomUUID().toString) ).unsafeRunTimed(2.minutes)(IORuntime.global).getOrElse { sys.error("Timeout when creating ZeroMQ connections") @@ -490,19 +510,25 @@ class KernelLauncher( sys.error("Timeout when opening ZeroMQ connections") } - val sess = session(conn, ctx) + val sess = session(conn, ctx, output) sessions = sess :: sessions sess } - def close(): Unit = { + def close(): Unit = + close(None) + def close(output: Option[TestOutput]): Unit = { + val ps = output match { + case Some(output0) => output0.printStream + case None => System.err + } sessions.foreach(_.close()) sessions = Nil jupyterDirs.foreach { dir => try os.remove.all(dir) catch { case e: FileSystemException if Properties.isWin => - System.err.println(s"Ignoring $e while trying to remove $dir") + ps.println(s"Ignoring $e while trying to remove $dir") } } jupyterDirs = Nil @@ -511,7 +537,7 @@ class KernelLauncher( proc.close() val timeout = 3.seconds if (!proc.waitFor(timeout.toMillis)) { - System.err.println( + ps.println( s"Test kernel still running after $timeout, destroying it forcibly" ) proc.destroyForcibly() @@ -526,12 +552,23 @@ class KernelLauncher( var runner0: Runner with AutoCloseable = null + val output = new TestOutput( + enableOutputFrame = enableOutputFrame, + enableSilentOutput = enableSilentOutput + ) + + var success = false try { - runner0 = runner() - f(runner0) + output.start() + runner0 = runner(output) + val res = f(runner0) + success = true + res } - finally + finally { runner0.close() + output.close(success = success, printOutputOnError = printOutputOnError) + } } } diff --git a/modules/scala/integration/src/test/scala/almond/integration/KernelTestsTwoStepStartup213.scala b/modules/scala/integration/src/test/scala/almond/integration/KernelTestsTwoStepStartup213.scala index 7b5f28ea9..9504c06e7 100644 --- a/modules/scala/integration/src/test/scala/almond/integration/KernelTestsTwoStepStartup213.scala +++ b/modules/scala/integration/src/test/scala/almond/integration/KernelTestsTwoStepStartup213.scala @@ -242,18 +242,19 @@ class KernelTestsTwoStepStartup213 extends KernelTestsDefinitions { os.write(tmpDir / "Handler.scala", handlerCode) - os.proc( - Tests.java17Cmd, - "-jar", - Tests.scalaCliLauncher.toString, - "--power", - "package", - ".", - "-o", - directivesHandler - ).call(cwd = tmpDir) - kernelLauncher.withKernel { implicit runner => + + os.proc( + Tests.java17Cmd, + "-jar", + Tests.scalaCliLauncher.toString, + "--power", + "package", + ".", + "-o", + directivesHandler + ).call(cwd = tmpDir, stderr = runner.output.map(_.processOutput).getOrElse(os.Inherit)) + implicit val sessionId: SessionId = SessionId() runner.withSession("--custom-directive-group", s"spark:$directivesHandler") { implicit session => diff --git a/modules/scala/scala-interpreter/src/main/scala-2/almond/internals/AlmondMetabrowseServer.scala b/modules/scala/scala-interpreter/src/main/scala-2/almond/internals/AlmondMetabrowseServer.scala index 0896fde35..f51653a99 100644 --- a/modules/scala/scala-interpreter/src/main/scala-2/almond/internals/AlmondMetabrowseServer.scala +++ b/modules/scala/scala-interpreter/src/main/scala-2/almond/internals/AlmondMetabrowseServer.scala @@ -12,9 +12,9 @@ import ammonite.runtime.Frame import ammonite.util.Util.newLine import metabrowse.server.{MetabrowseServer, Sourcepath} -import scala.collection.JavaConverters._ import scala.collection.compat._ import scala.collection.mutable +import scala.jdk.CollectionConverters._ import scala.meta.dialects import scala.tools.nsc.interactive.{Global => Interactive} import scala.util.Random diff --git a/modules/scala/scala-interpreter/src/main/scala-2/almond/internals/ScalaInterpreterInspections.scala b/modules/scala/scala-interpreter/src/main/scala-2/almond/internals/ScalaInterpreterInspections.scala index f29c857bd..4f7b57744 100644 --- a/modules/scala/scala-interpreter/src/main/scala-2/almond/internals/ScalaInterpreterInspections.scala +++ b/modules/scala/scala-interpreter/src/main/scala-2/almond/internals/ScalaInterpreterInspections.scala @@ -17,8 +17,8 @@ import scala.meta.pc.SymbolDocumentation import java.util.Optional -import scala.collection.JavaConverters._ import scala.collection.compat._ +import scala.jdk.CollectionConverters._ import scala.tools.nsc.interactive.{Global => Interactive} final class ScalaInterpreterInspections( diff --git a/modules/scala/scala-interpreter/src/test/scala/almond/ScalaKernelTests.scala b/modules/scala/scala-interpreter/src/test/scala/almond/ScalaKernelTests.scala index ce056930b..543a7468e 100644 --- a/modules/scala/scala-interpreter/src/test/scala/almond/ScalaKernelTests.scala +++ b/modules/scala/scala-interpreter/src/test/scala/almond/ScalaKernelTests.scala @@ -22,8 +22,8 @@ import cats.effect.IO import fs2.Stream import utest._ -import scala.collection.JavaConverters._ import scala.collection.compat._ +import scala.jdk.CollectionConverters._ object ScalaKernelTests extends TestSuite { diff --git a/modules/scala/scala-interpreter/src/test/scala/almond/TestUtil.scala b/modules/scala/scala-interpreter/src/test/scala/almond/TestUtil.scala index 39b1121cb..1ceefaf92 100644 --- a/modules/scala/scala-interpreter/src/test/scala/almond/TestUtil.scala +++ b/modules/scala/scala-interpreter/src/test/scala/almond/TestUtil.scala @@ -19,6 +19,7 @@ import fs2.Stream import java.nio.charset.StandardCharsets import java.nio.file.Paths +import scala.collection.compat._ import scala.concurrent.ExecutionContext import scala.concurrent.duration.Duration import scala.concurrent.duration.FiniteDuration @@ -64,12 +65,12 @@ object TestUtil { } final case class KernelRunner(kernel: Seq[String] => Kernel) extends Dsl.Runner { - def apply(options: String*): KernelSession = + private def apply(options: String*): KernelSession = new KernelSession(kernel(options)) - def withExtraClassPath(extraClassPath: String*)(options: String*): KernelSession = + private def withExtraClassPath(extraClassPath: String*)(options: String*): KernelSession = if (extraClassPath.isEmpty) apply(options: _*) else sys.error("Extra startup JARs unsupported in unit tests") - def withLauncherOptions(launcherOptions: String*)(options: String*): KernelSession = { + private def withLauncherOptions(launcherOptions: String*)(options: String*): KernelSession = { if (launcherOptions.nonEmpty) System.err.println( s"Warning: ignoring extra launcher options ${launcherOptions.mkString(" ")} in unit test" @@ -77,6 +78,8 @@ object TestUtil { apply(options: _*) } + def output = None + def withSession[T](options: String*)(f: Dsl.Session => T)(implicit sessionId: Dsl.SessionId ): T = { @@ -372,7 +375,7 @@ object TestUtil { for (k <- expectedReplies.keySet.--(replies0.keySet)) System.err.println(s"At line $k: expected ${expectedReplies(k)}, got nothing") - expect(replies0.mapValues(noCrLf).toMap == expectedReplies.mapValues(noCrLf).toMap) + expect(replies0.view.mapValues(noCrLf).toMap == expectedReplies.view.mapValues(noCrLf).toMap) expect(publish0.map(noCrLf) == publish.map(noCrLf)) } } diff --git a/modules/scala/test-definitions/src/main/scala/almond/integration/Tests.scala b/modules/scala/test-definitions/src/main/scala/almond/integration/Tests.scala index cc2b6f45c..e592425d3 100644 --- a/modules/scala/test-definitions/src/main/scala/almond/integration/Tests.scala +++ b/modules/scala/test-definitions/src/main/scala/almond/integration/Tests.scala @@ -10,7 +10,7 @@ import com.eed3si9n.expecty.Expecty.expect import java.io.File import java.util.UUID -import scala.collection.JavaConverters._ +import scala.jdk.CollectionConverters._ import scala.util.Properties object Tests { @@ -431,6 +431,14 @@ object Tests { val picocliJar = coursierapi.Fetch.create() .addDependencies(coursierapi.Dependency.of("info.picocli", "picocli", "4.7.3")) + .withCache( + coursierapi.Cache.create() + .withLogger( + coursierapi.Logger.progressBars( + runner.output.flatMap(_.outputStreamOpt).getOrElse(System.err) + ) + ) + ) .fetch() .asScala .head @@ -462,7 +470,11 @@ object Tests { "--print-class-path", "." ) - .call(cwd = tmpDir, stdin = os.Inherit) + .call( + cwd = tmpDir, + stdin = os.Inherit, + stderr = runner.output.map(_.processOutput).getOrElse(os.Inherit) + ) .out.trim() val predef = diff --git a/modules/shared/test-kit/src/main/scala/almond/testkit/Dsl.scala b/modules/shared/test-kit/src/main/scala/almond/testkit/Dsl.scala index e5b09f68d..c460ab970 100644 --- a/modules/shared/test-kit/src/main/scala/almond/testkit/Dsl.scala +++ b/modules/shared/test-kit/src/main/scala/almond/testkit/Dsl.scala @@ -8,6 +8,7 @@ import cats.effect.IO import com.eed3si9n.expecty.Expecty.expect import com.github.plokhotnyuk.jsoniter_scala.core.readFromArray import fs2.Stream +import io.github.alexarchambault.testutil.TestOutput import java.nio.charset.StandardCharsets import java.util.UUID @@ -17,10 +18,6 @@ import scala.util.Properties object Dsl { trait Runner { - def apply(options: String*): Session - def withExtraClassPath(extraClassPath: String*)(options: String*): Session - def withLauncherOptions(launcherOptions: String*)(options: String*): Session - def withSession[T](options: String*)(f: Session => T)(implicit sessionId: SessionId): T def withExtraClassPathSession[T](extraClassPath: String*)(options: String*)(f: Session => T)( implicit sessionId: SessionId @@ -30,6 +27,7 @@ object Dsl { ): T def differedStartUp: Boolean = false + def output: Option[TestOutput] } trait Session { diff --git a/modules/shared/test-kit/src/main/scala/almond/testkit/TestLogging.scala b/modules/shared/test-kit/src/main/scala/almond/testkit/TestLogging.scala index cb2563042..df12b68db 100644 --- a/modules/shared/test-kit/src/main/scala/almond/testkit/TestLogging.scala +++ b/modules/shared/test-kit/src/main/scala/almond/testkit/TestLogging.scala @@ -1,9 +1,10 @@ package almond.testkit import almond.logger.{Level, LoggerContext} +import io.github.alexarchambault.testutil.TestOutput object TestLogging { - val logCtx = LoggerContext.stderr( + private lazy val loggingLevel = sys.env.get("ALMOND_TEST_LOGGING") .orElse(sys.props.get("almond.test.logging")) .map { s => @@ -16,5 +17,9 @@ object TestLogging { .getOrElse( Level.Debug ) - ) + + def logCtxForOutput(output: TestOutput) = + LoggerContext.printStream(loggingLevel, output.printStream) + val logCtx = + LoggerContext.stderr(loggingLevel) } diff --git a/project/deps.sc b/project/deps.sc index 682c1a085..fabc281c8 100644 --- a/project/deps.sc +++ b/project/deps.sc @@ -76,6 +76,7 @@ object Deps { def scalatags = ivy"com.lihaoyi::scalatags:0.12.0" def slf4jNop = ivy"org.slf4j:slf4j-nop:1.7.36" def sourcecode = ivy"com.lihaoyi::sourcecode:0.3.0" + def testUtil = ivy"io.github.alexarchambault::test-util:0.1.3" def upickle = ivy"com.lihaoyi::upickle:3.1.4" // trying to use the same version as Ammonite, to avoid bin compat issues def upickleCompat(sv: String) = diff --git a/project/settings.sc b/project/settings.sc index 1e344144e..df522a223 100644 --- a/project/settings.sc +++ b/project/settings.sc @@ -209,6 +209,14 @@ trait AlmondSimpleModule with PublishLocalNoFluff with AlmondScalacOptions +trait AlmondUnpublishedModule + extends CrossSbtModule + with AlmondRepositories + with TransitiveSources + with AlmondArtifactName + with AlmondScala2Or3Module + with AlmondScalacOptions + trait AlmondModule extends CrossSbtModule with AlmondRepositories @@ -559,7 +567,7 @@ trait PropertyFile extends AlmondPublishModule { def propertyFilePath: String def propertyExtra: T[Seq[(String, String)]] = T(Seq.empty[(String, String)]) - def propResourcesDir = T.persistent { + def props = T { import sys.process._ val dir = T.dest / "property-resources" @@ -570,26 +578,26 @@ trait PropertyFile extends AlmondPublishModule { val f = dir / propertyFilePath.split('/').toSeq - val contentStr = - s"""commit-hash=${Seq("git", "rev-parse", "HEAD").!!.trim} - |version=$ver - |ammonite-spark-version=$ammSparkVer - |""".stripMargin + - propertyExtra() - .map { - case (k, v) => - s"""$k=$v - |""".stripMargin - } - .mkString + s"""commit-hash=${Seq("git", "rev-parse", "HEAD").!!.trim} + |version=$ver + |ammonite-spark-version=$ammSparkVer + |""".stripMargin + + propertyExtra() + .map { + case (k, v) => + s"""$k=$v + |""".stripMargin + } + .mkString + } + def propResourcesDir = T { + val dir = T.dest / "property-resources" + val f = dir / propertyFilePath.split('/').toSeq - val content = contentStr.getBytes("UTF-8") - val currentContentOpt = if (os.exists(f)) Some(os.read.bytes(f)) else None + val content = props().getBytes("UTF-8") - if (!os.exists(f) || !Arrays.equals(content, os.read.bytes(f))) { - os.write.over(f, content, createFolders = true) - System.err.println(s"Wrote $f") - } + os.write.over(f, content, createFolders = true) + System.err.println(s"Wrote $f") PathRef(dir) } @@ -599,7 +607,7 @@ trait PropertyFile extends AlmondPublishModule { } trait DependencyListResource extends CrossSbtModule { - def depResourcesDir = T.persistent { + def userDependencies = T { val (_, res) = Lib.resolveDependenciesMetadata( repositoriesTask(), transitiveIvyDeps(), @@ -607,7 +615,7 @@ trait DependencyListResource extends CrossSbtModule { customizer = resolutionCustomizer(), coursierCacheCustomizer = coursierCacheCustomizer() ) - val content = res + res .orderedDependencies .map { dep => (dep.module.organization.value, dep.module.name.value, dep.version) @@ -619,15 +627,15 @@ trait DependencyListResource extends CrossSbtModule { s"$org:$name:$ver" } .mkString("\n") - .getBytes("UTF-8") + } + def depResourcesDir = T { + val content = userDependencies().getBytes("UTF-8") val dir = T.dest / "dependency-resources" val f = dir / "almond" / "almond-user-dependencies.txt" - if (!os.exists(f) || !Arrays.equals(content, os.read.bytes(f))) { - os.write.over(f, content, createFolders = true) - System.err.println(s"Wrote $f") - } + os.write.over(f, content, createFolders = true) + System.err.println(s"Wrote $f") PathRef(dir) }