@@ -13,10 +13,17 @@ import java.io.File
1313
1414val usageMessage = """
1515 |Usage:
16- | > scala-cli project/scripts/bisect.scala -- <validation-script>
16+ | > scala-cli project/scripts/bisect.scala -- <validation-script-path> [versions-range]
1717 |
1818 |The validation script should be executable and accept a single parameter, which will be the scala version to validate.
1919 |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+ |
2027 |Don't use the example scripts modified in place as they might disappear from the repo during a checkout.
2128 |Instead copy them to a different location first.
2229 |
@@ -26,18 +33,23 @@ val usageMessage = """
2633""" .stripMargin
2734
2835@ main def dottyCompileBisect (args : String * ): Unit =
29- val validationScriptPath = args match
36+ val (validationScriptRawPath, versionsRange) = args match
3037 case Seq (path) =>
31- (new File (path)).getAbsolutePath.toString
38+ (path, VersionsRange .all)
39+ case Seq (path, ParsedVersionsRange (range)) =>
40+ (path, range)
3241 case _ =>
3342 println(" Wrong script parameters." )
3443 println()
3544 println(usageMessage)
3645 System .exit(1 )
3746 null
3847
48+ val validationScriptPath = (new File (validationScriptRawPath)).getAbsolutePath.toString
49+ given releases : Releases = Releases .fromRange(versionsRange)
50+
3951 val releaseBisect = ReleaseBisect (validationScriptPath)
40- val bisectedBadRelease = releaseBisect.bisectedBadRelease(Releases .allReleases )
52+ val bisectedBadRelease = releaseBisect.bisectedBadRelease(releases.releases )
4153 println(" \n Finished bisecting releases\n " )
4254
4355 bisectedBadRelease match
@@ -53,9 +65,37 @@ val usageMessage = """
5365 case None =>
5466 println(s " No bad release found " )
5567
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+
5696class ReleaseBisect (validationScriptPath : String ):
5797 def bisectedBadRelease (releases : Vector [Release ]): Option [Release ] =
58- Some (bisect(releases : Vector [ Release ] ))
98+ Some (bisect(releases))
5999 .filter(! isGoodRelease(_))
60100
61101 def bisect (releases : Vector [Release ]): Release =
@@ -75,11 +115,15 @@ class ReleaseBisect(validationScriptPath: String):
75115 println(s " Test result: ${release.version} is a ${if isGood then " good" else " bad" } release \n " )
76116 isGood
77117
118+ class Releases (val releases : Vector [Release ])
119+
78120object 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
81123 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 (_)))
83127
84128 case class Release (version : String ):
85129 private val re = raw " .+-bin-(\d{8})-(\w{7})-NIGHTLY " .r
@@ -92,10 +136,10 @@ object Releases:
92136 case re(_, hash) => hash
93137 case _ => sys.error(s " Could not extract hash from version $version" )
94138
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 )
97141 if idx == 0 then None
98- else Some (allReleases (idx - 1 ))
142+ else Some (r.releases (idx - 1 ))
99143
100144 override def toString : String = version
101145
0 commit comments