Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bloop: Set correct dependencies on meta modules #3

Merged
merged 1 commit into from
Jan 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
}