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
+ */
6
6
7
7
8
8
import sys .process ._
9
9
import scala .io .Source
10
10
import Releases .Release
11
11
import java .io .File
12
- import java .nio .file .{Files , Paths , StandardCopyOption }
12
+
13
+ val usageMessage = """
14
+ |Wrong script parameters.
15
+ |
16
+ |Usage:
17
+ | > scala-cli project/scripts/bisect.scala -- <validation-script>
18
+ |
19
+ |The validation script should be executable and accept a single parameter, which will be the scala version to validate.
20
+ |Look at bisect-cli-example.sh and bisect-expect-example.exp for reference.
21
+ |Don't use the example scripts modified in place as they might disappear from the repo during a checkout.
22
+ |Instead copy them to a different location first.
23
+ |
24
+ |Warning: The bisect script should not be run multiple times in parallel because of a potential race condition while publishing artifacts locally.
25
+ |
26
+ |Tip: Before running the bisect script run the validation script manually with some published versions of the compiler to make sure it succeeds/fails as expected.
27
+ """ .stripMargin
13
28
14
29
@ main def dottyCompileBisect (args : String * ): Unit =
15
- val (mainClass, compilerArgs) = args match
16
- case Seq (" --run " , mainClass, compilerArgs * ) =>
17
- (Some (mainClass), compilerArgs)
30
+ val validationScriptPath = args match
31
+ case Seq (path ) =>
32
+ (new File (path)).getAbsolutePath.toString
18
33
case _ =>
19
- (None , args)
34
+ println()
35
+ throw new IllegalArgumentException (usageMessage)
20
36
21
- val releaseBisect = ReleaseBisect (mainClass, compilerArgs.toList )
37
+ val releaseBisect = ReleaseBisect (validationScriptPath )
22
38
val bisectedBadRelease = releaseBisect.bisectedBadRelease(Releases .allReleases)
23
39
println(" \n Finished bisecting releases\n " )
24
40
@@ -28,14 +44,14 @@ import java.nio.file.{Files, Paths, StandardCopyOption}
28
44
case Some (lastGoodRelease) =>
29
45
println(s " Last good release: $lastGoodRelease" )
30
46
println(s " First bad release: $firstBadRelease" )
31
- val commitBisect = CommitBisect (mainClass, compilerArgs.toList )
47
+ val commitBisect = CommitBisect (validationScriptPath )
32
48
commitBisect.bisect(lastGoodRelease.hash, firstBadRelease.hash)
33
49
case None =>
34
50
println(s " No good release found " )
35
51
case None =>
36
52
println(s " No bad release found " )
37
53
38
- class ReleaseBisect (mainClass : Option [ String ], compilerArgs : List [ String ] ):
54
+ class ReleaseBisect (validationScriptPath : String ):
39
55
def bisectedBadRelease (releases : Vector [Release ]): Option [Release ] =
40
56
Some (bisect(releases : Vector [Release ]))
41
57
.filter(! isGoodRelease(_))
@@ -52,13 +68,8 @@ class ReleaseBisect(mainClass: Option[String], compilerArgs: List[String]):
52
68
53
69
private def isGoodRelease (release : Release ): Boolean =
54
70
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
71
+ val result = Seq (validationScriptPath, release.version).!
72
+ val isGood = result == 0
62
73
println(s " Test result: ${release.version} is a ${if isGood then " good" else " bad" } release \n " )
63
74
isGood
64
75
@@ -86,14 +97,15 @@ object Releases:
86
97
87
98
override def toString : String = version
88
99
89
- class CommitBisect (mainClass : Option [ String ], compilerArgs : List [ String ] ):
100
+ class CommitBisect (validationScriptPath : String ):
90
101
def bisect (lastGoodHash : String , fistBadHash : String ): Unit =
91
102
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 )
103
+ val bisectRunScript = s """
104
+ |scalaVersion= $$ (sbt "show scala3-compiler/version" | tail -1 | sed 's/ \\ [info \\ ] //')
105
+ |sbt "clean; scala3/publishLocal"
106
+ | $validationScriptPath " $$ scalaVersion"
107
+ """ .stripMargin
96
108
" git bisect start" .!
97
109
s " git bisect bad $fistBadHash" .!
98
110
s " git bisect good $lastGoodHash" .!
99
- s " git bisect run sh ${tempScriptFile.toAbsolutePath} ${runOption} ${compilerArgs.mkString( " " )} " .!
111
+ Seq ( " git" , " bisect" , " run" , " sh " , " -c " , bisectRunScript) .!
0 commit comments