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

scala.coursier.parse.DependencyParser.scala Maven / Gradle / Ivy

There is a newer version: 2.1.24
Show newest version
package coursier.parse

import coursier.core.{
  Attributes,
  Classifier,
  Configuration,
  Dependency,
  Extension,
  Module,
  ModuleName,
  Organization,
  Publication,
  Type
}
import coursier.core.Validation._
import coursier.util.ValidationNel
import coursier.util.Traverse._
import dependency.{NoAttributes, ScalaNameAttributes}
import dependency.parser.{DependencyParser => DepParser}

import scala.collection.mutable

/** These are not meant to be used by coursier users. Better coursier/dependency based parsers to
  * come.
  */
object DependencyParser {

  def dependency(
    input: String,
    defaultScalaVersion: String
  ): Either[String, Dependency] =
    dependency(input, defaultScalaVersion, Configuration.empty)

  def dependency(
    input: String,
    defaultScalaVersion: String,
    defaultConfiguration: Configuration
  ): Either[String, Dependency] =
    dependencyParams(input, defaultScalaVersion, defaultConfiguration).map(_._1)

  def dependencies(
    inputs: Seq[String],
    defaultScalaVersion: String
  ): ValidationNel[String, Seq[Dependency]] =
    dependencies(inputs, defaultScalaVersion, Configuration.empty)

  def dependencies(
    inputs: Seq[String],
    defaultScalaVersion: String,
    defaultConfiguration: Configuration
  ): ValidationNel[String, Seq[Dependency]] =
    dependenciesParams(inputs, defaultConfiguration, defaultScalaVersion)
      .map(_.map(_._1))

  def javaOrScalaDependencies(
    inputs: Seq[String]
  ): ValidationNel[String, Seq[JavaOrScalaDependency]] =
    javaOrScalaDependencies(inputs, Configuration.empty)

  def javaOrScalaDependencies(
    inputs: Seq[String],
    defaultConfiguration: Configuration
  ): ValidationNel[String, Seq[JavaOrScalaDependency]] =
    javaOrScalaDependenciesParams(inputs, defaultConfiguration)
      .map(_.map(_._1))

  /** Parses coordinates like org:name:version possibly with attributes, like
    * org:name;attr1=val1;attr2=val2:version
    */
  def moduleVersion(
    input: String,
    defaultScalaVersion: String
  ): Either[String, (Module, String)] = {

    val parts = input.split(":", 4)

    parts match {
      case Array(org, rawName, version) =>
        ModuleParser.module(s"$org:$rawName", defaultScalaVersion)
          .map((_, version))

      case Array(org, "", rawName, version) =>
        ModuleParser.module(s"$org::$rawName", defaultScalaVersion)
          .map((_, version))

      case _ =>
        Left(s"Malformed dependency: $input")
    }
  }

  def moduleVersions(
    inputs: Seq[String],
    defaultScalaVersion: String
  ): ValidationNel[String, Seq[(Module, String)]] =
    inputs.validationNelTraverse { input =>
      val e = moduleVersion(input, defaultScalaVersion)
      ValidationNel.fromEither(e)
    }

  /*
   * Validates the parsed attributes.
   *
   * Currently only "classifier", "type", "extension", and "url" are allowed. If more are
   * added, they should be passed in via the second parameter
   *
   * @param attrs Attributes parsed
   * @param dep String representing the dep being parsed
   * @param validAttrsKeys Valid attribute keys
   * @return A string if there is an error, otherwise None
   */
  private def validateAttributes(
    attrs: Set[String],
    dep: String,
    validAttrsKeys: Set[String]
  ): Option[String] = {
    val extraAttributes = attrs.diff(validAttrsKeys)

    if (attrs.size > validAttrsKeys.size || extraAttributes.nonEmpty)
      Some(
        s"The only attributes allowed are: ${validAttrsKeys.mkString(", ")}. ${if (extraAttributes.nonEmpty) s"The following are invalid: " +
            s"${extraAttributes.map(_ + s" in " + dep).mkString(", ")}"}"
      )
    else None
  }

  def dependencyParams(
    input: String,
    defaultScalaVersion: String
  ): Either[String, (Dependency, Map[String, String])] =
    dependencyParams(
      input,
      defaultScalaVersion,
      Configuration.empty
    )

  def javaOrScalaDependencyParams(
    input: String
  ): Either[String, (JavaOrScalaDependency, Map[String, String])] =
    javaOrScalaDependencyParams(input, Configuration.empty)

  /** Parses coordinates like org:name:version with attributes, like
    * org:name:version,attr1=val1,attr2=val2 and a configuration, like org:name:version:config or
    * org:name:version:config,attr1=val1,attr2=val2
    *
    * Currently only the "classifier" and "url attributes are used, and others throw errors.
    */
  def javaOrScalaDependencyParams(
    input: String,
    defaultConfiguration: Configuration
  ): Either[String, (JavaOrScalaDependency, Map[String, String])] =
    for {
      anyDep <- DepParser.parse(input, acceptInlineConfiguration = true)
      dep    <- JavaOrScalaDependency.from(anyDep)
      map = JavaOrScalaDependency.leftOverUserParams(anyDep)
        .map {
          case (k, v) =>
            (k, v.getOrElse(""))
        }
        .toMap
      _ <- validateAttributes(map.keySet, input, Set("url")).toLeft(())
    } yield (
      dep,
      JavaOrScalaDependency.leftOverUserParams(anyDep).map { case (k, v) => (k, v.getOrElse("")) }.toMap
    )

  /** Parses coordinates like org:name:version with attributes, like
    * org:name:version,attr1=val1,attr2=val2 and a configuration, like org:name:version:config or
    * org:name:version:config,attr1=val1,attr2=val2
    *
    * Currently only the "classifier", "type", "extension", and "url attributes are used, and others
    * throw errors.
    */
  def dependencyParams(
    input: String,
    defaultScalaVersion: String,
    defaultConfiguration: Configuration
  ): Either[String, (Dependency, Map[String, String])] =
    javaOrScalaDependencyParams(input, defaultConfiguration).map {
      case (dep, params) =>
        (dep.dependency(defaultScalaVersion), params)
    }

  def dependenciesParams(
    inputs: Seq[String],
    defaultConfiguration: Configuration,
    defaultScalaVersion: String
  ): ValidationNel[String, Seq[(Dependency, Map[String, String])]] =
    inputs.validationNelTraverse { input =>
      val e = dependencyParams(input, defaultScalaVersion, defaultConfiguration)
      ValidationNel.fromEither(e)
    }

  def javaOrScalaDependenciesParams(
    inputs: Seq[String]
  ): ValidationNel[String, Seq[(JavaOrScalaDependency, Map[String, String])]] =
    javaOrScalaDependenciesParams(inputs, Configuration.empty)

  def javaOrScalaDependenciesParams(
    inputs: Seq[String],
    defaultConfiguration: Configuration
  ): ValidationNel[String, Seq[(JavaOrScalaDependency, Map[String, String])]] =
    inputs.validationNelTraverse { input =>
      val e = javaOrScalaDependencyParams(input, defaultConfiguration)
      ValidationNel.fromEither(e)
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy