All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mill.scalalib.api.ZincWorkerUtil.scala Maven / Gradle / Ivy

package mill.scalalib.api

import mill.api.Loose.Agg
import mill.api.PathRef
import scala.util.matching.Regex

trait ZincWorkerUtil {

  def isDotty(scalaVersion: String): Boolean = scalaVersion.startsWith("0.")
  def isScala3(scalaVersion: String): Boolean = scalaVersion.startsWith("3.")
  def isScala3Milestone(scalaVersion: String): Boolean = scalaVersion.startsWith("3.0.0-M")
  def isDottyOrScala3(scalaVersion: String): Boolean =
    isDotty(scalaVersion) || isScala3(scalaVersion)

  // eg, grepJar(classPath, name = "scala-library", versionPrefix = "2.13.")
  // return first path in `classPath` that match:
  // **/scala-library-2.13.*.jar or
  // **/2.13.*/jars/scala-library.jar
  def grepJar(
      classPath: Agg[PathRef],
      name: String,
      versionPrefix: String,
      sources: Boolean = false
  ): PathRef = {
    val suffix = if (sources) "-sources.jar" else ".jar"
    lazy val dir = if (sources) "srcs" else "jars"

    def mavenStyleMatch(fname: String): Boolean =
      fname.startsWith(s"$name-$versionPrefix") && fname.endsWith(suffix)

    def ivyStyleMatch(p: os.Path): Boolean = {
      val fname = s"$name$suffix"
      p.segments.toSeq match {
        case _ :+ v :+ `dir` :+ `fname` if v.startsWith(versionPrefix) => true
        case _ => false
      }
    }

    classPath.iterator
      .find(pathRef => mavenStyleMatch(pathRef.path.last) || ivyStyleMatch(pathRef.path))
      .getOrElse(throw new Exception(
        s"Cannot find **/$name-$versionPrefix*$suffix or **/$versionPrefix*/$dir/$name$suffix in ${classPath.iterator.mkString("[", ", ", "]")}"
      ))
  }

  val PartialVersion: Regex = raw"""(\d+)\.(\d+)\.*""".r
  val ReleaseVersion: Regex = raw"""(\d+)\.(\d+)\.(\d+)""".r
  val MinorSnapshotVersion: Regex = raw"""(\d+)\.(\d+)\.([1-9]\d*)-SNAPSHOT""".r
  val DottyVersion: Regex = raw"""0\.(\d+)\.(\d+).*""".r
  val Scala3EarlyVersion: Regex = raw"""3\.0\.0-(\w+).*""".r
  val Scala3Version: Regex = raw"""3\.(\d+)\.(\d+).*""".r
  val DottyNightlyVersion: Regex = raw"""(0|3)\.(\d+)\.(\d+)-bin-(.*)-NIGHTLY""".r
  val NightlyVersion: Regex = raw"""(\d+)\.(\d+)\.(\d+)-bin-[a-f0-9]*""".r
  val TypelevelVersion: Regex = raw"""(\d+)\.(\d+)\.(\d+)-bin-typelevel.*""".r

  def scalaBinaryVersion(scalaVersion: String): String = scalaVersion match {
    case Scala3EarlyVersion(milestone) => s"3.0.0-$milestone"
    case Scala3Version(_, _) => "3"
    case ReleaseVersion(major, minor, _) => s"$major.$minor"
    case MinorSnapshotVersion(major, minor, _) => s"$major.$minor"
    case NightlyVersion(major, minor, _) => s"$major.$minor"
    case DottyVersion(minor, _) => s"0.$minor"
    case TypelevelVersion(major, minor, _) => s"$major.$minor"
    case _ => scalaVersion
  }

  private val ScalaJSFullVersion = """^([0-9]+)\.([0-9]+)\.([0-9]+)(-.*)?$""".r

  def scalaJSBinaryVersion(scalaJSVersion: String): String = scalaJSVersion match {
    case _ if scalaJSVersion.startsWith("0.6.") =>
      throw new Exception("Scala.js 0.6 is not supported")
    case ScalaJSFullVersion(major, minor, patch, suffix) =>
      if (suffix != null && minor == "0" && patch == "0")
        s"$major.$minor$suffix"
      else
        major
  }

  def scalaJSWorkerVersion(scalaJSVersion: String): String = scalaJSVersion match {
    case _ if scalaJSVersion.startsWith("0.6.") =>
      throw new Exception("Scala.js 0.6 is not supported")
    case ScalaJSFullVersion(major, _, _, _) =>
      major
  }

  private val ScalaNativeFullVersion = """^([0-9]+)\.([0-9]+)\.([0-9]+)(-.*)?$""".r

  def scalaNativeBinaryVersion(version: String): String = version match {
    case ScalaNativeFullVersion(major, minor, patch, suffix) =>
      if (suffix != null && patch == "0")
        version
      else
        s"$major.$minor"
  }

  def scalaNativeWorkerVersion(version: String): String = version match {
    case ScalaNativeFullVersion(major, minor, _, _) =>
      s"$major.$minor"
  }

  /* Starting from Scala.js 0.6.29 and in 1.x, test artifacts must depend on
   * scalajs-test-bridge instead of scalajs-test-interface.
   */
  @deprecated("No longer used", "Mill after 0.11.0-M0")
  def scalaJSUsesTestBridge(scalaJSVersion: String): Boolean = scalaJSVersion match {
    case ScalaJSFullVersion("0", "6", patch, _) => patch.toInt >= 29
    case _ => true
  }

  lazy val millCompilerBridgeScalaVersions: Set[String] =
    Versions.millCompilerBridgeScalaVersions.split(",").toSet

  /** @return true if the compiler bridge can be downloaded as an already compiled jar */
  def isBinaryBridgeAvailable(scalaVersion: String): Boolean =
    if (millCompilerBridgeScalaVersions.contains(scalaVersion)) true
    else scalaVersion match {
      case DottyNightlyVersion(major, minor, _, _) =>
        major.toInt > 0 || minor.toInt >= 14 // 0.14.0-bin or more (not 0.13.0-bin)
      case DottyVersion(minor, _) => minor.toInt >= 13 // 0.13.0-RC1 or more
      case Scala3EarlyVersion(_) | Scala3Version(_, _) => true
      case _ => false
    }

  /**
   * Given a version string using a semantic versioning scheme (like x.y.z) it
   * returns all the sub-versions in it (major, minor, patch, etc.).
   * For example, matchingVersions("2.0.0") returns "2.0.0", "2.0" and "2"
   */
  def matchingVersions(version: String): Seq[String] = {
    (for (segments <- version.split('.').inits.filter(_.nonEmpty))
      yield segments.mkString(".")).to(Seq)
  }

  /**
   * Given a version string and the sequence of all the possible versions strings
   * using a semantic versioning scheme (like x.y.z) it returns all the version
   * ranges that contain `version` for all sub-version (major, minor, patch) in
   * `allVersions`.
   * For example, `versionRanges("2.0", Seq("1.0", "2.0", "3.0"))` returns versions
   * like `"1+"`, `"3-"`, `"3.0-"`, `"2+"`, `"2-"` and so on.
   */
  def versionRanges(version: String, allVersions: Seq[String]): Seq[String] = {
    import scala.math.Ordering.Implicits._
    val versionParts = version.split('.').map(_.toIntOption).takeWhile(_.isDefined).map(_.get)
    val all = allVersions.flatMap(
      _.split('.').inits
        .flatMap { l =>
          try { Some(l.map(_.toInt)) }
          catch { case _: NumberFormatException => None }
        }
        .map(_.toSeq)
    )
    val plus =
      all.filter(v => v.nonEmpty && v <= versionParts.take(v.length)).map(_.mkString(".") + "+")
    val minus =
      all.filter(v => v.nonEmpty && v >= versionParts.take(v.length)).map(_.mkString(".") + "-")
    (plus ++ minus).distinct.toSeq
  }
}

object ZincWorkerUtil extends ZincWorkerUtil




© 2015 - 2024 Weber Informatics LLC | Privacy Policy