diff --git a/build.sbt b/build.sbt index b153b9aea..3a8a6a881 100644 --- a/build.sbt +++ b/build.sbt @@ -15,7 +15,7 @@ inThisBuild(List( ) )) -val coursierVersion0 = "2.0.0-RC6-16" +val coursierVersion0 = "2.0.0-RC6-18" lazy val `lm-coursier` = project .in(file("modules/lm-coursier")) diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala index addf9b9ce..82b00d189 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala @@ -25,14 +25,6 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen * sbt-coursier, that was moved to this module. */ - private lazy val excludeDependencies = conf - .excludeDependencies - .map { - case (strOrg, strName) => - (lmcoursier.definitions.Organization(strOrg), lmcoursier.definitions.ModuleName(strName)) - } - .toSet - def moduleDescriptor(moduleSetting: ModuleDescriptorConfiguration): ModuleDescriptor = CoursierModuleDescriptor(moduleSetting, conf) @@ -125,13 +117,14 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen } .map { case (config, dep) => - val dep0 = dep.withExclusions(dep.exclusions ++ excludeDependencies) - (ToCoursier.configuration(config), ToCoursier.dependency(dep0)) + (ToCoursier.configuration(config), ToCoursier.dependency(dep)) } - val configGraphs = Inputs.ivyGraphs( - Inputs.configExtends(module0.configurations) - ).map(_.map(ToCoursier.configuration)) + val orderedConfigs = Inputs.orderedConfigurations(Inputs.configExtendsSeq(module0.configurations)) + .map { + case (config, extends0) => + (ToCoursier.configuration(config), extends0.map(ToCoursier.configuration)) + } val typelevel = so == Typelevel.typelevelOrg @@ -143,10 +136,18 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen .withCredentials(conf.credentials.map(ToCoursier.credentials)) .withFollowHttpToHttpsRedirections(conf.followHttpToHttpsRedirections.getOrElse(true)) + val excludeDependencies = conf + .excludeDependencies + .map { + case (strOrg, strName) => + (coursier.Organization(strOrg), coursier.ModuleName(strName)) + } + .toSet + val resolutionParams = ResolutionParams( dependencies = dependencies, fallbackDependencies = conf.fallbackDependencies, - configGraphs = configGraphs, + orderedConfigs = orderedConfigs, autoScalaLibOpt = if (conf.autoScalaLibrary) Some((so, sv)) else None, mainRepositories = mainRepositories, parentProjectCache = Map.empty, @@ -162,15 +163,16 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen .withProfiles(conf.mavenProfiles.toSet) .withForceVersion(conf.forceVersions.map { case (k, v) => (ToCoursier.module(k), v) }.toMap) .withTypelevel(typelevel) - .withReconciliation(ToCoursier.reconciliation(conf.reconciliation)), + .withReconciliation(ToCoursier.reconciliation(conf.reconciliation)) + .withExclusions(excludeDependencies), strictOpt = conf.strict.map(ToCoursier.strict), missingOk = conf.missingOk, ) - def artifactsParams(resolutions: Map[Set[Configuration], Resolution]): ArtifactsParams = + def artifactsParams(resolutions: Map[Configuration, Resolution]): ArtifactsParams = ArtifactsParams( classifiers = classifiers, - resolutions = resolutions.values.toSeq, + resolutions = resolutions.values.toSeq.distinct, includeSignatures = false, loggerOpt = loggerOpt, projectName = projectName, @@ -193,7 +195,7 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen } def updateParams( - resolutions: Map[Set[Configuration], Resolution], + resolutions: Map[Configuration, Resolution], artifacts: Seq[(Dependency, Publication, Artifact, Option[File])] ) = UpdateParams( diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/Inputs.scala b/modules/lm-coursier/src/main/scala/lmcoursier/Inputs.scala index 23e1a0d86..da55d13b8 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/Inputs.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/Inputs.scala @@ -15,6 +15,11 @@ object Inputs { Configuration(from.value) -> Configuration(to.value) } + def configExtendsSeq(configurations: Seq[sbt.librarymanagement.Configuration]): Seq[(Configuration, Seq[Configuration])] = + configurations + .map(cfg => Configuration(cfg.name) -> cfg.extendsConfigs.map(c => Configuration(c.name))) + + @deprecated("Now unused internally, to be removed in the future", "2.0.0-RC6-5") def configExtends(configurations: Seq[sbt.librarymanagement.Configuration]): Map[Configuration, Seq[Configuration]] = configurations .map(cfg => Configuration(cfg.name) -> cfg.extendsConfigs.map(c => Configuration(c.name))) @@ -25,7 +30,7 @@ object Inputs { shadedConfig: Option[(String, Configuration)] = None ): Map[Configuration, Set[Configuration]] = { - val configs0 = configExtends(configurations) + val configs0 = configExtendsSeq(configurations).toMap def allExtends(c: Configuration) = { // possibly bad complexity @@ -55,6 +60,29 @@ object Inputs { } } + def orderedConfigurations( + configurations: Seq[(Configuration, Seq[Configuration])] + ): Seq[(Configuration, Seq[Configuration])] = { + + val map = configurations.toMap + + def helper(done: Set[Configuration], toAdd: List[Configuration]): Stream[(Configuration, Seq[Configuration])] = + toAdd match { + case Nil => Stream.empty + case config :: rest => + val extends0 = map.getOrElse(config, Nil) + val missingExtends = extends0.filterNot(done) + if (missingExtends.isEmpty) + (config, extends0) #:: helper(done + config, rest) + else + helper(done, missingExtends.toList ::: toAdd) + } + + helper(Set.empty, configurations.map(_._1).toList) + .toVector + } + + @deprecated("Now unused internally, to be removed in the future", "2.0.0-RC6-5") def ivyGraphs(configurations: Map[Configuration, Seq[Configuration]]): Seq[Set[Configuration]] = { // probably bad complexity, but that shouldn't matter given the size of the graphs involved... @@ -95,12 +123,12 @@ object Inputs { sets.values.toVector.distinct.map(_.set.toSet) } - def exclusions( + def exclusionsSeq( excludeDeps: Seq[InclExclRule], sv: String, sbv: String, log: Logger - ): Set[(Organization, ModuleName)] = { + ): Seq[(Organization, ModuleName)] = { var anyNonSupportedExclusionRule = false @@ -116,7 +144,6 @@ object Inputs { Seq((Organization(rule.organization), ModuleName(name))) } } - .toSet if (anyNonSupportedExclusionRule) log.warn("Only supported exclusion rule fields: organization, name") @@ -124,6 +151,14 @@ object Inputs { res } + def exclusions( + excludeDeps: Seq[InclExclRule], + sv: String, + sbv: String, + log: Logger + ): Set[(Organization, ModuleName)] = + exclusionsSeq(excludeDeps, sv, sbv, log).toSet + def forceVersions(depOverrides: Seq[ModuleID], sv: String, sbv: String): Seq[(Module, String)] = depOverrides.map(FromSbt.moduleVersion(_, sv, sbv)) diff --git a/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/IvyXml.scala b/modules/lm-coursier/src/main/scala/lmcoursier/IvyXml.scala similarity index 54% rename from modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/IvyXml.scala rename to modules/lm-coursier/src/main/scala/lmcoursier/IvyXml.scala index 5b9d614dd..b55dc1d16 100644 --- a/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/IvyXml.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/IvyXml.scala @@ -1,21 +1,15 @@ -package coursier.sbtcoursiershared - -import java.nio.charset.StandardCharsets.UTF_8 -import java.nio.file.Files +package lmcoursier +import lmcoursier.Inputs import lmcoursier.definitions.{Configuration, Project} -import org.apache.ivy.core.module.id.ModuleRevisionId -import sbt.{Def, Setting, Task, TaskKey} -import sbt.internal.librarymanagement.IvySbt -import sbt.librarymanagement.PublishConfiguration -import scala.collection.JavaConverters._ import scala.xml.{Node, PrefixedAttribute} object IvyXml { - private[sbtcoursiershared] def rawContent( + def apply( currentProject: Project, + exclusions: Seq[(String, String)], shadedConfigOpt: Option[Configuration] ): String = { @@ -28,42 +22,15 @@ object IvyXml { val printer = new scala.xml.PrettyPrinter(Int.MaxValue, 2) """""" + '\n' + - printer.format(content(currentProject, shadedConfigOpt)) + printer.format(content(currentProject, exclusions, shadedConfigOpt)) } // These are required for publish to be fine, later on. - private def writeFiles( - currentProject: Project, - shadedConfigOpt: Option[Configuration], - ivySbt: IvySbt, - log: sbt.util.Logger - ): Unit = { - - val ivyCacheManager = ivySbt.withIvy(log)(ivy => - ivy.getResolutionCacheManager - ) - - val ivyModule = ModuleRevisionId.newInstance( - currentProject.module.organization.value, - currentProject.module.name.value, - currentProject.version, - currentProject.module.attributes.asJava - ) - - val cacheIvyFile = ivyCacheManager.getResolvedIvyFileInCache(ivyModule) - val cacheIvyPropertiesFile = ivyCacheManager.getResolvedIvyPropertiesInCache(ivyModule) - - val content0 = rawContent(currentProject, shadedConfigOpt) - cacheIvyFile.getParentFile.mkdirs() - log.info(s"Writing Ivy file $cacheIvyFile") - Files.write(cacheIvyFile.toPath, content0.getBytes(UTF_8)) - - // Just writing an empty file here... Are these only used? - cacheIvyPropertiesFile.getParentFile.mkdirs() - Files.write(cacheIvyPropertiesFile.toPath, Array.emptyByteArray) - } - - private def content(project0: Project, shadedConfigOpt: Option[Configuration]): Node = { + private def content( + project0: Project, + exclusions: Seq[(String, String)], + shadedConfigOpt: Option[Configuration] + ): Node = { val filterOutDependencies = shadedConfigOpt.toSet[Configuration].flatMap { shadedConfig => @@ -148,53 +115,17 @@ object IvyXml { n % moduleAttrs } + val excludeElems = exclusions.toVector.map { + case (org, name) => + + } + {infoElem} {confElems} {publicationElems} - {dependencyElems} + {dependencyElems}{excludeElems} } - private def makeIvyXmlBefore[T]( - task: TaskKey[T], - shadedConfigOpt: Option[Configuration] - ): Setting[Task[T]] = - task := task.dependsOn { - Def.taskDyn { - import SbtCoursierShared.autoImport._ - val doGen = coursierGenerateIvyXml.value - if (doGen) - Def.task { - val currentProject = { - val proj = coursierProject.value - val publications = coursierPublications.value - proj.withPublications(publications) - } - writeFiles(currentProject, shadedConfigOpt, sbt.Keys.ivySbt.value, sbt.Keys.streams.value.log) - } - else - Def.task(()) - } - }.value - - private lazy val needsIvyXmlLocal = Seq(sbt.Keys.publishLocalConfiguration) ++ getPubConf("makeIvyXmlLocalConfiguration") - private lazy val needsIvyXml = Seq(sbt.Keys.publishConfiguration) ++ getPubConf("makeIvyXmlConfiguration") - - private[this] def getPubConf(method: String): List[TaskKey[PublishConfiguration]] = - try { - val cls = sbt.Keys.getClass - val m = cls.getMethod(method) - val task = m.invoke(sbt.Keys).asInstanceOf[TaskKey[PublishConfiguration]] - List(task) - } catch { - case _: Throwable => // FIXME Too wide - Nil - } - - def generateIvyXmlSettings( - shadedConfigOpt: Option[Configuration] = None - ): Seq[Setting[_]] = - (needsIvyXml ++ needsIvyXmlLocal).map(makeIvyXmlBefore(_, shadedConfigOpt)) - } diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala index ced79bf3c..56a99067a 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala @@ -10,11 +10,13 @@ import lmcoursier.FallbackDependency import lmcoursier.definitions.ToCoursier import coursier.util.Task +import scala.collection.mutable + // private[coursier] final case class ResolutionParams( dependencies: Seq[(Configuration, Dependency)], fallbackDependencies: Seq[FallbackDependency], - configGraphs: Seq[Set[Configuration]], + orderedConfigs: Seq[(Configuration, Seq[Configuration])], autoScalaLibOpt: Option[(Organization, String)], mainRepositories: Seq[Repository], parentProjectCache: ProjectCache, @@ -30,6 +32,18 @@ final case class ResolutionParams( missingOk: Boolean, ) { + lazy val allConfigExtends: Map[Configuration, Set[Configuration]] = { + val map = new mutable.HashMap[Configuration, Set[Configuration]] + for ((config, extends0) <- orderedConfigs) { + val allExtends = extends0 + .iterator + // the else of the getOrElse shouldn't be hit (because of the ordering of the configurations) + .foldLeft(Set(config))((acc, ext) => acc ++ map.getOrElse(ext, Set(ext))) + map += config -> allExtends + } + map.toMap + } + val fallbackDependenciesRepositories = if (fallbackDependencies.isEmpty) Nil diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionRun.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionRun.scala index dc34688e8..f853386af 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionRun.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionRun.scala @@ -9,6 +9,8 @@ import coursier.maven.MavenRepository import coursier.params.rule.RuleResolution import sbt.util.Logger +import scala.collection.mutable + // private[coursier] object ResolutionRun { @@ -16,7 +18,8 @@ object ResolutionRun { params: ResolutionParams, verbosityLevel: Int, log: Logger, - configs: Set[Configuration] + configs: Set[Configuration], + startingResolutionOpt: Option[Resolution] ): Either[coursier.error.ResolutionError, Resolution] = { val isScalaToolConfig = configs(Configuration("scala-tool")) @@ -80,6 +83,8 @@ object ResolutionRun { ThreadUtil.withFixedThreadPool(params.parallel) { pool => Resolve() + // re-using various caches from a resolution of a configuration we extend + .withInitialResolution(startingResolutionOpt) .withDependencies( params.dependencies.collect { case (config, dep) if configs(config) => @@ -126,7 +131,7 @@ object ResolutionRun { params: ResolutionParams, verbosityLevel: Int, log: Logger - ): Either[coursier.error.ResolutionError, Map[Set[Configuration], Resolution]] = { + ): Either[coursier.error.ResolutionError, Map[Configuration, Resolution]] = { // TODO Warn about possible duplicated modules from source repositories? @@ -141,13 +146,24 @@ object ResolutionRun { // Downloads are already parallel, no need to parallelize further, anyway. val resOrError = Lock.lock.synchronized { - params.configGraphs.foldLeft[Either[coursier.error.ResolutionError, Map[Set[Configuration], Resolution]]](Right(Map())) { - case (acc, config) => + var map = new mutable.HashMap[Configuration, Resolution] + val either = params.orderedConfigs.foldLeft[Either[coursier.error.ResolutionError, Unit]](Right(())) { + case (acc, (config, extends0)) => for { - m <- acc - res <- resolution(params, verbosityLevel, log, config) - } yield m + (config -> res) + _ <- acc + initRes = { + val it = extends0.iterator.flatMap(map.get(_).iterator) + if (it.hasNext) Some(it.next()) + else None + } + allExtends = params.allConfigExtends.getOrElse(config, Set.empty) + res <- resolution(params, verbosityLevel, log, allExtends, initRes) + } yield { + map += config -> res + () + } } + either.map(_ => map.toMap) } for (res <- resOrError) SbtCoursierCache.default.putResolution(params.resolutionKey, res) diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtCoursierCache.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtCoursierCache.scala index 23f8367c6..a018a565b 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtCoursierCache.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtCoursierCache.scala @@ -12,15 +12,15 @@ class SbtCoursierCache { import SbtCoursierCache._ - private val resolutionsCache = new ConcurrentHashMap[ResolutionKey, Map[Set[Configuration], Resolution]] + private val resolutionsCache = new ConcurrentHashMap[ResolutionKey, Map[Configuration, Resolution]] // these may actually not need to be cached any more, now that the resolutions // are cached private val reportsCache = new ConcurrentHashMap[ReportKey, UpdateReport] - def resolutionOpt(key: ResolutionKey): Option[Map[Set[Configuration], Resolution]] = + def resolutionOpt(key: ResolutionKey): Option[Map[Configuration, Resolution]] = Option(resolutionsCache.get(key)) - def putResolution(key: ResolutionKey, res: Map[Set[Configuration], Resolution]): Unit = + def putResolution(key: ResolutionKey, res: Map[Configuration, Resolution]): Unit = resolutionsCache.put(key, res) def reportOpt(key: ReportKey): Option[UpdateReport] = @@ -53,7 +53,7 @@ object SbtCoursierCache { final case class ReportKey( dependencies: Seq[(Configuration, Dependency)], - resolution: Map[Set[Configuration], Resolution], + resolution: Map[Configuration, Resolution], withClassifiers: Boolean, sbtClassifiers: Boolean, includeSignatures: Boolean diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala index 420b1fb34..17a6e52d8 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala @@ -132,7 +132,6 @@ private[internal] object SbtUpdateReport { private def moduleReports( thisModule: (Module, String), - config: Configuration, res: Resolution, interProjectDependencies: Seq[Project], classifiersOpt: Option[Seq[Classifier]], @@ -293,9 +292,8 @@ private[internal] object SbtUpdateReport { def apply( thisModule: (Module, String), configDependencies: Map[Configuration, Seq[Dependency]], - resolutions: Map[Configuration, Resolution], + resolutions: Seq[(Configuration, Resolution)], interProjectDependencies: Vector[Project], - configs: Map[Configuration, Set[Configuration]], classifiersOpt: Option[Seq[Classifier]], artifactFileOpt: (Module, String, Attributes, Artifact) => Option[File], fullArtifactsOpt: Option[Map[(Dependency, Publication, Artifact), Option[File]]], @@ -306,18 +304,11 @@ private[internal] object SbtUpdateReport { missingOk: Boolean ): UpdateReport = { - val configReports = configs.map { - case (config, extends0) => - val configDeps = extends0 - .toSeq - .sortBy(_.value) - .flatMap(configDependencies.getOrElse(_, Nil)) - .distinct - val subRes = resolutions(config).subset(configDeps) + val configReports = resolutions.map { + case (config, subRes) => val reports = moduleReports( thisModule, - config, subRes, interProjectDependencies, classifiersOpt, diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateParams.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateParams.scala index 5a5e641e9..6c3cfe93d 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateParams.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateParams.scala @@ -15,7 +15,7 @@ final case class UpdateParams( configs: Map[Configuration, Set[Configuration]], dependencies: Seq[(Configuration, Dependency)], interProjectDependencies: Seq[Project], - res: Map[Set[Configuration], Resolution], + res: Map[Configuration, Resolution], includeSignatures: Boolean, sbtBootJarOverrides: Map[(Module, String), File], classpathOrder: Boolean, diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateRun.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateRun.scala index cdd548b8a..7744dc3e8 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateRun.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateRun.scala @@ -57,11 +57,6 @@ object UpdateRun { log: Logger ): UpdateReport = Lock.lock.synchronized { - val configResolutions = params.res.flatMap { - case (configs, r) => - configs.iterator.map((_, r)) - } - val depsByConfig = grouped(params.dependencies)( config => params.shadedConfigOpt match { @@ -74,7 +69,7 @@ object UpdateRun { if (verbosityLevel >= 2) { val finalDeps = dependenciesWithConfig( - configResolutions, + params.res, depsByConfig, params.configs ) @@ -87,9 +82,8 @@ object UpdateRun { SbtUpdateReport( params.thisModule, depsByConfig, - configResolutions, + params.res.toVector.sortBy(_._1.value), // FIXME Order by config topologically? params.interProjectDependencies.toVector, - params.configs, params.classifiers, params.artifactFileOpt, params.fullArtifacts, diff --git a/modules/lm-coursier/src/test/scala/lmcoursier/IvyXmlTests.scala b/modules/lm-coursier/src/test/scala/lmcoursier/IvyXmlTests.scala new file mode 100644 index 000000000..ad0ae6818 --- /dev/null +++ b/modules/lm-coursier/src/test/scala/lmcoursier/IvyXmlTests.scala @@ -0,0 +1,27 @@ +package lmcoursier + +import lmcoursier.definitions.{Configuration, Info, Module, ModuleName, Organization, Project} +import org.scalatest.{Matchers, PropSpec} + +object IvyXmlTests extends PropSpec with Matchers { + + property("no truncation") { + val project = Project( + Module(Organization("org"), ModuleName("name"), Map()), + "ver", + Nil, + Map( + Configuration("foo") -> (1 to 80).map(n => Configuration("bar" + n)) // long list of configurations -> no truncation any way + ), + Nil, + None, + Nil, + Info("", "", Nil, Nil, None) + ) + + val content = IvyXml(project, Nil, None) + + assert(!content.contains("")) + } + +} diff --git a/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/InputsTasks.scala b/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/InputsTasks.scala index 3a687c483..97d77d458 100644 --- a/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/InputsTasks.scala +++ b/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/InputsTasks.scala @@ -28,32 +28,21 @@ object InputsTasks { private def coursierProject0( projId: ModuleID, dependencies: Seq[ModuleID], - excludeDeps: Seq[InclExclRule], configurations: Seq[sbt.librarymanagement.Configuration], sv: String, sbv: String, log: Logger ): Project = { - val exclusions0 = Inputs.exclusions(excludeDeps, sv, sbv, log) + val configMap = Inputs.configExtendsSeq(configurations).toMap - val configMap = Inputs.configExtends(configurations) - - val proj = FromSbt.project( + FromSbt.project( projId, dependencies, configMap, sv, sbv ) - - proj.withDependencies( - proj.dependencies.map { - case (config, dep) => - val dep0 = dep.withExclusions(dep.exclusions ++ exclusions0) - (config, dep0) - } - ) } private[sbtcoursiershared] def coursierProjectTask: Def.Initialize[sbt.Task[Project]] = @@ -68,7 +57,6 @@ object InputsTasks { coursierProject0( projectID.in(projectRef).get(state), allDependenciesTask.value, - actualExcludeDependencies.in(projectRef).get(state), // should projectID.configurations be used instead? ivyConfigurations.in(projectRef).get(state), scalaVersion.in(projectRef).get(state), diff --git a/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/IvyXmlGeneration.scala b/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/IvyXmlGeneration.scala new file mode 100644 index 000000000..35c681662 --- /dev/null +++ b/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/IvyXmlGeneration.scala @@ -0,0 +1,99 @@ +package coursier.sbtcoursiershared + +import java.nio.charset.StandardCharsets.UTF_8 +import java.nio.file.Files + +import lmcoursier.{Inputs, IvyXml} +import lmcoursier.definitions.{Configuration, Project} +import org.apache.ivy.core.module.id.ModuleRevisionId +import sbt.{Def, Setting, Task, TaskKey} +import sbt.internal.librarymanagement.IvySbt +import sbt.librarymanagement.{CrossVersion, PublishConfiguration} + +import scala.collection.JavaConverters._ + +object IvyXmlGeneration { + + // These are required for publish to be fine, later on. + private def writeFiles( + currentProject: Project, + exclusions: Seq[(String, String)], + shadedConfigOpt: Option[Configuration], + ivySbt: IvySbt, + log: sbt.util.Logger + ): Unit = { + + val ivyCacheManager = ivySbt.withIvy(log)(ivy => + ivy.getResolutionCacheManager + ) + + val ivyModule = ModuleRevisionId.newInstance( + currentProject.module.organization.value, + currentProject.module.name.value, + currentProject.version, + currentProject.module.attributes.asJava + ) + + val cacheIvyFile = ivyCacheManager.getResolvedIvyFileInCache(ivyModule) + val cacheIvyPropertiesFile = ivyCacheManager.getResolvedIvyPropertiesInCache(ivyModule) + + val content0 = IvyXml(currentProject, exclusions, shadedConfigOpt) + cacheIvyFile.getParentFile.mkdirs() + log.info(s"Writing Ivy file $cacheIvyFile") + Files.write(cacheIvyFile.toPath, content0.getBytes(UTF_8)) + + // Just writing an empty file here... Are these only used? + cacheIvyPropertiesFile.getParentFile.mkdirs() + Files.write(cacheIvyPropertiesFile.toPath, Array.emptyByteArray) + } + + private def makeIvyXmlBefore[T]( + task: TaskKey[T], + shadedConfigOpt: Option[Configuration] + ): Setting[Task[T]] = + task := task.dependsOn { + Def.taskDyn { + import SbtCoursierShared.autoImport._ + val doGen = coursierGenerateIvyXml.value + if (doGen) + Def.task { + val sv = sbt.Keys.scalaVersion.value + val sbv = sbt.Keys.scalaBinaryVersion.value + val log = sbt.Keys.streams.value.log + val currentProject = { + val proj = coursierProject.value + val publications = coursierPublications.value + proj.withPublications(publications) + } + val excludeDeps = Inputs.exclusionsSeq(InputsTasks.actualExcludeDependencies.value, sv, sbv, log) + .map { + case (org, name) => + (org.value, name.value) + } + writeFiles(currentProject, excludeDeps, shadedConfigOpt, sbt.Keys.ivySbt.value, log) + } + else + Def.task(()) + } + }.value + + private lazy val needsIvyXmlLocal = Seq(sbt.Keys.publishLocalConfiguration) ++ getPubConf("makeIvyXmlLocalConfiguration") + private lazy val needsIvyXml = Seq(sbt.Keys.publishConfiguration) ++ getPubConf("makeIvyXmlConfiguration") + + private[this] def getPubConf(method: String): List[TaskKey[PublishConfiguration]] = + try { + val cls = sbt.Keys.getClass + val m = cls.getMethod(method) + val task = m.invoke(sbt.Keys).asInstanceOf[TaskKey[PublishConfiguration]] + List(task) + } catch { + case _: Throwable => // FIXME Too wide + Nil + } + + def generateIvyXmlSettings( + shadedConfigOpt: Option[Configuration] = None + ): Seq[Setting[_]] = + (needsIvyXml ++ needsIvyXmlLocal).map(makeIvyXmlBefore(_, shadedConfigOpt)) + +} diff --git a/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/SbtCoursierShared.scala b/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/SbtCoursierShared.scala index 1f896c1b5..174042d62 100644 --- a/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/SbtCoursierShared.scala +++ b/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/SbtCoursierShared.scala @@ -174,7 +174,7 @@ object SbtCoursierShared extends AutoPlugin { versionReconciliation := Seq.empty ) ++ { if (pubSettings) - IvyXml.generateIvyXmlSettings() + IvyXmlGeneration.generateIvyXmlSettings() else Nil } diff --git a/modules/sbt-coursier-shared/src/test/scala/coursier/sbtcoursiershared/IvyXmlTests.scala b/modules/sbt-coursier-shared/src/test/scala/coursier/sbtcoursiershared/IvyXmlTests.scala deleted file mode 100644 index 6a460e0be..000000000 --- a/modules/sbt-coursier-shared/src/test/scala/coursier/sbtcoursiershared/IvyXmlTests.scala +++ /dev/null @@ -1,30 +0,0 @@ -package coursier.sbtcoursiershared - -import lmcoursier.definitions.{Configuration, Info, Module, ModuleName, Organization, Project} -import utest._ - -object IvyXmlTests extends TestSuite { - - val tests = Tests { - "no truncation" - { - - val project = Project( - Module(Organization("org"), ModuleName("name"), Map()), - "ver", - Nil, - Map( - Configuration("foo") -> (1 to 80).map(n => Configuration("bar" + n)) // long list of configurations -> no truncation any way - ), - Nil, - None, - Nil, - Info("", "", Nil, Nil, None) - ) - - val content = IvyXml.rawContent(project, None) - - assert(!content.contains("")) - } - } - -} diff --git a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ArtifactsTasks.scala b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ArtifactsTasks.scala index bf2a41121..39e3a24db 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ArtifactsTasks.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ArtifactsTasks.scala @@ -24,7 +24,7 @@ object ArtifactsTasks { val resTask: sbt.Def.Initialize[sbt.Task[Seq[Resolution]]] = if (withClassifiers && sbtClassifiers) - Def.task(Seq(coursierSbtClassifiersResolution.value)) + Def.task(coursierSbtClassifiersResolutions.value.values.toVector) else Def.task(coursierResolutions.value.values.toVector) diff --git a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/CoursierPlugin.scala b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/CoursierPlugin.scala index 7ccb8b98e..8cfdfbb14 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/CoursierPlugin.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/CoursierPlugin.scala @@ -30,7 +30,7 @@ object CoursierPlugin extends AutoPlugin { val coursierParentProjectCache = Keys.coursierParentProjectCache val coursierResolutions = Keys.coursierResolutions - val coursierSbtClassifiersResolution = Keys.coursierSbtClassifiersResolution + val coursierSbtClassifiersResolutions = Keys.coursierSbtClassifiersResolutions val coursierDependencyTree = Keys.coursierDependencyTree val coursierDependencyInverseTree = Keys.coursierDependencyInverseTree @@ -176,21 +176,18 @@ object CoursierPlugin extends AutoPlugin { coursierResolutions .value - .collectFirst { - case (configs, res) if configs(config) => - res - } - .getOrElse { + .getOrElse( + config, sys.error(s"Resolution for configuration $config not found") - } + ) }, - coursierSbtClassifiersResolution := (Def.taskDyn { + coursierSbtClassifiersResolutions := (Def.taskDyn { val missingOk = (updateConfiguration in updateSbtClassifiers).value.missingOk ResolutionTasks.resolutionsTask( sbtClassifiers = true, missingOk = missingOk, ) - }).value.head._2 + }).value ) override lazy val buildSettings = super.buildSettings ++ Seq( diff --git a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/DisplayTasks.scala b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/DisplayTasks.scala index d708f2bd8..8f56a12fc 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/DisplayTasks.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/DisplayTasks.scala @@ -13,7 +13,7 @@ import scala.collection.mutable object DisplayTasks { - private case class ResolutionResult(configs: Set[Configuration], resolution: Resolution, dependencies: Seq[Dependency]) + private case class ResolutionResult(config: Configuration, resolution: Resolution, dependencies: Seq[Dependency]) private def coursierResolutionTask( sbtClassifiers: Boolean = false, @@ -37,13 +37,9 @@ object DisplayTasks { val resolutionsTask = if (sbtClassifiers) - Def.task { - val currentProject = currentProjectTask.value - val classifiersRes = coursierSbtClassifiersResolution.value - Map(currentProject.configurations.keySet.map(ToCoursier.configuration) -> classifiersRes) - } + coursierSbtClassifiersResolutions else - Def.task(coursierResolutions.value) + coursierResolutions Def.task { @@ -57,19 +53,23 @@ object DisplayTasks { val resolutions = resolutionsTask.value for { - (subGraphConfigs, res) <- resolutions.toSeq - if subGraphConfigs.exists(includedConfigs) + (subGraphConfig, res) <- resolutions.toSeq + if includedConfigs(subGraphConfig) } yield { - val dependencies0 = currentProject.dependencies.collect { - case (cfg, dep) if includedConfigs(cfg) && subGraphConfigs(cfg) => dep - }.sortBy { dep => - (dep.module.organization, dep.module.name, dep.version) - } + val dependencies0 = currentProject + .dependencies + .collect { + case (`subGraphConfig`, dep) => + dep + } + .sortBy { dep => + (dep.module.organization, dep.module.name, dep.version) + } val subRes = res.subset(dependencies0) - ResolutionResult(subGraphConfigs, subRes, dependencies0) + ResolutionResult(subGraphConfig, subRes, dependencies0) } } } @@ -82,9 +82,9 @@ object DisplayTasks { val projectName = thisProjectRef.value.project val resolutions = coursierResolutionTask(sbtClassifiers, ignoreArtifactErrors).value - for (ResolutionResult(subGraphConfigs, resolution, dependencies) <- resolutions) { + for (ResolutionResult(subGraphConfig, resolution, dependencies) <- resolutions) { streams.value.log.info( - s"$projectName (configurations ${subGraphConfigs.toVector.sorted.mkString(", ")})" + "\n" + + s"$projectName (configuration ${subGraphConfig.value})" + "\n" + Print.dependencyTree( resolution, dependencies, @@ -110,13 +110,13 @@ object DisplayTasks { val resolutions = coursierResolutionTask(sbtClassifiers, ignoreArtifactErrors).value val result = new mutable.StringBuilder - for (ResolutionResult(subGraphConfigs, resolution, _) <- resolutions) { + for (ResolutionResult(subGraphConfig, resolution, _) <- resolutions) { val roots = resolution .minDependencies .filter(f => f.module == module) .toVector .sortBy(_.toString) // elements already have the same module, there's not much left for sorting… - val strToPrint = s"$projectName (configurations ${subGraphConfigs.toVector.sorted.map(_.value).mkString(", ")})" + "\n" + + val strToPrint = s"$projectName (configurations ${subGraphConfig.value})" + "\n" + Print.dependencyTree( resolution, roots, diff --git a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/InputsTasks.scala b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/InputsTasks.scala index 8f743a4fc..af1900ab3 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/InputsTasks.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/InputsTasks.scala @@ -26,10 +26,13 @@ object InputsTasks { } } - def ivyGraphsTask: Def.Initialize[sbt.Task[Seq[Set[Configuration]]]] = + def ivyGraphsTask: Def.Initialize[sbt.Task[Seq[(Configuration, Seq[Configuration])]]] = Def.task { val p = coursierProject.value - Inputs.ivyGraphs(p.configurations).map(_.map(ToCoursier.configuration)) + Inputs.orderedConfigurations(p.configurations.toSeq).map { + case (config, extends0) => + (ToCoursier.configuration(config), extends0.map(ToCoursier.configuration)) + } } def parentProjectCacheTask: Def.Initialize[sbt.Task[Map[Seq[sbt.librarymanagement.Resolver], Seq[coursier.ProjectCache]]]] = @@ -53,7 +56,7 @@ object InputsTasks { n.foldLeft(Map.empty[Seq[Resolver], Seq[ProjectCache]]) { case (caches, (ref, resolutions)) => val mainResOpt = resolutions.collectFirst { - case (k, v) if k(Configuration.compile) => v + case (Configuration.compile, v) => v } val r = for { diff --git a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/Keys.scala b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/Keys.scala index 4e4df6ad1..6fe4a8d28 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/Keys.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/Keys.scala @@ -21,7 +21,7 @@ object Keys { val coursierVerbosity = SettingKey[Int]("coursier-verbosity") - val coursierConfigGraphs = TaskKey[Seq[Set[Configuration]]]("coursier-config-graphs") + val coursierConfigGraphs = TaskKey[Seq[(Configuration, Seq[Configuration])]]("coursier-config-graphs") val coursierSbtClassifiersModule = TaskKey[GetClassifiersModule]("coursier-sbt-classifiers-module") @@ -29,11 +29,11 @@ object Keys { val coursierParentProjectCache = TaskKey[Map[Seq[Resolver], Seq[ProjectCache]]]("coursier-parent-project-cache") - val coursierResolutions = TaskKey[Map[Set[Configuration], Resolution]]("coursier-resolutions") + val coursierResolutions = TaskKey[Map[Configuration, Resolution]]("coursier-resolutions") private[coursier] val actualCoursierResolution = TaskKey[Resolution]("coursier-resolution") - val coursierSbtClassifiersResolution = TaskKey[Resolution]("coursier-sbt-classifiers-resolution") + val coursierSbtClassifiersResolutions = TaskKey[Map[Configuration, Resolution]]("coursier-sbt-classifiers-resolution") val coursierDependencyTree = TaskKey[Unit]( "coursier-dependency-tree", diff --git a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ResolutionTasks.scala b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ResolutionTasks.scala index ef7e923ba..ee3166fe0 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ResolutionTasks.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ResolutionTasks.scala @@ -19,9 +19,9 @@ object ResolutionTasks { def resolutionsTask( sbtClassifiers: Boolean = false, missingOk: Boolean = false, - ): Def.Initialize[sbt.Task[Map[Set[Configuration], coursier.Resolution]]] = { + ): Def.Initialize[sbt.Task[Map[Configuration, coursier.Resolution]]] = { - val currentProjectTask: sbt.Def.Initialize[sbt.Task[(Project, Seq[FallbackDependency], Seq[Set[Configuration]])]] = + val currentProjectTask: sbt.Def.Initialize[sbt.Task[(Project, Seq[FallbackDependency], Seq[(Configuration, Seq[Configuration])])]] = if (sbtClassifiers) Def.task { val sv = scalaVersion.value @@ -35,7 +35,7 @@ object ResolutionTasks { sbv ) - (proj, fallbackDeps, Vector(cm.configurations.map(c => Configuration(c.name)).toSet)) + (proj, fallbackDeps, cm.configurations.map(c => Configuration(c.name) -> Nil)) } else Def.task { @@ -97,7 +97,7 @@ object ResolutionTasks { val authenticationByRepositoryId = coursierCredentials.value.mapValues(_.authentication) - val (currentProject, fallbackDependencies, configGraphs) = currentProjectTask.value + val (currentProject, fallbackDependencies, orderedConfigs) = currentProjectTask.value val autoScalaLib = autoScalaLibrary.value && scalaModuleInfo.value.forall(_.overrideScalaVersion) @@ -114,6 +114,16 @@ object ResolutionTasks { .map(_.foldLeft[ProjectCache](Map.empty)(_ ++ _)) .getOrElse(Map.empty) + val excludeDeps = Inputs.exclusions( + coursier.sbtcoursiershared.InputsTasks.actualExcludeDependencies.value, + sv, + sbv, + log + ).map { + case (org, name) => + (Organization(org.value), ModuleName(name.value)) + } + val mainRepositories = resolvers .flatMap { resolver => Resolvers.repository( @@ -132,7 +142,7 @@ object ResolutionTasks { ResolutionParams( dependencies = currentProject.dependencies, fallbackDependencies = fallbackDependencies, - configGraphs = configGraphs, + orderedConfigs = orderedConfigs, autoScalaLibOpt = if (autoScalaLib) Some((so, sv)) else None, mainRepositories = mainRepositories, parentProjectCache = parentProjectCache, @@ -154,7 +164,8 @@ object ResolutionTasks { .withProfiles(userEnabledProfiles) .withForceVersion(userForceVersions.map { case (k, v) => (ToCoursier.module(k), v) }.toMap) .withTypelevel(typelevel) - .addReconciliation(versionReconciliations0: _*), + .addReconciliation(versionReconciliations0: _*) + .withExclusions(excludeDeps), strictOpt = strictOpt, missingOk = missingOk, ), diff --git a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/UpdateTasks.scala b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/UpdateTasks.scala index 693cc9df3..0cc24a47a 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/UpdateTasks.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/UpdateTasks.scala @@ -34,13 +34,9 @@ object UpdateTasks { val resTask = if (withClassifiers && sbtClassifiers) - Def.task { - val cm = coursierSbtClassifiersModule.value - val classifiersRes = coursierSbtClassifiersResolution.value - Map(cm.configurations.map(c => Configuration(c.name)).toSet -> classifiersRes) - } + coursierSbtClassifiersResolutions else - Def.task(coursierResolutions.value) + coursierResolutions // we should be able to call .value on that one here, its conditions don't originate from other tasks val artifactFilesOrErrors0Task = diff --git a/modules/sbt-coursier/src/sbt-test/sbt-coursier/dependency-graph/build.sbt b/modules/sbt-coursier/src/sbt-test/sbt-coursier/dependency-graph/build.sbt index 671c71f89..54a8ba1e9 100644 --- a/modules/sbt-coursier/src/sbt-test/sbt-coursier/dependency-graph/build.sbt +++ b/modules/sbt-coursier/src/sbt-test/sbt-coursier/dependency-graph/build.sbt @@ -12,5 +12,6 @@ import CoursierPlugin.autoImport._ whatDependsOnCheck := { val result = (coursierWhatDependsOn in Compile).toTask(" log4j:log4j").value val file = new File("whatDependsOnResult.log") - assert(IO.read(file).toString == result) + val expected = IO.read(file).toString + assert(expected == result, s"Expected '$expected', got '$result'") } diff --git a/modules/sbt-coursier/src/sbt-test/sbt-coursier/dependency-graph/src/main/scala/Main.scala b/modules/sbt-coursier/src/sbt-test/sbt-coursier/dependency-graph/src/main/scala/Main.scala deleted file mode 100644 index 032874759..000000000 --- a/modules/sbt-coursier/src/sbt-test/sbt-coursier/dependency-graph/src/main/scala/Main.scala +++ /dev/null @@ -1,8 +0,0 @@ -import java.io.File -import java.nio.file.Files - -import org.apache.zookeeper.ZooKeeper - -object Main extends App { - Files.write(new File("output").toPath, classOf[ZooKeeper].getSimpleName.getBytes("UTF-8")) -} diff --git a/modules/sbt-coursier/src/sbt-test/sbt-coursier/dependency-graph/whatDependsOnResult.log b/modules/sbt-coursier/src/sbt-test/sbt-coursier/dependency-graph/whatDependsOnResult.log index e0e5a5377..64d70c9bb 100644 --- a/modules/sbt-coursier/src/sbt-test/sbt-coursier/dependency-graph/whatDependsOnResult.log +++ b/modules/sbt-coursier/src/sbt-test/sbt-coursier/dependency-graph/whatDependsOnResult.log @@ -1,4 +1,4 @@ -dependency-graph (configurations compile, compile-internal, optional, provided, runtime, runtime-internal, test, test-internal) +dependency-graph (configurations compile) └─ log4j:log4j:1.2.17 ├─ org.apache.zookeeper:zookeeper:3.5.0-alpha log4j:log4j:1.2.16 -> 1.2.17 └─ org.slf4j:slf4j-log4j12:1.7.5 diff --git a/modules/sbt-coursier/src/sbt-test/shared-1/all-exclude-dependencies/coursier b/modules/sbt-coursier/src/sbt-test/shared-1/all-exclude-dependencies/coursier index 6cada6f8b..1153c1797 100755 Binary files a/modules/sbt-coursier/src/sbt-test/shared-1/all-exclude-dependencies/coursier and b/modules/sbt-coursier/src/sbt-test/shared-1/all-exclude-dependencies/coursier differ diff --git a/modules/sbt-coursier/src/sbt-test/shared-1/all-exclude-dependencies/src/main/scala/Main.scala b/modules/sbt-coursier/src/sbt-test/shared-1/all-exclude-dependencies/src/main/scala/Main.scala index 1bc056610..89960e16b 100644 --- a/modules/sbt-coursier/src/sbt-test/shared-1/all-exclude-dependencies/src/main/scala/Main.scala +++ b/modules/sbt-coursier/src/sbt-test/shared-1/all-exclude-dependencies/src/main/scala/Main.scala @@ -27,6 +27,4 @@ object Main extends App { !argonautFound, "Expected not to find classes from argonaut" ) - - Files.write(new File("output").toPath, "OK".getBytes("UTF-8")) } diff --git a/modules/sbt-coursier/src/sbt-test/shared-1/all-exclude-dependencies/test b/modules/sbt-coursier/src/sbt-test/shared-1/all-exclude-dependencies/test index 27ecd9d91..731ff86e2 100644 --- a/modules/sbt-coursier/src/sbt-test/shared-1/all-exclude-dependencies/test +++ b/modules/sbt-coursier/src/sbt-test/shared-1/all-exclude-dependencies/test @@ -1,5 +1,3 @@ -$ delete output > run -$ exists output > publishLocal $ exec java -jar coursier launch io.get-coursier.test:sbt-coursier-all-exclude-dependencies_2.12:0.1.0-SNAPSHOT diff --git a/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/src/main/scala/Main.scala b/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/a/src/main/scala/Main.scala similarity index 91% rename from modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/src/main/scala/Main.scala rename to modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/a/src/main/scala/Main.scala index 1bc056610..89960e16b 100644 --- a/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/src/main/scala/Main.scala +++ b/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/a/src/main/scala/Main.scala @@ -27,6 +27,4 @@ object Main extends App { !argonautFound, "Expected not to find classes from argonaut" ) - - Files.write(new File("output").toPath, "OK".getBytes("UTF-8")) } diff --git a/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/b/src/main/scala/Main.scala b/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/b/src/main/scala/Main.scala new file mode 100644 index 000000000..89960e16b --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/b/src/main/scala/Main.scala @@ -0,0 +1,30 @@ +import java.io.File +import java.nio.file.Files + +import scala.util.Try + +object Main extends App { + + def classFound(clsName: String) = Try( + Thread.currentThread() + .getContextClassLoader() + .loadClass(clsName) + ).toOption.nonEmpty + + val shapelessFound = classFound("shapeless.HList") + val argonautFound = classFound("argonaut.Json") + val argonautShapelessFound = classFound("argonaut.derive.MkEncodeJson") + + assert( + argonautShapelessFound, + "Expected to find class from argonaut-shapeless" + ) + assert( + !shapelessFound, + "Expected not to find classes from shapeless" + ) + assert( + !argonautFound, + "Expected not to find classes from argonaut" + ) +} diff --git a/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/build.sbt b/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/build.sbt index 0ac1493d5..7888e23ca 100644 --- a/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/build.sbt +++ b/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/build.sbt @@ -1,11 +1,26 @@ -scalaVersion := "2.12.8" +lazy val a = project + .settings( + organization := "io.get-coursier.test", + name := "sbt-coursier-exclude-dependencies", + version := "0.1.0-SNAPSHOT", + scalaVersion := "2.12.8", + libraryDependencies += "com.github.alexarchambault" %% "argonaut-shapeless_6.2" % "1.2.0-M11", + excludeDependencies += sbt.ExclusionRule("com.chuusai", "shapeless_2.12"), + excludeDependencies += "io.argonaut" %% "argonaut" + ) -organization := "io.get-coursier.test" -name := "sbt-coursier-exclude-dependencies" -version := "0.1.0-SNAPSHOT" - -libraryDependencies += "com.github.alexarchambault" %% "argonaut-shapeless_6.2" % "1.2.0-M11" - -excludeDependencies += sbt.ExclusionRule("com.chuusai", "shapeless_2.12") -excludeDependencies += "io.argonaut" %% "argonaut" +lazy val b = project + .settings( + organization := "io.get-coursier.test", + name := "sbt-coursier-exclude-dependencies-2", + version := "0.1.0-SNAPSHOT", + scalaVersion := "2.12.8", + libraryDependencies ++= Seq( + "com.github.alexarchambault" %% "argonaut-shapeless_6.2" % "1.2.0-M11", + "com.chuusai" %% "shapeless" % "2.3.3", + "io.argonaut" %% "argonaut" % "6.2.3" + ), + excludeDependencies += sbt.ExclusionRule("com.chuusai", "shapeless_2.12"), + excludeDependencies += "io.argonaut" %% "argonaut" + ) diff --git a/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/coursier b/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/coursier index 6cada6f8b..eb1b55198 100755 Binary files a/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/coursier and b/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/coursier differ diff --git a/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/test b/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/test index fa5d6a196..11d45a4a2 100644 --- a/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/test +++ b/modules/sbt-coursier/src/sbt-test/shared-1/exclude-dependencies/test @@ -1,5 +1,6 @@ -$ delete output -> run -$ exists output -> publishLocal +> a/run +> a/publishLocal $ exec java -jar coursier launch io.get-coursier.test:sbt-coursier-exclude-dependencies_2.12:0.1.0-SNAPSHOT +> b/run +> b/publishLocal +$ exec java -jar coursier launch io.get-coursier.test:sbt-coursier-exclude-dependencies-2_2.12:0.1.0-SNAPSHOT diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/per-config-resolution/build.sbt b/modules/sbt-coursier/src/sbt-test/shared-2/per-config-resolution/build.sbt new file mode 100644 index 000000000..f2f2507cf --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/per-config-resolution/build.sbt @@ -0,0 +1,8 @@ +scalaVersion := "2.13.2" +libraryDependencies ++= Seq( + "io.get-coursier" %% "coursier-core" % "2.0.0-RC6", + // depends on coursier-core 2.0.0-RC6-16 + "io.get-coursier" %% "coursier" % "2.0.0-RC6-16" % Test +) +mainClass.in(Compile) := Some("Main") +mainClass.in(Test) := Some("Test") diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/per-config-resolution/project/plugins.sbt b/modules/sbt-coursier/src/sbt-test/shared-2/per-config-resolution/project/plugins.sbt new file mode 100644 index 000000000..71a44ffd3 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/per-config-resolution/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/per-config-resolution/src/main/scala/Main.scala b/modules/sbt-coursier/src/sbt-test/shared-2/per-config-resolution/src/main/scala/Main.scala new file mode 100644 index 000000000..370b4e4bf --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/per-config-resolution/src/main/scala/Main.scala @@ -0,0 +1,7 @@ +object Main { + def main(args: Array[String]): Unit = { + val version = coursier.util.Properties.version + val expected = "2.0.0-RC6" + assert(version == expected, s"version: $version, expected: $expected") + } +} diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/per-config-resolution/src/test/scala/Test.scala b/modules/sbt-coursier/src/sbt-test/shared-2/per-config-resolution/src/test/scala/Test.scala new file mode 100644 index 000000000..9d91a9318 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/per-config-resolution/src/test/scala/Test.scala @@ -0,0 +1,7 @@ +object Test { + def main(args: Array[String]): Unit = { + val version = coursier.util.Properties.version + val expected = "2.0.0-RC6-16" + assert(version == expected, s"version: $version, expected: $expected") + } +} diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/per-config-resolution/test b/modules/sbt-coursier/src/sbt-test/shared-2/per-config-resolution/test new file mode 100644 index 000000000..e7abb0441 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/per-config-resolution/test @@ -0,0 +1,2 @@ +> run +> test:run