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

coursier.maven.MavenRepository.scala Maven / Gradle / Ivy

There is a newer version: 1.1.0-M7
Show newest version
package coursier.maven

import coursier.Fetch
import coursier.core._
import coursier.core.compatibility.encodeURIComponent

import scala.language.higherKinds
import scalaz._

object MavenRepository {

  def ivyLikePath(
    org: String,
    dirName: String,
    name: String,
    version: String,
    subDir: String,
    baseSuffix: String,
    ext: String
  ) =
    Seq(
      org,
      dirName,
      version,
      subDir,
      s"$name$baseSuffix.$ext"
    )

  def mavenVersioning(
    snapshotVersioning: SnapshotVersioning,
    classifier: String,
    extension: String
  ): Option[String] =
    snapshotVersioning
      .snapshotVersions
      .find(v => v.classifier == classifier && v.extension == extension)
      .map(_.value)
      .filter(_.nonEmpty)


  val defaultConfigurations = Map(
    "compile" -> Seq.empty,
    "runtime" -> Seq("compile"),
    "default" -> Seq("runtime"),
    "test" -> Seq("runtime")
  )

  val defaultPackaging = "jar"

  def defaultPublications(moduleName: String, packaging: String) = Seq(
    "compile" -> Publication(moduleName, packaging, MavenSource.typeExtension(packaging), ""),
    "docs" -> Publication(moduleName, "doc", "jar", "javadoc"),
    "sources" -> Publication(moduleName, "src", "jar", "sources")
  )

  def dirModuleName(module: Module, sbtAttrStub: Boolean): String =
    if (sbtAttrStub) {
      var name = module.name
      for (scalaVersion <- module.attributes.get("scalaVersion"))
        name = name + "_" + scalaVersion
      for (sbtVersion <- module.attributes.get("sbtVersion"))
        name = name + "_" + sbtVersion
      name
    } else
      module.name

}

case class MavenRepository(
  root: String,
  changing: Option[Boolean] = None,
  /** Hackish hack for sbt plugins mainly - what this does really sucks */
  sbtAttrStub: Boolean = false,
  authentication: Option[Authentication] = None
) extends Repository {

  import Repository._
  import MavenRepository._

  val root0 = if (root.endsWith("/")) root else root + "/"
  val source = MavenSource(root0, changing, sbtAttrStub, authentication)

  def projectArtifact(
    module: Module,
    version: String,
    versioningValue: Option[String]
  ): Artifact = {

    val path = module.organization.split('.').toSeq ++ Seq(
      dirModuleName(module, sbtAttrStub),
      version,
      s"${module.name}-${versioningValue getOrElse version}.pom"
    )

    Artifact(
      root0 + path.map(encodeURIComponent).mkString("/"),
      Map.empty,
      Map.empty,
      Attributes("pom", ""),
      changing = changing.getOrElse(version.contains("-SNAPSHOT")),
      authentication = authentication
    )
    .withDefaultChecksums
    .withDefaultSignature
  }

  def versionsArtifact(module: Module): Option[Artifact] = {

    val path = module.organization.split('.').toSeq ++ Seq(
      dirModuleName(module, sbtAttrStub),
      "maven-metadata.xml"
    )

    val artifact =
      Artifact(
        root0 + path.map(encodeURIComponent).mkString("/"),
        Map.empty,
        Map.empty,
        Attributes("pom", ""),
        changing = true,
        authentication = authentication
      )
      .withDefaultChecksums
      .withDefaultSignature

    Some(artifact)
  }

  def snapshotVersioningArtifact(
    module: Module,
    version: String
  ): Option[Artifact] = {

    val path = module.organization.split('.').toSeq ++ Seq(
      dirModuleName(module, sbtAttrStub),
      version,
      "maven-metadata.xml"
    )

    val artifact =
      Artifact(
        root0 + path.map(encodeURIComponent).mkString("/"),
        Map.empty,
        Map.empty,
        Attributes("pom", ""),
        changing = true,
        authentication = authentication
      )
      .withDefaultChecksums
      .withDefaultSignature

    Some(artifact)
  }

  def versions[F[_]](
    module: Module,
    fetch: Fetch.Content[F]
  )(implicit
    F: Monad[F]
  ): EitherT[F, String, Versions] =
    EitherT(
      versionsArtifact(module) match {
        case None => F.point(-\/("Not supported"))
        case Some(artifact) =>
          F.map(fetch(artifact).run)(eitherStr =>
            for {
              str <- eitherStr
              xml <- \/.fromEither(compatibility.xmlParse(str))
              _ <- if (xml.label == "metadata") \/-(()) else -\/("Metadata not found")
              versions <- Pom.versions(xml)
            } yield versions
          )
      }
    )

  def snapshotVersioning[F[_]](
    module: Module,
    version: String,
    fetch: Fetch.Content[F]
  )(implicit
    F: Monad[F]
  ): EitherT[F, String, SnapshotVersioning] = {

    EitherT(
      snapshotVersioningArtifact(module, version) match {
        case None => F.point(-\/("Not supported"))
        case Some(artifact) =>
          F.map(fetch(artifact).run)(eitherStr =>
            for {
              str <- eitherStr
              xml <- \/.fromEither(compatibility.xmlParse(str))
              _ <- if (xml.label == "metadata") \/-(()) else -\/("Metadata not found")
              snapshotVersioning <- Pom.snapshotVersioning(xml)
            } yield snapshotVersioning
          )
      }
    )
  }

  def findNoInterval[F[_]](
    module: Module,
    version: String,
    fetch: Fetch.Content[F]
  )(implicit
    F: Monad[F]
  ): EitherT[F, String, Project] =
    EitherT {
      def withSnapshotVersioning =
        snapshotVersioning(module, version, fetch).flatMap { snapshotVersioning =>
          val versioningOption =
            mavenVersioning(snapshotVersioning, "", "jar")
              .orElse(mavenVersioning(snapshotVersioning, "", ""))

          versioningOption match {
            case None =>
              EitherT[F, String, Project](
                F.point(-\/("No snapshot versioning value found"))
              )
            case versioning @ Some(_) =>
              findVersioning(module, version, versioning, fetch)
                .map(_.copy(snapshotVersioning = Some(snapshotVersioning)))
          }
        }

      F.bind(findVersioning(module, version, None, fetch).run) { eitherProj =>
        if (eitherProj.isLeft && version.contains("-SNAPSHOT"))
          F.map(withSnapshotVersioning.run)(eitherProj0 =>
            if (eitherProj0.isLeft)
              eitherProj
            else
              eitherProj0
          )
        else
          F.point(eitherProj)
      }
    }

  def findVersioning[F[_]](
    module: Module,
    version: String,
    versioningValue: Option[String],
    fetch: Fetch.Content[F]
  )(implicit
    F: Monad[F]
  ): EitherT[F, String, Project] = {

    fetch(projectArtifact(module, version, versioningValue)).flatMap { str =>
      EitherT {
        F.point[String \/ Project] {
          for {
            xml <- \/.fromEither(compatibility.xmlParse(str))
            _ <- if (xml.label == "project") \/-(()) else -\/("Project definition not found")
            proj <- Pom.project(xml)
          } yield {
            val packagingOpt = Pom.packagingOpt(xml)

            proj.copy(
              configurations = defaultConfigurations,
              publications = defaultPublications(
                module.name,
                packagingOpt.getOrElse(defaultPackaging)
              )
            )
          }
        }
      }
    }
  }

  def find[F[_]](
    module: Module,
    version: String,
    fetch: Fetch.Content[F]
  )(implicit
    F: Monad[F]
  ): EitherT[F, String, (Artifact.Source, Project)] = {

    Parse.versionInterval(version)
      .orElse(Parse.ivyLatestSubRevisionInterval(version))
      .filter(_.isValid) match {
        case None =>
          findNoInterval(module, version, fetch).map((source, _))
        case Some(itv) =>
          versions(module, fetch).flatMap { versions0 =>
            val eitherVersion = {
              val release = Version(versions0.release)

              if (itv.contains(release)) \/-(versions0.release)
              else {
                val inInterval = versions0.available
                  .map(Version(_))
                  .filter(itv.contains)

                if (inInterval.isEmpty) -\/(s"No version found for $version")
                else \/-(inInterval.max.repr)
              }
            }

            eitherVersion match {
              case -\/(reason) => EitherT[F, String, (Artifact.Source, Project)](F.point(-\/(reason)))
              case \/-(version0) =>
                findNoInterval(module, version0, fetch)
                  .map(_.copy(versions = Some(versions0)))
                  .map((source, _))
            }
          }
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy