ocaml-project-index#
Index of packages, dune libraries, and modules in an OCaml project.
ocaml-project-index walks _opam/lib/, _build/install/default/lib/,
and the source tree of a project, then answers questions that tools keep
re-asking from raw filesystem state: which libraries a package provides,
which libraries a package's source tree depends on, whether a library is
only referenced from (test ...) stanzas, and which packages declare a
pin-depends:. The walk runs once; the resulting in-memory record is
queried by package, by typed package/library views, or by explicit
inventory queries such as libraries_of_name.
The library is the shared scanning layer behind several tools in the
blacksun monorepo: merlint dependency-declaration
rules and monopam publish and push. Any future linter or
package-management tool that needs opam-to-dune cross-references can build
on it without re-parsing .opam files.
Install#
$ opam install ocaml-project-index
If opam cannot find the package, it may not yet be released in the public
opam-repository. Add the overlay repository, then install it:
$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git
$ opam update
$ opam install ocaml-project-index
Usage#
Build an index once, query it many times:
open Project_index
(* Build the index once for the project rooted at [dir]. *)
let load fs dir = build ~fs ~monorepo:(Fpath.v dir) ()
(* Every package paired with the dune libraries it provides. *)
let package_libraries_by_name idx =
packages idx
|> List.filter_map (package idx)
|> List.map (fun pkg ->
(Package.name pkg, List.map Library.name (package_libraries pkg)))
(* Resolve a package's own [(libraries ...)] entries within its scope, so a
same-named private helper in another package can't leak in. *)
let resolve_uses idx pkg_name names =
match package idx pkg_name with
| None -> []
| Some pkg -> libraries_used_by pkg names
Find package documentation files that are not covered by an (mdx (files ...))
stanza:
let untested_package_docs idx pkg_name =
match package idx pkg_name with
| None -> []
| Some pkg ->
Package.doc_files pkg
|> List.filter (fun (doc : doc_file) -> not doc.mdx)
What's in the index#
Each entry is keyed by a package name. Source-tree packages can come from
.opam files, (package ...) stanzas in dune-project, or a package-less
pure dune project (name ...).
| Accessor | What it answers |
|---|---|
packages |
every package known to the index |
origin |
Local (locally built) or Opam (installed dep) |
libraries |
dune libraries provided by a package |
source_dir |
filesystem location of the package's source metadata |
tags |
tags: field of the .opam |
depends |
runtime depends: (skips {with-test} / {with-doc}) |
test_depends |
{with-test} deps only |
doc_depends |
{with-doc} deps only |
pin_depends |
(lhs, url) pairs from pin-depends: |
packages_with_pins |
packages whose .opam declares at least one pin-depends: |
raw_opam |
exact contents of the source-tree .opam |
raw_dune_project |
exact contents of the neighbouring dune-project |
library_source_dir |
directory of the dune file declaring a library |
library_libraries |
(libraries ...) field of a library's source stanza |
Package.doc_files |
package-root .md / .mld files, tagged with MDX coverage |
Library.doc_files |
library docs and .mli files, tagged with MDX coverage |
test_only_libraries |
libraries referenced only from (test ...) / (tests ...) stanzas |
runtime_library_uses |
libraries pulled in from (library ...) / public (executable ...) |
test_library_uses |
libraries pulled in from (test ...) / private (executable ...) |
package |
typed package view for package-scoped navigation |
package_libraries |
typed libraries provided by a package |
library_used_by |
resolve one already-observed (libraries ...) entry in a package's dependency cone |
libraries_used_by |
resolve multiple already-observed (libraries ...) entries in that cone |
libraries_of_name |
inventory lookup for all libraries with a name, preserving package identity |
source_files |
non-vendored source files by default; pass ~include_vendored:true |
Discovery sources#
The index combines three filesystem locations:
_opam/lib/<pkg>/holds opam-installed external dependencies._build/install/default/lib/<pkg>/holds locally built packages. It is scanned after_opam, so matching local builds replace installed package library metadata andorigincomes out asLocal.- The source tree is walked for
<dir>/<pkg>.opamfiles and packages declared bydune-project((package ...)or pure-project(name ...)) alongside theirdunefiles. This populatessource_dir, opam metadata when present,library_libraries,test_only_libraries, the raw file accessors, documentation files tagged by(mdx (files ...)), and the per-stanza-kind*_library_usesviews.
When _opam/<pkg>/ has a dune-package, the index reads it for the
authoritative library/module listing. Otherwise it falls back to a
*.cmi scan, which gets the top-level library and its module names but
not sub-library hierarchies (zarith.top etc.). The fallback is
sufficient for the "is this name in scope?" question that callers
typically have.
License#
ISC.