Skip to content

Commit

Permalink
Merge pull request #3 from tindzk/bug/meta-modules
Browse files Browse the repository at this point in the history
Bloop: Set correct dependencies on meta modules
  • Loading branch information
tindzk authored Jan 24, 2019
2 parents 4d46236 + b671366 commit aaf5b11
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 15 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
build/
target/
project/target/
test/
9 changes: 5 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ FROM alpine:3.8 as build
ARG BINTRAY_USERNAME
ARG BINTRAY_API

RUN apk add --no-cache openjdk8 python curl
RUN apk add --no-cache openjdk8 python curl nodejs

ENV LANG C.UTF-8
ENV JAVA_HOME /usr/lib/jvm/java-1.8-openjdk
ENV PATH $PATH:$JAVA_HOME/jre/bin:$JAVA_HOME/bin
ENV PATH $PATH:$JAVA_HOME/jre/bin:$JAVA_HOME/bin:/seed/bloop

COPY build.sbt BLOOP SEED COURSIER /seed/
COPY project/ /seed/project/
Expand All @@ -27,12 +27,13 @@ RUN curl -L https://github.com/scalacenter/bloop/releases/download/v$(cat BLOOP)

# Pre-fetch bridges and their dependencies to speed up dependency resolution
# later
RUN bloop/blp-coursier fetch \
RUN blp-coursier fetch \
ch.epfl.scala:bloop-js-bridge-0-6_2.12:$(cat BLOOP) \
ch.epfl.scala:bloop-js-bridge-1-0_2.12:$(cat BLOOP) \
ch.epfl.scala:bloop-native-bridge_2.12:$(cat BLOOP)

RUN set -x && \
(blp-server &) && \
curl -o csbt https://raw.githubusercontent.com/coursier/sbt-launcher/master/csbt && \
chmod +x csbt && \
(./csbt compile || \
Expand Down Expand Up @@ -62,7 +63,7 @@ RUN set -x && \
./csbt test && \
BINTRAY_USER=$BINTRAY_USERNAME BINTRAY_PASS=$BINTRAY_API ./csbt --add-coursier=true "; publishLocal; publish"

RUN bloop/blp-coursier bootstrap tindzk:seed_2.12:$(cat SEED) -f -o seed
RUN blp-coursier bootstrap tindzk:seed_2.12:$(cat SEED) -f -o seed

#
# Run stage
Expand Down
3 changes: 2 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ libraryDependencies ++= Seq(
"com.joefkelley" %% "argyle" % "1.0.0",
"org.scalaj" %% "scalaj-http" % "2.4.1",
"commons-io" % "commons-io" % "2.6",
"io.monix" %% "minitest" % "2.2.2" % "test",
"com.zaxxer" % "nuprocess" % "1.2.4" % "test",
"io.monix" %% "minitest" % "2.3.2" % "test",

scalaOrganization.value % "scala-reflect" % scalaVersion.value
)
Expand Down
14 changes: 4 additions & 10 deletions src/main/scala/seed/generation/Bloop.scala
Original file line number Diff line number Diff line change
Expand Up @@ -438,14 +438,11 @@ object Bloop {
name = name + "-test",
bloopPath = bloopPath,
buildPath = buildPath,
dependencies = targets.map(name + "-" + _ + "-test"),
dependencies = targets.map(t => name + "-" + t.id + "-test"),
classesDir = buildPath,
classPath = List(),
sources = List(),
// TODO Cannot be set to None
scalaCompiler = Some(Resolution.ScalaCompiler(
build.project.scalaOrganisation, build.project.scalaVersion, List(),
List())),
scalaCompiler = None,
scalaOptions = List(),
testFrameworks = List(),
platform = None)
Expand All @@ -457,14 +454,11 @@ object Bloop {
name = name,
bloopPath = bloopPath,
buildPath = buildPath,
dependencies = module.targets.map(name + "-" + _),
dependencies = module.targets.map(t => name + "-" + t.id),
classesDir = buildPath,
classPath = List(),
sources = List(),
// TODO Cannot be set to None
scalaCompiler = Some(Resolution.ScalaCompiler(
build.project.scalaOrganisation, build.project.scalaVersion, List(),
List())),
scalaCompiler = None,
scalaOptions = List(),
testFrameworks = List(),
platform = None)
Expand Down
75 changes: 75 additions & 0 deletions src/test/scala/seed/generation/BloopIntegrationSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package seed.generation

import java.nio.file.{Files, Paths}

import minitest.SimpleTestSuite
import org.apache.commons.io.FileUtils
import seed.artefact.{ArtefactResolution, Coursier}
import seed.generation.util.ProcessHelper
import seed.model.{Build, Platform}

import scala.concurrent.ExecutionContext.Implicits._

object BloopIntegrationSpec extends SimpleTestSuite {
testAsync("Generate and compile meta modules") {
val projectPath = Paths.get("test/meta-module")
if (Files.exists(projectPath)) FileUtils.deleteDirectory(projectPath.toFile)

val bloopPath = projectPath.resolve(".bloop")
val buildPath = projectPath.resolve("build")
val sourcePath = projectPath.resolve("src")

Set(bloopPath, buildPath, sourcePath)
.foreach(Files.createDirectories(_))

val build = Build(
project = Build.Project(
"2.12.8", scalaJsVersion = Some("0.6.26")),
module = Map("example" -> Build.Module(
sources = List(sourcePath),
targets = List(Platform.JVM, Platform.JavaScript))))

val resolvedIvyPath = Coursier.DefaultIvyPath
val resolvedCachePath = Coursier.DefaultCachePath

val compilerDeps = ArtefactResolution.allCompilerDeps(build)
val platformDeps = ArtefactResolution.allPlatformDeps(build)
val libraryDeps = ArtefactResolution.allLibraryDeps(build)

val resolution =
Coursier.resolveAndDownload(platformDeps ++ libraryDeps, build.resolvers,
resolvedIvyPath, resolvedCachePath, false)
val compilerResolution =
compilerDeps.map(d =>
Coursier.resolveAndDownload(d, build.resolvers, resolvedIvyPath,
resolvedCachePath, false))

Bloop.buildModule(
projectPath,
bloopPath,
buildPath,
build,
resolution,
compilerResolution,
build.module.keys.head,
build.module.values.head)

FileUtils.write(sourcePath.resolve("Main.scala").toFile,
"""object Main extends App { println("hello") }""",
"UTF-8")

def compile =
ProcessHelper.runBloop(projectPath)("compile", "example").map { x =>
assertEquals(x.contains("Compiled example-jvm"), true)
assertEquals(x.contains("Compiled example-js"), true)
}

def run =
ProcessHelper.runBloop(projectPath)("run", "example-js", "example-jvm")
.map { x =>
assertEquals(x.split("\n").count(_ == "hello"), 2)
}

for { _ <- compile; _ <- run } yield ()
}
}
95 changes: 95 additions & 0 deletions src/test/scala/seed/generation/util/ProcessHelper.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package seed.generation.util

import java.nio.ByteBuffer
import java.nio.file.Path
import java.util.concurrent.{Executors, TimeUnit}

import com.zaxxer.nuprocess.{NuAbstractProcessHandler, NuProcess, NuProcessBuilder}
import seed.Log

import scala.collection.JavaConverters._
import scala.concurrent.{Future, Promise}

sealed trait ProcessOutput
object ProcessOutput {
case class StdErr(output: String) extends ProcessOutput
case class StdOut(output: String) extends ProcessOutput
}

/**
* @param onProcStart Takes PID
* @param onProcExit Takes exit code
*/
class ProcessHandler(onLog: ProcessOutput => Unit,
onProcStart: Int => Unit,
onProcExit: Int => Unit
) extends NuAbstractProcessHandler {
override def onStart(nuProcess: NuProcess): Unit =
onProcStart(nuProcess.getPID)

override def onExit(statusCode: Int): Unit = onProcExit(statusCode)

override def onStderr(buffer: ByteBuffer, closed: Boolean): Unit =
if (!closed) {
val bytes = new Array[Byte](buffer.remaining)
buffer.get(bytes)
new String(bytes).split("\n").foreach(line =>
onLog(ProcessOutput.StdErr(line)))
}

override def onStdout(buffer: ByteBuffer, closed: Boolean): Unit =
if (!closed) {
val bytes = new Array[Byte](buffer.remaining)
buffer.get(bytes)
new String(bytes).split("\n").foreach(line =>
onLog(ProcessOutput.StdOut(line)))
}
}

object ProcessHelper {
val scheduler = Executors.newScheduledThreadPool(1)
def schedule(seconds: Int)(f: => Unit): Unit =
scheduler.schedule({ () => f }: Runnable, seconds, TimeUnit.SECONDS)

def runBloop(cwd: Path, silent: Boolean = false)
(args: String*): Future[String] = {
val promise = Promise[String]()
val sb = new StringBuilder
val pb = new NuProcessBuilder((List("bloop") ++ args).asJava)

var terminated = false

pb.setProcessListener(new ProcessHandler(
{ case ProcessOutput.StdOut(output) =>
if (!silent) Log.info("stdout: " + output)
sb.append(output + "\n")
case ProcessOutput.StdErr(output) =>
if (!silent) Log.error("stderr: " + output)
sb.append(output + "\n")
},
pid => if (!silent) Log.info("PID: " + pid) else (),
{ statusCode =>
if (!silent) Log.info("Status code: " + statusCode)
if (terminated || statusCode == 0) promise.success(sb.toString)
else promise.failure(new Exception("Status code: " + statusCode))
}
))
pb.setCwd(cwd)
val proc = pb.start()

// Work around a CI problem where onExit() does not get called on
// ProcessHandler
schedule(60) {
if (!promise.isCompleted) {
Log.error(s"Process did not terminate after 60s (isRunning = ${proc.isRunning})")
if (proc.isRunning) {
Log.error("Forcing termination...")
terminated = true
proc.destroy(true)
}
}
}

promise.future
}
}

0 comments on commit aaf5b11

Please sign in to comment.