@@ -13,10 +13,17 @@ import java.io.File
13
13
14
14
val usageMessage = """
15
15
|Usage:
16
- | > scala-cli project/scripts/bisect.scala -- <validation-script>
16
+ | > scala-cli project/scripts/bisect.scala -- <validation-script-path> [versions-range]
17
17
|
18
18
|The validation script should be executable and accept a single parameter, which will be the scala version to validate.
19
19
|Look at bisect-cli-example.sh and bisect-expect-example.exp for reference.
20
+ |The optional versions range specifies which releases should be taken into account while bisecting.
21
+ |The range format is <first>...<last>, where both <first> and <last> are optional, e.g.
22
+ |* 3.1.0-RC1-bin-20210827-427d313-NIGHTLY..3.2.1-RC1-bin-20220716-bb9c8ff-NIGHTLY
23
+ |* 3.2.1-RC1-bin-20220620-de3a82c-NIGHTLY..
24
+ |* ..3.3.0-RC1-bin-20221124-e25362d-NIGHTLY
25
+ |The ranges are treated as inclusive.
26
+ |
20
27
|Don't use the example scripts modified in place as they might disappear from the repo during a checkout.
21
28
|Instead copy them to a different location first.
22
29
|
@@ -26,18 +33,23 @@ val usageMessage = """
26
33
""" .stripMargin
27
34
28
35
@ main def dottyCompileBisect (args : String * ): Unit =
29
- val validationScriptPath = args match
36
+ val (validationScriptRawPath, versionsRange) = args match
30
37
case Seq (path) =>
31
- (new File (path)).getAbsolutePath.toString
38
+ (path, VersionsRange .all)
39
+ case Seq (path, ParsedVersionsRange (range)) =>
40
+ (path, range)
32
41
case _ =>
33
42
println(" Wrong script parameters." )
34
43
println()
35
44
println(usageMessage)
36
45
System .exit(1 )
37
46
null
38
47
48
+ val validationScriptPath = (new File (validationScriptRawPath)).getAbsolutePath.toString
49
+ given releases : Releases = Releases .fromRange(versionsRange)
50
+
39
51
val releaseBisect = ReleaseBisect (validationScriptPath)
40
- val bisectedBadRelease = releaseBisect.bisectedBadRelease(Releases .allReleases )
52
+ val bisectedBadRelease = releaseBisect.bisectedBadRelease(releases.releases )
41
53
println(" \n Finished bisecting releases\n " )
42
54
43
55
bisectedBadRelease match
@@ -53,9 +65,37 @@ val usageMessage = """
53
65
case None =>
54
66
println(s " No bad release found " )
55
67
68
+ case class VersionsRange (first : Option [String ], last : Option [String ]):
69
+ def filter (versions : Seq [String ]) =
70
+ def versionIndex (version : String ) =
71
+ val lastMatchingNightly =
72
+ if version.contains(" -bin-" ) then version else
73
+ versions.filter(_.startsWith(version)).last
74
+ versions.indexOf(lastMatchingNightly)
75
+
76
+ val startIdx = first.map(versionIndex(_)).getOrElse(0 )
77
+ assert(startIdx >= 0 , s " ${first} is not a nightly compiler release " )
78
+ val endIdx = last.map(versionIndex(_) + 1 ).getOrElse(versions.length)
79
+ assert(endIdx > 0 , s " ${endIdx} is not a nightly compiler release " )
80
+ val filtered = versions.slice(startIdx, endIdx).toVector
81
+ assert(filtered.nonEmpty, " No matching releases" )
82
+ filtered
83
+
84
+
85
+ object VersionsRange :
86
+ def all = VersionsRange (None , None )
87
+
88
+ object ParsedVersionsRange :
89
+ def unapply (range : String ): Option [VersionsRange ] = range match
90
+ case s " ${first}... ${last}" => Some (VersionsRange (
91
+ Some (first).filter(_.nonEmpty),
92
+ Some (last).filter(_.nonEmpty)
93
+ ))
94
+ case _ => None
95
+
56
96
class ReleaseBisect (validationScriptPath : String ):
57
97
def bisectedBadRelease (releases : Vector [Release ]): Option [Release ] =
58
- Some (bisect(releases : Vector [ Release ] ))
98
+ Some (bisect(releases))
59
99
.filter(! isGoodRelease(_))
60
100
61
101
def bisect (releases : Vector [Release ]): Release =
@@ -75,11 +115,15 @@ class ReleaseBisect(validationScriptPath: String):
75
115
println(s " Test result: ${release.version} is a ${if isGood then " good" else " bad" } release \n " )
76
116
isGood
77
117
118
+ class Releases (val releases : Vector [Release ])
119
+
78
120
object Releases :
79
- lazy val allReleases : Vector [Release ] =
80
- val re = raw " (?<=title= $ ")(.+-bin-\d{8}-\w{7}-NIGHTLY)(?=/ $" ) " .r
121
+ private lazy val allReleases : Vector [String ] =
122
+ val re = raw """ (?<=title=")(.+-bin-\d{8}-\w{7}-NIGHTLY)(?=/") "" " .r
81
123
val html = Source .fromURL(" https://repo1.maven.org/maven2/org/scala-lang/scala3-compiler_3/" )
82
- re.findAllIn(html.mkString).map(Release .apply).toVector
124
+ re.findAllIn(html.mkString).toVector
125
+
126
+ def fromRange (range : VersionsRange ): Releases = Releases (range.filter(allReleases).map(Release (_)))
83
127
84
128
case class Release (version : String ):
85
129
private val re = raw " .+-bin-(\d{8})-(\w{7})-NIGHTLY " .r
@@ -92,10 +136,10 @@ object Releases:
92
136
case re(_, hash) => hash
93
137
case _ => sys.error(s " Could not extract hash from version $version" )
94
138
95
- def previous : Option [Release ] =
96
- val idx = allReleases .indexOf(this )
139
+ def previous ( using r : Releases ) : Option [Release ] =
140
+ val idx = r.releases .indexOf(this )
97
141
if idx == 0 then None
98
- else Some (allReleases (idx - 1 ))
142
+ else Some (r.releases (idx - 1 ))
99
143
100
144
override def toString : String = version
101
145
0 commit comments