Ecosystem: Library Development and Distribution with Leiningen
This short guide covers how to create your own typical pure Clojure library and distribute it to the community via Clojars. It uses Clojure 1.10 and Leiningen 2.9.1, and requires you have git installed (though very little familiarity with git is required).
It's assumed that you're already somewhat familiar with Clojure. If not, see the Getting Started and Introduction guides.
For the purposes of this guide, the library we'll be making is named "trivial-library-example".
This work is licensed under a Creative Commons Attribution 3.0 Unported License (including images & stylesheets). The source is available on Github.
Create the Project
Create your new library project. Names are usually hyphen-separated lowercase words:
lein new trivial-library-example
cd trivial-library-example
Typical lein usage is lein new <proj-type> <proj-name>
, but if you
leave out <proj-type>
(as we've done above), lein defaults to
creating a library project for you.
Our trivial library example project will have a dependency on flatland's "useful" library.
Open up our new project.clj file and make a few changes:
- Add our dependency (
[org.flatland/useful "0.9.0"]
) to the:dependencies
vector. - Remove "-SNAPSHOT" from version string.
- Write a short description.
- Add a url (if not a homepage, then where it's source is hosted online).
- If you're using a different license, change the value for
:license
.
Regarding your choice of license, probably the three most common for Clojure libs (along with a grossly oversimplified blurb (by this author) for each) are:
- The Eclipse Public License (the default).
- The LGPL (focused most on code and additions always being free; includes language addressing s/w patent concerns). See the FSF's recommendations and their instructions for use.
- The MIT License (focused most on the user's freedom to do what they want with the code). The FSF calls this the "Expat" License.
Whichever one you choose, update your project.clj (if necessary) to reflect that choice and save the text of the license as a file named "LICENSE" or "COPYING" in your project directory.
A Note Regarding Project Naming
The top line of your project.clj includes something like defproject my-project-name
. This means that your project has an artifact-id
of "my-project-name", but it also implies a group-id of
"my-project-name" (group-id = artifact-id).
The artifact-id is the name of your project. The group-id is used for namespacing (not the same thing as Clojure namespaces) --- it identifies to which group/organization a project belongs. Some examples of group-id's: clojurewerkz, sonian, and org.your-domain.
You may choose to explicitly use a group-id for your project, if you like. For example:
(defproject org.my-domain/my-project-name ...
...)
The maintainers of Clojars require that new libs be published using verified groups, such as org.my-domain.
Read more about groups at https://github.com/clojars/clojars-web/wiki/Groups.
Update the README
Aside from providing a good overview, rationale, and introduction at the top, you're encouraged to provide some usage examples as well. A link to the lib's (future) Clojars page (which we'll get to below) might also be appreciated. Add acknowledgements near the end, if appropriate. Adjust the copyright and license info at the bottom of the README as needed.
Lein provides you with a doc directory and a starter doc/intro.md file. If you find that you have more to say than will comfortably fit into the README.md, consider moving content into the doc dir.
Other goodies you might include in your README.md or doc/*.md files: tutorial, news, bugs, limitations, alternatives, troubleshooting, configuration.
Note that you generally won't add hand-written API documentation into your readme or other docs, as there are tools for creating that directly from your source (discussed later).
Create your project's local git repository
Before going much further, you probably want to get your project under
version control. Make sure you've got git installed and configured to
know your name and email address (i.e., that at some point you've run
git config --global user.name "Your Name"
and
git config --global user.email "your-email@somewhere.org"
).
Then, in your project dir, run:
git init
git add .
git commit -m "The initial commit."
At any time after you've made changes and want to inspect them and commit them to the repository:
git diff
git add -p
git commit -m "The commit message."
Write Tests
In test/trivial_library_example/core_test.clj, add tests as needed. An example is provided in there to get you started.
Write Code
Write code to make your tests pass.
Remember to add a note at the top of each file indicating copyright and the license under which the code is distributed.
Run Tests
In your project dir:
lein test
Commit any remaining changes
Before continuing to the next step, make sure all tests pass and
you've committed all your changes. Check to see the status of your
repo at any time with git status
and view changes with git diff
.
Create github project and Upload there
This guide makes use of github to host your project code. If you don't already have a github account, create one, then log into it. Github provides good documentation on how to get started and how to create an SSH key pair. If you haven't already done so, get that set up before continuing.
Create a new repo there for your project using the icon/button/link near the top-right.
You will have your local repository, and also a remote duplicate of it at github.
For the repository name, use the same name as your project directory. Provide a one-line description and hit "Create repository".
Once this remote repo has been created, follow the instructions on the
resulting page to "Push an existing repository from the command
line". You'll of course run the git
commands from your project
directory:
git remote add origin git@github.com:uvtc/trivial-library-example.git
git push -u origin master
You can now access your online repo. For this tutorial, it's https://github.com/uvtc/trivial-library-example.
Any changes you commit to your local repository can now be pushed to the remote one at github:
# work work work
git add -p
git commit -m "commit message here"
git push
Create a GPG key for signing your releases
You'll need to create a gpg key pair, which will be used by lein to sign any release you make to Clojars. Make sure you've got gpg installed and kick the tires:
gpg --list-keys
(The first time that command is run, you'll see some notices about it creating necessary files in your home dir.)
To create a key pair:
gpg --gen-key
Take the default key type (RSA and RSA), and default key size (2048). When asked for how long the key should remain valid, choose a year or two. Give it your real name and email address. When it prompts you for a comment, you might add one as it can be helpful if you have multiple keys to keep track of. When prompted for a passphrase, come up with one that is different from the one used with your ssh key.
When gpg has completed generating your keypair, you can have it list what keys it knows about:
gpg --list-keys
We'll use that public key in the next section.
Upload to Clojars
If you don't already have an account at https://clojars.org/, create one. After doing so, you'll need to supply your ssh and gpg public keys to Clojars. For the ssh public key, you can use the same one as used with github. For the gpg public key, get it by running:
gpg --export -a <your-key-id>
where <your-key-id>
is in the output of gpg --list-keys
(the
8-character part following the forward slash on the line starting with
"pub"). Copy/paste that output (including the "-----BEGIN PGP PUBLIC
KEY BLOCK-----" and "-----END PGP PUBLIC KEY BLOCK-----") into the
form on your Clojars profile page.
For more info on working with Clojars, see the Clojars wiki.
Once your Clojars account is all set up, and it has your public keys, upload your library to Clojars like so:
lein deploy clojars
You will be asked for your (Clojars) username and password.
Then you'll be asked for your gpg passphrase. (You won't be asked for
your ssh passphrase because lein deploy clojars
uses http rather
than scp --- though Clojars supports both.)
You should now be able to see your lib's Clojars page: for example, https://clojars.org/trivial-library-example!
Generate API docs (optional)
For larger library projects, you may want to automatically generate API docs (from your docstrings). See codox. If your library project is hosted at github, you can use github pages to host the resulting docs.
Announce (optional)
You're welcome to announce the availability of your new library on the Clojure Mailing List.
Make Updates to your library
Making updates to your lib follows the same pattern as described above:
# work test work test
# update version string in project.clj
git add -p
git commit
git push
lein deploy clojars
And optionally announce the release on the ML.
Merging pull-requests
Note that if you receive a pull-request at github, you can easily merge those changes into your project (right there, via the web page describing the pull-request). Afterwards, update your local repo to grab those changes as well:
git pull
See Also
For more detailed documentation on various aspects of the procedures described here, see:
- the Clojars wiki
- the Leiningen tutorial and deploy guide
Contributors
John Gabriele jmg3000@gmail.com (original author)