Irmin lwt shim#2406
Draft
balat wants to merge 26 commits into
Draft
Conversation
Adds opam metadata for [irmin-lwt] core and the eight backend / helper packages: [irmin-lwt-mem], [irmin-lwt-pack], [irmin-lwt-fs], [irmin-lwt-chunk], [irmin-lwt-containers], [irmin-lwt-git], [irmin-lwt-client], [irmin-lwt-tezos], plus the test harness [irmin-lwt-test].
This commit imports 83 module-type and module-implementation files from [main:src/irmin/], unchanged. They form the Lwt-typed surface layer of the shim: - Module types and signatures: read_only, append_only, indexable, content_addressable, atomic_write, contents, branch, node, commit, metadata, schema, slice, remote, sync, dot, watch, storage, lock, lru, store, store_properties, tree, proof, object_graph, hash, path, info, conf, key, perms, type, diff, merge, metrics, version, backend, plus their *_intf.ml siblings. - Implementation files imported verbatim: branch.ml, commit.ml, contents.ml, dot.ml, hash.ml, info.ml, lock.ml, lru.ml, metadata.ml, metrics.ml, node.ml, object_graph.ml, path.ml, perms.ml, proof.ml, remote.ml, schema.ml, slice.ml, storage.ml, store.ml, store_properties.ml, sync.ml, tree.ml, type.ml, watch.ml, plus the export_for_backends and import shims. Each file is byte-identical to its main:src/irmin/<basename> source at the time of import. Subsequent commits adapt them to the shim's needs (project-wide ocamlformat reformat, stripping of [Make] implementations, transparent re-exports of pure modules from Irmin 4, signature tweaks).
The Irmin 3 ([main]) sources imported in the previous commit were formatted under ocamlformat 0.26.2; the [eio] branch we are layering on top uses 0.29.0. [dune fmt] reformats the imported files to match the project's current style. No semantic change.
[Store.Make (B : Backend.S)] (~1300 lines, [main:src/irmin/store.ml]) and [Tree.Make (B : Backend.S)] (~2800 lines, [main:src/irmin/tree.ml]) are removed from the shim. They are not needed: a later commit adds [Wrap_store.Make], which wraps the already-built Eio [Generic_key.S] from [Inner] back into a Lwt-typed surface, delegating tree machinery to [Inner.Tree]. The two functor declarations are also removed from [Store_intf.Sigs] and [Tree_intf.Sigs]; only the module types stay. [Json_tree] and the [type Remote.t += Store of ...] constructor are preserved in [store.ml] (they operate on any [Store.S]). The rest of the file is reduced to [include Store_intf].
[main:src/irmin/store_properties.ml] declared a fresh [exception Closed]. With Irmin 4 layered underneath, exceptions raised by the Eio backend through [Lwt_eio.run_eio] would be of type [Irmin.Closed] (the Eio one), not the local fresh [Closed]. User code that wrote [Lwt.catch ... (function Irmin.Closed -> ...)] would silently miss those exceptions. Aliasing the local [Closed] to [Irmin.Closed] makes the two constructors equal -- pattern matching on either reaches the same exception value.
Twelve modules in [main:src/irmin/] are pure (no [Lwt.t] / [Merge.t] /
no Lwt-typed sub-stores in their signatures): they're identical in
shape between Irmin 3 and Irmin 4. Rather than carry a separate copy
in the shim, each is reduced to a one-line transparent re-export of
the Irmin 4 module. The list:
- [path.ml] -> [include Irmin.Path]
- [hash.ml] -> [include Irmin.Hash]
- [info.ml] -> [include Irmin.Info]
- [conf.ml] / [conf.mli] -> re-export [Irmin.Backend.Conf]
- [key.ml] -> [include Irmin.Key]
- [diff.ml] -> [include Irmin.Diff]
- [perms.ml] -> [include Irmin.Perms]
- [export_for_backends.ml] -> [include Irmin.Export_for_backends]
- [type.ml] -> [include Repr] + a small [Defaultable]
local type
- [metrics.ml] -> [include Irmin.Metrics]
- [append_only.ml] -> collapsed to [include Append_only_intf]
(alongside its existing [_intf.ml])
- [read_only.ml] -> collapsed to [include Read_only_intf]
…fication) Without this alias, the shim's [Remote.t] and [Irmin.remote] are two distinct extensible variants. Constructors added by Irmin 4 backends (notably [Backend.E of endpoint] inside any [Inner] store) cannot be re-exported from the shim's surface. Declaring [type t = Irmin.remote = ..] makes them the same type and lets [Wrap_store.Make] forward the inner [E] constructor with [type Remote.t += E = Inner.E].
A collection of bidirectional adapter functors between the shim's Lwt-typed module types and Irmin 4's Eio-typed module types. Each adapter wraps a function via [Lwt_eio.run_eio] (Eio direct -> Lwt.t) or [Lwt_eio.Promise.await_lwt] (Lwt.t -> Eio direct), depending on direction. Provides: - [merge_of_eio] / [merge_to_eio] -- bridge [Irmin.Merge.t] to / from [Merge.t] for a given type descriptor. - [Metadata] / [Contents] -- lift Lwt-typed Schema sub-modules to [Irmin.Metadata.S] / [Irmin.Contents.S]. - [Schema] / [Schema_extended] -- lift a Lwt [Schema.S] to [Irmin.Schema.S] / [Irmin.Schema.Extended] for backends like [Irmin_pack_unix.Maker] that need [Extended]. - [Indexable_of_eio] / [Atomic_write_of_eio] -- Eio store -> Lwt store wrappers, one operation per call. - [Indexable_to_eio] / [Atomic_write_to_eio] -- mirror direction. - [Content_addressable] / [Atomic_write] / [Append_only] -- Lwt Maker -> Eio Maker bridges, used to feed user-supplied Lwt backend Makers into [Irmin.Maker]. Used internally by [Wrap_store], [Maker_v2], and per-package shims.
…S (new code) [Wrap_store.Make (S : Schema.S) (Schema_eio : Irmin.Schema.S with ...) (Inner : Irmin.Generic_key.S with module Schema = Schema_eio)] produces a Lwt-typed [Generic_key.S] whose [Schema] is the user's input [S] and whose effectful operations forward to [Inner] through [Lwt_eio.run_eio]. This is the core of the shim. Every backend produced by [irmin-lwt] goes through it: the per-package shim builds an Eio [Inner] and passes it to [Wrap_store.Make] alongside the user's Lwt-typed [Schema] and a parallel Eio-typed [Schema_eio] (constructed via [Lwt_to_eio.Schema] or [Lwt_to_eio.Schema_extended]). Wraps: - types [repo, t, contents, contents_key, node_key, commit_key, hash, metadata, tree, ...] (passed through from [Inner]) - top-level read and write ops ([find / mem / set_exn / test_and_set / merge / ...]) - 35+ ops - [Repo] sub-module (v / close / heads / branches / batch / export / import / ...) - [Branch] sub-module (Atomic_write-like ops with watch callbacks bridged) - [Head] / [Commit] / [Info] / [Status] / [Hash] sub-modules - [Tree] sub-module (in-memory tree ops, sub-modules including [Proof] / [Private] / converters / [counters] hoisted to top for nominal type identity) - [Backend] sub-module (Slice with iter callbacks bridged, Branch re-exposed, Repo with batch bridged, Remote, plus Node and Commit with their merges bridged via [merge_of_eio]) - [Sync.E] forwarded as [Inner.E] for cross-store remote endpoints Result: the user gets a fully Lwt-flavoured [Generic_key.S] backed by an Irmin 4 store.
[Maker_v2.Make (CA) (AW) (S)] is the Lwt-flavoured [Irmin.Maker] implementation: module CA_eio (H) (V) = Lwt_to_eio.Content_addressable (CA) (H) (V) module AW_eio (K) (V) = Lwt_to_eio.Atomic_write (AW) (K) (V) module Schema_eio = Lwt_to_eio.Schema (S) module Inner_maker = Irmin.Maker (CA_eio) (AW_eio) module Inner = Inner_maker.Make (Schema_eio) include Wrap_store.Make (S) (Schema_eio) (Inner) The user's Lwt-typed sub-Makers are bridged to Eio, fed to [Irmin.Maker], and the resulting Eio store is wrapped back to a Lwt-typed [Generic_key.S] via [Wrap_store.Make].
The shim's public entry point. The .mli is structured like [main:src/irmin/irmin.mli] (same module layout, same modules exposed at top-level), so application code that targets [Irmin.X] in Irmin 3 can switch to [Irmin_lwt.X] with no other change. The .ml ties everything together: - [module Maker (CA) (AW) = struct ... module Make (S) = Maker_v2.Make (CA) (AW) (S) end] - [module KV_maker = Maker.Make o Schema.KV] - [Of_storage] using the Maker chain - [module Lwt_to_eio] / [module Wrap_store] re-exposed for downstream backend packages - [type remote = Remote.t = ..] - [module Sync] re-exposed - Closed alias re-exposed [Of_backend] and the [Generic_key.Maker] functor are intentionally *not* exposed -- see the documentation paragraphs in the .mli and [LIMITATIONS.md] (added in a later commit). Adds the [src/irmin-lwt/core/dune] file declaring the [irmin_lwt] library.
Imports [main:src/irmin-test/] into [src/irmin-lwt/test/] unchanged. The harness consumes a Lwt-typed [Irmin.S] / [Irmin.KV] and runs the standard Irmin test suite (Generic_key tests, store tests, watch tests, branch tests, etc.). Each file is byte-identical to its main:src/irmin-test source. The next commit adapts it to consume [Irmin_lwt] in place of [Irmin] and reformats it under the project's ocamlformat 0.29.0.
Three substantive patches (~120 lines effective across ~3700 lines): - [test/helpers.ml]: [module Irmin = Irmin_lwt] (replaces the [Irmin] reference in the harness with the shim's surface). - [test/import.ml]: add [include Lwt.Syntax] and [( >>= )] / [( >|= )] aliases used elsewhere in the harness. - [test/common.ml]: replace one call site that used [Irmin.Type.of_string (Conf.ty k)] with [Conf.of_string k] (the [Conf.ty] entry point exists on main but not on Irmin 4 -- the new [Conf] surface exposes [of_string] on each key directly, with the same semantics). Plus the dune file for the [irmin-lwt-test] library and an ocamlformat 0.29.0 reformat of the imported files.
Wraps [Irmin_mem]'s Append_only / Content_addressable / Atomic_write Makers, each operation forwarded through [Lwt_eio.run_eio]. Plugs the Lwt-typed Makers into [Irmin_lwt.Maker] and [Irmin_lwt.KV_maker]. Smoke test exercises: basic set/get, branches and commits, sync between two repos, [S.E] [Remote.t] constructor type-check, [Dot] output, and the full [irmin-lwt-test] harness on top (29/29 tests).
A Lwt shim over [Irmin_pack_unix]. The user's Lwt-typed [Schema.S]
is bridged to [Irmin.Schema.Extended] via
[Lwt_to_eio.Schema_extended], the inner Eio store is built with
[Irmin_pack_unix.Maker (Config).Make], and the result is re-wrapped
to a Lwt-typed [Generic_key.S] via [Wrap_store.Make].
[Maker.Make]'s output extends [Generic_key.S] with the irmin-pack-unix
specific surface, each Eio-direct effectful operation wrapped in
[Lwt.t] via [Lwt_eio.run_eio]:
- Integrity checks ([integrity_check], [integrity_check_inodes],
[traverse_pack_file], [test_traverse_pack_file]).
- Chunking / lower / on-disk ([split], [is_split_allowed],
[add_volume], [reload], [flush], [create_one_commit_store]).
- Statistics ([stats]).
- Garbage collection ([Gc.start_exn], [finalise_exn], [run] (with
[?finished] callback bridged), [wait], [cancel], [is_finished],
[behaviour], [is_allowed], [latest_gc_target]).
- Snapshots ([Snapshot.export] (with callback bridged),
[Snapshot.Import.{v, save_elt, close}], plus the pure data
types re-exported as type-equal to [Inner.Snapshot.*]).
A few entry points unavoidably leak Eio types because they take Eio
capabilities ([_ Eio.Domain_manager.t] for [Gc.start_exn] / [Gc.run]
/ [create_one_commit_store]; [Eio.Fs.dir_ty Eio.Path.t] for
[create_one_commit_store] / [Snapshot.export ?on_disk]); Lwt callers
must obtain these from their [Eio_main.run] runner.
Smoke test on a temporary directory: basic set/get, branch and
commit, persistence across reopen, plus the advanced surface
([flush], [integrity_check], [is_split_allowed], [Gc.is_allowed],
[Gc.is_finished], [stats]). [Gc.run] is not exercised by the smoke
test (would need a live [Eio.Domain_manager.t] and a non-trivial
repo state).
A Lwt-flavoured shim over [Irmin_fs_unix], mirroring the [irmin-lwt-mem] structure. Each Eio-direct operation in the Append_only and Atomic_write Makers is wrapped through [Lwt_eio.run_eio]; Content_addressable is derived from Append_only via [Irmin_lwt.Content_addressable.Make]; the result is plugged into [Irmin_lwt.Maker / KV_maker]. [config ~root ~clock] takes Eio types ([_ Eio.Path.t] and [_ Eio.Time.clock]) directly: the shim does not hide Eio in this entry point. Lwt callers obtain these from their [Eio_main.run] runner (typically [Eio.Stdenv.fs env] and [env#clock]). Smoke test on a temporary directory: basic set/get, branch and commit, persistence across reopen.
A Lwt-flavoured shim over [Irmin_chunk.Content_addressable], the meta-backend that stores values cut into fixed-size chunks on top of an [Append_only.Maker]. The functor takes a Lwt-typed [Irmin_lwt.Append_only.Maker], lifts it to its Eio counterpart through [Lwt_to_eio.Append_only], runs it through [Irmin_chunk.Content_addressable] to obtain an Eio [Irmin.Content_addressable.Maker], and bridges each operation back to Lwt via [Lwt_eio.run_eio]. [Irmin_chunk.Conf] and [config] are re-exported transparently. Smoke test combines chunking with [Irmin_lwt_mem]'s Append_only and Atomic_write to build a chunked KV store; writes a small (3-byte) and a large (5000-byte, above the chunk threshold) value, reads both back.
Lwt-flavoured port of [irmin-containers] for [irmin-lwt]. Each data structure is re-implemented on top of [Irmin_lwt]'s Lwt-typed Store API; the merge logic is reused from the Eio side ([Irmin.Merge.counter] for the counter; [Irmin.Merge.option (v t merge_eio)] for time-stamped values) and bridged to a [Merge.t] via [Irmin_lwt.Lwt_to_eio.merge_of_eio]. Modules: - [Counter] -- int64 counter with inc / dec / read. - [Lww_register] -- last-writer-wins register parameterised by a [Time.S] and a value type. - [Blob_log] -- append-only log of timestamped values. Each module exposes [.Make (Backend : Irmin_lwt.KV_maker)], plus [.FS] / [.Mem] instantiations on top of [Irmin_lwt_fs.KV] / [Irmin_lwt_mem.KV]. [Linked_log] from [irmin-containers] is not ported: its merge function performs reads on a content-addressable handle, and bridging that to Lwt would require threading a Lwt-typed CAS handle through the merge. Skipped for now.
A Lwt shim over [Irmin_git_unix]. The user provides a Lwt-typed [Contents.S]; the shim bridges it to Eio via [Lwt_to_eio.Contents], applies the git Maker, and wraps the resulting Eio store back to a Lwt-typed [Generic_key.S] via [Wrap_store.Make]. Git-specific extras ([module Git], [git_commit], [git_of_repo], [repo_of_git], [remote]) are passed through unchanged. The Lwt-side [Schema] reuses [Inner.Schema]'s pure modules (Hash, Branch, Info, Path) directly because their module types have no [Lwt.t] in either the Lwt or the Eio module type definitions. Only [Metadata] needs a Lwt-bridged [merge]. Exposes: - [Maker (G : Irmin_git.G)] producing [KV] / [Ref] convenience instantiations for any ocaml-git store. - [Mem] = [Maker (Irmin_git.Mem)] -- in-memory git store. - [FS] = [Maker (Git_unix.Store)] -- on-disk git store. Smoke test on Mem: basic set/get, branch and commit, [git_commit] passthrough verifying the underlying ocaml-git commit object is retrievable from a commit handle.
A Lwt shim over [Irmin_client_unix]. The user provides only a Lwt-typed [Contents.S]; the shim synthesises an Eio reference store ([Irmin_mem.KV.Make (V_eio)]) purely as a Schema carrier (the local mem backend is never used since the client routes all ops over the wire), feeds it to [Irmin_client_unix.Make_codec], and wraps the result back to [Irmin_lwt.Generic_key.S] via [Wrap_store.Make]. Client extras ([connect], [reconnect], [dup], [Batch], [export], [import], etc.) are passed through, with Eio-direct ones wrapped in [Lwt.t] for caller convenience. Modules: - [Make_codec (Codec) (V)] -- Make parameterised by codec. - [Make (V)] -- default binary codec. - [Make_json (V)] -- JSON codec. - [config] / [Error] re-exported from [Irmin_client_unix]. Smoke test spawns an [Irmin_server_unix] in an Eio fiber on a Unix-domain socket, connects with the Lwt client, runs basic set / get / find.
A Lwt shim exposing the Tezos-specific Irmin schema (BLAKE2B + Base58 hash, V1 pre-hashing for Node / Commit / Contents) on top of [irmin-pack-unix], with a Lwt-typed Store API. Implementation trick: instead of going through [Irmin_lwt_pack.Maker (Conf).Make] -- which would replace the Tezos Schema's V1 pre-hashing with the default [Generic_key.Make] via the [Lwt_to_eio.Schema_extended] adapter -- the shim uses [Irmin_tezos.Schema] directly as [Schema_eio] in [Wrap_store.Make], constructing in parallel a Lwt-side [Schema_lwt] that reuses [Schema.Hash / Branch / Info / Path] (pure modules, satisfy both Lwt and Eio Schema.S constraints) and bridges [Schema.Metadata.merge] and [Schema.Contents.merge] via [Lwt_to_eio.merge_of_eio]. The V1 pre-hashing is preserved end-to-end, so on-disk data is wire- compatible with regular [irmin-tezos] data. Smoke test: write a [bytes] value to a fresh temporary pack store and read it back.
Three documentation artefacts: - [doc/irmin-lwt/index.mld]: package landing page for irmin.org. Opens with a prominent warning that the main loop must be Eio (the central limitation of the shim: every operation goes through [Lwt_eio] and requires a running [Eio_main.run] scheduler at the top level). Lists each shim package with one usage example. - [doc/irmin-lwt/migration.mld]: step-by-step migration guide from Irmin 3 (Lwt) to Irmin 4 via the shim. Restructures the main loop, swaps opam deps, renames module references, adjusts the configurations that take Eio types directly, wires up the watch switch when needed, lists workarounds for the dropped entry points ([Of_backend], [Generic_key.Maker] functor). - [src/irmin-lwt/LIMITATIONS.md]: canonical list of what the shim does not support, with rationale for each entry ([Of_backend], [Generic_key.Maker] functor, [Watch.set_watch_switch] caveat, un-ported sister packages [graphql], [mirage], [cli], [server]).
Adds a [Irmin_lwt_test.Irmin_test.Suite] for [Irmin_lwt_fs] alongside the existing smoke tests. The full Irmin test suite (basic, branches, nodes, commits, slices, sync, watch, ...) runs against the filesystem backend and passes 28/28. Filesystem watching needs a [listen_dir_hook]; we bridge [Irmin_watcher.hook] (Lwt-typed) to [Irmin.Backend.Watch.hook] (Eio direct-style) and register it before [Lwt_eio.with_event_loop].
Combines [Irmin_lwt_chunk.Content_addressable (Irmin_lwt_mem.Append_only)] with [Irmin_lwt_mem.Atomic_write] to obtain a full [Irmin_lwt.Maker], and runs the harness on it: 29/29 tests pass.
…/28 tests) [Irmin_lwt_git.Mem.KV] satisfies [Irmin_test.Generic_key]; running the harness on it gives 28/28 tests passing (one less than mem because Git has no [Metadata.None] -- the suite skips one test).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
WIP. Not ready for review
This PR adds
irmin-lwt, a thin shim that exposes the familiar Lwt-typed Irmin 3 API on top of Irmin 4's direct-styleimplementation.
Important limitation: The application's main loop must be Eio:
TL;DR for reviewers — the PR is smaller than the diff suggests
The diff shows ~18 400 lines added. ~14 700 of them are mechanically verifiable copies of Irmin 3 source code, not new code to review. The remaining ~3 700 lines are the actual shim implementation plus tests, docs, and opam metadata.
If you have 30 minutes for this PR, read these commits only:
add Lwt_to_eio adapter functorsadd Wrap_storeGeneric_key.S. The core of the shim.add Maker_v2top-level Irmin_lwt.{ml,mli} + dune filemem,pack,fs,chunk,containers,git,client,tezos)Total to review carefully: ~3 050 lines.
The other commits are either pure file copies or trivial mechanical adaptations:
copy Lwt-typed Irmin 3 sources verbatim from mainmain:src/irmin/.git diff main:src/irmin/X src/irmin-lwt/core/X→ empty for each filereformat imported sources with project ocamlformat (0.29.0)dune fmtapplied (main is on 0.26.2).git show <commit> --statshows only the files touched bydune fmtstrip Store.Make and Tree.Make implementationsinclude Sigs. Reason: replaced byWrap_store.alias [Closed] to [Irmin.Closed]reduce non-Lwt modules to re-exports of Irmin 4include Irmin.X.alias [Remote.t] to [Irmin.remote]irmin-lwt-test: import Irmin 3 test harness verbatim from mainmain:src/irmin-test/.git diff main:src/irmin-test/X src/irmin-lwt/test/X→ emptyirmin-lwt-test: adapt harness to Irmin_lwt + reformatIrmin → Irmin_lwt, addLwt.Syntax, replace oneConf.tycall withConf.of_string), plus adune fmt.CHANGESand the doc commit.mld/.mddocsThe commits are designed so each can be reviewed independently with a clear acceptance criterion. The actual shim work is small; the rest is the necessary Irmin 3 Lwt-typed surface re-hosted to make the shim self-contained.
What's in this PR
Eight new opam packages, plus the core shim and a test harness:
irmin-lwtWrap_store/Lwt_to_eiomachineryirmin-lwt-testirmin-testfor Lwt-typed storesirmin-lwt-memirmin-lwt-packirmin-lwt-fsirmin-lwt-chunkirmin-lwt-containersirmin-lwt-gitirmin-lwt-clientirmin-serverirmin-lwt-tezosirmin-tezos)API users replace
Irmin.XwithIrmin_lwt.Xin their code; module shape, operation names and types are preserved (effectful ops returnLwt.t, like Irmin 3). A few configurations (config ~root ~clock,Gc.run ~domain_mgr,Snapshot.export ?on_disk) take Eio types directly; the shim does not hide Eio entirely.Architecture in two pieces
Lwt_to_eio(src/irmin-lwt/core/lwt_to_eio.ml) — a small library of bridge adapter functors between the shim's Lwt-typed module types and Irmin 4's Eio-typed counterparts. Each adapter wraps a function throughLwt_eio.run_eioorLwt_eio.Promise.await_lwt.Wrap_store(src/irmin-lwt/core/wrap_store.ml, ~800 lines) the heart of the shim. Takes a user's Lwt-typedSchema, a parallel Eio-typedSchema_eio, and an EioInner : Generic_key.S; produces a Lwt-typedGeneric_key.Swhose effectful operations forward toInnerthroughLwt_eio.run_eio. Every package goes through it.How to review
The history is structured for review-friendliness:
main:src/irmin/(byte-identical, easy to verify)dune fmtreformat (main is on ocamlformat 0.26.2, project is on 0.29.0)Store.Make/Tree.Make, aliasClosedtoIrmin.Closed, reduce non-Lwt modules toinclude Irmin.X, aliasRemote.ttoIrmin.remoteLwt_to_eio,Wrap_store,Maker_v2,Irmin_lwt.{ml,mli}+ duneirmin-lwt-testharness: verbatim copy frommain:src/irmin-test/then minor adaptations (module Irmin = Irmin_lwt,Conf.ty→Conf.of_string)mem,pack,fs,chunk,containers,git,client,tezos), each self-contained: lib + opam + smoke testdoc/irmin-lwt/index.mld+ migration guide +LIMITATIONS.md) andCHANGES.mdEach commit message states whether the change is a literal copy, a reformat, a small adaptation, or new code, with rationale.
What is not supported
Documented in
src/irmin-lwt/LIMITATIONS.md. Headlines:Of_backend— not exposed. Routing a hand-rolled Lwt-typedBackend.Sthrough Irmin 4 would require ~400 lines of bridges and a per-operation Lwt → Eio → Lwt round-trip. Backend authors should build againstIrmin's direct-styleBackend.Sand re-wrap withWrap_store.Make.Generic_key.Maker(functor) — the module type is exposed (so backends likeirmin-lwt-packdeclare against it); only the functor implementation is dropped, for the same round-trip reason.irmin-graphql,irmin-mirage*,irmin-cli,irmin-server— not ported.irmin-graphqlis already Lwt-typed upstream;irmin-mirage-gitis already Lwt-typed in its public API (Mirage_kv forces it);irmin-cliis a binary;irmin-serveris consumed viairmin-lwt-client.Tests
Each backend ships a smoke test under
test/irmin-lwt-<pkg>/test.ml. On top of the smoke tests, the fullirmin-testharness from main (ported asirmin-lwt-test) runs against four backends:irmin-testirmin-lwt-memirmin-lwt-fsirmin-lwt-chunkirmin-lwt-memAtomic_writeirmin-lwt-gitirmin-lwt-packPending_flushon concurrent close,Big Yikesvia Atomic_write watcher) — same constraints handled bymain:test/irmin-packwith a dedicated suiteirmin-lwt-containersGeneric_key.Sbackend (data structures)irmin-lwt-clientirmin-server, smoke spawns one in-processirmin-lwt-tezosContents = bytes; harness requiresContents.t = stringTotal: 114 harness tests + 9 dedicated smoke tests = 123 tests.
Sample run:
Migration
A step-by-step migration guide for users moving from Irmin 3 to Irmin 4 via the shim is in
doc/irmin-lwt/migration.mld.Code metrics