Adding a new non-Maven/Ivy repository & dependency type

(Schalk Cronjé) #1

Getting back to an old problem. I basically want to add a resolver for RubyGems that does not use all of the fragile workarounds we have in jruby-gradle until now. Basically I want to be able to:

  • add a non-maven/ivy repo to repositories.
  • add some-fu that can translate a group./artifact/version into an appropriate URL for rubygems.
  • have it transparent to the user i.e. the script author just want to add something to dependencies like gems 'rubygems:rails:1.2.3.

Adding something to repositories, although not trivial is, is easy. It implements ExtensionAware. So no big issue there. The problem comes in the trnalsation from somethign defined ona configuration to actuall requesting it from a repository.

A couple of things I was thinking is:

  • Create RubyGemsModule that extends Component, because that in theory should be queryable via the Artifact Query API. However, how is Gradle even going to be aware o this new Component. Can a handler be registred for it somewhere.
  • Add something that implements ClientModule. That could be a rubygems extension to DependencyHandler, but I still don’t know if Gradle will recognise this.

Any pointers here will help, even if at this point means hooking up an internal API.

(Schalk Cronjé) #2

I think this is neigh impossible to do a RubyGemsModule 9based on IvyModule/MavenModule with the 4.x series. This requires a service registration that will need a RubyGemsService to be placed in META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry. This will fail due to:

  1. The restriction on ArtifactType only being one of sources, javadoc, maven pom or ivy descriptor. (it’s an enum so cannto be extended)
  2. The service registry probably being initialised without acess to the plugin classpath.


(guai) #3

You can try to workaround like this: define a new method in the dependencies block via groovy metaclass or other extension capabilities. In this method you download a gem, place it on the file system, then delegate as if it was a flat dir dependency. You’ll also need to define this flat dir repo first.
This is doable but certainly not so straightforward. And even more hassle would be if you want transitive deps.
And it kinda violates gradle design since you resolving deps on configuration phase.

(Schalk Cronjé) #4

@gual A dependency method can be added to DependencyHandler as it is ExtensionAware. That is how the rust-gradle-plugin functions today. It creates objects which extends the Dependency interface. The end result is that one has to implement a resolving mechanism which is do-able and still fits into the Gradle model. It still feels like a bolt-on.

The nodejs-gradle-plugin has a similar approach although it extends Dependencyhandler by something that implements SelfResolvingDependency instead. The issue with this approach is that due to a bug in the current Gradle implementation one has to implement SelfResolvingDependencyInternal (an internal Gradle class) instead.

So there are some solutions, but it requires more work than I believe should be required. Besides adding your own resolving mechanism, one also has to implement a caching mechanism as there is no access to the (very effetcive) one that Gradle uses.

Ruby gems are also special in this regards. It stores all of the transitive information in the GEM itself, plus it has some dependency notation which behaves slightly deifferent from the standard Gradle way. The are some libraries available that can convert GEM info into Maven info, but it is hard to use directly in Gradle. Most of these issue previously described, would be easily dealt with for Rubgygems, if there was a simple mechanism for a plugin to register additional Maven protocol handlers.

Note: it is not good Gradle practice to use Groovy metaclass extensions. It is better to extensions or services.