Streaming findlib META file codec for OCaml
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

OCaml 97.0%
Dune 0.9%
Other 2.1%
11 1 0

Clone this repository

https://tangled.org/gazagnaire.org/ocaml-meta https://tangled.org/did:plc:jhift2vwcxhou52p3sewcrpx/ocaml-meta
git@git.recoil.org:gazagnaire.org/ocaml-meta git@git.recoil.org:did:plc:jhift2vwcxhou52p3sewcrpx/ocaml-meta

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

ocaml-meta#

A type-safe codec library for findlib META files, using a combinator-based approach inspired by Jsont and the conventions of ocaml-opam and ocaml-json.

Layout#

  • lib/ — value AST, lexer, parser, printer, codec combinators.
  • lib/bytesrw/ — streaming I/O via Bytesrw.

Installation#

Install with opam:

opam install nox-meta

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 nox-meta

For Eio, combine with bytesrw-eio:

let read_meta_from_flow flow =
  let r = Bytesrw_eio.bytes_reader_of_flow flow in
  Meta_bytesrw.of_reader r

For Unix channels, use Bytesrw directly:

let read_meta_from_path path =
  let r = Bytesrw.Bytes.Reader.of_in_channel (open_in path) in
  Meta_bytesrw.of_reader ~file:path r

## Quick start

Define a codec for a record:

```ocaml
type pkg = {
  description : string;
  version : string;
  requires : string list;
  archives : (string list * string) list;
}

let space_list =
  Meta.map ~kind:"space-list"
    ~dec:(fun s ->
      List.filter (( <> ) "") (String.split_on_char ' ' s))
    ~enc:(String.concat " ")
    Meta.string

let pkg_codec : pkg Meta.File.t =
  Meta.File.(
    obj (fun description version requires archives ->
      { description; version; requires; archives })
    |> field "description" Meta.string ~enc:(fun p -> p.description)
    |> field "version"     Meta.string ~enc:(fun p -> p.version)
    |> field "requires"    space_list
         ~dec_absent:[] ~enc:(fun p -> p.requires)
    |> field_all "archive" space_list
         ~dec_absent:[] ~enc:(fun p -> p.archives)
    |> finish)

let decode_pkg input =
  match Meta.decode_string pkg_codec input with
  | Ok pkg -> pkg
  | Error e -> failwith (Meta.Error.to_string e)

For raw value parsing without codecs, use Meta_bytesrw.of_string / of_reader.

Grammar#

findlib META files describe a package's installed artefacts:

description = "My library"
version = "1.0"
requires = "base fmt"
requires(byte) = "base fmt"
archive(byte) = "mylib.cma"
archive(native) = "mylib.cmxa"

package "sub" (
  requires = "mylib"
  archive(byte) = "mylib_sub.cma"
)

Values are always double-quoted strings; predicate-guarded assignments like archive(byte,mt) = ... select an entry at query time. Subpackages nest inside package "name" ( ... ).

Errors#

Errors carry a Loc.t source location. Typed kinds live as extensions of Loc.Error.kind:

let report_error s =
  match Meta.decode_string pkg_codec s with
| Ok _ -> ()
| Error (_, _, Meta.Error.Missing_field name) ->
    Fmt.pr "missing %s@." name
| Error e -> prerr_endline (Meta.Error.to_string e)

References#