Dependency management

48 views
Skip to first unread message

Richard Newman

unread,
Jan 21, 2010, 8:21:12 PM1/21/10
to clo...@googlegroups.com
Hi folks,

Apparently everyone is jumping on the Leiningen bandwagon and deleting
their build.xml files. I guess that means I'm moving, too.

Now, I like to keep track of Clojure master. Right now, Clojure
reports "Clojure 1.2.0-master-SNAPSHOT".

(I don't see that in Maven Central or in Clojars, so I guess I have to
put it in my local repository...?)

Unfortunately, not everybody keeps up-to-date like I do; most of the
projects I use demand "1.1.0-alpha-SNAPSHOT". I'm sure there are still
projects that demand 1.0.

Adjusting the lein script to use my local Clojure install gave me a
great error:

Caused by: java.lang.NoSuchMethodError: clojure.lang.RestFn.<init>(I)V
at clojure.contrib.with_ns$with_ns__7929.<init>(with_ns.clj:20)
at clojure.contrib.with_ns__init.load(Unknown Source)
at clojure.contrib.with_ns__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at clojure.lang.RT.loadClassForName(RT.java:1523)
at clojure.lang.RT.load(RT.java:396)
at clojure.lang.RT.load(RT.java:378)
at clojure.core$load__4869$fn__4876.invoke(core.clj:4294)
at clojure.core$load__4869.doInvoke(core.clj:4293)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at clojure.core$load_one__4810.invoke(core.clj:4130)
at clojure.core$load_lib__4825.doInvoke(core.clj:4167)
at clojure.lang.RestFn.applyTo(RestFn.java:143)
at clojure.core$apply__3434.invoke(core.clj:478)
at clojure.core$load_libs__4841.doInvoke(core.clj:4193)
at clojure.lang.RestFn.applyTo(RestFn.java:138)
at clojure.core$apply__3434.invoke(core.clj:480)
at clojure.core$use__4865.doInvoke(core.clj:4271)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at leiningen.core$eval__5$loading__4758__auto____6.invoke(core.clj:1)
at leiningen.core$eval__5.invoke(core.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:5349)

and I saw a similar problem with builds that referred to libraries
built with different versions of Clojure.

How do people deal with this? How can one simultaneously use two
libraries which have hardwired dependencies on two different Clojure
versions, each of which might be mutually incompatible?

What's the community protocol around locally installing Clojure 1.2,
and adding that as a dependency for a published library?

What's the right way to get lein itself to use a recent Clojure build,
rather than the version with which it ships?

Thoughts -- and answers! -- welcome.

Thanks,

-R

Sean Devlin

unread,
Jan 21, 2010, 8:37:46 PM1/21/10
to Clojure
> What's the community protocol around locally installing Clojure 1.2,  
> and adding that as a dependency for a published library?

I'll take a shot at this question.

Clojure stresses immutability, and dependencies should be no
different. I'd say it's bad form to force a dependency on an
unreleased version of Clojure, because it's a moving target. Granted,
there should be a mechanism for version 1.1.x, or 1.x so that
libraries are forward compatible to a certain version.

Just my $.02
Sean

wlr

unread,
Jan 21, 2010, 10:43:02 PM1/21/10
to Clojure

On Jan 21, 8:37 pm, Sean Devlin <francoisdev...@gmail.com> wrote:
> Clojure stresses immutability, and dependencies should be no
> different.  I'd say it's bad form to force a dependency on an
> unreleased version of Clojure, because it's a moving target.  Granted,

BTW, Clojure also stresses *controlled mutability*. I'd say it's bad
form to impose a value judgment in place of a technical solution. If
some 1.2 features make for a better project development experience,
why rule them out?

Mark Derricutt

unread,
Jan 22, 2010, 12:40:19 AM1/22/10
to clo...@googlegroups.com
We're not all jumping on Leiningen, some of us are sticking with
maven, using the maven-clojure-compiler plugin, and also the
experimental Maven Polyglot Clojure build support:

http://polyglot.sonatype.org/clojure.html


(disclojure - both of these are my projects so I'm somewhat biased)

--
Pull me down under...

Richard Newman

unread,
Jan 22, 2010, 1:23:10 AM1/22/10
to clo...@googlegroups.com
> We're not all jumping on Leiningen, some of us are sticking with
> maven, using the maven-clojure-compiler plugin, and also the
> experimental Maven Polyglot Clojure build support:

It's not the "Leiningen" that's important, it's the "jumping": away
from Ant, not Maven. Every library I use had an Ant build script. I
never saw a POM.

(Apologies for this diversion. Maybe it'll be of interest to some on
this list.)

I'm somewhat swayed by Leiningen because it makes doing some things
easy (uberjar! starting a REPL! neat!), at the cost of making other
things (such as managing dependencies myself) more frustrating.
However, if it wasn't for all the people blindly deleting their Ant
build scripts, I would be sticking with my Ant workflow for another
few months. I don't think Lein is quite targeted at users like me.*

That's OK, and I'm sure it'll change over time. I'm looking forward to
more plugins arriving to perhaps allow me to define per-project tasks
(for database operations, say).

I'm not at all swayed by Maven itself. XML *and* bloated opaque
dependency management! What's not to love?

(Yes, I know it does a lot of cool stuff -- http://blog.lick-me.org/2010/01/maven-sucks/
is a good start on the pros and cons -- I just don't care about
most of that stuff, and I do care about the horrible parts.)


> http://polyglot.sonatype.org/clojure.html

That certainly makes Maven's syntax less repellent, but it still has
Maven underneath.

-R

* For those who might ask "and what kind of user are you?":
* I keep up to date with Clojure master. I don't use binary releases.
* I fix bugs and make changes in my local Clojure/contrib/third-
party library trees, and I want *all* of my builds to use *those*, not
their own choice of versions. With lein/mvn I have to install a custom
version of those libraries into my repo, then change all of my
libraries to use the custom version. New build = changing every
library's project file again (or overwriting the repo version... not
sure how acceptable a solution that is). With my previous approach I
simply had to overwrite a jar (allowing my VCS to track the old
version).
* I prefer using Git commit IDs to unambiguously reference
versions, not an arbitrary version string which I have to change in a
separate commit.
* I run arbitrary Ant tasks -- such as SQL scripts -- in my
projects. I don't see that in Leiningen. I'd love someone to point me
to it.
* Not all of my projects are open-source, so I like to store their
cross-dependencies in version control, not in some custom repository
server. I don't want to have to figure out how to run my own Maven
repo somewhere, solving the auth problem again, etc. etc.

Phil Hagelberg

unread,
Jan 22, 2010, 1:56:53 AM1/22/10
to clo...@googlegroups.com
Richard Newman <holy...@gmail.com> writes:

> Adjusting the lein script to use my local Clojure install gave me a
> great error:
>
> Caused by: java.lang.NoSuchMethodError: clojure.lang.RestFn.<init>(I)V
>

> How do people deal with this? How can one simultaneously use two
> libraries which have hardwired dependencies on two different Clojure
> versions, each of which might be mutually incompatible?
>
> What's the community protocol around locally installing Clojure 1.2,
> and adding that as a dependency for a published library?

It's necessary in these circumstances to use AOT as sparingly as
possible. If there's no AOT done, there's no problem with mixing Clojure
versions (within reason). So the latest version of Leiningen does zero
AOT'ing unless you explicitly ask for it.

> What's the right way to get lein itself to use a recent Clojure build,
> rather than the version with which it ships?

Leiningen allows the project to use a different version of Clojure than
Leiningen itself, so (modulo a bug in the repl task for which this
doesn't apply) this is a non-issue.

-Phil

Richard Newman

unread,
Jan 22, 2010, 2:20:26 AM1/22/10
to clo...@googlegroups.com
>> How do people deal with this? How can one simultaneously use two
>> libraries which have hardwired dependencies on two different Clojure
>> versions, each of which might be mutually incompatible?
>>
>> What's the community protocol around locally installing Clojure 1.2,
>> and adding that as a dependency for a published library?
>
> It's necessary in these circumstances to use AOT as sparingly as
> possible. If there's no AOT done, there's no problem with mixing
> Clojure
> versions (within reason). So the latest version of Leiningen does zero
> AOT'ing unless you explicitly ask for it.

That wasn't quite my question.

Say I rely on a particular feature in 1.2, perhaps


commit b63af1ad6ce38b50552be3c424ea166cb063ee7c
Author: Chouser <cho...@n01se.net>
Date: Mon Jan 11 02:04:32 2010 -0500

Add agent error handlers and error modes :fail and :continue.
Fixes #30


My code doesn't work on 1.1 or earlier.

* How can I express a dependency in a published library for a library
which has not been published? Tough question. People will be annoyed
if I upload my own build of 1.2, then don't fix my POM when Clojure
1.2 is officialy released.

* What happens when someone else's code -- which explicitly specifies
Clojure 1.1 -- wants to use my library? If one uses AOT, you might get
some odd stack trace. If one does not use AOT, you get a compile
error. Much better solutions are "you get a warning", or "you can
specify a range of allowable versions, and the build software chooses
the right version".

This is a hard problem, and any dependency management system which
requires you to pick a single version of a dependency, when multiple
versions exist (and your code might work on more than one) is going to
hit it. I don't think "everybody has to upgrade at once" is a good
solution.


>> What's the right way to get lein itself to use a recent Clojure
>> build,
>> rather than the version with which it ships?
>
> Leiningen allows the project to use a different version of Clojure
> than
> Leiningen itself, so (modulo a bug in the repl task for which this
> doesn't apply) this is a non-issue.

Thanks for clarifying.

It appears that it does not work with 1.2, because running `lein`
after changing CLOJURE_JAR to point to my 1.2 build caused that error
to occur!

-R

Konrad Hinsen

unread,
Jan 22, 2010, 3:11:12 AM1/22/10
to clo...@googlegroups.com
On 22 Jan 2010, at 07:23, Richard Newman wrote:

> * For those who might ask "and what kind of user are you?":
> * I keep up to date with Clojure master. I don't use binary releases.
> * I fix bugs and make changes in my local Clojure/contrib/third-
> party library trees, and I want *all* of my builds to use *those*,
> not their own choice of versions. With lein/mvn I have to install a
> custom version of those libraries into my repo, then change all of
> my libraries to use the custom version. New build = changing every
> library's project file again (or overwriting the repo version... not
> sure how acceptable a solution that is). With my previous approach I
> simply had to overwrite a jar (allowing my VCS to track the old
> version).

My needs are pretty similar, which is why I have not adopte leiningen
either.

I typically work on a set of related projects, all of which are under
development at the same time. I don't want anything AOT compiled and I
must be able to specify dependencies that exist only as source code on
my computer and have no version number. So for the moment, I am
managing everything manually; fortunately my projects are small and
few enough for that. I'd love to be able to use leiningen for some of
the tasks, and I hope it will evolve along those lines.

Konrad.

Meikel Brandmeyer

unread,
Jan 22, 2010, 1:35:54 AM1/22/10
to Clojure
Hi,

On Jan 22, 6:40 am, Mark Derricutt <m...@talios.com> wrote:

> We're not all jumping on Leiningen, some of us are sticking with
> maven, using the maven-clojure-compiler plugin, and also the
> experimental Maven Polyglot Clojure build support:
>
>  http://polyglot.sonatype.org/clojure.html
>
> (disclojure - both of these are my projects so I'm somewhat biased)

And for completeness sake there is clojuresque - a Clojure plugin for
Gradle. (I'm too biased, because I'm the author ;P)

Now for the original question: http://groups.google.com/group/clojure/browse_thread/thread/6cef4fcf523f936

The problem is AOT compiled code. After that discussion I switched the
default in clojuresque from AOT to source. AOT must no explicitly be
enabled. Another possibility would be to provide two jars: one AOT'd
and one src-only.

As for the snapshots: you can find them on http://build.clojure.org/snapshots.
So you (can but) don't have to put them into a local repository.

Sincerely
Meikel

Sergey Galustyan

unread,
Jan 22, 2010, 6:09:37 AM1/22/10
to clo...@googlegroups.com
I got a similar issue, yesteday I tried to update from github to newest version of clojure\clojure-contrib, 
and clojure-contrib showed me "Caused by: java.lang.NoSuchMethodError: clojure.lang.RestFn.<init>(I)V",
I checked out lot's of branched in clojure-contrib, but ended up unpacking manually downloaded zip (with 1.1.x probably),
anyway it looked like clojure-contrib really not up to date with clojure (master, or new, or any other branch).

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en



--
Best regards,
   Sergey Galustyan.

Matt Clark

unread,
Jan 22, 2010, 8:30:26 AM1/22/10
to Clojure
From my googling, the only way to solve this in the general case (IE
the java case) is through using OSGi. I have no idea what the state
of compatibility is between clojure and OSGi at this time. I'd be
curious to find out in fact. Here's the stackoverflow.com page I
found that describes the situation as I understand it:

http://stackoverflow.com/questions/1553567/java-classloader-how-to-reference-different-versions-of-a-jar

Seth

unread,
Jan 22, 2010, 9:18:09 AM1/22/10
to Clojure
>    * I keep up to date with Clojure master. I don't use binary releases.
>    * I fix bugs and make changes in my local Clojure/contrib/third-
> party library trees, and I want *all* of my builds to use *those*, not  
> their own choice of versions. With lein/mvn I have to install a custom  
> version of those libraries into my repo, then change all of my  
> libraries to use the custom version. New build = changing every  
> library's project file again (or overwriting the repo version... not  
> sure how acceptable a solution that is). With my previous approach I  
> simply had to overwrite a jar (allowing my VCS to track the old  
> version).

I wrote a Rakefile to support locally juggling various clojure /
contrib repos. It pushes symlinks to jars into ~/.clojure and the
local maven repo, as well as brings up a repl, pulls changes from
GitHub, etc. The only major caveat is that the wipe command doesn't
check for local changes before deleting files.

http://bitbucket.org/seths/clojuggle/src/tip/README.txt

P.S. Sorry to involve yet another language's build system, it's just
that Rake is a great tool.

Perry Trolard

unread,
Jan 22, 2010, 10:14:39 AM1/22/10
to Clojure
On Jan 21, 7:21 pm, Richard Newman <holyg...@gmail.com> wrote:
> Now, I like to keep track of Clojure master. Right now, Clojure  
> reports "Clojure 1.2.0-master-SNAPSHOT".
>
> (I don't see that in Maven Central or in Clojars, so I guess I have to  
> put it in my local repository...?)

Richard, this doesn't address your larger points, but I wanted to make
sure you're aware of

http://build.clojure.org

which is a maven repo for clojure & contrib artifacts. At /snapshots,
there are builds for Clojure 1.2 (1.2.0-master-SNAPSHOT). Leiningen is
aware of this repo by default, so you can specify the 1.2.0-master
snapshot as a dependency in your project.clj.

Perry

Stuart Sierra

unread,
Jan 22, 2010, 10:18:25 AM1/22/10
to Clojure
On Jan 21, 8:21 pm, Richard Newman <holyg...@gmail.com> wrote:
> Apparently everyone is jumping on the Leiningen bandwagon and deleting  
> their build.xml files. I guess that means I'm moving, too.

Deleting build.xml files is good. After that, you've got several
options, including Leiningen and clojure-maven-plugin, both of which
are based on the Maven dependency model.

> Now, I like to keep track of Clojure master. Right now, Clojure  
> reports "Clojure 1.2.0-master-SNAPSHOT".
>
> (I don't see that in Maven Central or in Clojars, so I guess I have to  
> put it in my local repository...?)

Clojure and clojure-contrib have daily snapshots in a Maven repository
at http://build.clojure.org/snapshots

> Unfortunately, not everybody keeps up-to-date like I do; most of the  
> projects I use demand "1.1.0-alpha-SNAPSHOT". I'm sure there are still  
> projects that demand 1.0.

This is the problem of a young language and immature libraries. You
may need to compile those projects yourself and install them in a
local repository.

-SS

David Brown

unread,
Jan 22, 2010, 11:46:10 AM1/22/10
to clo...@googlegroups.com
On Thu, Jan 21, 2010 at 10:23:10PM -0800, Richard Newman wrote:

>I'm somewhat swayed by Leiningen because it makes doing some things
>easy (uberjar! starting a REPL! neat!), at the cost of making other
>things (such as managing dependencies myself) more frustrating.
>However, if it wasn't for all the people blindly deleting their Ant
>build scripts, I would be sticking with my Ant workflow for another
>few months. I don't think Lein is quite targeted at users like me.*

For one project, I have a JNI that needs to be built as part of it. I
tried converting this to Maven, and once I realized that I needed
numerous fake subprojects to work around Maven's rigid flow model, I
ended up going back to ant.

I ended up making a fairly general ant script that I can drop into any
project and build java/JNI/clojure source as needed. If anyone is
interested, the code is at
<http://github.com/d3zd3z/webweight>

The build.xml is at the top, and the support files are under 'etc'.

David

Laurent PETIT

unread,
Jan 22, 2010, 11:46:49 AM1/22/10
to clo...@googlegroups.com
Is it possible in maven or leiningen to place a dependency not on a
specific version of a pre-built artifact, but rather on a specific scm
revision (or just head, aka SNAPSHOT for binary releases) of a
project's source repository, and having the machinery understand it
has to first locally build the dependency into a jar/whatever in the
process of compiling one's project ?

Alternatively, is it possible to at least depend on a "source" version
of the dependency, having it compiled on the fly locally when
compiling the main project ? (so that one could benefit from AOP, and
this could also solve the problem of a library mixing java and clojure
source) ?

Does all that make sense ?

2010/1/22 Stuart Sierra <the.stua...@gmail.com>:

Phil Hagelberg

unread,
Jan 22, 2010, 12:39:03 PM1/22/10
to clo...@googlegroups.com
Laurent PETIT <lauren...@gmail.com> writes:

> Is it possible in maven or leiningen to place a dependency not on a
> specific version of a pre-built artifact, but rather on a specific scm
> revision (or just head, aka SNAPSHOT for binary releases) of a
> project's source repository, and having the machinery understand it
> has to first locally build the dependency into a jar/whatever in the
> process of compiling one's project ?

When you upload to clojars a version number ending in SNAPSHOT, I
believe it is replaced with the current timestamp on the server.

See http://clojars.org/repo/org/danlarkin/clojure-json/1.1-SNAPSHOT/ for
an example.

So if you're just interested in pinning yourself to a specific SNAPSHOT
rather than just any one out there, that would be the trick. But there's
no mechanism for building it yourself, though it's quite easy to do
manually.

> Alternatively, is it possible to at least depend on a "source" version
> of the dependency, having it compiled on the fly locally when
> compiling the main project ? (so that one could benefit from AOP, and
> this could also solve the problem of a library mixing java and clojure
> source) ?

I've thought about this, and I think it's a great idea. I will probably
implement it eventually, but it might take a while since I don't have
any projects that would benefit from it right now. So it's a great
opportunity for a potential contributor to step up. =)

-Phil

Richard Newman

unread,
Jan 22, 2010, 1:24:40 PM1/22/10
to clo...@googlegroups.com
> Richard, this doesn't address your larger points, but I wanted to make
> sure you're aware of
>
> http://build.clojure.org
>
> which is a maven repo for clojure & contrib artifacts. At /snapshots,
> there are builds for Clojure 1.2 (1.2.0-master-SNAPSHOT). Leiningen is
> aware of this repo by default, so you can specify the 1.2.0-master
> snapshot as a dependency in your project.clj.

Yup, apparently my own 1.2.0-master-SNAPSHOT was replaced by an
upstream version sometime yesterday (that is, Lein found a POM).
Contrib still wasn't listed, though.

Thanks for pointing this out.

Richard Newman

unread,
Jan 22, 2010, 1:28:40 PM1/22/10
to clo...@googlegroups.com
>> Apparently everyone is jumping on the Leiningen bandwagon and
>> deleting
>> their build.xml files. I guess that means I'm moving, too.
>
> Deleting build.xml files is good. After that, you've got several
> options, including Leiningen and clojure-maven-plugin, both of which
> are based on the Maven dependency model.

It's good *if you want to use Maven*. I don't agree that the removal
of that choice is good.

> This is the problem of a young language and immature libraries. You
> may need to compile those projects yourself and install them in a
> local repository.

... and modify *every* library to make sure they all point to the same
local Clojure version, otherwise some of them will still be building
with some older release.

Oh, and if I don't want three versions of Commons libs (some want
Logging 1.1, some Logging 1.1.1, etc.), I have to modify those
projects again. Seems a lot like manual dependency management. :)

Richard Newman

unread,
Jan 22, 2010, 1:31:12 PM1/22/10
to clo...@googlegroups.com
>> Alternatively, is it possible to at least depend on a "source"
>> version
>> of the dependency, having it compiled on the fly locally when
>> compiling the main project ? (so that one could benefit from AOP, and
>> this could also solve the problem of a library mixing java and
>> clojure
>> source) ?
>
> I've thought about this, and I think it's a great idea. I will
> probably
> implement it eventually, but it might take a while since I don't have
> any projects that would benefit from it right now. So it's a great
> opportunity for a potential contributor to step up. =)

I'd do it if I knew how!

What I'd like is for Leiningen to know about my ~/repos directory,
which contains all of my libraries and a load of other people's. If a
project file mentions a library, *look there first*. (And don't look
upstream for a POM.)

Sean Devlin

unread,
Jan 22, 2010, 1:32:33 PM1/22/10
to Clojure
Does anyone know what Debian does? That might be a good starting
point.

Meikel Brandmeyer

unread,
Jan 22, 2010, 10:31:15 AM1/22/10
to Clojure
Hi,

On Jan 22, 8:20 am, Richard Newman <holyg...@gmail.com> wrote:

> My code doesn't work on 1.1 or earlier.

In maven specifying eg. 1.1 means "use whatever appropriate but prefer
1.1". Now you specify 1.2 and there is a conflict. By saying "use the
newer version", 1.2 will be used. AOT compiled libraries should
probably specify [1.1], which means only and only 1.1.

> * How can I express a dependency in a published library for a library  
> which has not been published? Tough question. People will be annoyed  
> if I upload my own build of 1.2, then don't fix my POM when Clojure  
> 1.2 is officialy released.

You can specify [1.2-SNAPSHOT,) as depedency. I *believe* this will
work then also, when 1.2 is released.

BTW: commit ids as version numbers break down here, because they are
not ordered.

> * What happens when someone else's code -- which explicitly specifies  
> Clojure 1.1 -- wants to use my library? If one uses AOT, you might get  
> some odd stack trace. If one does not use AOT, you get a compile  
> error. Much better solutions are "you get a warning", or "you can  
> specify a range of allowable versions, and the build software chooses  
> the right version".

When the specification of your library is [1.2-SNAPSHOT,) and the
other is [1.1] maven will complain, I would expect, before you run
into strange compile errors.

> This is a hard problem, and any dependency management system which  
> requires you to pick a single version of a dependency, when multiple  
> versions exist (and your code might work on more than one) is going to  
> hit it. I don't think "everybody has to upgrade at once" is a good  
> solution.

Neither maven nor ivy are so simple-minded to allow only one version.
How well ranges work out... I can't really know. I only know the
theory for now.

Sincerely
Meikel

Richard Newman

unread,
Jan 22, 2010, 2:54:09 PM1/22/10
to clo...@googlegroups.com
> Now for the original question: http://groups.google.com/group/clojure/browse_thread/thread/6cef4fcf523f936
>
> The problem is AOT compiled code.

Not only. If my library refer to a function that's first defined in
library-X version 1.5, and some other code uses library-X 1.4 *and* my
library, then there is a fundamental problem whenever you add a
dependency on both my library and the other library. This will happen
any time a library's API changes and you have dependencies that cross
the line.

AOT compilation might make the problem appear at compile-time in some
cases, or more often if the library is a "compiler" (i.e., leaves
shreds of its implementation in your compiled code), but you don't
eliminate the problem by avoiding AOT compilation.

Using a sophisticated dependency system -- having a library specify
its requirements, not a dumb version number -- drastically reduces
these problems by resolving the requirements to a particular release,
or spotting the error and failing fast. Using a dumb version system
screws you whenever this occurs, *and* makes it awkward for you to
manually resolve the collision.

(OSGI attempts to address this by allowing multiple library versions,
but Clojure needs its own classloader, and also enables code to 'flow'
across library boundaries through macroexpansion.)

> As for the snapshots: you can find them on http://build.clojure.org/snapshots
> .
> So you (can but) don't have to put them into a local repository.

Of course, you still do if you have made changes to Clojure in your
local checkout.

Richard Newman

unread,
Jan 22, 2010, 3:07:03 PM1/22/10
to clo...@googlegroups.com, lein...@googlegroups.com
> BTW: commit ids as version numbers break down here, because they are
> not ordered.

They have a partial ordering wrt a particular repo. Many repos have
straight-line histories, and thus have a total ordering.

> Neither maven nor ivy are so simple-minded to allow only one version.
> How well ranges work out... I can't really know. I only know the
> theory for now.

That the underlying system allows it is no comfort when there seems to
be no obvious provision in project.clj for this:

:dependencies [[org.clojure/clojure "1.1.0"]
[org.clojure/clojure-contrib "1.0-SNAPSHOT"]
[clout "0.1"]]

Does that mean "use whatever's appropriate", or "I must use 1.1.0
only"? Do these version strings admit that Maven syntax?

How does one tell Maven/lein "never use two different versions of
Clojure"? How does one tell Maven to *rebuild* a library -- e.g.,
Compojure -- using 1.2, so that I can safely use it in my requires-1.2
project? (Or "look in a repo to find a version of Compojure built
using 1.2"?)

These are questions that I think must be addressed, because these
problems come up all the time.

Just this week I noticed that Apache HttpComponents 4.0.1 and 4.1 use
completely different methods to apply pre-emptive HTTP Basic Auth, and
have even changed class hierarchies. A version of clj-apache-http
targeted at 4.0.1 won't even run against a 4.1 jar (and vice versa),
*even without AOT*, because the package names are different. On the
other hand, some libraries -- such as log4j -- preserve API
compatibility across versions.

Sorry to be raining on everyone's parade with this...

-R

Richard Newman

unread,
Jan 22, 2010, 7:34:06 PM1/22/10
to clo...@googlegroups.com, lein...@googlegroups.com
> Just this week I noticed that Apache HttpComponents 4.0.1 and 4.1
> use completely different methods to apply pre-emptive HTTP Basic
> Auth, and have even changed class hierarchies. A version of clj-
> apache-http targeted at 4.0.1 won't even run against a 4.1 jar (and
> vice versa), *even without AOT*, because the package names are
> different. On the other hand, some libraries -- such as log4j --
> preserve API compatibility across versions.

In fact, I just hit a concrete example of this.

clj-apache-http uses httpcomponents 4.0.1.
ring uses 4.0-alpha6, which is obsolete.

One of my projects currently will not build because ring's transitive
dependency gets pulled into lib, and apparently gets on the classpath
first, causing the load of clj-apache-http to fail:

[null] java.lang.IllegalArgumentException: No matching ctor found
for class org.apache.http.protocol.BasicHttpContext (http.clj:274)

Now I have to fix Ring, and hope that mmcgrana will accept the fix and
deploy to the central repo. That fix might break someone else's code
in turn. Oh, the tangled webs we weave.

ataggart

unread,
Jan 22, 2010, 8:13:56 PM1/22/10
to Clojure

I have yet to use lein, but Ivy will take the higher version when it
sees different transitive dependency versions. Further, it will allow
the depending project's ivy.xml file to specify that the version it
specifies should override that default behavior. I assume similar
functionality would be necessary for any dependency management system.

And as for Apache HttpComponents, it sounds like they don't grok the
notion that breaking backwards compatibility should only occur with a
major-version change.

Richard Newman

unread,
Jan 22, 2010, 8:25:43 PM1/22/10
to clo...@googlegroups.com
> And as for Apache HttpComponents, it sounds like they don't grok the
> notion that breaking backwards compatibility should only occur with a
> major-version change.

Yeah, it's a pain to use their stuff -- I've never seen *so many
packages* in one library -- but it seems to be the only feature-rich
HTTP client in the Java world (y'know, that can actually set
parameters on requests, that sort of thing). The JRE stuff sucks badly.

Meikel Brandmeyer

unread,
Jan 22, 2010, 4:48:30 PM1/22/10
to clo...@googlegroups.com
Hi,

Am 22.01.2010 um 21:07 schrieb Richard Newman:

>> BTW: commit ids as version numbers break down here, because they are
>> not ordered.
>
> They have a partial ordering wrt a particular repo. Many repos have straight-line histories, and thus have a total ordering.

So how do I find out the ordering of your x repository here in my machine, possibly without having x installed. Or your repo cloned?

>> Neither maven nor ivy are so simple-minded to allow only one version.
>> How well ranges work out... I can't really know. I only know the
>> theory for now.
>
> That the underlying system allows it is no comfort when there seems to be no obvious provision in project.clj for this:
>
> :dependencies [[org.clojure/clojure "1.1.0"]
> [org.clojure/clojure-contrib "1.0-SNAPSHOT"]
> [clout "0.1"]]
>
> Does that mean "use whatever's appropriate", or "I must use 1.1.0 only"? Do these version strings admit that Maven syntax?

One can investigate this. If lein doesn't support this notation.. Sorry to play the tool card: maven does, ant+ivy does, gradle does.

> How does one tell Maven/lein "never use two different versions of Clojure"?

It does never use two different versions of Clojure. Either there is a range of allowed versions, then some conflict resolver (choosable by you) chooses an appropriate version. If no such range is available, it stops telling you about the problem.

> How does one tell Maven to *rebuild* a library -- e.g., Compojure -- using 1.2, so that I can safely use it in my requires-1.2 project?

For Clojure this is only an issue when using AOT. Without it just works. If there is a problem, because it uses for example a removed function, then a rebuild wouldn't help anyway.

> (Or "look in a repo to find a version of Compojure built using 1.2"?)

With AOT you are (maybe) locked into a specific Clojure version. One solution could be to provide several versions compatible with the different versions of the dependency. But that would be not very nice I agree. But see below.

> These are questions that I think must be addressed, because these problems come up all the time.
>
> Just this week I noticed that Apache HttpComponents 4.0.1 and 4.1 use completely different methods to apply pre-emptive HTTP Basic Auth, and have even changed class hierarchies. A version of clj-apache-http targeted at 4.0.1 won't even run against a 4.1 jar (and vice versa), *even without AOT*, because the package names are different. On the other hand, some libraries -- such as log4j -- preserve API compatibility across versions.
>
> Sorry to be raining on everyone's parade with this...

Then let me open the umbrella.

The root cause of this situation is not a broken version system, but broken API design. If you need 4.1 and clj-apache-http needs 4.0.1 and both can't coexist, then you are hosed. And no whatsoever clever system of handling dependencies will ever be able to fix that. If log4j does preserve API compatibility.. hooray *clapclap*. But then you will also have no problem with the version systems.

Sincerely
Meikel

Richard Newman

unread,
Jan 22, 2010, 11:58:16 PM1/22/10
to clo...@googlegroups.com
>> They have a partial ordering wrt a particular repo. Many repos have
>> straight-line histories, and thus have a total ordering.
>
> So how do I find out the ordering of your x repository here in my
> machine, possibly without having x installed. Or your repo cloned?

I'm assuming that a source-based versioning system has a checkout of
the source, just as a binary-based versioning system has a copy of the
binary.

> The root cause of this situation is not a broken version system, but
> broken API design. If you need 4.1 and clj-apache-http needs 4.0.1
> and both can't coexist, then you are hosed.

That's not the problem situation I'm talking about; of course truly
mutual incompatibility can't easily be resolved. I'm talking about
*describing* dependencies.

If my library *requires* 4.0.1, and another library puts 4.1 in its
descriptor (perhaps that's the latest version on the website), then
problems will arise when I combine the two. Without AOT, one will fail
to build. With AOT, one will fail at runtime.

The solution depends on knowledge of the library's requirements: you
have to know which libraries will or won't work with a certain version
(and cascade that through all of their dependencies). It might be
perfectly acceptable to use the other library with 4.0.1. It might
even be acceptable to use both versions simultaneously, or both if you
load them in the right order!

If Lein/etc. allows you to specify "I must have something API-
compatible with 4.0.1", and have that resolved, then great. So far I
haven't seen a way to do that. Leiningen brushes it off with "use
semantic versioning", which isn't much help if your requirements are
more fine-grained (say if the next version is -- strictly speaking --
API compatible, but you need or want to use a different implementation
to reflect new API availability).

I foresee a future with a lot more time spent modifying other people's
project files.

Maybe we need to spend a little time thinking of the appropriate way
to codify workarounds for this kind of thing: imposing corrected
dependencies on upstream libraries; specifying that some library
should be built from source; using predicates to decide on
dependencies; etc.

From what you've written it appears that work has been done on
dependency management systems that make some of these tasks easier
(e.g., Gradle). Unfortunately, this whole adventure with Leiningen was
prompted by a ton of libraries that I use moving to Leiningen, and
removing any way for me to build them without it, so I'm interested in
solutions for Leiningen. If I wanted to spend the time integrating
these libraries with another build system, I'd restore the build.xml
from their history...

Thanks for the discussion.

Steve Purcell

unread,
Jan 23, 2010, 6:40:48 AM1/23/10
to clo...@googlegroups.com
I believe some people use HttpUnit for this purpose. It's a very full-featured HTTP client. YMMV.

Jeff Rose

unread,
Jan 23, 2010, 7:23:33 AM1/23/10
to Clojure
I use leiningen to download and publish libraries, but in terms of
setting up for development I use a bash script that adds whatever I
need for the project to the CLASSPATH and starts the nailgun server.
(swank for vimclojure) This seems to work pretty well, although it
would be nice if Leiningen had mechanisms like Ant where you could
customize the classpath on a project and/or task basis.

Below is the script I'm using to create the classpath for a project
that has multiple git submodules located in src/lib, jars downloaded
with lein deps sitting in lib, and the code in src and test. I'm
normally on Ubuntu but works under Cygwin also.

-Jeff

-------------------------------------------------------

#!/bin/bash

DEPS=lib
SUBMODULES=src/lib

CLASSPATH="./src:./test"

# Add jar files
for f in "$DEPS"/*.jar; do
CLASSPATH=$CLASSPATH:$f
done

# Add sub-modules
for f in "$SUBMODULES"/**/src; do
CLASSPATH=$CLASSPATH:$f
done

if [[ "$OSTYPE" == 'cygwin' ]]; then
CLASSPATH=`cygpath -wp "$CLASSPATH"`
fi

echo "$CLASSPATH"

On Jan 22, 2:21 am, Richard Newman <holyg...@gmail.com> wrote:
> Hi folks,


>
> Apparently everyone is jumping on the Leiningen bandwagon and deleting  
> their build.xml files. I guess that means I'm moving, too.
>

> Now, I like to keep track of Clojure master. Right now, Clojure  
> reports "Clojure 1.2.0-master-SNAPSHOT".
>
> (I don't see that in Maven Central or in Clojars, so I guess I have to  
> put it in my local repository...?)
>

> Unfortunately, not everybody keeps up-to-date like I do; most of the  
> projects I use demand "1.1.0-alpha-SNAPSHOT". I'm sure there are still  
> projects that demand 1.0.
>

Stuart Sierra

unread,
Jan 23, 2010, 11:10:20 AM1/23/10
to Clojure
On Jan 22, 11:58 pm, Richard Newman <holyg...@gmail.com> wrote:
> I foresee a future with a lot more time spent modifying other people's  
> project files.

This is the past, the present, and the forever-after of open-source
software development.

If you need lots of libraries, you need your own Maven repository with
your own builds, tweaked to work together.

-SS

Richard Newman

unread,
Jan 23, 2010, 1:11:26 PM1/23/10
to clo...@googlegroups.com
> If you need lots of libraries, you need your own Maven repository with
> your own builds, tweaked to work together.

I'm actually looking at your "Run your own Maven repository" article
right now :)

I think the only attitude to keep me sane is that Maven is a huge
system that replicates my "deps" directory (once I put everything in a
private repository).

I still have to do all my own dependency management, just using `lein
jar; lein pom; lein install; cp pom.xml ...` instead of `ant; cp
foo.jar ../deps/`.

(Why copy the pom? So lein can do transitive deps, apparently.)

Reply all
Reply to author
Forward
0 new messages