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

coursier.internal.FetchCache.scala Maven / Gradle / Ivy

The newest version!
package coursier.internal

import java.io.File
import java.math.BigInteger
import java.nio.charset.StandardCharsets
import java.nio.file.{Files, Path, Paths, StandardCopyOption}
import java.security.MessageDigest

import coursier.cache.CacheLocks
import coursier.core.{Classifier, Dependency, Repository, Type}
import coursier.params.ResolutionParams
import coursier.paths.CachePath

final case class FetchCache(base: Path) {

  def dir(key: FetchCache.Key): Path =
    base.resolve(s"${key.sha1.take(2)}/${key.sha1.drop(2)}")
  def resultFile(key: FetchCache.Key): Path =
    dir(key).resolve("artifacts")
  def lockFile(key: FetchCache.Key): Path =
    dir(key).resolve("lock")

  def read(key: FetchCache.Key): Option[Seq[File]] = {
    val resultFile0 = resultFile(key)
    if (Files.isRegularFile(resultFile0)) {
      val artifacts = Predef.augmentString(new String(Files.readAllBytes(resultFile0), StandardCharsets.UTF_8))
        .lines
        .map(_.trim)
        .filter(_.nonEmpty)
        .map(Paths.get(_))
        .toVector

      if (artifacts.forall(Files.isRegularFile(_)))
        Some(artifacts.map(_.toFile))
      else
        None
    } else
      None
  }

  def write(key: FetchCache.Key, artifacts: Seq[File]): Boolean = {
    val resultFile0 = resultFile(key)
    val tmpFile = CachePath.temporaryFile(resultFile0.toFile).toPath

    def doWrite(): Unit = {
      Files.write(tmpFile, artifacts.map(_.getAbsolutePath).mkString("\n").getBytes(StandardCharsets.UTF_8))
      Files.move(tmpFile, resultFile0, StandardCopyOption.ATOMIC_MOVE)
    }

    CacheLocks.withLockOr(
      base.toFile,
      resultFile0.toFile
    )(
      { doWrite(); true },
      Some(false)
    )
  }

}

object FetchCache {

  final case class Key(
    dependencies: Seq[Dependency],
    repositories: Seq[Repository],
    resolutionParams: ResolutionParams,

    // these 3 come from ResolutionParams, but are ordered here
    forceVersion: Seq[(coursier.core.Module, String)],
    forcedProperties: Seq[(String, String)],
    profiles: Seq[String],

    cacheLocation: String,
    classifiers: Seq[Classifier],
    mainArtifacts: Option[Boolean],
    artifactTypesOpt: Option[Seq[Type]]
  ) {
    lazy val repr: String =
      productIterator.mkString("(", ", ", ")")
    lazy val sha1: String = {
      val md = MessageDigest.getInstance("SHA-1")
      val b = md.digest(repr.getBytes(StandardCharsets.UTF_8))
      val s = new BigInteger(1, b).toString(16)
      ("0" * (40 - s.length)) + s
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy