package locswijch
Install
dune-project
Dependency
Authors
Maintainers
Sources
md5=45d3307da2ff22ee2a1a6c6a6c2ffa75
sha512=ee3658f4346b7b06700a9be7ab3920ba7f26285c79f677340efdf3ff2096a2f93aee68087dcee2060252e2acaac4f3d7ba17a9c6526bdd709c4891f54145f383
Description
dune pkg stores built packages in _build/.pkg/, invisible to the standard opam switch mechanism that tools like ocamllsp, merlin, and utop rely on. locswijch mirrors those built artifacts into a real opam switch using hard links, so editor tooling works unchanged, and the switch doubles as a backup of dune.lock/ and _build/.pkg/ that survives dune clean. Subcommands: sync (project to switch), restore (switch to project), migrate (opam switch to dune.lock/), and trip (end-to-end round-trip test).
Added to opam-repository:
README
locswijch
The uncomfortably obvious dependency bridge
Problem
dune pkg stores built packages in _build/, invisible to the standard opam switch mechanism that tools like ocamllsp, merlin, and utop rely on. And dune.lock/ plus the built artifacts live only in the project tree — there is no switch-level record to recover them from.
Solution
locswijch creates an opam switch that serves dual purpose:
- Working opam switch — tools like ocamllsp, merlin, and utop can find packages via the standard opam switch mechanism.
- Backup of
dune.lock/and_build/.pkg/— survivesdune clean(and even deletion ofdune.lock/) and can reconstruct both from switch metadata.
Hard links (same filesystem) make both sync and restore zero-cost in disk space. dune clean just decrements link counts; files survive in the switch. A design heresy, the human brain politely refises to process the full trauma of its functionality.
Note: instant rebuilds are dune's job, not locswijch's
Dune decides whether to re-run a rule from _build/.db, which dune clean deletes — restored target trees alone are never trusted, so a rebuild after restore re-executes every package rule. The fix is dune's own shared cache: run builds with DUNE_CACHE=enabled. The default cache mode (enabled-except-user-rules) excludes lock-dir package actions; with DUNE_CACHE=enabled a post-clean rebuild hard-links everything back from ~/.cache/dune/db in about a second. Use restore to recover the dune.lock/ + _build/.pkg/ state itself; use the dune cache for speed.
Commands
locswijch sync
Run after dune build. Hard-links package artifacts from _build/_private/default/.pkg/*/target/ into an opam switch prefix. Stores reconstruction metadata (cookie files, digest directory names, per-package .install manifests).
locswijch sync [--switch NAME] [--project DIR]locswijch restore
Run after dune clean (or after losing dune.lock/). Recreates dune.lock/ and _build/_private/default/.pkg/ from the switch via hard-links. Note that the next dune build does not trust the restored targets by themselves (see above) — pair with DUNE_CACHE=enabled for fast rebuilds.
locswijch restore [--switch NAME] [--project DIR]locswijch migrate
Generate dune.lock/ from an existing opam switch. This is a one-way translation of opam package metadata into dune's .pkg format. A full dune build is required afterward (the source artifacts must be fetched and compiled by dune), followed by locswijch sync to augment the switch as backup.
locswijch migrate [--switch NAME] [--project DIR]Typical workflows
New project using dune pkg
export DUNE_CACHE=enabled # let dune cache package builds too
# Initial setup
dune pkg lock
dune build
locswijch sync
# After dune clean
dune clean
locswijch restore # recover dune.lock/ + _build/.pkg/
dune build # ~1s — packages hard-linked from the dune cacheMigrating from opam to dune pkg
locswijch migrate --switch default
# Edit dune-project to declare dependencies
dune build # full rebuild (unavoidable)
locswijch sync # switch now serves as backupDay-to-day development
dune build # builds project + any new deps
locswijch sync # keep switch in sync (fast, idempotent)Options
--switch NAME,-s NAME— opam switch name. Defaults to project directory basename.--project DIR,-C DIR— project root. Defaults to nearest ancestor containingdune-project.
How it works
Sync
- Enumerates
_build/_private/default/.pkg/<name>.<ver>-<digest>/directories, keeping only the digest dirs the currentdune.lockbuilds (asked viadune pkg print-digest, never recomputed). Stale digest dirs — accumulated acrossmigrateiterations — are deleted from both_build/.pkg/and the switch store; if the dune inPATHlacksprint-digest, pruning is skipped with a warning and everything is synced as before. For each package with a
target/subdirectory:- Hard-links files into the switch prefix (
lib/,bin/, etc.). - Generates an
.installmanifest listing which files belong to this package. - Copies the binary cookie file to
.opam-switch/locswijch/.
- Hard-links files into the switch prefix (
- Generates opam metadata:
switch-config,switch-state, per-package.opamfiles,environment. - Registers the switch in
~/.opam/config.
Restore
- Reads stored digest directory names from
.opam-switch/locswijch/. - For each package, recreates the
_build/.pkg/<digest>/target/tree by hard-linking files back from the switch, using.installmanifests to attribute files to packages. - Copies cookie files back.
Cross-device fallback
If _build and ~/.opam are on different filesystems, hard links are impossible. The tool detects this and falls back to copying with a warning.
Building
opam install cmdliner opam-file-format
dune buildTesting
dune runtestRuns parser unit tests plus a self-contained end-to-end smoke test: a tiny two-package fixture closure (generated in a temp dir, no compiler, local sources) goes through the full migrate → build → sync → clean → restore → rebuild cycle, and the post-restore rebuild must beat a time threshold that a real package rebuild cannot meet. Requires opam and dune on PATH.
Limitations
- Restore does not make rebuilds instant: dune re-executes any rule absent from
_build/.db(deleted bydune clean) regardless of the restored targets. UseDUNE_CACHE=enabledfor that;restorerecovers state, not build time. - Cookie format coupling: dune's binary cookie format may change across versions. If it does, stored cookies become invalid and a full rebuild is needed (graceful degradation).
- No incremental sync: every
syncis a full re-sync. This is fast (hard-links are O(1) per file) but removes stale files from the switch. - migrate is approximate: the opam-to-dune translation covers common patterns but may not handle all opam build instructions perfectly.
- The dune on
PATHorchestrates:tripandsyncinvoke plaindune, deliberately notopam exec -- dune— opam would resolve the switch from the target project's directory, and a project with a local_opamwould supply its own (possibly older) dune. The invoking dune must support the locked dune's language version: locking dune ≥ 3.24 pulls in satellite packages (dune-configurator,ordering, ...) whosedune-projectsays(lang dune 3.24). - Filters are evaluated for the migrating host: os/arch conditions in opam build commands and dependencies are resolved at
migratetime (the switch's solution is host-specific anyway). The generateddune.lock/is not portable across operating systems.
AI disclosure
In the interest of transparency, and in keeping with the transparency principles of the EU Artificial Intelligence Act (Regulation (EU) 2024/1689):
- This repository was developed with substantial assistance from a generative AI system — Anthropic's Claude, used through the Claude Code agentic coding tool. AI assistance covered source code, tests, documentation, and design discussion. All AI-produced content was reviewed and is maintained under human direction; the maintainer is responsible for the contents of this repository.
- locswijch itself is not an AI system. It contains no machine-learning models and performs no AI inference at runtime. Its output is deterministic: hard-linked file trees and mechanical metadata translation between the dune pkg and opam switch formats. Consequently, locswijch does not fall within the scope of the AI Act's obligations for AI systems, and it produces no "AI-generated content" within the meaning of Article 50.
- This notice is a voluntary provenance disclosure. It is not a claim of formal certification or conformity assessment under the AI Act, which governs AI systems placed on the EU market rather than the use of AI as a development aid.
License
Released under the MIT License. © 2026 Cuihtlauac Alvarado.
Dependencies (4)
-
opam-file-format
>= "2.1.3" -
cmdliner
>= "1.1.0" -
dune
>= "3.0" -
ocaml
>= "4.14.0"
Dev Dependencies (1)
-
odoc
with-doc
Used by
None
Conflicts
None