From 33aa61e8eb53304f939168b2ef48d48849763489 Mon Sep 17 00:00:00 2001 From: Eric Peters Date: Fri, 22 Mar 2019 03:07:35 -0700 Subject: [PATCH] Parse Ivy-compatible RawRepository resolvers (#49) --- .../scala/coursier/lmcoursier/FromSbt.scala | 106 +++++++++++++----- .../src/sbt-test/shared-2/s3/build.sbt | 51 +++++++++ .../shared-2/s3/project/build.properties | 1 + .../sbt-test/shared-2/s3/project/extra.sbt | 1 + .../sbt-test/shared-2/s3/project/plugins.sbt | 1 + .../shared-2/s3/project/project/plugins.sbt | 13 +++ .../shared-2/s3/src/main/scala/Foo.scala | 1 + .../src/sbt-test/shared-2/s3/test | 1 + 8 files changed, 144 insertions(+), 31 deletions(-) create mode 100644 modules/sbt-coursier/src/sbt-test/shared-2/s3/build.sbt create mode 100644 modules/sbt-coursier/src/sbt-test/shared-2/s3/project/build.properties create mode 100644 modules/sbt-coursier/src/sbt-test/shared-2/s3/project/extra.sbt create mode 100644 modules/sbt-coursier/src/sbt-test/shared-2/s3/project/plugins.sbt create mode 100644 modules/sbt-coursier/src/sbt-test/shared-2/s3/project/project/plugins.sbt create mode 100644 modules/sbt-coursier/src/sbt-test/shared-2/s3/src/main/scala/Foo.scala create mode 100644 modules/sbt-coursier/src/sbt-test/shared-2/s3/test diff --git a/modules/lm-coursier/src/main/scala/coursier/lmcoursier/FromSbt.scala b/modules/lm-coursier/src/main/scala/coursier/lmcoursier/FromSbt.scala index 25b15b3e7..0dcbd5f82 100644 --- a/modules/lm-coursier/src/main/scala/coursier/lmcoursier/FromSbt.scala +++ b/modules/lm-coursier/src/main/scala/coursier/lmcoursier/FromSbt.scala @@ -3,14 +3,15 @@ package coursier.lmcoursier import coursier.ivy.IvyRepository import coursier.ivy.IvyXml.{mappings => ivyXmlMappings} import java.net.MalformedURLException - import coursier.cache.CacheUrl import coursier.{Attributes, Dependency, Module} import coursier.core._ import coursier.maven.MavenRepository +import org.apache.ivy.plugins.resolver.IBiblioResolver import sbt.internal.librarymanagement.mavenint.SbtPomExtraProperties import sbt.librarymanagement.{Configuration => _, MavenRepository => _, _} import sbt.util.Logger +import scala.collection.JavaConverters._ object FromSbt { @@ -259,43 +260,86 @@ object FromSbt { mavenRepositoryOpt("file://" + mavenCompatibleBase, log, authentication) } - case r: URLRepository - if r.patterns.ivyPatterns.lengthCompare(1) == 0 && - r.patterns.artifactPatterns.lengthCompare(1) == 0 => - - val mavenCompatibleBaseOpt0 = mavenCompatibleBaseOpt(r.patterns) - - mavenCompatibleBaseOpt0 match { - case None => - - val repo = IvyRepository.parse( - r.patterns.artifactPatterns.head, - metadataPatternOpt = Some(r.patterns.ivyPatterns.head), - changing = None, - properties = ivyProperties, - dropInfoAttributes = true, - authentication = authentication - ) match { - case Left(err) => - sys.error( - s"Cannot parse Ivy patterns ${r.patterns.artifactPatterns.head} and ${r.patterns.ivyPatterns.head}: $err" - ) - case Right(repo) => - repo - } - - Some(repo) - - case Some(mavenCompatibleBase) => - mavenRepositoryOpt(mavenCompatibleBase, log, authentication) - } + case r: URLRepository if patternMatchGuard(r.patterns) => + parseMavenCompatResolver(log, ivyProperties, authentication, r.patterns) case raw: RawRepository if raw.name == "inter-project" => // sbt.RawRepository.equals just compares names anyway None + // Pattern Match resolver-type-specific RawRepositories + case IBiblioRepository(p) => + parseMavenCompatResolver(log, ivyProperties, authentication, p) + case other => log.warn(s"Unrecognized repository ${other.name}, ignoring it") None } + private object IBiblioRepository { + + private def stringVector(v: java.util.List[_]): Vector[String] = + Option(v).map(_.asScala.toVector).getOrElse(Vector.empty).collect { + case s: String => s + } + + private def patterns(resolver: IBiblioResolver): Patterns = Patterns( + ivyPatterns = stringVector(resolver.getIvyPatterns), + artifactPatterns = stringVector(resolver.getArtifactPatterns), + isMavenCompatible = resolver.isM2compatible, + descriptorOptional = !resolver.isUseMavenMetadata, + skipConsistencyCheck = !resolver.isCheckconsistency + ) + + def unapply(r: Resolver): Option[Patterns] = + r match { + case raw: RawRepository => + raw.resolver match { + case b: IBiblioResolver => + Some(patterns(b)) + .filter(patternMatchGuard) + case _ => + None + } + case _ => + None + } + } + + private def patternMatchGuard(patterns: Patterns): Boolean = + patterns.ivyPatterns.lengthCompare(1) == 0 && + patterns.artifactPatterns.lengthCompare(1) == 0 + + private def parseMavenCompatResolver( + log: Logger, + ivyProperties: Map[String, String], + authentication: Option[Authentication], + patterns: Patterns + ): Option[Repository] = { + val mavenCompatibleBaseOpt0 = mavenCompatibleBaseOpt(patterns) + + mavenCompatibleBaseOpt0 match { + case None => + + val repo = IvyRepository.parse( + patterns.artifactPatterns.head, + metadataPatternOpt = Some(patterns.ivyPatterns.head), + changing = None, + properties = ivyProperties, + dropInfoAttributes = true, + authentication = authentication + ) match { + case Left(err) => + sys.error( + s"Cannot parse Ivy patterns ${patterns.artifactPatterns.head} and ${patterns.ivyPatterns.head}: $err" + ) + case Right(repo) => + repo + } + + Some(repo) + + case Some(mavenCompatibleBase) => + mavenRepositoryOpt(mavenCompatibleBase, log, authentication) + } + } } diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/s3/build.sbt b/modules/sbt-coursier/src/sbt-test/shared-2/s3/build.sbt new file mode 100644 index 000000000..fcb2f81c7 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/s3/build.sbt @@ -0,0 +1,51 @@ +scalaVersion := "2.12.8" + +resolvers += "Private S3 Snapshots" atS3 + "s3://s3-us-west-2.amazonaws.com/bucket-name/snapshots" +resolvers += "Private S3 Releases" atS3 + "s3://s3-us-west-2.amazonaws.com/bucket-name/releases" + +// TODO: Would need a public s3 bucket to download an artifact + +lazy val check = taskKey[Unit]("") + +// Checks FromSbt.repository parses the "s3://" urls correctly. + +check := { + val s: TaskStreams = streams.value + + val sbtResolvers: Seq[sbt.librarymanagement.Resolver] = coursierResolvers.value + + // Sanity check to ensure SBT is loading the resolvers properly + assert(sbtResolvers.exists(_.name == "Private S3 Snapshots")) + assert(sbtResolvers.exists(_.name == "Private S3 Releases")) + + // Have Coursier SBT Plugin Parse the SBT Resolvers + val parsedCoursierResolvers: Seq[coursier.core.Repository] = + sbtResolvers.flatMap{ sbtResolver: sbt.librarymanagement.Resolver => + coursier.lmcoursier.FromSbt.repository( + resolver = sbtResolver, + ivyProperties = coursier.lmcoursier.ResolutionParams.defaultIvyProperties(), + log = s.log, + authentication = None, + ) + } + + // Verify the input resolvers == output resolvers + assert( + sbtResolvers.size == parsedCoursierResolvers.size, + s"SBT resolvers size (${sbtResolvers.size}) did not match " + + s"Coursier resolvers size (${parsedCoursierResolvers.size})" + ) + + def containsRepo(repo: String): Boolean = { + parsedCoursierResolvers.collectFirst { + case m: coursier.maven.MavenRepository if m.root == repo => true + }.exists{ _ == true } + } + + assert(containsRepo("s3://s3-us-west-2.amazonaws.com/bucket-name/snapshots/"), + "Didn't have snapshots s3 repo") + assert(containsRepo("s3://s3-us-west-2.amazonaws.com/bucket-name/releases/"), + "Didn't have releases s3 repo") +} \ No newline at end of file diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/s3/project/build.properties b/modules/sbt-coursier/src/sbt-test/shared-2/s3/project/build.properties new file mode 100644 index 000000000..c0bab0494 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/s3/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.2.8 diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/s3/project/extra.sbt b/modules/sbt-coursier/src/sbt-test/shared-2/s3/project/extra.sbt new file mode 100644 index 000000000..8bb66653d --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/s3/project/extra.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.frugalmechanic" % "fm-sbt-s3-resolver" % "0.18.0") \ No newline at end of file diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/s3/project/plugins.sbt b/modules/sbt-coursier/src/sbt-test/shared-2/s3/project/plugins.sbt new file mode 100644 index 000000000..3a2d48ea4 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/s3/project/plugins.sbt @@ -0,0 +1 @@ +addSbtCoursier diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/s3/project/project/plugins.sbt b/modules/sbt-coursier/src/sbt-test/shared-2/s3/project/project/plugins.sbt new file mode 100644 index 000000000..71a44ffd3 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/s3/project/project/plugins.sbt @@ -0,0 +1,13 @@ +addSbtPlugin { + + val name = sys.props.getOrElse( + "plugin.name", + sys.error("plugin.name Java property not set") + ) + val version = sys.props.getOrElse( + "plugin.version", + sys.error("plugin.version Java property not set") + ) + + "io.get-coursier" % name % version +} \ No newline at end of file diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/s3/src/main/scala/Foo.scala b/modules/sbt-coursier/src/sbt-test/shared-2/s3/src/main/scala/Foo.scala new file mode 100644 index 000000000..d37c10456 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/s3/src/main/scala/Foo.scala @@ -0,0 +1 @@ +object Foo \ No newline at end of file diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/s3/test b/modules/sbt-coursier/src/sbt-test/shared-2/s3/test new file mode 100644 index 000000000..a5912a391 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/s3/test @@ -0,0 +1 @@ +> check \ No newline at end of file