Migrating from deps-modules¶
You share dependency versions across modules with deps-modules: a
:exoscale.deps/managed-dependencies map in the root deps.edn,
:exoscale.deps/inherit markers in the modules, and a merge-deps step
that rewrites the deps.edn files on disk. (If you also run
tools.project, see that guide. The steps here fit
inside its step 3.)
What you have today¶
Root deps.edn:
{:exoscale.deps/managed-dependencies
{org.clojure/clojure {:mvn/version "1.10.2"}
com.example/thing-core {:mvn/version "1.0.0"}
com.example/thing-not-core {:mvn/version "2.0.0" :exclusions [something/else]}}
:exoscale.deps/managed-aliases
{:dev {:extra-deps {lambdaisland/kaocha {:mvn/version "1.66.1034"}}}}}
Module deps.edn, before the merge:
{:paths ["src"]
:deps {org.clojure/clojure {:exoscale.deps/inherit :all}}
:aliases
{:dev {:extra-deps {com.example/thing-core {:exoscale.deps/inherit [:mvn/version]}
com.example/thing-not-core {:exoscale.deps/inherit :all}}}}}
And the sync step — run it after any change to the managed map, commit the rewritten files:
clj -T:deps-modules exoscale.deps-modules/merge-deps
# Writing deps.edn
# Writing modules/foo1/deps.edn
# Writing modules/foo2/deps.edn
# Done merging files
The limitation: the merged values live in two places (the managed map and the rewritten files), and nothing checks they agree. If you forget the step, or run a partial merge, the modules build against versions that are not the ones you declared centrally. The divergence stays invisible until something breaks.
What replaces it¶
Two files, one job each:
:rig/depsin the root — the requirements (versions you intend). You declare them once.rig checkreads them, andrig updatekeeps them in sync. Rig never merges them into a module classpath: each module still declares its own:deps.deps.lock— the pins (versions you actually build against), with hashes.rig lockwrites the file, you commit it, and every command checks it.
The migration itself does not create :rig/deps: rig migrate
materializes the pool into the :deps of the modules and drops it, so
each module stays self-contained. :rig/deps is what you opt into when
you want a shared requirement across modules (step 3 below).
There is no merge step. The tooling does not rewrite module manifests on
disk. The only manifest edits Rig makes are your explicit
rig add/update/remove (and the one-shot rig migrate),
format-preserving, in one visible diff. Drift is not invisible; it is a
named, reported condition:
check: warn [drift] modules/lib org.clojure/test.check: module requires "1.1.1", workspace requires "1.1.0"
check: error [stale-lock] modules/app com.example/shared: manifest requires "1.0.0"; lock pins "0.7.2" — run rig update
The migration¶
rig migrate does the mechanical part — steps 1 and 2 — in one command
(--dry-run first, then the real run), reporting every file it changes.
Each module ends up declaring what it declared before. The pool fills
only the keys a module left undeclared. A declared version/source key
wins over the pool. Each such win produces a warning, not a silent
rewrite. The migration does not fix the drift the managed map masked.
That is steps 3 and 4. Each step below describes one action and your
part in it:
1. Materialize the managed map into the modules, then drop it¶
Copy each pool entry into the :deps of every module that inherits it
(:exoscale.deps/inherit :all or a key subset). Drop any
:exoscale.deps/inherit markers on the entries themselves. They are
inert residue. A migrated manifest must carry no exoscale.* key
anywhere. Then delete the managed map, and delete
:exoscale.deps/managed-aliases. Rig has no alias inheritance, so
aliases are per-module. Shared test dependencies move to the :test
aliases of the modules, or to :rig/deps requirements:
migrate: deps.edn: :exoscale.deps/managed-dependencies dropped (versions materialized into the modules' :deps; not carried as :rig/deps shared requirements)
The next example shows a migrated module (trimmed). A comment notes the pool values the merge used to inject:
;; pool: org.clojure/clojure {:mvn/version "1.10.2"}
;; com.example/thing-core {:mvn/version "1.0.0"}
;; before
:deps {org.clojure/clojure {:exoscale.deps/inherit :all}
com.example/thing-core {:exoscale.deps/inherit [:mvn/version]
:exclusions [something/else]}}
;; after
:deps {org.clojure/clojure {:mvn/version "1.10.2"}
com.example/thing-core {:mvn/version "1.0.0"
:exclusions [something/else]}}
The pool does not become a root :rig/deps shared requirement. Pins no
module declared were inert in the old model, and a shared requirement
would turn them into live workspace-wide constraints. If you want the old
"single version file" back, add the shared requirements to :rig/deps
deliberately in step 3. rig update keeps them in sync with the modules.
2. Declared values win over the pool¶
Where a module declared a version/source key the pool also carries
(:mvn/version, :git/*, :local/root), Rig keeps the value of the
module. A repo whose CI never ran merge-deps built against the declared
versions, and the migration does not change what it built against. Each
such win over a differing pool value produces a per-dep warning:
migrate: modules/app/deps.edn: dep com.example/shared: :mvn/version "1.0.0" (managed "0.7.2") (declared kept; merge-deps would have used the managed value)
The pool still fills the keys the module did not declare. A vector
inherit selects a subset of the keys of the pool. A pool :local/root
is workspace-root-relative, so Rig rewrites it to a module-relative path
before the merge. A :local/root of a module is already module-relative,
and Rig keeps it as-is.
3. Lock and surface the remaining drift¶
The migration already warned about every declared-vs-managed divergence.
rig check compares each module requirement against the lock, and
against :rig/deps if you added shared requirements above. These are the
places the old model let diverge. Fix each finding deliberately:
4. Drop the tooling¶
- Remove the
merge-deps/merge-aliasesMakefile targets. There is no merge step anymore. - Remove the deps-modules alias /
clj -Tmdepsinstall from the toolchain. - If the managed
:projectalias existed to carry the:exoscale.deps/inheritmachinery of deps-modules into the:projectnamespace, it disappears with the tools.project migration.
What you lose, and why it is fine¶
| deps-modules feature | In Rig |
|---|---|
| single version file for all modules | :rig/deps — declared once, read at resolve time |
selective inheritance (:inherit [:mvn/version]) |
not needed: a module's own requirement map already expresses exactly what it wants; shared coordinates are aligned by rig update, not by rewriting |
alias synchronization (managed-aliases) |
not needed: aliases are per-module by design; shared test deps go through :rig/deps requirements + each module's :test alias |
dry-run? preview |
the manifest diff is the preview — rig update prints each edit before writing |
| comments/formatting preserved on merge | Rig never rewrites manifests except for your explicit dep edits, which are format-preserving |
| forgetting the sync step | no sync step exists; rig check fails loudly on drift instead |