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#
- findlib documentation: http://projects.camlcity.org/projects/dl/findlib-1.9.6/doc/guide-html/r759.html
META.5(man page shipped with findlib)