-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from tindzk/bug/meta-modules
Bloop: Set correct dependencies on meta modules
- Loading branch information
Showing
6 changed files
with
182 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ | |
build/ | ||
target/ | ||
project/target/ | ||
test/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 () | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |