Skip to content

Commit 967aa1b

Browse files
authored
Merge pull request #162 from scala-cli/update
Update fork to all the newest deps and code
2 parents eaf463e + aecb40a commit 967aa1b

File tree

74 files changed

+1216
-1265
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+1216
-1265
lines changed

.github/workflows/ci.yml

+7-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ jobs:
4242
run: |
4343
.github/setup-test-projects.sh &&\
4444
./mill -i "bridges.scalajs-1[_].publishLocal" &&\
45-
./mill -i "bridges.scalajs-1[_].test"
45+
./mill -i "bridges.scala-native-04[_].publishLocal" &&\
46+
./mill -i "bridges.scala-native-05[_].publishLocal" &&\
47+
./mill -i "bridges.scalajs-1[_].test" &&\
48+
./mill -i "bridges.scala-native-04[_].test" &&\
49+
./mill -i "bridges.scala-native-05[_].test"
4650
shell: bash
4751

4852
test:
@@ -67,8 +71,8 @@ jobs:
6771
.github/setup-test-projects.sh &&\
6872
./mill -i 'backend[_].test.compile' &&\
6973
./mill -i 'frontend[_].test.compile' &&\
70-
./mill -i 'backend[2.12.18].test' &&\
71-
./mill -i 'frontend[2.12.18].test'
74+
./mill -i 'backend[2.12.19].test' &&\
75+
./mill -i 'frontend[2.12.19].test'
7276
shell: bash
7377

7478
jvm-tests:

.scalafmt.conf

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version = "3.7.15"
1+
version = "3.8.0"
22

33
align.preset = more
44
maxColumn = 100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package bloop
2+
3+
import java.io.File
4+
import java.util.concurrent.atomic.AtomicReference
5+
6+
import scala.jdk.CollectionConverters._
7+
8+
import bloop.io.AbsolutePath
9+
import bloop.task.Task
10+
11+
import monix.reactive.Observable
12+
import monix.reactive.subjects.PublishSubject
13+
import sbt.internal.inc.PlainVirtualFileConverter
14+
import xsbti.VirtualFileRef
15+
import xsbti.compile.CompileAnalysis
16+
import xsbti.compile.analysis.Stamp
17+
18+
/**
19+
* Each time a new compile analysis is produced for a given client, it is given to
20+
* the [[ClientClassObserver]] which computes the list of classes that changed or got created.
21+
*
22+
* A client can subscribe to the observer to get notified of classes to update.
23+
* It is used by DAP to hot reload classes in the debuggee process.
24+
*
25+
* @param clientClassesDir the class directory for the client
26+
*/
27+
private[bloop] class ClientClassesObserver(val classesDir: AbsolutePath) {
28+
private val converter = PlainVirtualFileConverter.converter
29+
private val previousAnalysis: AtomicReference[CompileAnalysis] = new AtomicReference()
30+
private val classesSubject: PublishSubject[Seq[String]] = PublishSubject()
31+
32+
def observable: Observable[Seq[String]] = classesSubject
33+
34+
def nextAnalysis(analysis: CompileAnalysis): Task[Unit] = {
35+
val prev = previousAnalysis.getAndSet(analysis)
36+
if (prev != null && classesSubject.size > 0) {
37+
Task {
38+
val previousStamps = prev.readStamps.getAllProductStamps
39+
analysis.readStamps.getAllProductStamps.asScala.iterator.collect {
40+
case (vf, stamp) if isClassFile(vf) && isNewer(stamp, previousStamps.get(vf)) =>
41+
getFullyQualifiedClassName(vf)
42+
}.toSeq
43+
}
44+
.flatMap { classesToUpdate =>
45+
Task.fromFuture(classesSubject.onNext(classesToUpdate)).map(_ => ())
46+
}
47+
} else Task.unit
48+
}
49+
50+
private def isClassFile(vf: VirtualFileRef): Boolean = vf.id.endsWith(".class")
51+
52+
private def isNewer(current: Stamp, previous: Stamp): Boolean =
53+
previous == null || {
54+
val currentHash = current.getHash
55+
val previousHash = previous.getHash
56+
currentHash.isPresent &&
57+
(!previousHash.isPresent || currentHash.get != previousHash.get)
58+
}
59+
60+
private def getFullyQualifiedClassName(vf: VirtualFileRef): String = {
61+
val path = converter.toPath(vf)
62+
val relativePath = classesDir.underlying.relativize(path)
63+
relativePath.toString.replace(File.separator, ".").stripSuffix(".class")
64+
}
65+
}

backend/src/main/scala/bloop/CompileBackgroundTasks.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import bloop.tracing.BraveTracer
88

99
abstract class CompileBackgroundTasks {
1010
def trigger(
11-
clientClassesDir: AbsolutePath,
11+
clientClassesObserver: ClientClassesObserver,
1212
clientReporter: Reporter,
1313
clientTracer: BraveTracer,
1414
clientLogger: Logger
@@ -20,7 +20,7 @@ object CompileBackgroundTasks {
2020
val empty: CompileBackgroundTasks = {
2121
new CompileBackgroundTasks {
2222
def trigger(
23-
clientClassesDir: AbsolutePath,
23+
clientClassesObserver: ClientClassesObserver,
2424
clientReporter: Reporter,
2525
clientTracer: BraveTracer,
2626
clientLogger: Logger

backend/src/main/scala/bloop/Compiler.scala

+67-36
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import sbt.util.InterfaceUtil
4040
import xsbti.T2
4141
import xsbti.VirtualFileRef
4242
import xsbti.compile.{CompilerCache => _, ScalaInstance => _, _}
43+
import scala.util.Try
4344

4445
case class CompileInputs(
4546
scalaInstance: ScalaInstance,
@@ -319,6 +320,7 @@ object Compiler {
319320
val classpathOptions = compileInputs.classpathOptions
320321
val compilers = compileInputs.compilerCache.get(
321322
scalaInstance,
323+
classpathOptions,
322324
compileInputs.javacBin,
323325
compileInputs.javacOptions.toList
324326
)
@@ -451,11 +453,12 @@ object Compiler {
451453

452454
val backgroundTasks = new CompileBackgroundTasks {
453455
def trigger(
454-
clientClassesDir: AbsolutePath,
456+
clientClassesObserver: ClientClassesObserver,
455457
clientReporter: Reporter,
456458
clientTracer: BraveTracer,
457459
clientLogger: Logger
458460
): Task[Unit] = Task.defer {
461+
val clientClassesDir = clientClassesObserver.classesDir
459462
clientLogger.debug(s"Triggering background tasks for $clientClassesDir")
460463
val updateClientState =
461464
updateExternalClassesDirWithReadOnly(clientClassesDir, clientTracer, clientLogger)
@@ -471,10 +474,20 @@ object Compiler {
471474
}
472475

473476
val deleteNewClassesDir = Task(BloopPaths.delete(AbsolutePath(newClassesDir)))
474-
val allTasks = List(deleteNewClassesDir, updateClientState, writeAnalysisIfMissing)
477+
val publishClientAnalysis = Task {
478+
rebaseAnalysisClassFiles(
479+
analysis,
480+
readOnlyClassesDir,
481+
clientClassesDir.underlying,
482+
sourcesWithFatal
483+
)
484+
}
485+
.flatMap(clientClassesObserver.nextAnalysis)
475486
Task
476-
.gatherUnordered(allTasks)
477-
.map(_ => ())
487+
.gatherUnordered(
488+
List(deleteNewClassesDir, updateClientState, writeAnalysisIfMissing)
489+
)
490+
.flatMap(_ => publishClientAnalysis)
478491
.onErrorHandleWith(err => {
479492
clientLogger.debug("Caught error in background tasks"); clientLogger.trace(err);
480493
Task.raiseError(err)
@@ -494,14 +507,12 @@ object Compiler {
494507
)
495508
} else {
496509
val allGeneratedProducts = allGeneratedRelativeClassFilePaths.toMap
497-
val analysisForFutureCompilationRuns = {
498-
rebaseAnalysisClassFiles(
499-
analysis,
500-
readOnlyClassesDir,
501-
newClassesDir,
502-
sourcesWithFatal
503-
)
504-
}
510+
val analysisForFutureCompilationRuns = rebaseAnalysisClassFiles(
511+
analysis,
512+
readOnlyClassesDir,
513+
newClassesDir,
514+
sourcesWithFatal
515+
)
505516

506517
val resultForFutureCompilationRuns = {
507518
resultForDependentCompilationsInSameRun.withAnalysis(
@@ -516,12 +527,12 @@ object Compiler {
516527
// Schedule the tasks to run concurrently after the compilation end
517528
val backgroundTasksExecution = new CompileBackgroundTasks {
518529
def trigger(
519-
clientClassesDir: AbsolutePath,
530+
clientClassesObserver: ClientClassesObserver,
520531
clientReporter: Reporter,
521532
clientTracer: BraveTracer,
522533
clientLogger: Logger
523534
): Task[Unit] = {
524-
val clientClassesDirPath = clientClassesDir.toString
535+
val clientClassesDir = clientClassesObserver.classesDir
525536
val successBackgroundTasks =
526537
backgroundTasksWhenNewSuccessfulAnalysis
527538
.map(f => f(clientClassesDir, clientReporter, clientTracer))
@@ -542,15 +553,26 @@ object Compiler {
542553
val syntax = path.syntax
543554
if (syntax.startsWith(readOnlyClassesDirPath)) {
544555
val rebasedFile = AbsolutePath(
545-
syntax.replace(readOnlyClassesDirPath, clientClassesDirPath)
556+
syntax.replace(readOnlyClassesDirPath, clientClassesDir.toString)
546557
)
547558
if (rebasedFile.exists) {
548559
Files.delete(rebasedFile.underlying)
549560
}
550561
}
551562
}
552563
}
553-
Task.gatherUnordered(List(firstTask, secondTask)).map(_ => ())
564+
565+
val publishClientAnalysis = Task {
566+
rebaseAnalysisClassFiles(
567+
analysis,
568+
newClassesDir,
569+
clientClassesDir.underlying,
570+
sourcesWithFatal
571+
)
572+
}.flatMap(clientClassesObserver.nextAnalysis)
573+
Task
574+
.gatherUnordered(List(firstTask, secondTask))
575+
.flatMap(_ => publishClientAnalysis)
554576
}
555577

556578
allClientSyncTasks.doOnFinish(_ => Task(clientReporter.reportEndCompilation()))
@@ -632,25 +654,33 @@ object Compiler {
632654
case None => scalacOptions
633655
case Some(_) if existsReleaseSetting || sameHome => scalacOptions
634656
case Some(version) =>
635-
try {
636-
val numVer = if (version.startsWith("1.8")) 8 else version.takeWhile(_.isDigit).toInt
637-
val bloopNumVer = JavaRuntime.version.takeWhile(_.isDigit).toInt
638-
if (bloopNumVer > numVer) {
639-
scalacOptions ++ List("-release", numVer.toString())
640-
} else {
641-
logger.warn(
642-
s"Bloop is runing with ${JavaRuntime.version} but your code requires $version to compile, " +
643-
"this might cause some compilation issues when using JDK API unsupported by the Bloop's current JVM version"
644-
)
645-
scalacOptions
657+
val options: Option[Array[String]] =
658+
for {
659+
numVer <- parseJavaVersion(version)
660+
bloopNumVer <- parseJavaVersion(JavaRuntime.version)
661+
if (bloopNumVer >= 9 && numVer != bloopNumVer)
662+
} yield {
663+
if (bloopNumVer > numVer) {
664+
scalacOptions ++ List("-release", numVer.toString())
665+
} else {
666+
logger.warn(
667+
s"Bloop is running with ${JavaRuntime.version} but your code requires $version to compile, " +
668+
"this might cause some compilation issues when using JDK API unsupported by the Bloop's current JVM version"
669+
)
670+
scalacOptions
671+
}
646672
}
647-
} catch {
648-
case NonFatal(_) =>
649-
scalacOptions
650-
}
673+
options.getOrElse(scalacOptions)
651674
}
652675
}
653676

677+
private def parseJavaVersion(version: String): Option[Int] =
678+
version.split('-').head.split('.').toList match {
679+
case "1" :: minor :: _ => Try(minor.toInt).toOption
680+
case single :: _ => Try(single.toInt).toOption
681+
case _ => None
682+
}
683+
654684
private def getCompilationOptions(
655685
inputs: CompileInputs,
656686
logger: Logger,
@@ -688,11 +718,12 @@ object Compiler {
688718
): CompileBackgroundTasks = {
689719
new CompileBackgroundTasks {
690720
def trigger(
691-
clientClassesDir: AbsolutePath,
721+
clientClassesObserver: ClientClassesObserver,
692722
clientReporter: Reporter,
693723
tracer: BraveTracer,
694724
clientLogger: Logger
695725
): Task[Unit] = {
726+
val clientClassesDir = clientClassesObserver.classesDir
696727
val backgroundTasks = tasks.map(f => f(clientClassesDir, clientReporter, tracer))
697728
Task.gatherUnordered(backgroundTasks).memoize.map(_ => ())
698729
}
@@ -780,19 +811,19 @@ object Compiler {
780811
*/
781812
def rebaseAnalysisClassFiles(
782813
analysis0: CompileAnalysis,
783-
readOnlyClassesDir: Path,
784-
newClassesDir: Path,
814+
origin: Path,
815+
target: Path,
785816
sourceFilesWithFatalWarnings: scala.collection.Set[File]
786817
): Analysis = {
787818
// Cast to the only internal analysis that we support
788819
val analysis = analysis0.asInstanceOf[Analysis]
789820
def rebase(file: VirtualFileRef): VirtualFileRef = {
790821

791822
val filePath = converter.toPath(file).toAbsolutePath()
792-
if (!filePath.startsWith(readOnlyClassesDir)) file
823+
if (!filePath.startsWith(origin)) file
793824
else {
794825
// Hash for class file is the same because the copy duplicates metadata
795-
val path = newClassesDir.resolve(readOnlyClassesDir.relativize(filePath))
826+
val path = target.resolve(origin.relativize(filePath))
796827
converter.toVirtualFile(path)
797828
}
798829
}

backend/src/main/scala/bloop/CompilerCache.scala

+10-6
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ import sbt.internal.util.LoggerWriter
3535
import xsbti.ComponentProvider
3636
import xsbti.VirtualFile
3737
import xsbti.compile.ClassFileManager
38+
import xsbti.compile.ClasspathOptions
3839
import xsbti.compile.Compilers
3940
import xsbti.compile.JavaCompiler
4041
import xsbti.compile.Output
41-
import xsbti.compile.ScalaCompiler
4242
import xsbti.{Logger => XLogger}
4343
import xsbti.{Reporter => XReporter}
4444

@@ -50,19 +50,21 @@ final class CompilerCache(
5050
logger: Logger
5151
) {
5252

53-
private val scalaCompilerCache = new ConcurrentHashMap[ScalaInstance, ScalaCompiler]()
54-
53+
private val scalaInstanceCache = new ConcurrentHashMap[ScalaInstance, ScalaInstance]()
5554
private val javaCompilerCache = new ConcurrentHashMap[JavacKey, JavaCompiler]()
5655

5756
def get(
5857
scalaInstance: ScalaInstance,
58+
classpathOptions: ClasspathOptions,
5959
javacBin: Option[AbsolutePath],
6060
javacOptions: List[String]
6161
): Compilers = {
62-
val scalaCompiler = scalaCompilerCache.computeIfAbsent(
62+
val scalaInstanceFromCache = scalaInstanceCache.computeIfAbsent(
6363
scalaInstance,
64-
getScalaCompiler(_, componentProvider)
64+
_ => scalaInstance
6565
)
66+
val scalaCompiler =
67+
getScalaCompiler(scalaInstanceFromCache, classpathOptions, componentProvider)
6668

6769
val allowLocal = !hasRuntimeJavacOptions(javacOptions)
6870
val javaCompiler =
@@ -108,19 +110,21 @@ final class CompilerCache(
108110

109111
def getScalaCompiler(
110112
scalaInstance: ScalaInstance,
113+
classpathOptions: ClasspathOptions,
111114
componentProvider: ComponentProvider
112115
): AnalyzingCompiler = {
113116
val bridgeSources = BloopComponentCompiler.getModuleForBridgeSources(scalaInstance)
114117
val bridgeId = BloopComponentCompiler.getBridgeComponentId(bridgeSources, scalaInstance)
115118
componentProvider.component(bridgeId) match {
116-
case Array(jar) => ZincUtil.scalaCompiler(scalaInstance, jar)
119+
case Array(jar) => ZincUtil.scalaCompiler(scalaInstance, jar, classpathOptions)
117120
case _ =>
118121
BloopZincLibraryManagement.scalaCompiler(
119122
scalaInstance,
120123
BloopComponentsLock,
121124
componentProvider,
122125
Some(Paths.getCacheDirectory("bridge-cache").toFile),
123126
bridgeSources,
127+
classpathOptions,
124128
logger
125129
)
126130
}

backend/src/main/scala/bloop/io/ParallelOps.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ object ParallelOps {
173173
()
174174
} catch {
175175
case NonFatal(t) =>
176-
logger.report(
176+
logger.error(
177177
s"Unexpected error when copying $originFile to $targetFile, you might need to restart the build server.",
178178
t
179179
)

0 commit comments

Comments
 (0)