Skip to content

Commit

Permalink
Merge branch 'master' into dsilvasc-implementation-deps
Browse files Browse the repository at this point in the history
  • Loading branch information
dsilvasc committed Sep 4, 2018
2 parents 40f9bbb + f8492fd commit d6c250f
Show file tree
Hide file tree
Showing 46 changed files with 2,554 additions and 579 deletions.
57 changes: 45 additions & 12 deletions backend/src/main/scala/bloop/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,32 @@ import xsbti.compile._
import xsbti.T2
import java.util.Optional
import java.io.File
import java.net.URI

import bloop.internal.Ecosystem
import bloop.io.{AbsolutePath, Paths}
import bloop.logging.Logger
import bloop.reporter.Reporter
import sbt.internal.inc.{FreshCompilerCache, Locate, ZincUtil}
import sbt.internal.inc.bloop.{BloopZincCompiler, CompileMode}
import sbt.internal.inc.{FreshCompilerCache, Locate}
import _root_.monix.eval.Task
import sbt.internal.inc.bloop.internal.StopPipelining

case class CompileInputs(
scalaInstance: ScalaInstance,
compilerCache: CompilerCache,
sources: Array[AbsolutePath],
classpath: Array[AbsolutePath],
picklepath: Array[URI],
classesDir: AbsolutePath,
baseDirectory: AbsolutePath,
scalacOptions: Array[String],
javacOptions: Array[String],
compileOrder: CompileOrder,
classpathOptions: ClasspathOptions,
previousResult: PreviousResult,
reporter: Reporter,
mode: CompileMode,
logger: Logger
)

Expand All @@ -40,12 +47,27 @@ object Compiler {
final case object Empty extends Result
final case class Blocked(on: List[String]) extends Result
final case class Cancelled(elapsed: Long) extends Result
final case class Failed(problems: Array[xsbti.Problem], elapsed: Long) extends Result
final case class Failed(problems: List[xsbti.Problem], t: Option[Throwable], elapsed: Long)
extends Result
final case class Success(reporter: Reporter, previous: PreviousResult, elapsed: Long)
extends Result

object Ok {
def unapply(result: Result): Option[Result] = result match {
case s @ (Success(_, _, _) | Empty) => Some(s)
case _ => None
}
}

object NotOk {
def unapply(result: Result): Option[Result] = result match {
case f @ (Failed(_, _, _) | Cancelled(_) | Blocked(_)) => Some(f)
case _ => None
}
}
}

def compile(compileInputs: CompileInputs): Result = {
def compile(compileInputs: CompileInputs): Task[Result] = {
def getInputs(compilers: Compilers): Inputs = {
val options = getCompilationOptions(compileInputs)
val setup = getSetup(compileInputs)
Expand All @@ -62,9 +84,11 @@ object Compiler {
.withClassesDirectory(classesDir)
.withSources(sources.map(_.toFile))
.withClasspath(classpath)
.withPicklepath(inputs.picklepath)
.withScalacOptions(inputs.scalacOptions)
.withJavacOptions(inputs.javacOptions)
.withClasspathOptions(inputs.classpathOptions)
.withOrder(inputs.compileOrder)
}

def getSetup(compileInputs: CompileInputs): Setup = {
Expand All @@ -79,26 +103,35 @@ object Compiler {
else Ecosystem.supportDotty(IncOptions.create())
}
val progress = Optional.empty[CompileProgress]
Setup.create(lookup, skip, cacheFile, compilerCache, incOptions, reporter, progress, empty)
val setup =
Setup.create(lookup, skip, cacheFile, compilerCache, incOptions, reporter, progress, empty)
compileInputs.mode match {
case CompileMode.Pipelined(pickleUri, _) => setup.withPicklePromise(pickleUri)
case CompileMode.ParallelAndPipelined(_, pickleUri, _) => setup.withPicklePromise(pickleUri)
case _ => setup
}
}

val start = System.nanoTime()
val scalaInstance = compileInputs.scalaInstance
val classpathOptions = compileInputs.classpathOptions
val compilers = compileInputs.compilerCache.get(scalaInstance)
val inputs = getInputs(compilers)
val incrementalCompiler = ZincUtil.defaultIncrementalCompiler

// We don't want nanosecond granularity, we're happy with milliseconds
def elapsed: Long = ((System.nanoTime() - start).toDouble / 1e6).toLong

try {
val result0 = incrementalCompiler.compile(inputs, compileInputs.logger)
val result = PreviousResult.of(Optional.of(result0.analysis()), Optional.of(result0.setup()))
Result.Success(compileInputs.reporter, result, elapsed)
} catch {
case f: xsbti.CompileFailed => Result.Failed(f.problems(), elapsed)
case _: xsbti.CompileCancelled => Result.Cancelled(elapsed)
import scala.util.{Success, Failure}
BloopZincCompiler.compile(inputs, compileInputs.mode, compileInputs.logger).materialize.map {
case Success(result) =>
val prev = PreviousResult.of(Optional.of(result.analysis()), Optional.of(result.setup()))
Result.Success(compileInputs.reporter, prev, elapsed)
case Failure(f: StopPipelining) => Result.Blocked(f.failedProjectNames)
case Failure(f: xsbti.CompileFailed) => Result.Failed(f.problems().toList, None, elapsed)
case Failure(_: xsbti.CompileCancelled) => Result.Cancelled(elapsed)
case Failure(t: Throwable) =>
t.printStackTrace()
Result.Failed(Nil, Some(t), elapsed)
}
}
}
130 changes: 130 additions & 0 deletions backend/src/main/scala/bloop/monix/Java8Compat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* Copyright (c) 2014-2018 by The Monix Project Developers.
* See the project homepage at: https://monix.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package bloop.monix

import java.util.concurrent.{CancellationException, CompletableFuture, CompletionException}
import java.util.function.BiFunction

import monix.execution.cancelables.SingleAssignmentCancelable
import monix.execution.misc.NonFatal
import monix.execution.schedulers.TrampolinedRunnable
import monix.execution.{Cancelable, CancelableFuture}

import scala.concurrent.{ExecutionContext, Future, Promise}
import scala.util.{Failure, Success, Try}


/** Utilities for integration with Java 8 classes
*
* Provides methods to convert between `scala.concurrent.Future`
* and `java.util.concurrent.CompletableFuture`.
*
* These utilities have been copy-pasted from the following PR (only
* merged in the 3.x series): https://github.com/monix/monix/pull/584
*/
object Java8Compat {

/** Given a registration function that can execute an asynchronous
* process, executes it and builds a [[CancelableFuture]] value
* out of it.
*
* The given `registration` function can return a [[Cancelable]]
* reference that can be used to cancel the executed async process.
* This reference can be [[Cancelable.empty empty]].
*
* {{{
* def delayedResult[A](f: => A)(implicit s: Scheduler): CancelableFuture[A] =
* CancelableFuture.async { complete =>
* val task = s.scheduleOnce(10.seconds) { complete(Try(f)) }
*
* Cancelable { () =>
* println("Cancelling!")
* task.cancel()
* }
* }
* }}}
*
* This is much like working with Scala's
* [[scala.concurrent.Promise Promise]], only safer.
*/
def async[A](register: (Try[A] => Unit) => Cancelable)(
implicit ec: ExecutionContext): CancelableFuture[A] = {

val p = Promise[A]()
val cRef = SingleAssignmentCancelable()

// Light async boundary to guard against stack overflows
ec.execute(new TrampolinedRunnable {
def run(): Unit = {
try {
cRef := register(p.complete)
} catch {
case e if NonFatal(e) =>
if (!p.tryComplete(Failure(e)))
ec.reportFailure(e)
}
}
})

CancelableFuture(p.future, cRef)
}

implicit class JavaCompletableFutureUtils[A](val source: CompletableFuture[A]) extends AnyVal {

/** Convert `CompletableFuture` to [[monix.execution.CancelableFuture]]
*
* If the source is cancelled, returned `Future` will never terminate
*/
def asScala(implicit ec: ExecutionContext): CancelableFuture[A] =
async(cb => {
source.handle[Unit](new BiFunction[A, Throwable, Unit] {
override def apply(result: A, err: Throwable): Unit = {
err match {
case null =>
cb(Success(result))
case _: CancellationException =>
()
case ex: CompletionException if ex.getCause ne null =>
cb(Failure(ex.getCause))
case ex =>
cb(Failure(ex))
}
}
})
Cancelable(() => {source.cancel(true); ()})
})
}

implicit class ScalaFutureUtils[A](val source: Future[A]) extends AnyVal {

/** Convert Scala `Future` to Java `CompletableFuture`
*
* NOTE: Cancelling resulting future will not have any
* effect on source
*/
def asJava(implicit ec: ExecutionContext): CompletableFuture[A] = {
val cf = new CompletableFuture[A]()
source.onComplete {
case Success(a) =>
cf.complete(a)
case Failure(ex) =>
cf.completeExceptionally(ex)
}
cf
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,6 @@ import scala.compat.Platform.EOL
object DefaultReporterFormat extends (ConfigurableReporter => ReporterFormat) {
override def apply(reporter: ConfigurableReporter): DefaultReporterFormat =
new DefaultReporterFormat(reporter)

case class Position(line: Int, column: Int)

def toOption[T](m: java.util.Optional[T]): Option[T] = if (m.isPresent) Some(m.get) else None
def position(position: xsbti.Position): Option[Position] = {
toOption(position.line).flatMap(l => toOption(position.pointer).map(c => Position(l, c)))
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion backend/src/main/scala/bloop/reporter/Problem.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ object Problem {
override def toString: String = s"$errors errors, $warnings warnings"
}

def count(problems: Array[xsbti.Problem]): DiagnosticsCount = {
def count(problems: List[xsbti.Problem]): DiagnosticsCount = {
// Compute the count manually because `count` returns an `Int`, not a `Long`
var errors = 0L
var warnings = 0L
Expand Down
Loading

0 comments on commit d6c250f

Please sign in to comment.