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
+ */
6
7
7
8
8
9
import sys .process ._
9
10
import scala .io .Source
10
11
import Releases .Release
11
12
import 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
13
27
14
28
@ 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
18
32
case _ =>
19
- (None , args)
33
+ println(" Wrong script parameters." )
34
+ println()
35
+ println(usageMessage)
36
+ System .exit(1 )
37
+ null
20
38
21
- val releaseBisect = ReleaseBisect (mainClass, compilerArgs.toList )
39
+ val releaseBisect = ReleaseBisect (validationScriptPath )
22
40
val bisectedBadRelease = releaseBisect.bisectedBadRelease(Releases .allReleases)
23
41
println(" \n Finished bisecting releases\n " )
24
42
@@ -28,14 +46,14 @@ import java.nio.file.{Files, Paths, StandardCopyOption}
28
46
case Some (lastGoodRelease) =>
29
47
println(s " Last good release: $lastGoodRelease" )
30
48
println(s " First bad release: $firstBadRelease" )
31
- val commitBisect = CommitBisect (mainClass, compilerArgs.toList )
49
+ val commitBisect = CommitBisect (validationScriptPath )
32
50
commitBisect.bisect(lastGoodRelease.hash, firstBadRelease.hash)
33
51
case None =>
34
52
println(s " No good release found " )
35
53
case None =>
36
54
println(s " No bad release found " )
37
55
38
- class ReleaseBisect (mainClass : Option [ String ], compilerArgs : List [ String ] ):
56
+ class ReleaseBisect (validationScriptPath : String ):
39
57
def bisectedBadRelease (releases : Vector [Release ]): Option [Release ] =
40
58
Some (bisect(releases : Vector [Release ]))
41
59
.filter(! isGoodRelease(_))
@@ -52,13 +70,8 @@ class ReleaseBisect(mainClass: Option[String], compilerArgs: List[String]):
52
70
53
71
private def isGoodRelease (release : Release ): Boolean =
54
72
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
62
75
println(s " Test result: ${release.version} is a ${if isGood then " good" else " bad" } release \n " )
63
76
isGood
64
77
@@ -86,14 +99,16 @@ object Releases:
86
99
87
100
override def toString : String = version
88
101
89
- class CommitBisect (mainClass : Option [ String ], compilerArgs : List [ String ] ):
102
+ class CommitBisect (validationScriptPath : String ):
90
103
def bisect (lastGoodHash : String , fistBadHash : String ): Unit =
91
104
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
96
111
" git bisect start" .!
97
112
s " git bisect bad $fistBadHash" .!
98
113
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