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

mill.scalalib.internal.ModuleUtils.scala Maven / Gradle / Ivy

There is a newer version: 0.12.0-RC2-17-07e173
Show newest version
package mill.scalalib.internal

import mill.api.BuildScriptException
import mill.define.{Module, Segments}

import scala.annotation.tailrec

@mill.api.internal
object ModuleUtils {

  /**
   * Computes a display name for a module which is also disambiguates foreign modules.
   */
  def moduleDisplayName(module: Module): String = {
    (module.millModuleShared.value.getOrElse(Segments()) ++ module.millModuleSegments).render
  }

  /**
   * Find all dependencies.
   * The result contains `start` and all its transitive dependencies provided by `deps`,
   * but does not contain duplicates.
   * If it detects a cycle, it throws an exception with a meaningful message containing the cycle trace.
   * @param name The nane is used in the exception message only
   * @param start the start element
   * @param deps A function provided the direct dependencies
   * @throws BuildScriptException if there were cycles in the dependencies
   */
  // FIMXE: Remove or consolidate with copy in ZincModuleImpl
  def recursive[T](name: String, start: T, deps: T => Seq[T]): Seq[T] = {

    @tailrec def rec(
        seenModules: List[T],
        toAnalyze: List[(List[T], List[T])]
    ): List[T] = {
      toAnalyze match {
        case Nil => seenModules
        case traces :: rest =>
          traces match {
            case (_, Nil) => rec(seenModules, rest)
            case (trace, cand :: remaining) =>
              if (trace.contains(cand)) {
                // cycle!
                val rendered =
                  (cand :: (cand :: trace.takeWhile(_ != cand)).reverse).mkString(" -> ")
                val msg = s"${name}: cycle detected: ${rendered}"
                println(msg)
                throw new BuildScriptException(msg)
              }
              rec(
                if (seenModules.contains(cand)) seenModules
                else { seenModules ++ Seq(cand) },
                toAnalyze = ((cand :: trace, deps(cand).toList)) :: (trace, remaining) :: rest
              )
          }
      }
    }

    rec(
      seenModules = List(),
      toAnalyze = List((List(start), deps(start).toList))
    ).reverse
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy