From ba786bbd8725231d950a030b8515794d5b78eab9 Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Sat, 1 Aug 2020 12:20:03 -0700 Subject: [PATCH 1/6] Preserve line endings in scalafmt --- .scalafmt.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/.scalafmt.conf b/.scalafmt.conf index 50897894c3..79ff0a5908 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -2,6 +2,7 @@ version = 2.1.0-RC1 maxColumn = 100 project.git = true project.excludeFilters = [ /sbt-test/, /input_sources/, /contraband-scala/ ] +lineEndings = preserve # http://docs.scala-lang.org/style/scaladoc.html recommends the JavaDoc style. # scala/scala is written that way too https://github.com/scala/scala/blob/v2.12.2/src/library/scala/Predef.scala From ffae65e947e6fa45a5b57d88fa2e4aa46170a69f Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Sat, 1 Aug 2020 11:30:56 -0700 Subject: [PATCH 2/6] Add scripted source files to scripted watch triggers --- build.sbt | 1 + 1 file changed, 1 insertion(+) diff --git a/build.sbt b/build.sbt index 2f846a280f..0120cdd368 100644 --- a/build.sbt +++ b/build.sbt @@ -150,6 +150,7 @@ lazy val zincRoot: Project = (project in file(".")) mimaPreviousArtifacts := Set.empty, scriptedBufferLog := true, scripted := scriptedTask.evaluated, + scripted / watchTriggers += baseDirectory.value.toGlob / "zinc" / "src" / "sbt-test" / **, Scripted.scriptedSource := (zinc212 / sourceDirectory).value / "sbt-test", Scripted.scriptedCompileToJar := false, noPublish, From c03772e0d3b4d96d479d90bdd682ac9bca329e43 Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Sat, 1 Aug 2020 10:15:34 -0700 Subject: [PATCH 3/6] Create java class directory if missing It is possible to invoke the java compiiler in astate where the output directory doens't exist. When this happens, the compiler throws an IllegalStateException: [error] sbt.internal.inc.BatchScriptRunner$PreciseScriptedError: {line 8} Command failed: 'run' [error] Caused by: java.lang.IllegalStateException: directory not found: /var/folders/zv/2wskcxc14cn6kyj4yb53whc40000gn/T/sbt_4bd7559c/target/classes [error] at com.sun.tools.javac.main.Main.error(Main.java:186) [error] at com.sun.tools.javac.main.Main.checkDirectory(Main.java:345) [error] at com.sun.tools.javac.main.Main.processArgs(Main.java:274) [error] at com.sun.tools.javac.main.Main.compile(Main.java:414) [error] at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129) [error] at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138) [error] at sbt.internal.inc.javac.LocalJavaCompiler.run(LocalJava.scala:327) [error] at sbt.internal.inc.javac.AnalyzingJavaCompiler.$anonfun$compile$12(AnalyzingJavaCompiler.scala:167) ... --- .../src/main/scala/sbt/internal/inc/javac/LocalJava.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/zinc-compile-core/src/main/scala/sbt/internal/inc/javac/LocalJava.scala b/internal/zinc-compile-core/src/main/scala/sbt/internal/inc/javac/LocalJava.scala index e8776d98d0..b5733be602 100644 --- a/internal/zinc-compile-core/src/main/scala/sbt/internal/inc/javac/LocalJava.scala +++ b/internal/zinc-compile-core/src/main/scala/sbt/internal/inc/javac/LocalJava.scala @@ -298,6 +298,10 @@ final class LocalJavaCompiler(compiler: javax.tools.JavaCompiler) extends XJavaC log.warn(invalidOptions.mkString("\t", ", ", "")) } val outputOption = CompilerArguments.outputOption(output) + output.getSingleOutputAsPath match { + case p if p.isPresent => Files.createDirectories(p.get) + case _ => + } val fileManager = { if (cleanedOptions.contains("-XDuseOptimizedZip=false")) { From cdd07973a57815433c84a35bc2ecce1218a0bbcd Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Mon, 3 Aug 2020 11:27:36 -0700 Subject: [PATCH 4/6] Always create output directories We should always call Files.createDirectories to ensure the output directory exists. If the directory already exists and is a directory, Files.createDirectories is a no-op and is the same amount of io as the Files.exists check. If the directory exists but is actually a file, then that is a bug and compilcation is likely to fail so we should throw an exception. --- .../main/scala/sbt/internal/inc/MixedAnalyzingCompiler.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/zinc/src/main/scala/sbt/internal/inc/MixedAnalyzingCompiler.scala b/zinc/src/main/scala/sbt/internal/inc/MixedAnalyzingCompiler.scala index 1734ffbebb..3e309d10c0 100644 --- a/zinc/src/main/scala/sbt/internal/inc/MixedAnalyzingCompiler.scala +++ b/zinc/src/main/scala/sbt/internal/inc/MixedAnalyzingCompiler.scala @@ -113,9 +113,7 @@ final class MixedAnalyzingCompiler( val dir = if (d.toString.endsWith(".jar")) d.getParent else d - if (!Files.exists(dir)) { - Files.createDirectories(dir) - } + Files.createDirectories(dir) } outputDirs } From b62bd7b64d0457eba60de740682ab2b29ff8bd46 Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Sat, 1 Aug 2020 10:29:19 -0700 Subject: [PATCH 5/6] Only recompile all java sources if any have changed When any java source is invalidated, we want to recompile the entire subproject to generate the java class signatures. For this reason, it is necessary to invalidate _all_ of the java sources when any change is detected. We don't however want to recompile all of the java sources if _none_ of them have changed. Prior to this change, in the sbt build with pipelining off, changing any scala source in a mixed project would rebuild all of the java sources which could trigger a cascade of invalidations that could potentially invalidate the entire project even when none of the java sources had actually changed. Due to this behavioral change, in 0504f70454fdbe9db2cba4003c710888f6e31e2a it was necessary to change the iteration count in less-inter-inv-java test from 3 to 2 because the overcompiling behavior made it only do one cycle when a single source file was changed because all of the sources were automatically invalidated. This commit restores the old behavior so the test can be restored as well. It also adds a test for mixed projects to ensure that changing a scala file does not automatically trigger recompilation of java files. --- .../src/main/scala/sbt/internal/inc/Incremental.scala | 10 +++++----- .../source-dependencies/less-inter-inv-java/test | 2 +- .../mixed-java-invalidations/changes/A.scala | 3 +++ .../mixed-java-invalidations/changes/B.scala | 4 ++++ .../mixed-java-invalidations/incOptions.properties | 2 ++ .../mixed-java-invalidations/src/main/java/Foo.java | 1 + .../mixed-java-invalidations/src/main/scala/A.scala | 1 + .../mixed-java-invalidations/src/main/scala/B.scala | 3 +++ .../source-dependencies/mixed-java-invalidations/test | 10 ++++++++++ 9 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/changes/A.scala create mode 100644 zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/changes/B.scala create mode 100644 zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/incOptions.properties create mode 100644 zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/src/main/java/Foo.java create mode 100644 zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/src/main/scala/A.scala create mode 100644 zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/src/main/scala/B.scala create mode 100644 zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/test diff --git a/internal/zinc-core/src/main/scala/sbt/internal/inc/Incremental.scala b/internal/zinc-core/src/main/scala/sbt/internal/inc/Incremental.scala index ecec751ae8..f586dadb7d 100644 --- a/internal/zinc-core/src/main/scala/sbt/internal/inc/Incremental.scala +++ b/internal/zinc-core/src/main/scala/sbt/internal/inc/Incremental.scala @@ -340,17 +340,17 @@ object Incremental { incremental.invalidateInitial(previous.relations, initialChanges) // If there's any compilation at all, invalidate all java sources too, so we have access to their type information. - val javaSources: Set[VirtualFileRef] = sources - .filter(_.name.endsWith(".java")) - .map(_.asInstanceOf[VirtualFileRef]) + val javaSources: Set[VirtualFileRef] = sources.collect { + case s: VirtualFileRef if s.name.endsWith(".java") => s + } val isPickleJava = currentSetup.options.scalacOptions.contains("-Ypickle-java") assert( javaSources.isEmpty || !options.pipelining || isPickleJava, s"-Ypickle-java must be included into scalacOptions if pipelining is enabled with Java sources" ) val initialInvSources = - if (initialInvSources0.nonEmpty) initialInvSources0 ++ javaSources - else Set.empty[VirtualFileRef] + if (isPickleJava && initialInvSources0.nonEmpty) initialInvSources0 ++ javaSources + else initialInvSources0 if (initialInvClasses.nonEmpty || initialInvSources.nonEmpty) { if (initialInvSources == sources) incremental.log.debug(s"all ${initialInvSources.size} sources are invalidated") diff --git a/zinc/src/sbt-test/source-dependencies/less-inter-inv-java/test b/zinc/src/sbt-test/source-dependencies/less-inter-inv-java/test index bce7884f9c..85a7c97e97 100644 --- a/zinc/src/sbt-test/source-dependencies/less-inter-inv-java/test +++ b/zinc/src/sbt-test/source-dependencies/less-inter-inv-java/test @@ -6,4 +6,4 @@ $ copy-file changes/A2.java A.java # 1 iteration to recompile all descendents and direct dependencies # no further iteration, because APIs of directs don't change > run -> checkIterations 2 +> checkIterations 3 diff --git a/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/changes/A.scala b/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/changes/A.scala new file mode 100644 index 0000000000..00f7cf413c --- /dev/null +++ b/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/changes/A.scala @@ -0,0 +1,3 @@ +object A { + val x = 1 +} diff --git a/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/changes/B.scala b/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/changes/B.scala new file mode 100644 index 0000000000..c8117907cd --- /dev/null +++ b/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/changes/B.scala @@ -0,0 +1,4 @@ +object B { + val foo = new Foo + val y = 2 +} diff --git a/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/incOptions.properties b/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/incOptions.properties new file mode 100644 index 0000000000..baf15b03f3 --- /dev/null +++ b/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/incOptions.properties @@ -0,0 +1,2 @@ +# turn off pipelining because compileAllJava over-compiles +pipelining = false diff --git a/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/src/main/java/Foo.java b/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/src/main/java/Foo.java new file mode 100644 index 0000000000..4a2b44daf6 --- /dev/null +++ b/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/src/main/java/Foo.java @@ -0,0 +1 @@ +public class Foo {} diff --git a/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/src/main/scala/A.scala b/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/src/main/scala/A.scala new file mode 100644 index 0000000000..69c493db21 --- /dev/null +++ b/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/src/main/scala/A.scala @@ -0,0 +1 @@ +object A diff --git a/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/src/main/scala/B.scala b/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/src/main/scala/B.scala new file mode 100644 index 0000000000..2b8ee49103 --- /dev/null +++ b/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/src/main/scala/B.scala @@ -0,0 +1,3 @@ +object B { + val foo = new Foo +} diff --git a/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/test b/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/test new file mode 100644 index 0000000000..5fa262be4c --- /dev/null +++ b/zinc/src/sbt-test/source-dependencies/mixed-java-invalidations/test @@ -0,0 +1,10 @@ +> compile +> checkIterations 1 + +$ copy-file changes/A.scala src/main/scala/A.scala +> compile +> checkIterations 2 + +$ copy-file changes/B.scala src/main/scala/B.scala +> compile +> checkIterations 3 From de0f4db3632840d0e6f0cbc824c38163e1285cfd Mon Sep 17 00:00:00 2001 From: eugene yokota Date: Mon, 3 Aug 2020 14:57:06 -0400 Subject: [PATCH 6/6] Update comment about invalidating all Java sources --- .../zinc-core/src/main/scala/sbt/internal/inc/Incremental.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/zinc-core/src/main/scala/sbt/internal/inc/Incremental.scala b/internal/zinc-core/src/main/scala/sbt/internal/inc/Incremental.scala index f586dadb7d..43284502dc 100644 --- a/internal/zinc-core/src/main/scala/sbt/internal/inc/Incremental.scala +++ b/internal/zinc-core/src/main/scala/sbt/internal/inc/Incremental.scala @@ -339,7 +339,7 @@ object Incremental { val (initialInvClasses, initialInvSources0) = incremental.invalidateInitial(previous.relations, initialChanges) - // If there's any compilation at all, invalidate all java sources too, so we have access to their type information. + // During pipelining, if there's any compilation at all, invalidate all Java sources too, so the downstream Scala subprojects would have type information via early output (pickle jar). val javaSources: Set[VirtualFileRef] = sources.collect { case s: VirtualFileRef if s.name.endsWith(".java") => s }