def generateBzlFile()

in multiversion/src/main/scala/multiversion/commands/ExportCommand.scala [291:404]


  def generateBzlFile(
      index: ResolutionIndex,
      cache: FileCache[Task]
  ): Result[Path] = {
    val resolvedArtifacts = index.unevictedArtifacts
    val outputIndex: mutable.Map[String, ArtifactOutput] =
      collection.concurrent.TrieMap.empty[String, ArtifactOutput]
    val progressBar =
      new DownloadProgressRenderer(resolvedArtifacts.length, app.env.clock)
    val files: List[Task[List[Either[Throwable, ArtifactOutput]]]] =
      resolvedArtifacts.map { r =>
        val logger = progressBar.loggers.newCacheLogger(r.dependency)
        type Fetch[T] = Task[Either[ArtifactError, T]]
        def tryFetch(artifact: Artifact, policy: CachePolicy): Fetch[File] =
          cache
            .withCachePolicies(List(policy))
            .withLogger(logger)
            .file(artifact)
            .run
        def foldShas(attempts: List[Fetch[File]]): Fetch[File] =
          if (attempts.isEmpty) Task.point(Left(new ArtifactError.NotFound("")))
          else
            attempts.tail.foldLeft(attempts.head) { case (task, nextAttempt) =>
              task.flatMap {
                case Left(_) =>
                  // Fetch failed, try next (Url, CachePolicy) combination
                  nextAttempt
                case success => Task.point(success)
              }
            }
        val shas = foldShas(for {
          // Attempt 1: Fetch "*.jar.sha256" URL locally
          // Attempt 2: Fetch "*.jar" URL locally
          // Attempt 3: Fetch "*.jar.sha256" URL remotely
          // Attempt 4: Fetch "*.jar" URL remotely
          url <- List(
            r.artifact.checksumUrls.get("SHA-256"),
            Some(r.artifact.url)
          ).flatten
          policy <- List(CachePolicy.LocalOnly, CachePolicy.Update)
        } yield tryFetch(r.artifact.withUrl(url), policy))
        val sourcesShas = foldShas(for {
          url <- List(
            r.sourcesArtifact.flatMap(_.checksumUrls.get("SHA-256")),
            r.sourcesArtifact.map(_.url),
          ).flatten
          policy <- List(CachePolicy.LocalOnly, CachePolicy.Update)
        } yield tryFetch(r.artifact.withUrl(url), policy))
        shas.flatMap {
          case Right(file) =>
            (sourcesShas
              .map {
                case Right(sourceFile) => Some(sourceFile)
                case Left(_)           => None
              })
              .map { sourceSha =>
                List(Try {
                  val output = ArtifactOutput(
                    dependency = r.dependency,
                    artifact = r.artifact,
                    artifactSha256 = Sha256.compute(file),
                    sourcesArtifact = r.sourcesArtifact,
                    sourcesArtifactSha256 = sourceSha.map(Sha256.compute)
                  )
                  outputIndex.put(r.dependency.bazelLabel, output)
                  output
                }.toEither)
              }
          case Left(value) =>
            // Ignore download failures. It's common that some dependencies have
            // pom files but no jar files. For example,
            // https://repo1.maven.org/maven2/io/monix/monix_2.12/2.3.2/ There
            // exists `Artifact.optional` and `Dependency.optional`, which seem
            // helpful to distinguish these kinds of dependencies but they are
            // true by default so I'm not sure if they're intended to be used
            // for that purpose.
            Task.point(Nil)
        }
      }
    val all = runParallelTasks(files, progressBar, cache.ec).flatten
    val errors = all.collect { case Left(error) => Diagnostic.exception(error) }
    Diagnostic.fromDiagnostics(errors.toList) match {
      case Some(error) =>
        ErrorResult(error)
      case None =>
        val artifacts: Seq[ArtifactOutput] = all
          .collect({ case Right(a) => a })
          .toList
          .distinctBy(_.label)
        if (artifacts.isEmpty) {
          ErrorResult(
            Diagnostic.error(
              "no resolved artifacts." +
                "To fix this problem, make sure your configuration declares a non-empty list of 'dependencies'."
            )
          )
        } else {
          val rendered =
            DepsOutput(
              artifacts.sortBy(_.dependency.repr),
              index,
              outputIndex
            ).render
          val out =
            if (outputPath.isAbsolute()) outputPath
            else app.env.workingDirectory.resolve(outputPath)
          if (!Files.exists(out.getParent())) {
            Files.createDirectories(out.getParent())
          }
          Files.write(out, rendered.getBytes(StandardCharsets.UTF_8))
          ValueResult(out)
        }
    }
  }