Overblog Suivre ce blog
Editer l'article Administration Créer mon blog
2 mars 2016 3 02 /03 /mars /2016 19:14

Chatting with a friend one of the last few days, I realized that Dub is an unknown tool, whereas it is certainly one of the best arguments in favor of D these days. I had to repair this injustice.


Introducing Dub

Dub, the D package manager is a masterpiece in D tooling world. It is the D counterpart to tools like Cargo in Rust, Pip in Python or CPAN in Perl.

Dub is written by Sönke Ludwig, the author of Vibe.d. It can be downloaded on http://code.dlang.org. There are different packages for different Linux distros, as well as precompiled binaries for Windows and OSX.

Dub replaces make and integrates with IDEs such as MonoDevelop's Mono-D plugin. It can also generate Visual D projects if you want to use Visual studio build system on Windows.

Creating a project

Let's suppose we want to create an awesome TodoList project. Our project will use sqlite to store lists. Let's create a project

$ mkdir todolist
$ cd todolist
$ dub init

The dub init command creates an empty project file named dub.sdl and a source directory containing an app.d source file:

.
        ├── dub.sdl
        └── source
            └── app.d

The source directory will contain the source code of your project. The app.d file is the file containing the main() function. For now, it is barely more thar a hello world file.

The dub.sdl file contains the project description in the SDLang (http://sdlang.org) format. This file could also be written in JSON in you prefer the JSON format. For now, its content is minimal:

name "todolist"
description "A minimal D application."
copyright "Copyright © 2016, olivier"
authors "olivier"

Dub homepage also contains a list of packages. By browsing them, you discover the d2sqlite3 package which is a binding to the sqlite C API. Let's tell Dub you want to use it in your project by adding the following line at the end of the dub.sdl file.

dependency "d2sqlite3" version=">=0.9.7"

Version 0.9.7 is the latest package version available at the time I write this post. The greater than sign before it tells Dub I want to be able to upgrade it to newer versions when they will be released. Let's try to build and run our project:

$ dub
Fetching d2sqlite3 0.9.7 (getting selected version)...
Placing d2sqlite3 0.9.7 to /home/olivier/.dub/packages/...
Performing "debug" build using dmd for x86_64.
d2sqlite3 0.9.7: building configuration "with-lib"...
todolist ~master: building configuration "application"...
Linking...
Running ./todolist
Edit source/app.d to start your project.

Let's explain what has just happened. Dub has downloaded the application dependency, the d2sqlite3 package. This package was put into a local dub registry and compiled. If this package also had other dependencies, they would had been fetched and compiled too. Fortunately, for the sake of our basic example, I selected package with no dependency. The application
was compiled with the DMD compiler in debug configuration. The last line shows the output of our program, telling us to edit source/app.d to start our project.

Editing the code

Let's listen to what dub says and edit the app.d file. First I will import the d2sqlite3 module.

import d2sqlite3;

Dub takes care of passing the path to the modules it downloaded to the compiler for us, so we don't have to bother rememebering where they are (they are put in my /home/olivier/.dub/packages directory). Let's create our database file.

private void createDatabase(string filename)
{
    auto db = Database(filename);
    db.begin();
    scope (success) db.commit();
    scope (failure) db.rollback();

    // create our tables
    createListTable(db);
    createEntryTable(db);
}

This code makes use of D's transactional features (AKA scope statement) to make sure the database is either committed or rolled back, but never half-baked. Let's now create our tables:

private void createListTable(ref Database db)
{
    db.execute(
        "CREATE TABLE LIST(
            LIST_ID INTEGER PRIMARY KEY AUTOINCREMENT,
            LIST_NAME TEXT UNIQUE
        )");
}

private void createEntryTable(ref Database db)
{
    db.execute(
        "CREATE TABLE ENTRY(
            ENTRY_ID INTEGER PRIMARY KEY AUTOINCREMENT,
            ENTRY_POSITION INTEGER,
            ENTRY_VALUE TEXT,
            ENTRY_LIST_ID INTEGER,
            FOREIGN KEY (ENTRY_LIST_ID) REFERENCES LIST(LIST_ID)
        )");
}

Again, nothing really complicated here, this is just plain SQL, as I don't want to distract you by introducing complex database bindings or ORMs. This code should be pretty straightfoward. A list has a name and contains entries which have a position in the list and a textual value. Entries store a reference to the list they belong to as a foreign key.

Let's call the createDatabase function from main:

import std.file;

void main()
{
    if (!exists("todo.db"))
        createDatabase("todo.db");
}

Save it and compile/run it again.

$ dub
Performing "debug" build using dmd for x86_64.
d2sqlite3 0.9.7: target for configuration "with-lib" is up to date.
todolist ~master: building configuration "application"...
Linking...
To force a rebuild of up-to-date targets, run again with --force.
Running ./todolist

Dub tells me that the sqlite package is still up to date (fortunately!), then rebuilds and run the application. I now have a 5 kB todo.db file in my directory containing my database, meaning that my code did work:

.
        ├── dub.sdl
        ├── dub.selections.json
        ├── source
        │   └── app.d
        ├── todo.db
        └── todolist

This is the end of our small example. Its purpose was simply to show how easy it is to integrate packages with dub and start coding. I leave to you the complete implementation of the TodoList application if you are interested in this.

Publishing packages

Publishing a Dub package is fairly easy. You have to publish your project on GitHub or BitBucket and to register it into Dub (you need a Dub account, which is free). Then anyone who adds the name of your project as a dependency in her/her dub.sdl project file will automatically have the content of your git repository available to his/her project. Whenever you want to release a new version, you'll simply have to create a git tag in your repository, and your users will be warned about a new release the next time they recompile their project.

At the time of this writing, the Dub package index contains about 700 packages.

Conclusion

I hope this post did interest you enough to go and check out the Dub documentation available at http://code.dlang.org. You'll learn a ton of things I did not cover in this post, such as creating libraries or running unit test builds.

Dub makes D development a lot easier by managing dependencies and letting the developer focus on the important thing: the code. It is a really nice tool that every D coder should be aware of.

Partager cet article

Repost 0
Published by Olivier - dans Programmation
commenter cet article

commentaires

Présentation

Recherche

Liens