ERGO User Manual

Table of Contents


1 Introduction

ergo’ is a project dependencies management program and project builder. Given a project stored in a git repository, ‘ergo’ fetches the project and its dependencies (also git repositories), builds them, and loads, tests, or runs the project.

Any git repository, public or private, can be a project or a dependency: there is no central index to register with. Each project selects the versions of its dependencies (branch, tag, release, or commit), and the versions actually used are recorded in a lock file, so that builds are reproducible.

ergo’ provides three user interfaces:

Note: ‘ergo’ is under development; this manual documents the interfaces as designed. Cf. the specifications document for the current status.


2 Concepts


2.1 Projects and the Project File

A project is a git repository. It may contain an ‘ergo’ project file, ‘<name>.ergo’, listing its dependencies and the commands to build, test, and run it:

(ergo:project
 :designator   (gitlab "informatimago/clage")
 :dependencies ((github "sharplispers/ironclad"       :tag :latest)
                (github "sharplispers/split-sequence" :tag "v2.0.0")
                (gitlab "com-informatimago/com-informatimago"))
 :build (asdf "com.informatimago.clage")
 :test  (asdf "com.informatimago.clage.test")
 :run   (lisp "(clage:main)"))

For simple projects — a single asdf or alpm system — the project file may be omitted: ‘ergo’ scans the repository, finds the system definition file, and infers the dependencies from it.


2.2 Repository Designators

A project or a dependency is designated by one of:

  • the git url itself: ‘https://gitlab.com/com-informatimago/com-informatimago.git’ or ‘git@github.com:informatimago/lisp.git’;
  • a collection-qualified designator: the name of a collection and the path of the repository in it — ‘gitlab:owner/repo’ in the shell and AutoLISP syntax, ‘(gitlab "owner/repo")’ in Common Lisp;
  • a simplified designator: the path alone — ‘owner/repo’; the collections are searched, and when several match, you are asked to choose. Simplified designators are accepted interactively, but not in project files.

A version may be attached to the designator; without one, the repository’s default branch is tracked:

shell / AutoLISPCommon Lispmeaning
…@refactor:branch "refactor"a branch
…@v2.0.1:tag "v2.0.1"a tag
…@4d16a40…:commit "4d16a40…"a commit hash
…@latest:tag :latest’ or ‘:release :latestlatest tag or release

2.3 Collections

A collection is a named site serving git repositories: gitlab.com, github.com, a private gitlab or gitea instance, or a plain git server. The collection database is made of files of ‘ergo:define-collection’ forms, in three layers: built-in (distributed with ‘ergo’), site (the ‘ergo/collections.d/’ subdirectory of the ‘$XDG_CONFIG_DIRS’ directories), and user (‘$XDG_CONFIG_HOME/ergo/collections.d/’, ie. ‘~/.config/ergo/collections.d/’ by default). A user definition overrides a site or built-in definition with the same name.

;; ~/.config/ergo/collections.d/my-collections.lisp
(ergo:define-collection origin
  :kind       plain
  :git-user   "pjb"
  :git-server "git.informatimago.com"
  :git-root   "/srv/git/public")

ergo collections’ lists the database in search order.


2.4 The System-Name Index

A collection maps a repository path to a url; the system-name index maps a bare system name (‘alexandria’, ‘hunchentoot’) to a repository designator, so a dependency that ships no ‘.ergo’ file can still be found by name. It is made of ‘ergo:index-system’ forms, in the same three layers as the collection database (built-in, site, user); a higher layer overrides a lower one.

;; ~/.config/ergo/index.d/user.lisp
(ergo:index-system "my-lib" (git "https://example.org/me/my-lib.git"))

ergo index add <name> <designator>’ writes a user entry; ‘ergo index <name>’ shows the matches; ‘ergo search’ consults the index too.

The built-in layer is generated from the quicklisp-projects data (the same catalogue quicklisp uses), so ergo resolves the ~2300 git-hosted quicklisp libraries by name. Installing ‘ergo’ generates a fresh index into its built-in layer (‘make install’ runs the generator; opt out with ‘GENERATE_INDEX=0’, eg. for an offline build).

Quicklisp-projects is updated roughly monthly. Refresh your copy whenever you like — the way you update a quicklisp dist when you choose — by running the installed generator over a fresh checkout, writing to your user layer so it overrides the system one:

$ git clone --depth 1 https://github.com/quicklisp/quicklisp-projects.git
$ sbcl --script "$PREFIX/share/ergo/generate-quicklisp-index.lisp" \
        quicklisp-projects \
        ~/.config/ergo/index.d/quicklisp.lisp \
        ~/.config/ergo/index.d/quicklisp-skipped.txt

Sources quicklisp fetches by other means — tarballs, plain ‘http’ files, ‘svn’, ‘darcs’, ‘mercurial’ — are not git, so ergo cannot fetch them as-is; they are listed in the generator’s skip report, and you can give any of them a git mirror with an ‘ergo:index-system’ entry of your own, which — being in a higher layer — wins over the generated one.


2.5 The Lock File

The project file expresses intent, and may be loose: tracked branches, ‘latest’ tags. When ‘ergo’ resolves it, it writes the lock file, ‘<name>.erglock’, next to the project file: the complete dependency graph, with the exact commit of each dependency, direct or transitive.

Commit the lock file with your project. All the build, test, run, and load operations obey it exactly: everyone rebuilding the project gets the very same sources. The lock file changes only when you run ‘ergo update’ — review the diff, and commit it.


2.6 The Repository Cache

Clones are kept in a shared cache:

~/ergo/repositories/{collection}/{path}/{branch-or-tag-or-commit}/

Two projects requiring the same version of a dependency share the clone; requiring different versions, they use separate directories. Repositories with the same path in different collections (eg. ‘gitlab:foo/bar’ and ‘github:foo/bar’) are distinct and can coexist.


3 The ergo Command


3.1 Synopsis

ergo <subcommand> [option…] [argument…]

The command determines the current project by searching the current directory, then its ancestors, for a ‘*.ergo’ project file. Subcommands taking an optional designator default to the current project.


3.2 Common Options

-C <dir>

change to ‘<dir>’ before doing anything.

--project <file>

use ‘<file>’ as the project file.

--offline

use only the lock file and the local cache; fail rather than access the network.

--dry-run

report what would be done, without doing it.

--https

resolve collection-qualified designators (‘github:…’, ‘gitlab:…’, …) to their ‘https’ url. This is the default: an anonymous, read-only clone that needs no ssh key, which is what you want for fetching and in CI.

--ssh

resolve them to their ‘git@…’ (ssh) url instead, for push access — use it to clone a dependency you intend to edit and push back. A specific designator (‘(git "…")’) always keeps its own url; only the url synthesised from a collection changes. Because a repository’s identity is transport-independent, ‘--ssh’ and ‘--https’ share one cache entry and one lock entry: switching neither re-clones nor perturbs the lock. (An already-cached mirror keeps the transport it was first cloned with; remove it, or use a fresh cache, to re-clone over ssh.) The default can be set with ‘(ergo:configure :git-transport ssh)’.

-v’, ‘--verbose

show the underlying git and build commands.

--sexp

print the results as s-expressions, for tools.

-V’, ‘--version

print the ‘ergo’ version and exit.

-h’, ‘--help

print the usage and exit; after a subcommand (‘ergo build --help’), print the usage of that subcommand.

The version options ‘--branch <name>’, ‘--tag <name>’, ‘--release <name>’, and ‘--commit <hash>’ may be used instead of the ‘@<ref>’ suffix when the ref kind must be explicit.


3.3 Subcommands

ergo fetch [<designator>]

clone or pull the project and its dependencies, obeying the lock file; no build.

ergo build [<designator>]

fetch, then build the project and its dependencies.

ergo test [<designator>]

fetch, build, then run the tests.

ergo run [<designator>] [-- <argument>…]

fetch, build, then run the project; the arguments after ‘--’ are passed to the program.

ergo all [<designator>]

fetch, build, test, and if possible run.

ergo repl [<designator>]

start the interactive environment of the project with the project loaded: a Common Lisp REPL for asdf projects, an AutoLISP REPL for alpm projects, a shell in the project directory otherwise.

ergo update [<component>…]

re-resolve the loose designators of the project file — all of them, or only the given components — and rewrite the lock file.

ergo search <name>

search the collections for repositories matching ‘name’; ‘--collections <c1>,<c2>,…’ restricts the search.

ergo where-from [<component>]

report the provenance: url, branch, tag, or commit.

ergo where-is [<component>]

print the directory of the local clone.

ergo uninstall <designator>

drop one repository’s clone from the cache — its bare mirror and every per-ref worktree. Unlike ‘ergo gc’, which sweeps worktrees no lock still references, this removes one repository outright.

ergo search <name> --installed

restrict a search to the repositories already materialized in the local cache.

ergo status

report the current project, the freshness of the lock file, and any local modification in the clones.

ergo init [<designator>]

create an ‘ergo’ project file in the current directory, inferring the class of project and the dependencies; with a designator, fetch that project first.

ergo collections

list the collection database, in search order, with the layer providing each collection.

ergo clean

remove the build products of the project.


3.4 Exit Status

Subcommands exit with status 0 on success, and non-zero on failure; diagnostics are printed on the standard error stream.


3.5 Example Session

$ ergo search split-sequence
github:sharplispers/split-sequence   https://github.com/sharplispers/split-sequence.git

$ ergo init gitlab:informatimago/clage
$ ergo build
$ ergo test
$ ergo update cl-babel/babel
$ git diff clage.erglock
$ git commit -am 'Updated babel.'
$ ergo run -- --help

4 The Common Lisp Package

The ‘ERGO’ package provides the same operations inside a Common Lisp image; the loading operations load the systems into the current image, like ‘ql:quickload’.

Designators are given either as strings, in the same syntax as the command line (‘"gitlab:owner/repo@v1.2"’), or as forms: ‘(gitlab "owner/repo" :tag "v1.2")’, ‘(git "https://…/repo.git" :branch "dev")’.


4.1 Functions

(ergo:load designator)

fetch, build, and load the project into the current image.

(ergo:compile designator)

fetch and build (compile), without loading.

(ergo:test designator)

fetch, build, and run the tests.

(ergo:run designator)

fetch, build, load, and run the project, as specified by its ‘:run’ clause.

(ergo:ergo designator)

fetch, build, load, test, and if possible run.

(ergo:update &optional designator components)

re-resolve the loose designators and rewrite the lock file.

(ergo:reload designator)

re-read the project from its local clone and force-reload it into the image, offline — pick up local edits or a prior ‘ergo:update’ in a dev loop, the way quicklisp’s ‘clear-system’ + reload does.

(ergo:load/new-packages designator)

like ‘ergo:load’, but return the sorted names of the packages the load newly defined — a quick way to discover what a system provides.

(ergo:uninstall designator)

remove one repository’s clone from the cache; return the removed directory.

(ergo:search name &key collections)

search the collections; return the list of matches.

(ergo:where-from designator)

return the provenance (url, branch/tag/commit) of the project or component.

(ergo:project &key designator dependencies resolutions build load test run …)

the macro used in project files; cf. the Project File section above.

(ergo:define-collection name &key kind git-user git-server git-root git-extension api-url)

the macro used in the collection database files; cf. the Collections section above.


4.2 Session Example

(ergo:load "gitlab:com-informatimago/com-informatimago")
;; clones (or pulls) the repository and its dependencies,
;; compiles, and loads the systems into the image.

(ergo:test "github:sharplispers/split-sequence@v2.0.1")

(ergo:where-from "com-informatimago/com-informatimago")
;; → url, branch, and commit of the loaded version.

5 The AutoLISP Package

The ‘ergo’ AutoLISP package provides the same operations inside an AutoLISP engine: AutoCAD, BricsCAD, or clautolisp. It requires:

AutoLISP has no packages: the functions are prefixed with ‘ergo-’. Designators are given as strings, in the command line syntax.


5.1 Functions

(ergo-load <designator>)

fetch, build, and load the alpm system into the engine.

(ergo-reload <designator>)

force-reload the alpm system into the engine (pick up local edits or a prior ‘ergo-update’ without restarting).

(ergo-compile <designator>)

fetch and build, without loading.

(ergo-test <designator>)

fetch, build, and run the tests.

(ergo-run <designator>)

fetch, build, load, and run.

(ergo-update <designator>)

re-resolve and rewrite the lock file.

(ergo-uninstall <designator>)

remove the repository’s clone from the local cache.

(ergo-search <name>)

search the collections; return the list of matches.

(ergo-where-from <designator>)

return the provenance.


5.2 Session Example

(load "ergo.lsp")
(ergo-load "gitlab:informatimago/some-autolisp-library@v1.2")
;; the library and its dependencies are fetched and built by the
;; ergo command, then loaded into the engine with alpm.

6 Files

<name>.ergo

the project file: designator, dependencies, resolutions, build/test/run clauses. Written by the author (or generated by ‘ergo init’).

<name>.erglock

the lock file: the resolved dependency graph with exact commits. Generated by ‘ergo’; committed with the project; rewritten only by ‘ergo update’.

$XDG_CONFIG_HOME/ergo/’ (‘~/.config/ergo/’ by default)

the user configuration.

$XDG_CONFIG_HOME/ergo/collections.d/

the user layer of the collection database.

<dir>/ergo/collections.d/’ (for each ‘<dir>’ of ‘$XDG_CONFIG_DIRS’)

the site layer of the collection database.

~/ergo/repositories/

the shared cache of cloned repositories, indexed by collection, path, and version.