So, this is not a feature page right now, but it is a feature I have
been working on during my spare time, as it seems to be a recurring thorn
in our sides. The last time I looked into this, I sent a mail to list,
with mixed results:
https://fedorahosted.org/pipermail/aeolus-devel/2012-January/008014.html
Vit had some valid points, which I tried to take into consideration as
I rethought things a bit. My first inclination was to still move the
Gemfile and Gemfile.lock to be <$name>.in, and document the steps
needed depending on whether you were going to be developing in a
distro environment or as a pure ruby developer (or switching between
the two). I was well along this path, and had a couple rake tasks all
set to ease this process, which I was thinking would go in the (not
yet built) aeolus developer commandline tool (ccc or act, depending on
my mood that day). I was working through some issues that came up on
workflows I was expecting, such as rake failing, since the new developer
would not yet have the dependencies, but would have to run 'rake
dev:upstream' in order to then bundle install. Granted they could
just cp the files over themselves, but I wanted to add a simple
command to ease that. This too had fairly simple fixes (specify the
rake file to use when calling a task, wrap that in a shorter command),
but this seemed to indicate a recurring issue that I kept skirting
around.
Something Vit said in an earlier exchange hit it - 'you can
work with upstream ruby, or RPM-based systems, but not both, I am
afraid' (somewhat summarized quote). However, this did not sit well
with me, as not only do I want it to be easy for RPM distros to
package our stuff, but any other distro, whether I know anything about
said distro or not. Then I remembered this idea I had quite some time
ago to fix our 'temporary hack' of putting regular requires in the
application.rb that were basically duplicates of what we specified in
the Gemfile (which always grated on me, but I figured we'd fix it
eventually). The idea was some kind of 'shim layer' that would read
the Gemfile and create the requires for us. So now to revisit that
and present my results.
We have been using the above plus some hacks to the Gemfile (commented
out source, for instance), and an env var (USE_BUNDLER). We check
this var on startup, and only use bundler if it is 'yes'. This was
intended to make it easy to run as rpm, and possible, but not easy, to
run as a ruby developer. For the latter case you would have to set
your var to 'yes' _and_ uncomment the source line to properly bundle
install our app. This always struck me as suboptimal at best.
Shouldn't we be able to:
* Keep our deps in one place (ignoring the fact that they are
duplicated in rpm specs and such)
* Make it easy for upstream, while still not making it hard for
distros?
I thought the answer was 'yes', so I went rooting around in the
bundler code to see what I could find. Obviously the distro mentality
is opposite of bundler's view (which I think is equally valid and
actually makes a ton of sense in many other cases), but I had this idea
that maybe I could reuse something in bundler itself to enable my mad
scheme. After surprisingly little searching, I found a class called 'Dsl'.
No, I know what you are thinking, there was in fact no modem inside
this class! What there was, was a simple method that takes...(wait
for it) a gemfile, and parses it! This returns a list of Definition
objects, which in turn have names, which are what get used to require
the library (with the exception of gems who have a different name
needed to require them, like deltacloud for the deltacloud-client gem,
but that is handled too, via an 'autorequire' attr). So, there may be
some more hooks to find, but I think this is basically our solution.
I have started coding an Ext class with a Ext.system_require method,
and the basic idea seems to work. No lockfile is generated or used,
and we dont have to duplicate the requires in our application.rb.
Further, we could default our USE_BUNDLER to 'no' to ease upstream
dev, and simply set it in the initscripts for distros. The
application.rb would just check ENV var and do either a normal
Bundler.require, or our custom one. Note this code is not done, but
is far enough along that I am pretty confident it could be used. I was
hoping to have all this just be a patchset, but given my change of
directions, I couldn't quite get that together.
Now, here is an extra thought I had as I was about to start writing up
this proposal. Why not just make _bundler itself_ aware of the
USE_BUNDLER env var? Then _any_ app (or library) could stay with
their normal practice of using Bundler.require (guess it would have to
work with Bundler.setup too, to really be seemless) and get 'work on
any distro' for free (well, minus the packaging work, but this would
simplify that substanially as well, imo). I am not sure I would ever
be able to convince upstream bundler to take such an enhancement, but
perhaps if we had enough people that thought it was a good idea, then
maybe they would consider it. Anyway, once I have this mostly
working, I'll probably refactor it a bit to use Bunlder.require
instead of my current Bundler::Ext.system_require.
So what do you all think, am I certifiable (for this, not in general)?
Could it work? Are there some major issues I have totally missed or
forgotten here? Hopefully I have not forgotten an key details that
brought me to this (what seems like an) epiphany, but if I have,
perhaps questions will jar them from my addled brain. Ok, I can't
rattle on any longer, bring on the dissent!
-j