User:Nathan M. Swan/DPM Proposal

From D Wiki
Jump to: navigation, search

This is a proposal for dpm, a D package manager. I don't want to start working on any code until I get feedback from the community.

It has these conflicting principles:

  • ease of use. If the package manager is complicated, you might as well use git and make alone.
  • almost backwards compatibility. Platforms are only as good as the software that uses them; therefore, it should be really easy to dpm-ize packages.
  • Turing-complete customization. D projects are full of automatic C binders, documentation generators, and other useful stuff that the package manager shouldn't get in the way of.


These are the main scenarios:

  • A package user installing/managing packages they import/run
  • A package creator creating/configuring packages they wrote
  • A build script doing things with the source/binary/headers/docs/whatever.

Installing packages


You enter the command:

   $ dpm install <package-name> [<package-version>] [from <cpr-name>]

And you can now either run the executable or import/link the library in other projects.


The repository can be a "genuine" or "pseudo" package. A genuine package has been created with dpm, which means that it simply follows the instructions of the dpm configuration file.

Pseudo-packages are D code repositories that have yet to use dpm. Because of this, it will open a shell in the top directory of the installed repository, telling the user they will have to install it manually, encouraging them to checkout the READMEs and INSTALLs it finds.

Genuine packages have a file dpmconfig.d at the top directory, which contains the code run to install the package. Technically, it can do what it wants, though it most likely will import dpm;, a separate D file compiled alongside it. That file will contain a series of useful functions for making it easy to program the config file, including ways to call common build methods like make or rdmd.

Creating packages


If this is an old project you're migrating over, you enter the command:

   $ dpm create template <build type>

If this is a new project:

   $ dpm create init <make | raw>


Migrating to dpm should be easy. Therefore, users with existing build options shouldn't have to redo it, just have dpmconfig.d call existing build code.

There will be a dpm command called create template, which automatically generates these configuration file templates:

   Template              Build Script
   make               -> make();
   make-install       -> make("install");
   make-make-install  -> make(); make("install");
   rdmd-build         -> rdmd("build.d");
   exec "code"        -> // executes "code"
   empty              -> // does nothing

The create init command can happen two ways: make will generate a Makefile, which has the advantage of not requiring dpm; or a raw file, which builds right from the config file script (with all the lovely dpm.d APIs).

The dpm.d API would contain various process-calling convenience functions, directory-scanning functions, and so on. One important function is:

    void depend(string repo, string version_="");

Which makes dpm install that package if it isn't there already.

It has a variant for non-D projects, which does a default system install (e.g. apt-get), e.g. gtk as a dependency for gtkD:

    void dependSys(string repo);

To ensure the right versioning requirements, this command generates dependency requests for every package dpm has installed:

   $ dpm freeze > commands.d

These can be edited down and pasted into the config file.


Example bare-bones config file:

import dpm;
void dpm_main() {

System Interface


Central Package Repositories


A package is simply a reference in a git repository. It can either refer to the tip of a branch, or a tag. They are referred to using this notation:

   <git repository url> [branch=<branch> | tag=<tag>]

The repository-url and branch/tag are respectively the package-name and package-version of the install command.

But directly specifying URLs can be inconvenient, so there can exist a CPR, a Central Package Repository. A CPR is simply a configured URL to which requests for a repository are sent. A system can be configured to have multiple CPRs.

CPR Management

Users can add/remove CPRs using the cpr add and cpr rm commands, respectively:

   dpm cpr add <name> <url>
   dpm cpr rm <name>

They are added like a LIFO stack, so when multiple CPRs give a successful resolution, the CPR most recently added is chosen.

The order can be changed with the dpm cpr store, which gives the filename for a CPR store:

    [vim | emacs] `dpm cpr store`

It is of the following format:

   <item1-name> <item1-url>
   <item2-name> <item2-url>

With the top items taking precedence.

Package Resolution Protocol

A request for package resolution is an HTTP POST request to the given URL, with the following application/json body:

    {"prp-version":"0.1", "name": "<name>", "version": "<version>"}

The response will have a status of 200 and a body of either

    {"prp-version":"0.1", "git-url": "<repo url>", ["branch": "<branch>" | "tag": "<tag>"]}


    {"prp-version":"0.1", "notfound-message": "<error message>"}

Sample packages

These are all popular D libraries (as far as I can tell), which I will use to test dpm's ease-of-use and flexibility: