1- // Usage
2- // > scala-cli project/scripts/dottyCompileBisect.scala -- [--run <main.class.name>] [<compiler-option> ...] <file1.scala> [<fileN.scala> ...]
3- //
4- // This script will bisect the compilation failure starting with a fast bisection on released nightly builds.
5- // Then it will bisect the commits between the last nightly that worked and the first nightly that failed.
1+ /*
2+ This script will bisect a problem with the compiler based on success/failure of the validation script passed as an argument.
3+ It starts with a fast bisection on released nightly builds.
4+ Then it will bisect the commits between the last nightly that worked and the first nightly that failed.
5+ Look at the `usageMessage` below for more details.
6+ */
67
78
89import sys .process ._
910import scala .io .Source
1011import Releases .Release
1112import java .io .File
12- import java .nio .file .{Files , Paths , StandardCopyOption }
13+
14+ val usageMessage = """
15+ |Usage:
16+ | > scala-cli project/scripts/bisect.scala -- <validation-script>
17+ |
18+ |The validation script should be executable and accept a single parameter, which will be the scala version to validate.
19+ |Look at bisect-cli-example.sh and bisect-expect-example.exp for reference.
20+ |Don't use the example scripts modified in place as they might disappear from the repo during a checkout.
21+ |Instead copy them to a different location first.
22+ |
23+ |Warning: The bisect script should not be run multiple times in parallel because of a potential race condition while publishing artifacts locally.
24+ |
25+ |Tip: Before running the bisect script run the validation script manually with some published versions of the compiler to make sure it succeeds and fails as expected.
26+ """ .stripMargin
1327
1428@ main def dottyCompileBisect (args : String * ): Unit =
15- val (mainClass, compilerArgs) = args match
16- case Seq (" --run " , mainClass, compilerArgs * ) =>
17- (Some (mainClass), compilerArgs)
29+ val validationScriptPath = args match
30+ case Seq (path ) =>
31+ (new File (path)).getAbsolutePath.toString
1832 case _ =>
19- (None , args)
33+ println(" Wrong script parameters." )
34+ println()
35+ println(usageMessage)
36+ System .exit(1 )
37+ null
2038
21- val releaseBisect = ReleaseBisect (mainClass, compilerArgs.toList )
39+ val releaseBisect = ReleaseBisect (validationScriptPath )
2240 val bisectedBadRelease = releaseBisect.bisectedBadRelease(Releases .allReleases)
2341 println(" \n Finished bisecting releases\n " )
2442
@@ -28,14 +46,14 @@ import java.nio.file.{Files, Paths, StandardCopyOption}
2846 case Some (lastGoodRelease) =>
2947 println(s " Last good release: $lastGoodRelease" )
3048 println(s " First bad release: $firstBadRelease" )
31- val commitBisect = CommitBisect (mainClass, compilerArgs.toList )
49+ val commitBisect = CommitBisect (validationScriptPath )
3250 commitBisect.bisect(lastGoodRelease.hash, firstBadRelease.hash)
3351 case None =>
3452 println(s " No good release found " )
3553 case None =>
3654 println(s " No bad release found " )
3755
38- class ReleaseBisect (mainClass : Option [ String ], compilerArgs : List [ String ] ):
56+ class ReleaseBisect (validationScriptPath : String ):
3957 def bisectedBadRelease (releases : Vector [Release ]): Option [Release ] =
4058 Some (bisect(releases : Vector [Release ]))
4159 .filter(! isGoodRelease(_))
@@ -52,13 +70,8 @@ class ReleaseBisect(mainClass: Option[String], compilerArgs: List[String]):
5270
5371 private def isGoodRelease (release : Release ): Boolean =
5472 println(s " Testing ${release.version}" )
55- val testCommand = mainClass match
56- case Some (className) =>
57- s " run --main-class ' $className' "
58- case None =>
59- " compile"
60- val res = s """ scala-cli $testCommand -S ' ${release.version}' ${compilerArgs.mkString(" " )}""" .!
61- val isGood = res == 0
73+ val result = Seq (validationScriptPath, release.version).!
74+ val isGood = result == 0
6275 println(s " Test result: ${release.version} is a ${if isGood then " good" else " bad" } release \n " )
6376 isGood
6477
@@ -86,14 +99,16 @@ object Releases:
8699
87100 override def toString : String = version
88101
89- class CommitBisect (mainClass : Option [ String ], compilerArgs : List [ String ] ):
102+ class CommitBisect (validationScriptPath : String ):
90103 def bisect (lastGoodHash : String , fistBadHash : String ): Unit =
91104 println(s " Starting bisecting commits $lastGoodHash.. $fistBadHash\n " )
92- val runOption = mainClass.map(className => s " --run $className" ).getOrElse(" " )
93- val scriptFile = Paths .get(" project" , " scripts" , " dottyCompileBisect.sh" )
94- val tempScriptFile = File .createTempFile(" dottyCompileBisect" , " sh" ).toPath
95- Files .copy(scriptFile, tempScriptFile, StandardCopyOption .REPLACE_EXISTING )
105+ val bisectRunScript = s """
106+ |scalaVersion= $$ (sbt "print scala3-compiler-bootstrapped/version" | tail -n1)
107+ |rm -r out
108+ |sbt "clean; scala3-bootstrapped/publishLocal"
109+ | $validationScriptPath " $$ scalaVersion"
110+ """ .stripMargin
96111 " git bisect start" .!
97112 s " git bisect bad $fistBadHash" .!
98113 s " git bisect good $lastGoodHash" .!
99- s " git bisect run sh ${tempScriptFile.toAbsolutePath} ${runOption} ${compilerArgs.mkString( " " )} " .!
114+ Seq ( " git" , " bisect" , " run" , " sh " , " -c " , bisectRunScript) .!
0 commit comments