Which programming language has the best package manager?

I have to work with a lot (9) of different package managers at my daily work at VersionEye. Part of our mission is it to make manual updating of dependencies extinct, because it’s a manual and time consuming task which nobody enjoys. That’s why we are building a notification system for open source software libraries to make Continuous Updating easy and fun. And since we support several programming languages – 8 at this point! – I get to write crawlers and parsers for all of them. To give you a better overview over the strengths and weaknesses of these package managers, I picked the most popular one for each language and will compare them. The contenders are:

  • RubyGems / Bundler (Ruby)
  • PIP / PyPI (Python)
  • Packagist / Composer (PHP)
  • NPM (Node.JS)
  • Bower (JS, CSS, HTML)
  • CocoaPods (Objective-C)
  • Maven (Java)
  • Lein (Clojure)

What are package managers?

Package managers are tools for software developers to help them easily share and consume software libraries and of course to manage dependencies! Specially transitive dependencies. If you are a software developer and you are still downloading software libraries with your browser and placing them into the right directory by hand, then you are doing something wrong! That is totally 1999!

Nowadays every software developer uses at least 1 package manager at work. That means you define the software libraries (dependencies) you want to use in your project in a project file. The package manager is then  responsible for

  • downloading the software libraries from a repository
  • placing the downloaded libraries into the right place and linking them correctly into the project
  • resolving transitive dependencies

A package manager always has 2 parts:

  • a Repository of binaries or source code
  • a client which communicates with the repository and performs some work on the client side. This is in most cases a command line tool

The advantages of such a system is pretty clear. It’s much easier to stay in control of dependencies since you just change a number in a text file and execute a command. The package manager is doing all the work for you. Another big advantage is that you don’t need to checkin the actual software libraries into your SCM. You only checkin the project file from your package manager.

RubyGems / Bundler (Ruby)

RubyGems is the package manager for Ruby. Libraries that are bundled as such are also called gems. A gem contains a directory with source code and a *.gemspec file. The *.gemspec file contains meta information to the gem, such as name, version, author, license and of course the dependencies of the gem. A gem can be build with the command line tool “gem” like this:

gem build rails.gemspec

And published to the central gem repository like this:

gem push rails-1.0.0.gem

In an non library (gem) project the dependencies are mostly managed by bundler, a very popular dependency manager for RubyGems. Bundler manages dependencies defined in a Gemfile, a simple text file. Here is an example:

source 'https://rubygems.org'

gem 'rails' , '3.2.16'
gem 'jquery-rails' , '2.2.1'

group :test do
  gem 'rspec' , '2.14.0'
end

The file starts with defining the repository. Which is rubygems.org, the central repository for all ruby gems. Each line in the file defines a gem, with name and version. Gems can be grouped together for different environments. E.g. gems in the test group are not required on production, but in test environments.

You don’t need to define an exact version number. You can also define a range of versions and take advantage of pre defined operators. Everything well documented on bundler.io.

Just execute the command in the directory where the Gemfile is placed and it will fetch all dependencies from the repository, resolves transitive dependencies and places them into the right directory.

bundle install

This command also creates or updates the file Gemfile.lock. This file contains the actually locked versions of the dependencies in the Gemfile and their transitive dependencies. The locked versions in the Gemfile.lock are specially important when you work with pessimistic version constraints. The Gemfile.lock is something you checkin to your SCM and never change by hand! More on that on bundler.io.

Pros

  • All gems are stored centralized on RubyGems.org. Really all ruby open source developers are using it and pushing their gems to it.
  • Learning curve is very low, very easy to understand how it works.
  • It’s very easy to publish new gems on rubygems.org. It takes less then a minute!
  • It has a very good REST JSON API.
  • Besides gems, a tag on a git repository can be defined as a dependency. That makes it very easy to fork & patch a software library.
  • Bundler supports semantic versioning and the pessimistic version constraints specifier enables to fetch the latest patches without breaking to support fetching always the newest patch/minor version of a gem.
  • There is a mirror at http://mirror1.prod.rhcloud.com/mirror/ruby/

Cons

  • Usually gems are not cryptographically signed! This can lead to security issues! It is possible to sign gems, but it’s not mandatory and most developers don’t sign their gems.
  • Defining a license for a gem is not mandatory. But most of the gems are using the MIT license.

You will not find much negative writing about it on the internet, besides the points which are listed here.

NPM (Node.JS)

NPM is the package manager for Node.JS. Libraries are stored as tgz files in the central Node.JS repository, which is npmjs.org. An NPM package is a zipped directory with source code and a package.json file, which contains all the meta information about the package, such as name, version, description, dependencies and so on. A package can be published like this:

npm publish

Here is an example for a package.json file from a well known Node.JS library. I modified the file a bit to get it shorter.

{
  "name": "request",
  "description": "Simplified HTTP request client.",
  "version": "2.31.1",
  "author": "Mikeal Rogers",
  "repository": {
    "type": "git",
    "url": "http://github.com/mikeal/request.git"
  },
  "bugs": {
    "url": "http://github.com/mikeal/request/issues"
  },
  "engines": [
    "node >= 0.8.0"
  ],
  "main": "index.js",
  "dependencies": {
    "qs": "~0.6.0",
    "json-stringify-safe": "~5.0.0",
    "forever-agent": "~0.5.0",
    "node-uuid": "~1.4.0",
    "mime": "~1.2.9"
  },
  "optionalDependencies": {
    "tough-cookie": "~0.10.0",
    "form-data": "~0.1.0",
    "tunnel-agent": "~0.3.0",
    "http-signature": "~0.10.0",
    "oauth-sign": "~0.3.0",
    "hawk": "~1.0.0",
    "aws-sign2": "~0.5.0"
  },
  "scripts": {
    "test": "node tests/run.js"
  }
}

By executing the following command in a directory with a package.json file, NPM will download all dependencies from the package.json file, resolve transitive dependencies and place them into the right place.

npm install

Pros

  • All packages are centralized at npmjs.org.
  • Learning curve is very low.
  • It’s very easy to publish new packages on npmjs.org.
  • It has a very good REST JSON API.
  • There is an NPM mirror in Europe.
  • Besides NPM packages, a tag on a git repository can be defined as a dependency. That makes it very easy to fork & patch a software library.
  • NPM supports semantic versioning and has an own operator which supports fetching always the newest patch/minor version of a package.

Cons

  • The NPM packages are not signed! That might lead to security issues!
  • Defining a license for a package is not mandatory.

NPM is a very young package manager. They learned from the failures of other package managers. It’s almost perfect!

Packagist / Composer (PHP)

Composer is the new package manager for PHP. It was written to replace PEAR. There are still less then 1.000 packages on Pear, but already more then 25K packages on packagist.org, the central repository for Composer packages.

Composer is similar to NPM. Dependencies are defined in a JSON file, called composer.json. Here is a very simple example:

{
  "name": "your-vendor-name/package-name",
  "version": "1.0.0",
  "require": {
    "php": ">=5.3.0",
    "another-vendor/package": "1.*"
  }
}

Executing this command in a directory with composer.json will install all dependencies into your project and generate a composer.lock file, same as in Ruby the Gemfile.lock.

php composer.phar install

One big difference to NPM is that packagist.org doesn’t host any files. It is completely based on Git/Svn/Hn tags. Submitting a package to packagist.org means submitting a link to a public Git, Subversion or Mercurial repository. packagist.org expects a composer.json file in the root directory of the master branch AND tags on the repository. The name of the tag is the version number displayed on packagist.org.

Pros

  • All packages are centralized at packagist.org.
  • Learning curve is very low.
  • It’s very easy to publish new packages.
  • It has a very good REST JSON API.
  • Licenses are mandatory.
  • It supports semantic versioning and has an own operator which supports fetching always the newest patch/minor version of a package.
  • Composer has a very unique and cool feature called “minimum stability”, which allows to specify the minimum stability for a requested dependency. More on that on the official documentation.

Cons

  • There are no mirrors. If packagist.org is down you can not fetch packages anymore.
  • The packages are not signed! It might lead to security issues!

The Composer / Packagist project is even younger then NPM. It is a big step forward for the whole PHP community. All big PHP frameworks moved already to Composer / Packagist.

PyPI (Python)

PyPI is the central repository for python packages. Dependencies are defined in a setup.py file, which is pretty much pure Python code. Here is an example:

 
from setuptools import setup
import os

setup(name='giki',
    version='0.1pre',
    description='a Git-based wiki',
    author='Adam Brenecki',
    author_email='adam@brenecki.id.au',
    url='',
    packages=['.'.join(i[0].split(os.sep))
        for i in os.walk('giki')
        if '__init__.py' in i[2]],
    install_requires=[
        'dulwich==0.8.5',
        'argparse', 'requests>=1.1.0,<1.3.0', 'colorama',
        'jinja2==2.6',
        'Werkzeug==0.8.3',
        'markdown2==2.0.1',
        'docutils==0.9.1',
        'textile==2.1.5',
    ],
    extras_require = {
        'test':  [
            'nose==1.1.2',
            'WebTest==1.4.0',
        ],
        'faster_markdown':  [
            'misaka==1.0.2',
        ],
    },
    entry_points = {
    'console_scripts':
        ['giki = giki.cli:main'],
    },
)

Installing the dependencies works like this:

python setup.py install

The packages at PyPI are hosted as “*.tar.gz” files. Each packages contains the source code and a setup.py file with meta informations, such as name, version and dependencies.

With a little bit preparation a package can be published to PyPI with this 2 commands:

 python setup.py register -r PyPI
 python setup.py sdist upload -r PyPI

Pros

  • All packages are centralized at PyPI.
  • Learning curve is very low.
  • It’s easy to publish new packages on PyPI.
  • There are multiple mirrors for fail-over scenarios.

Cons

  • The packages are not signed! That can lead to security issues.
  • Defining a license for a package is not mandatory.
  • No build-in support for semantic versioning.

PyPI is a robust package manager! There is room for improvements, that for sure. But the core commiters behind the project are aware of that and new features are in the pipeline.

CocoaPods (Objective-C)

CocoaPods.org is the central repository for CocoaPods, a package manager for Objective-C software libraries and mainly used by iOS developers. The CocoaPods command line tool is implemented in Ruby and hosted on RubyGems.org. It can be installed like this:

gem install cocoapods

Dependencies are defined in a simple text file called Podfile. Here a simple example:

platform :ios
pod 'JSONKit', '1.4'
pod 'Reachability', '3.0.0'

Executing this command in the root directory will install the dependencies:

pod install

Currently CocoaPods is completely relying on GitHub as backend. There is one CocoaPods/Specs repository with all Pod specifications available on CocoPods.org. Submitting a new pod package works via pull-request. Each pull-request gets reviewed and merged by a human after passing automated tests. This doesn’t scale infinitely but it scales for the current size and guarantees a high quality for the pod specs.

Pros

  • All packages are centralized at CocoaPods/Specs.
  • Learning curve is very low.
  • Very good documentation.
  • It’s easy to publish new packages, with a pull-request.
  • License information is mandatory! Pull-requests for Pods without license definition will not be merged.
  • It supports semantic versioning and has an own operator which supports fetching always the newest patch/minor version of a package.

Cons

  • The packages are not signed! That can lead to security issues.
  • No mirrors available.

CocoaPods is a young project. The quality of the Pod specs is very high, because of the human review. If they grow to the size of RubyGems this workflow will not scale anymore. But for right now it’s good enough.

Bower (Frontside JS & CSS)

Bower.io is a package manager for frontside JavaScript and CSS. Pretty much for everything what you are loading from the server to the browser. Packages like jQuery and Bootstrap for example.

The bower command line tool is available as package on NPM. It can be installed globally like this:

npm install -g bower

Installing a bower package works like this:

bower install <package>#<version>

It downloads the package and it’s dependencies into a directory called bower_components.

Every bower package is described in a bower.json file. Here’s an example:

{
  "name": "my-project",
  "version": "1.0.0",
  "main": "path/to/main.css",
  "ignore": [
    ".jshintrc",
    "**/*.txt"
  ],
  "dependencies": {
    "<name>": "<version>",
    "<name>": "<folder>",
    "<name>": "<package>"
  },
  "devDependencies": {
    "<test-framework-name>": "<version>"
  }
}

Bower is completely Git based and works without any user authentication. Everybody can register new packages like this:
bower register <my-package-name> <git-endpoint>
Bower expects the root of the git-endpoint to contain a bower.json file, describing the bower package. And it expects that there are some tags on the Git repository. The names of the tags are the version numbers.

To unregister a package you have to ask the maintainers in the longest GitHub issue in the history of mankind.

Pros

  • All packages are centralized at bower.io.
  • Learning curve is very low.
  • It’s easy to publish new packages. Works even without registration.

Cons

  • The packages are not signed! That can lead to security issues.
  • No mirrors available.
  • The process for unregistering a package is a No-Go.
  • License informations are not mandatory.
  • Many registered packages doesn’t provide a bower.json in their git repository. The package registration process doesn’t check if the package is valid, if it really contains a bower.json file or if there are some tags on the repository.

Bower is kind of cool, but the quality of the packages is many times bad. Unregistering a package is a pain. And a couple hundred registered packages even doesn’t provide a bower.json file in their repositories. User authentication and package validation would be necessary to improve this.

Maven (Java)

Maven is the package manager for Java. The central Maven repository is Search.maven.org.
A project and it’s dependencies are described in an pom.xml file. Here is an example.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>org.ploin.pmf</groupId>
  <artifactId>ploinMailFactory</artifactId>
  <packaging>jar</packaging>
  <version>1.4.1</version>
  <name>ploinMailFactory</name>
  <url>http://www.ploinmailfactory.org</url>
  <description>Loadbalancing for Mail Sending</description>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junitVersion}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.1</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

</project>

Each dependency is identified by:

  • groupId
  • artifactId
  • version

Other properties like scope are optional. As you can see you need at least 5 lines to define 1 single dependency. Dependencies are checked, fetched, resolved and installed on each compile time.

mvn compile

The packages on the Maven Repository Server are pretty much maintained in a pre defined directory structure, based on groupId, artifactId and version of the artifact. The artifacts themselves are binaries, mostly *.jar files. You can see it on this mirror from ibiblio.

Publishing an artifact on the central maven repository takes only 1 week. No! I’m not kidding you! First of all you have to signup at JIRA and open a ticket. The whole process is described here. And be prepared to scroll :-)

Pros

  • The artifacts are singed!
  • Licenses are mandatory for publishing!
  • There are many mirrors available all over the world.

Cons

  • Pushing artifacts to the maven central repository is not as easy as it should be. Because this process is a pain in the ass ALL big Java Frameworks and Companies are maintaining their own Maven Repository Servers. They push their artifacts first to their own MVN Server and then 1 or 2 weeks later the artifact appears on search.maven.org.
  • Not really centralized. Because of the previous point. There are at least 30 different public maven repository servers out there, who are not mirroring search.maven.org, but host other artifacts who are not available on search.maven.org. Java developers have to google for the right repository server with the desired artifacts.
  • Maven is a very complex tool! A pom.xml file can inherit from another pom.xml file. And a pom.xml file can include other pom.xml files. All that leads to high complexity and sometimes to resolution errors. Another side effect of this architecture is that resolving transitive dependencies this way is very slow, because different xml files have to be downloaded and parsed to build a complete model for 1 single artifact.
  • Maven violates the “Single Responsibility” pattern. Maven is not only doing dependency management! It is doing all kind of things which has nothing to do with dependency management. For example executing tests, generating reports, generating JavaDoc, doing deployments and many other things which are, in other languages, done by other tools.
  • Not sure why an artifact/package needs a “GroupId” AND an “ArtifactID” AND a version number. All other package managers are satisfied with a name and a version. KIS!
  • Having 5 lines of XML code for 1 single dependency is kind of overkill!

Maven is by far the most complex package manager I know. And know many of them!

Lein (Clojure)

Leiningen is the package manager for Clojure. It uses a maven repository as backend. Lein itself has the same scope as Maven. It’s not just doing dependency management! At the same time it’s a build tool. Dependencies are defined in a project.clj file. Here an example:

(defproject leiningen.org "1.0.0"
  :description "Generate static HTML for http://leiningen.org"
  :dependencies [[enlive "1.0.1"]
                 [cheshire "4.0.0"]
                 [org.markdownj/markdownj "0.3.0-1.0.2b4"]]
  :main leiningen.web)

Defining a dependency fits here into 1 line. And “GroupId” is not required for Clojure packages! Leiningen is using 2 sources for the dependency resolution.

The dependencies in a project.clj file can be explicitly fetched with this command:

lein deps

But they will be fetched anyway at compile time.

Publishing a package on clojars.org is pretty easy, after you signed up.

lein pom
scp pom.xml mylib.jar clojars@clojars.org:

Pros

  • The artifacts are signed!
  • It simplifies the dependency definition of maven.
  • It’s easy to publish new artifacts.
  • It’s easy to learn how it works.
  • It allows to reuse Java artifacts from other maven repositories.

Cons

  • It violates the “Single Responsibility” pattern. Same as Maven.
  • Licenses are not mandatory.
  • No Mirrors.

Leiningen is not perfect, but it is doing many things right.

Maven based package managers

There are many languages running on the JVM and most of them have their own package managers. But all of them are more or less based on Maven repositories. That means they all use a Maven Repository as backend and just have a better client (command line tool) and different conventions to deal with the backend.  These are the package managers from this family:

Ivy, SBT and Gradle support own repository types, beside Maven Repositories. But it kind of makes sense that they all access Maven Repositories, because they all want to reuse existing Maven artifacts.

Conclusion

All discussed package managers are open source and can be hosted internally as well. All of them are easy to get started with, except for Maven which is more complex and less fun. I’ve created a comparison matrix to highlight the differences with the most important attributes on the x axis. Unfortunately, there is no single package manager that offers every desired feature:

Comparison Package Managers

There is no clear winner and imho, there is no perfect package manager :-( There are of course more package managers, such as CPAN (Perl) and Nuget (.NET), and we hope to be able to cover them in the future. You can find a complete list of package managers here. We are working continuously to add additional languages to our API and make VersionEye available for every software developer in the world!

What is your favorite package manager? And why? And which features are missing in current package managers? I’d love to hear your thoughts! Leave a comment or send me a tweet.

Follow the discussion on hacker news and Reddit.

if you read this far, you might want to monitor your packages on VersionEye ;-)

73 thoughts on “Which programming language has the best package manager?

  1. And then there would be perl and cpan which is mirrored, documented, tested, bugtracked, web-interfaced and commandlined, searchable and everything else…

    Oh, lots of modules in there, too. ;)

  2. When you get around to also handling the grand-daddy of package managers (seriously, why did you leave out CPAN, one of the biggest and earliest ones?) please do add categories for testing and reporting of testing to a central infrastructure. Otherwise you’re missing out on some of the most crucial features of these installers.

    • Simply because of limited time and resources. We are currently only 3 devs at VersionEye. And we got more requests for Bower and CocoaPods. But CPAN is on our list as well. We will add it and it will be part of the next comparison.

  3. With regard to your complaint about the dependency management tool (Maven/Leiningen) also being a build tool: be aware that the languages they are used for are compiled languages! When you use RubyGems to build and deploy a Gem, it does not need to download any of the dependencies because the language is not compiled. When building and deploying a JAR, however, it is necessary to download and use all of the dependencies in order to compile the code. Typically, a package manager is not needed in order to run an artifact that has been built. For example, once a WAR has been built, no more dependency resolution needs to be performed in order to deploy it to an app server. Zip assemblies are also used to produce artifacts that contain all the necessary dependencies in a ready-to-deploy-and-run package. If, however, that does not meet your needs there is still Ivy and Aether.

    I’m used to Maven, and having used Bundler there were a lot of frustrating things that I wished worked the same way as Maven. There is not a good equivalent to snapshot versions, for example. That leads you to needing to excessively increment version numbers manually or deleting gems from your gem server so the version can be re-pushed. Also, dealing with a project that has multiple gems worth of source code (eg. modularized rails apps) or multiple repositories can be annoying with Bundler.

    FYI: it appears Leiningen does support resolving artifacts from a mirror: https://github.com/technomancy/leiningen/issues/271

    • First to Leiningen. I didn’t say it can’t resolve artifacts from mirrors. Of course it can, because it’s Maven based. I’m just saying that there is currently on mirror for clojars.org. Please correct me if I’m wrong.

      I’m using Maven now since 8 years. And I still use it in active projects at VersionEye. For a compiled language it might make sense to combine dependency management and build tool. But that are not the only 2 jobs maven “tries” to do. Executing tests, generating reports and doing deployments is totally out of the scope. In other languages, not only dynamic ones, these kind of jobs are done by different tool. Specially in Ruby you have small tools which are doing 1 thing, but that they do right. And they can smoothly work together. But Maven tries to do everything. And I don’t think that that’s a good idea.

      Not everything that Maven does is bad. The signing and mirroring is a good feature. Also making the licenses mandatory is great. I would wish RubyGems would do it the same way. But the overall developer experience with bundler is still much better then with Maven. Even if it less secure.

  4. Nuget and CPAN are very important. Sorry that they are not included this time. As soon Nuget and CPAN are integrated into VersionEye I will write a new comparison, where Nuget and CPAN are included as well. It’s just a madder of time and man power. We are not a big company and we didn’t had the resources to add them. But it’s coming!

    • Same story with bundler / RubyGems. The people don’t use it because it’s extra work and developers are lazy. It’s much more convenient not to do it. There is just one way out. The package manager has to enforce it. On maven all new submissions without signature getting declined. That’s the only reason why all Jar files on the official Maven repository are signed. But I didn’t saw one single self hosted maven repository there they sign their packages :-)

    • I know that you can use composer with a self hosted version of packagist. But currently there is no official mirror of packagist.org. That means if packagist.org is down then you have no access to the 25K packages anymore. And there is no official mirror you could point your composer to in that case. Right? Or did I miss something?

      • @Bram: The self-hosting column was very misleading. That did NOT mean that you can not host it by yourself. You can host ALL package managers here by yourself. It just means that the packages themselves are hosted by the package manager. That is not the case for packagist, because the downloads are mostly on GitHub. I talked with Nils Adermann about that point and I renamed the column to “Hosts downloads”. Hope that clears the confusion.

  5. To the point that Leiningen violates the “single responsibility principle”, because it handles the dependencies–this isn’t really the case; all the dependency handling is performed by the Aether library. Leiningen just hooks up a couple functions from that library to the config it reads from disk; there is no support in Leiningen itself for handling dependencies because the “single responsibility” it has is executing Clojure code, not managing packages.

    • Hi Allan. Good point. I took already a brief look to Dart and PUB. How popular is Dart nowadays in the Valley? You are the first one asking for Dart. It’s definitively on my radar, but further down the list. CPAN and Nuget are currently more up.

  6. The process for deploying Maven artifacts to Maven Central is much simpler after the first time (when you have to register your groupId). I also find the groupId / artifactId / version scheme much better than the “flat” namespace that tools such as RubyGems offer much more scalable… no worries about your package name conflicting with some other package that’s out there. The XML syntax *COULD* use a bit of pruning, though.

    • You might be right with the deployment. But I think anyway it’s kind of over engineered. Every time somebody wants to push a new groupId, it gets reviewed by a human. Last time I did that, they asked me to change my groupId to the reverse domain of my server. And they checked if I’m really the owner of the server. That’s just to much control!
      That reminds my on the PEAR project. It worked the same way and the PHP community didn’t really adapt it. Than Packagist / Composer was coming around and it let everybody push what ever they want to push. 2 Years later there are 25K projects on Packagist and PEAR is almost dead.

      Having “long” or “flat” namespaces might be good or bad. But why not let decide the community? You can have long names on RubyGems and NPM as well. But obviously not many people desire that. First-come, first-served works pretty good. Even on GitHub with 6 million projects.
      What’s the point of forcing people to choose super long identifiers for little Jar files? First they force you to choose a groupId and then afterwards they start to change the namespaces because it doesn’t fit in their logical order. Best example is the spring framework. First the groupId was “spring”, then it was “springframework” and now it’s “org.springframework”. Maybe next year it’s “com.springframework” because it’s a profitable company. Who knows?

      XML was hip … 10 years ago. Maven is the only package manager which is still using XML as configuration. And because Maven is doing many things at the same time the pom.xml files are growing like crazy. I saw already pom.xml files with 2000 lines. And now tell me that it’s better then Ant!? :-)

    • The column “Self hosted” in the infographic is misleading. I doesn’t mean that you can self host it or not. It means that the artifacts are hosted on the repository and are not just links to git tags. I just talked with Nils Adermann about that and he recommended to rename the column to “hosts downloads”.

      I know that you can mirror packagist. But is there currently an official mirror of packagist? If packagist.org goes down now, is there an alternative mirror with all meta informations?

  7. I notice that you haven’t included Nuget, which is a pretty good package manager for C#. Is this List exclusively for open tools ? Even if it is Nuget being open source is a valid contender. just my 2 cents

    • Hi Vivek. I didn’t explicitly exclude Nuget! There are many other application level package managers like Nuget and CPAN. I just didn’t had time to check them out closely. But I will do it in the next months and in the next comparison Nuget will be included.

      • Thanks Robert, Looking forward to it! Now if you’ll excuse me I’ll have to the get my beer promised to me by Microsoft ;)

  8. If you intend to investigate more package managers, I’d like to raise your attention towards Quicklisp, which is the package manager for Common Lisp, and which has been extremely useful in helping both newcomers and old-timers find and install libraries. Before QL, this was an incredibly cumbersome process which has now been replaced by a single command. More information here: http://www.quicklisp.org/

  9. Has anybody ever tried to solve this problem in a language independent fashion?

    To a very limited extent, RubyGems is used outside of Ruby. There are plenty of “Ruby” gems out there that are essentially just wrappers around a JavaScript or CSS library, allowing for that library to be included in Rails’ asset management.

    • Very good point. A language agnostic package manager would make my life much easier :-)

      As far as I know there is currently no language agnostic package manager. I know that Sonatype tries to integrate Ruby into their Maven Repository System (Java). Another good candidate would be npmjs, because they store packages as tgz files, basically simple zip files. Currently the zip files contain JavaScript code and a json file with meta information. I would prefer NPM or RubyGems because they are both less complex then Maven.

  10. Gradle and IVY don’t require a maven backend. The can consume it, but they don’t require it. There are seperate Gradle and IVY backends, which are similar to Maven backends, but not quite the same. IVY handles SNAPSHOTS much different then Maven for example. Gradle was originally based on Ivy, but has since moved on to it’s own slightly different backend.

    • I just added an additional sentence for that to the article. Sure Ivy and Gradle can handle different repo types. But in the official Ivy documentation, the quick starter they write: “Ivy uses the maven 2 repository to resolve the dependencies you declare in an Ivy file”. And somehow that makes sense because you want to take advantage of existing artifacts in the central Maven repository.
      There is a lot to say to Java build & dependency tools. But the article is already long enough and I just gave a very short intro to this tools. I hope it was anyway good brain food :)

  11. One thing I am missing from maven pom parsing is a list of the included plugins. While those are not libraries in the strictest sense of the word, nevertheless they influence the build result of your software and therefore deserve to be tracked as well.

  12. I would love if the maven pom parser could extract maven plugins from the poms as well. While not libraries in the strictest sense of the word, plugins influence the result of your build in a major way as well, so I feel they deserve tracking too.

    What I really don’t know is how well something like https://github.com/apache/maven-plugins or git://git.apache.org/maven-plugins.git can be tracked by versioneye, though.

    • Totally agree on that. I guess I will write a separate blog post about bower with more details. Bower is currently really not perfect. But it’s a very young project. There is a lot of room for improvements and I hope they will come soon.

  13. Composer/PHP does not support multithreading or multiprocess downloads due to no native support in the PHP language itself. This is a huge issue (con) when you have many package dependencies in your project, it can take literally forever to download. I’ve also found many inconsistent issues when trying to update projects by having to manually clear composer caches with rm -rf etc.

    The no signature thing is major. With so many projects and developers trusting these repositories they need to get their act together and quickly.

    Other than signatures, what are these package manager repositories doing in terms of mitigating actual malicious packages themselves? Are they performing any type of code analysis? I highly doubt it. Everyone’s blindly trusting the other which can be extremely dangerous.

    Basically no mater what package manager you use, do not use it on your production systems, in any circumstance. Other than high probability of stuff breaking, someone needs to actually look at what the hell it has pulled down in to your codebase to be pushed up…

    • Code analyses is not the job of a package manager.
      If you don’t use any package manager how do you deal with open source libraries? Do you download them with your browser? How is that better? Or do you don’t use open source libraries at all?

      • I’m not advocating to not use a package manager. For a developer, they are fantastic. I’m saying that it’s a common threat between all languages that security seems to be last on the list. This is unfortunate. I could argue that Google isn’t an antivirus company yet they provide Google Safe Browsing project to keep people away from unsafe websites. Others have even used this in their products (multiple browsers, etc). http://en.wikipedia.org/wiki/Google_Safe_Browsing

        Attacks are getting more sophisticated and if someone managed to add a backdoor to one of the top projects to any of the mentioned language package managers, the damage would be massive.

        App stores also verify the integrity of applications to keep users safe. Personally I see package managers as being no different.

        I think this type of thing will come as more people become aware and require more security.

      • OK. Now I get your point. And it’s totally valid!
        But I didn’t missed that. Security is part of this comparison. In the infographic there is a column “signed”. If there is a blue dot in that column then the packages on the server are cryptographically signed and with the public key of the author you can check that the package was not manipulated. You still have to trust the author of the package, but at least you can be sure that the package was not modified by a 3rd party. Unfortunately Maven and Lein are the only 2 ones who are enforcing signing. Most of the other package managers have that feature, too, but they don’t enforce it.

  14. Day to day at work I mostly use Cocoapods which I am very happy with. I had to unfortunatly spend some time getting to know Maven. I liked your review because it made me not feel stupid about feeling overwhelmed and confused by it. But I think Go might potentially have the best system, since they have integrated it very well with the language. A source code file just link directly to github for libraries it depends on. So essentially a go project does not need any configuration files either for building or package management. It still has a few rough edges but this seems to be the way to go. It helps that they have thought about this from the very start.

    • No! You are not stupid ;-)

      I still have to check out go. People told me already about that feature. But how does that work with versioning? Do you always point to the master head? That can be dangerous, specially if the code is under active development. I guess you can also point to tags of a git repo. Right?

      • Last time I checked it was like that. Hence my “a few rough edges”. So I think people often clone repos today to keep better control. Apparently the (current) “go way” is to create a new repo path when your library is no longer compatible.

        You can fetch repos directly with git if you want a specific version though. But I agree this is a little primitive compared to having say a Cocoa Pods file specifying all the versions you are using.

        Btw I also think the Julia package system would be worth checking out. I program in Julia at the moment, but I can’t say I have quite understood the package system yet. But what I find intersting there is that you typically don’t use an external tool to fetch packages. You just add packages from the Julia command line (REPL). Like Cocoapods and Go they also build their package system on top of git.

      • I’m still not sure if I like package managers based on git. The disadvantage is that the package manager is not anymore in control of the artifacts. The owner of the repository can every time delete a tag. And the tags are not signed.

  15. It appears nobody has mentioned Cabal yet, which is the corresponding tool for Haskell. You might want to include it if and when you review a larger set.

    • It’s not easy to pick the right columns. Everybody wants to see something else. But obviously JSON is hip nowadays and XML was hip 10 years ago. The column is just a result of Zeitgeist.
      But which other feature would like to see instead of JSON?

  16. Nice writeup. I use Maven mostly and I have to agree with all the cons you’ve listed. I’ve used Ivy on top of it sometimes and it is a bit nicer to manage but it only helps with some of the problems.

    I’ve used Dart’s Pub manager as well and I really like the approach.It’s still young and missing some features but compared to Maven it’s heaven. Would be interested to see it included in the next write-up.

    • Thanks for the Feedback :-)
      I can not promise you that Pub will be included in the next comparison. First of all we have to take care of Nuget and CPAN. But Pub is on my radar ;-)

  17. When you write your follow-up article, you might find this comparison table I made useful: https://docs.google.com/spreadsheet/lv?key=0AnVCQSzTU_medDBUWTM2cGJodkYwUXdPZ3NJT3hycFE&usp=drive_web

    And I second the calls above from Perl hackers to talk about testing infrastructure. CPAN Testers (a crowdsourced run-your-tests-on-platforms-you’ve-never-heard-of system, see http://static.cpantesters.org/) is a thing of wonder, and I don’t believe any other language’s packaging system has anything like it – but they should!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s