package locswijch

  1. Overview
  2. Docs
Bidirectional bridge between dune pkg and opam switches

Install

dune-project
 Dependency

Authors

Maintainers

Sources

v0.1.1.tar.gz
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:

  1. Working opam switch — tools like ocamllsp, merlin, and utop can find packages via the standard opam switch mechanism.
  2. Backup of dune.lock/ and _build/.pkg/ — survives dune clean (and even deletion of dune.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 cache

Migrating 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 backup

Day-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 containing dune-project.

How it works

Sync

  1. Enumerates _build/_private/default/.pkg/<name>.<ver>-<digest>/ directories, keeping only the digest dirs the current dune.lock builds (asked via dune pkg print-digest, never recomputed). Stale digest dirs — accumulated across migrate iterations — are deleted from both _build/.pkg/ and the switch store; if the dune in PATH lacks print-digest, pruning is skipped with a warning and everything is synced as before.
  2. For each package with a target/ subdirectory:

    • Hard-links files into the switch prefix (lib/, bin/, etc.).
    • Generates an .install manifest listing which files belong to this package.
    • Copies the binary cookie file to .opam-switch/locswijch/.
  3. Generates opam metadata: switch-config, switch-state, per-package .opam files, environment.
  4. Registers the switch in ~/.opam/config.

Restore

  1. Reads stored digest directory names from .opam-switch/locswijch/.
  2. For each package, recreates the _build/.pkg/<digest>/target/ tree by hard-linking files back from the switch, using .install manifests to attribute files to packages.
  3. 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 build

Testing

dune runtest

Runs 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 by dune clean) regardless of the restored targets. Use DUNE_CACHE=enabled for that; restore recovers 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 sync is 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 PATH orchestrates: trip and sync invoke plain dune, deliberately not opam exec -- dune — opam would resolve the switch from the target project's directory, and a project with a local _opam would 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, ...) whose dune-project says (lang dune 3.24).
  • Filters are evaluated for the migrating host: os/arch conditions in opam build commands and dependencies are resolved at migrate time (the switch's solution is host-specific anyway). The generated dune.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)

  1. opam-file-format >= "2.1.3"
  2. cmdliner >= "1.1.0"
  3. dune >= "3.0"
  4. ocaml >= "4.14.0"

Dev Dependencies (1)

  1. odoc with-doc

Used by

None

Conflicts

None