Substituting Ivy Modules Transitively

I use Ivy programmatically (in the context of SBT), and I need to be able to transitively replace a small set of modules with a compatible set that has a different organization, but the names of artifacts, changes, etc.

To indicate a specific example, I want to replace

org.scala-lang#scala-reflect;2.11.8 

with,

 org.typelevel#scala-reflect;2.11.8 

everywhere in the dependency graph. Note that I only want to add a dependency on org.typelevel # scala -reflect; 2.11.8 if there is a dependency on org.scala-lang # scala -reflect; 2.11.8 somewhere in the graph (which I do not know in advance), so this is not enough to unconditionally exclude the org.scala-lang module and enable org.typelevel one.

Is it possible? If so, pointers to the necessary mechanism will be very happy. If this is not the case, suggestions for workarounds will also be very welcome.

+5
source share
2 answers

This can be done using the Ivy DependencyDescriptorMediator . The following will do the rewriting described in the question for module type DefaultModuleDescriptor ,

 class OverrideScalaMediator(scalaOrganization: String, scalaVersion: String) extends DependencyDescriptorMediator { def mediate(dd: DependencyDescriptor): DependencyDescriptor = { val transformer = new NamespaceTransformer { def transform(mrid: ModuleRevisionId): ModuleRevisionId = { if (mrid == null) mrid else mrid.getName match { case name @ "scala-reflect" => ModuleRevisionId.newInstance( scalaOrganization, name, mrid.getBranch, scalaVersion, mrid.getQualifiedExtraAttributes ) case _ => mrid } } def isIdentity: Boolean = false } DefaultDependencyDescriptor.transformInstance(dd, transformer, false) } } val mediator = new OverrideScalaMediator("org.typelevel", version) module.addDependencyDescriptorMediator( new ModuleId("org.scala-lang", "*"), ExactPatternMatcher.INSTANCE, mediator ) 

You can see it in SBT here .

0
source

Although this is not a completely clean solution, I think you can achieve this by capturing a resolver project (which is responsible for resolving dependencies between projects in SBT).

Somewhere in your build file:

 // ... .settings( projectResolver <<= (projectDescriptors, streams) map { (m, s) => new RawRepository(new ProjectResolver("custom-resolver", m) { import org.apache.ivy.core.module.descriptor.DependencyDescriptor import org.apache.ivy.core.resolve.ResolveData import org.apache.ivy.core.resolve.ResolvedModuleRevision override def getDependency(dd: DependencyDescriptor, data: ResolveData): ResolvedModuleRevision = { s.log.info("Resolving " + dd.getDependencyId.getName) // adjust your dependency descriptor and possibly resolve // from another source? super.getDependency(dd, data) } }) } ) 

This new project converter can configure specific dependency descriptors and then resolve them against a regular chain of resolvers ... I think. You may need to override some additional methods.

0
source

All Articles