Managing multiple projects depending on different versions of
OpenLilyLib can sometimes get tricky. This post introduces a little
wrapper for lilypond, called
ollc, to automatically handle such
dependencies.


OpenLilyLib is
“a place to store and collaborate on LilyPond tools”,
similar in spirit to the
Lilypond Snippet Repository (LSR).
With respect to the LSR, its goal is to provide more flexibility for
both contributors and users, by allowing multi-file extensions,
scripts, etc., and by leveraging
git to provide version control and a
collaboration platform.

Regular OpenLilyLib users are encouraged to clone the OpenLilyLib
repository in a directory on their own machine (say in
~/openlilylib), and then include it in the scores that need some of
the extensions provided by OpenLilyLib. Suppose you are working on a
score, located in ~/scores/score1. To compile it including
OpenLilyLib code, you just have to issue the following command

$ cd ~/scores/score1
$ lilypond -I ~/openlilylib -I ~/openlilylib/ly score1.ly

The advantage of this approach (as opposed to copying and pasting code
in your own project) is that by performing a single git pull inside
the ~/openlilylib directory you get all the latest updates and
bugfixes, for all the projects including that directory. While this
is of great convenience, it can also be the source of some problems.

A motivating example

OpenLilyLib is undergoing a fundamental reorganization that involves,
among other things, renaming some files and changing the directory
structure, and changing the interface of some functions. Moreover,
some of the libraries provided by OpenLilyLib are not yet stable. For
instance,
GridLY
was just updated to version 0.6.0, which simplifies the public
interface a the cost of breaking backwards compatibility.

Now, imagine the following situation. You just finished working on the
previously mentioned score1 using a version of OpenLilyLib that
provides GridLY 0.5.0. You want to start a new score, say score2,
using the latest version of GridLY, i.e. 0.6.0. Hence you update
your OpenLilyLib clone

$ cd ~/openlilylib
$ git pull

and proceed to work on score2

$ cd ~/scores/score2
$ lilypond -I ~/openlilylib -I ~/openlilylib/ly score2.ly

Afterwards, you notice that there is a typo in score1 but, when you
try to fix it, your score no longer compiles, because the last update
pulled in some breaking changes! Now, you could follow the
migration guide
and update the source files of score1, however it is unlikely that
you want to spend time to do this upgrade only to fix a typo! Fear
not, for OpenLilyLib is versioned using git: you could just go
inside ~/openlilylib, inspect the output of git log, find the
commit that merged GridLY 0.6.0 into master, check it out, and then
recompile your score. It sounds like a lot of work to do, and indeed
it is. While it works, this solution is completely unacceptable.

A simpler solution…

Enter ollc, a tool to automate the
management of OpenLilyLib versions. This simple script is able to
clone the OpenLilyLib repository to a predefined location on its first
run, and adds to Lilypond’s include path all the relevant OpenLilyLib
directories. Most importantly, it keeps track of the version of
OpenLilyLib that was used to compile a score. This way, you are
guaranteed that each time you compile the same score you always use
the same version of OpenLilyLib, unless you explicitly want to
update to another version.

So, let’s see how this would work in the previous example. You are
working on score1, using a version of OpenLilyLib that provides
GridLY 0.5.0. You can compile the score with

$ cd ~/scores/score1
$ ollc score1.ly

The previous command will clone OpenLilyLib (if needed), it will invoke
lilypond to compile the score, and will create a file named
ollc.conf with the following contents

[repository]
revision = a1aab4eab7334ed95f9edf793e385bb05200fbd6

The revision string is the git revision of OpenLilyLib version used
to compile score1.

Now you start to work on score2. Since you want to work with the
latest version of GridLY in this score, you can compile the score with
this command

$ cd ~/scores/score2
$ ollc --rev master score2.ly

The --rev master option tells ollc to pull the latest changes from
the upstream branch master of OpenLilyLib. Again, the program
creates a file named ollc.conf with the following contents

[repository]
revision = 049ecdd5762c76573f5c58ae45db834f4be44f40

See how the git revision is different from the one stored in
~/scores/score1/ollc.conf?

Now, if you go back to score1 to fix some typos and compile the
score again, ollc will read the revision identifier from
ollc.conf. It will then checkout the local copy of OpenLilyLib to
that revision and add that version to Lilypond’s include path! Now
you can do any modifications you want without being forced to upgrade
your score’s sources, nor to manually handle the checouts of
OpenLilyLib. If at some point you want to upgrade score1 to the
latest OpenLilyLib version, you just have to call
ollc --rev master score1.ly and it will pull the latest changes,
overwriting the previous version of ollc.conf.

… but there’s still work to do

The approach adopted by ollc solves the problem of maintaining
multiple projects depending on different versions of
OpenLilyLib. However, it doesn’t handle the following use case, where
a score uses both GridLY and
ScholarLY. Suppose
that we want the latest version of ScholarLY, but we do not want to
upgrade GridLY. Unfortunately, we are stuck.

The solution to this problem requires the introduction of a full
featured package manager, whose discussion is beyond the scope of this
post.