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.91.1392"}}}}}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 filesThe 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 updateThe 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. Pool :local/root
paths are workspace-root-relative, so Rig rewrites them to module-relative
paths before the merge. A module's own :local/root is already
module-relative, and Rig keeps it as-is.
3. Lock and surface the remaining drift#
rig lock
rig checkThe 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:
rig update org.clojure/test.check 1.1.1 # settle a cross-module version4. 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 |