This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

View file

@ -0,0 +1,37 @@
name: Main workflow
on:
pull_request:
push:
schedule:
# Prime the caches every Monday
- cron: 0 1 * * MON
jobs:
build:
strategy:
fail-fast: false
matrix:
os:
- macos-latest
- windows-latest
ocaml-compiler:
- 4.08.x
- 4.14.x
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Use OCaml ${{ matrix.ocaml-compiler }}
uses: ocaml/setup-ocaml@v2
with:
ocaml-compiler: ${{ matrix.ocaml-compiler }}
- run: opam install . --deps-only --with-test
- run: opam exec -- dune build
- run: opam exec -- dune runtest

View file

@ -0,0 +1,4 @@
_build/
.merlin
*.install
_opam/

View file

@ -0,0 +1,3 @@
profile = default
version = 0.23.0
ocaml-version = 4.08

View file

@ -0,0 +1,116 @@
## v4.0.0 (2025-02-17)
* Update to mirage-kv-mem 4.0.0 API changes (fewer functors) (#68 @hannesm)
## v3.3.1 (2022-08-05)
* Fixed a regression in v3.3.0 where periods ('.') had to be specified
in the extention list. (#62, @MisterDA, fixes #61 reported by @cemerick)
## v3.3.0 (2022-07-24)
* Open files in binary mode so buffers don't underread on Windows.
(#54, @jonahbeckford)
* Always use Unix-style paths for path keys (#58, @MisterDA)
* Add -s and --silent flags (#52, #60, @MisterDA)
* Add `hash` and `size` functions to the plain module (#53, #60, @MisterDA)
* Update to cmdliner 1.1 (#55, @MisterDA)
## v3.2.0 (2019-12-14)
* Make crunch reproducible: use a Map.Make(String) instead of Hashtbl.
Iterating over the former is guaranteed to be sorted over the keys.
(#51 @hannesm)
* The state (Map.t) is passed explicit to `scan_file`, `output_implementation`
and `walk_directory_tree`. The value `empty` is provided to construct an
empty `t`. (#51 @hannesm)
## v3.1.0 (2019-11-01)
* Adapt mirage-kv 3.0.0 interface (#50 @hannesm)
## v3.0.0 (2019-02-28)
* Implement the mirage-kv 2.0.0 interface, using mirage-kv-mem
(#47 @linse @hannesm)
* Removed no longer used size function (#47 @linse @hannesm)
## v2.2.0 (2019-02-05)
* Port to dune from jbuilder (#46 @hannesm)
* use `SOURCE_DATE_EPOCH` instead of gettimeofday if set to
support reproducible builds (#45 @xclerc)
## v2.1.0 (2017-06-24)
* Port to Jbuilder and simplify test dependencies (#38 by @rgrinberg)
## v2.0.0 (2016-02-24)
* Fix reading of files consisting of multiple pages (#30 by @hannesm)
* Port to MirageOS3 API: removed unused `id` type (#17), add Failure
error type (#20), `connect` does not return a result anymore.
* Generate a `mem` function for the filesystem (#18)
* Port to topkg and respect the odig packaging convention (#24 via @fgimenez)
* Add `LICENSE` file to repository (#19 via @djs55)
## v1.4.1 (2016-02-08)
* Use a poor-man `realpath` instead of relying on C bindings which are not
available under Cygwin
## v1.4.0 (2015-03-09)
* Add an explicit `connect` function to the signature of generated code. (#13)
* Use centralised Travis CI scripts.
## v1.3.0 (2014-03-08)
* Deduplicate file chunks so that only one copy of each
sector is allocated in the static module.
## v1.2.3 (2013-12-24)
* Fix compilation of 0-length files.
## v1.2.2 (2013-12-08)
* Use the `V1.KV_RO` signature from mirage-types>=0.5.0
* Add Travis CI scripts.
## v1.2.1 (2013-12-08)
* Generate the correct signature for `V1.KV_RO`.
## v1.2.0 (2013-12-08)
* Use the `V1.KV_RO` signature from mirage-types>=0.3.0
## v1.1.2 (2013-12-07)
* Do not skip files without an extension.
## v1.1.1 (2013-12-06)
* Bugfix release.
## v1.1.0 (2013-12-05)
* New release to adapt to the new mirage-types API
## v0.7.0 (2013-07-21)
* Add a `-nolwt` output mode which simply uses strings and has
no dependence on Lwt. For the modern user who demands ultra-convenience.
## v0.6.0 (2013-07-09)
* Adapt output to mirage-platform-0.9.2 Io_page API.
## v0.5.0 (2013-03-28)
* Added a -o option (needed for mirari)
## 0.4.0 (2012-12-20)
* Initial public release

View file

@ -0,0 +1,16 @@
(*
* Copyright (c) <the authors, see individual headers on files>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*)

View file

@ -0,0 +1,10 @@
.PHONY: build clean test
build:
dune build
test:
dune runtest
clean:
dune clean

View file

@ -0,0 +1,68 @@
# ocaml-crunch — convert a filesystem into a static OCaml module
`ocaml-crunch` takes a directory of files and compiles them into a standalone
OCaml module which serves the contents directly from memory. This can be
convenient for libraries that need a few embedded files (such as a web server)
and do not want to deal with all the trouble of file configuration.
Run `ocaml-crunch --help` for more information:
```
NAME
ocaml-crunch - Convert a directory structure into a standalone OCaml
module that can serve the file contents without requiring an external
filesystem to be present.
SYNOPSIS
ocaml-crunch [--ext=VALID EXTENSION] [--mode=MODE] [--output=OUTPUT]
[OPTION]… DIRECTORIES…
ARGUMENTS
DIRECTORIES (required)
Directories to recursively walk and crunch.
OPTIONS
-e VALID EXTENSION, --ext=VALID EXTENSION
If specified, only these extensions will be included in the
crunched output. If not specified, then all files will be crunched
into the output module.
-m MODE, --mode=MODE (absent=lwt)
Interface access mode: either lwt or plain. lwt is the default.
-o OUTPUT, --output=OUTPUT
Output file for the OCaml module.
-s, --silent
Silent mode.
COMMON OPTIONS
--help[=FMT] (default=auto)
Show this help in format FMT. The value FMT must be one of auto,
pager, groff or plain. With auto, the format is pager or plain
whenever the TERM env var is dumb or undefined.
--version
Show version information.
EXIT STATUS
ocaml-crunch exits with the following status:
0 on success.
123 on indiscriminate errors reported on standard error.
124 on command line parsing errors.
125 on unexpected internal errors (bugs).
ENVIRONMENT
These environment variables affect the execution of ocaml-crunch:
SOURCE_DATE_EPOCH
Specifies the last modification of crunched files for reproducible
output.
BUGS
Email bug reports to <mirage-devel@lists.xenproject.org>.
```

View file

@ -0,0 +1,47 @@
version: "4.0.0"
opam-version: "2.0"
maintainer: "MirageOS team"
authors: ["Anil Madhavapeddy" "Thomas Gazagnaire" "Stefanie Schirmer" "Hannes Mehnert"]
homepage: "https://github.com/mirage/ocaml-crunch"
bug-reports: "https://github.com/mirage/ocaml-crunch/issues"
doc: "https://mirage.github.io/ocaml-crunch/"
license: "ISC"
dev-repo: "git+https://github.com/mirage/ocaml-crunch.git"
tags: ["org:mirage" "org:xapi-project"]
depends: [
"ocaml" {>= "4.08.0"}
"cmdliner" {>= "1.1"}
"ptime"
"dune" {>= "2.5"}
"lwt" {with-test}
"mirage-kv" {with-test & >= "3.0.0"}
"mirage-kv-mem" {with-test & >= "4.0.0"}
"fmt" {with-test}
]
conflicts: [
"mirage-kv" {< "3.0.0"}
"mirage-kv-mem" {< "4.0.0"}
]
build: [
["dune" "subst"] {dev}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
synopsis: "Convert a filesystem into a static OCaml module"
description: """
`ocaml-crunch` takes a directory of files and compiles them into a standalone
OCaml module which serves the contents directly from memory. This can be
convenient for libraries that need a few embedded files (such as a web server)
and do not want to deal with all the trouble of file configuration.
"""
x-maintenance-intent: [ "(latest)" ]

View file

@ -0,0 +1,3 @@
(lang dune 2.5)
(name crunch)
(version v4.0.0)

View file

@ -0,0 +1,227 @@
(*
* Copyright (c) 2009-2013 Anil Madhavapeddy <anil@recoil.org>
* Copyright (c) 2013 Thomas Gazagnaire <thomas@gazagnaire.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)
module SM = Map.Make (String)
type file_info = {
chunk_digests : string list;
file_digest : string;
size : int;
}
type t = string SM.t * file_info SM.t
let make () = (SM.empty, SM.empty)
module Filename = struct
include Filename
(* Always use Unix-style filenames for keys *)
let dir_sep = "/"
let is_dir_sep s i = s.[i] = '/'
let concat dirname filename =
let l = String.length dirname in
if l = 0 || is_dir_sep dirname (l - 1) then dirname ^ filename
else dirname ^ dir_sep ^ filename
end
(* Walk directory and call walkfn on every file that matches extension ext *)
let walk_directory_tree t exts walkfn root_dir =
(* Recursive directory walker *)
let rec walk_dir dir t =
let dh = Unix.opendir dir in
let rec repeat t =
match Unix.readdir dh with
| exception End_of_file -> t
| "." | ".." -> repeat t
| f -> (
let n = Filename.concat dir f in
if Sys.is_directory n then repeat (walk_dir n t)
else
let name = String.sub n 2 (String.length n - 2) in
(* If extension list is empty then let all through, otherwise white list *)
match (exts, Filename.extension f) with
| [], _ -> repeat (walkfn t root_dir name)
| exts, e
when e <> ""
&& List.mem (String.sub e 1 (String.length e - 1)) exts ->
repeat (walkfn t root_dir name)
| _ -> repeat t)
in
let result = repeat t in
Unix.closedir dh;
result
in
Unix.chdir root_dir;
walk_dir "." t
let now () =
try float_of_string (Sys.getenv "SOURCE_DATE_EPOCH")
with Not_found -> Unix.gettimeofday ()
let output_generated_by oc binary =
let t = now () in
let months =
[|
"Jan";
"Feb";
"Mar";
"Apr";
"May";
"Jun";
"Jul";
"Aug";
"Sep";
"Oct";
"Nov";
"Dec";
|]
in
let days = [| "Sun"; "Mon"; "Tue"; "Wed"; "Thu"; "Fri"; "Sat" |] in
let time = Unix.gmtime t in
let date =
Printf.sprintf "%s, %d %s %d %02d:%02d:%02d GMT" days.(time.Unix.tm_wday)
time.Unix.tm_mday months.(time.Unix.tm_mon) (time.Unix.tm_year + 1900)
time.Unix.tm_hour time.Unix.tm_min time.Unix.tm_sec
in
Printf.fprintf oc "(* Generated by: %s\n Creation date: %s *)\n\n" binary
date
(** Generate a set of MD5 hashed blocks, abort on collision *)
let scan_file (chunk_info, file_info) root name =
let full_name = Filename.concat root name in
let stats = Unix.stat full_name in
let size = stats.Unix.st_size in
let fin = open_in_bin full_name in
let buf = Buffer.create size in
Buffer.add_channel buf fin size;
let s = Buffer.contents buf in
close_in fin;
let rev_chunks = ref [] in
let calc_chunk chunk_info b =
let digest = Digest.to_hex (Digest.string b) in
rev_chunks := digest :: !rev_chunks;
match SM.find_opt digest chunk_info with
| None -> SM.add digest b chunk_info
| Some cur ->
if not (String.equal cur b) then
failwith ("MD5 hash collision in file " ^ name)
else chunk_info
in
(* Split the file as a series of chunks, of size up to 4096 (to simulate reading sectors) *)
let sec = 4096 in
(* sector size *)
let rec consume idx chunk_info =
if idx = size then chunk_info (* EOF *)
else if idx + sec < size then
let chunk_info' = calc_chunk chunk_info (String.sub s idx sec) in
consume (idx + sec) chunk_info'
else
(* final chunk, short *)
calc_chunk chunk_info (String.sub s idx (size - idx))
in
(* consume fills !rev_chunks as a side effect, so sequentialise this*)
let ci = consume 0 chunk_info in
let entry =
{
chunk_digests = List.rev !rev_chunks;
file_digest = Digest.(to_hex (string s));
size = String.length s;
}
in
(ci, SM.add name entry file_info)
let output_implementation (chunk_info, file_info) oc =
let pf fmt = Printf.fprintf oc fmt in
pf "module Internal = struct\n";
SM.iter (fun name chunk -> pf " let d_%s = %S\n\n" name chunk) chunk_info;
pf " let file_chunks = function\n";
SM.iter
(fun name { chunk_digests; _ } ->
pf " | %S | \"/%s\" -> Some [" name (String.escaped name);
List.iter (pf " d_%s;") chunk_digests;
pf " ]\n")
file_info;
pf " | _ -> None\n\n";
pf " let file_list = [ ";
SM.iter (fun name _ -> pf "%S; " name) file_info;
pf "]\n";
pf "end\n"
let output_plain_skeleton_ml (_, file_info) oc =
let pf fmt = Printf.fprintf oc fmt in
pf
{|
let file_list = Internal.file_list
let read name =
match Internal.file_chunks name with
| None -> None
| Some c -> Some (String.concat "" c)
let hash = function
|};
SM.iter
(fun name { file_digest; _ } ->
pf " | %S | \"/%s\" -> Some \"%s\"\n" name (String.escaped name)
file_digest)
file_info;
pf " | _ -> None\n\n";
pf "let size = function\n";
SM.iter
(fun name { size; _ } ->
pf " | %S | \"/%s\" -> Some %d\n" name (String.escaped name) size)
file_info;
pf " | _ -> None\n"
let output_lwt_skeleton_ml oc =
let days, ps =
Ptime.Span.to_d_ps
@@ Ptime.to_span
(match Ptime.of_float_s (now ()) with
| None -> assert false
| Some x -> x)
in
Printf.fprintf oc
{|
open Lwt
include Mirage_kv_mem
let file_content name =
match Internal.file_chunks name with
| None -> Lwt.fail_with ("expected file content, found no blocks " ^ name)
| Some blocks -> Lwt.return (String.concat "" blocks)
let add store name =
file_content name >>= fun data ->
set store (Mirage_kv.Key.v name) data >>= function
| Ok () -> Lwt.return_unit
| Error e -> Lwt.fail_with (Fmt.to_to_string pp_write_error e)
let connect () =
connect ~now:(fun () -> Ptime.v (%d, %LdL)) () >>= fun store ->
Lwt_list.iter_s (add store) Internal.file_list >|= fun () -> store
|}
days ps
let output_lwt_skeleton_mli oc =
Printf.fprintf oc {|include Mirage_kv.RO
val connect : unit -> t Lwt.t
|}

View file

@ -0,0 +1,49 @@
(*
* Copyright (c) 2009-2013 Anil Madhavapeddy <anil@recoil.org>
* Copyright (c) 2013 Thomas Gazagnaire <thomas@gazagnaire.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)
(** Expose the contents of a directory as a static filesystem. *)
type t
(** The type of a crunch. *)
val make : unit -> t
(** [make ()] is an empty crunch. *)
val output_generated_by : out_channel -> string -> unit
(** [output_generated_by oc binary_name] generate a comments saying
who generates that file. *)
val scan_file : t -> string -> string -> t
(** [scan_file t root file] records the contents of [root]/[file] in [t]. *)
val output_implementation : t -> out_channel -> unit
(** Output the footer. *)
val output_lwt_skeleton_ml : out_channel -> unit
(** Output the Lwt helpers. *)
val output_lwt_skeleton_mli : out_channel -> unit
(** Output the Lwt helpers. *)
val output_plain_skeleton_ml : t -> out_channel -> unit
(** Output a simple skeleton. *)
val walk_directory_tree :
t -> string list -> (t -> string -> string -> t) -> string -> t
(** [walk t extensions fn root_dir] traverses all the directory
structure starting from [root_dir] and keeping only the [extensions]
provided (or do not filter anything if the list is empty). *)

View file

@ -0,0 +1,28 @@
(library
; Dummy library to detect the OCaml version
(name realpath)
(modules)
(enabled_if
(< %{ocaml_version} "4.13")))
(library
(name crunch)
(wrapped false)
(synopsis "Compile static files into a static filesystem")
(modules crunch)
(public_name crunch)
(libraries unix ptime)
(flags :standard -safe-string))
(executable
(name main)
(modules main realpath)
(public_name ocaml-crunch)
(libraries
cmdliner
crunch
(select
realpath.ml
from
(realpath -> realpath.pre_413.ml)
(-> realpath.unix.ml))))

View file

@ -0,0 +1,118 @@
(*
* Copyright (c) 2009-2013 Anil Madhavapeddy <anil@recoil.org>
* Copyright (c) 2013 Thomas Gazagnaire <thomas@gazagnaire.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)
let binary = Sys.argv.(0) |> Filename.basename |> Filename.remove_extension
let walker output mode dirs exts silent =
let log fmt =
if silent then Printf.ifprintf stdout fmt
else Printf.fprintf stdout (fmt ^^ "%!")
in
let dirs = List.map Realpath.realpath dirs in
let oc =
match output with
| None -> stdout
| Some f ->
log "Generating %s\n" f;
open_out_bin f
in
let cwd = Sys.getcwd () in
let t =
List.fold_left
(fun t -> Crunch.walk_directory_tree t exts Crunch.scan_file)
(Crunch.make ()) dirs
in
Crunch.output_generated_by oc binary;
Crunch.output_implementation t oc;
(match mode with
| `Lwt -> Crunch.output_lwt_skeleton_ml oc
| `Plain -> Crunch.output_plain_skeleton_ml t oc);
close_out oc;
match output with
| Some f when Filename.check_suffix f ".ml" && mode = `Lwt ->
let mli = Filename.chop_extension f ^ ".mli" in
log "Generating %s\n" mli;
Sys.chdir cwd;
let oc = open_out_bin mli in
Crunch.output_generated_by oc binary;
Crunch.output_lwt_skeleton_mli oc;
close_out oc
| Some _ -> log "Skipping generation of .mli\n"
| None -> ()
open Cmdliner
let () =
let dirs =
Arg.(
non_empty & pos_all dir []
& info [] ~docv:"DIRECTORIES"
~doc:"Directories to recursively walk and crunch.")
in
let output =
Arg.(
value
& opt (some string) None
& info [ "o"; "output" ] ~docv:"OUTPUT"
~doc:"Output file for the OCaml module.")
in
let modes = [ ("lwt", `Lwt); ("plain", `Plain) ] in
let mode =
Arg.(
value
& opt (enum modes) `Lwt
& info [ "m"; "mode" ] ~docv:"MODE"
~doc:
(Printf.sprintf
"Interface access mode: %s. $(b,lwt) is the default."
(Arg.doc_alts_enum modes)))
in
let exts =
Arg.(
value & opt_all string []
& info [ "e"; "ext" ] ~docv:"VALID EXTENSION"
~doc:
"If specified, only these extensions will be included in the \
crunched output. If not specified, then all files will be \
crunched into the output module.")
in
let quiet = Arg.(value & flag & info [ "s"; "silent" ] ~doc:"Silent mode.") in
let cmd_t = Term.(const walker $ output $ mode $ dirs $ exts $ quiet) in
let info =
let doc =
"Convert a directory structure into a standalone OCaml module that can \
serve the file contents without requiring an external filesystem to be \
present."
in
let envs =
[
Cmd.Env.info
~doc:
"Specifies the last modification of crunched files for \
reproducible output."
"SOURCE_DATE_EPOCH";
]
in
let man =
[
`S "BUGS";
`P "Email bug reports to <mirage-devel@lists.xenproject.org>.";
]
in
Cmd.info "ocaml-crunch" ~version:"v4.0.0" ~doc ~man ~envs
in
exit @@ Cmd.eval (Cmd.v info cmd_t)

View file

@ -0,0 +1,18 @@
(* poor-man reimplementation of realpath, from OPAM's system library *)
let realpath p =
let getchdir s =
let p = Sys.getcwd () in
Sys.chdir s;
p
in
let normalize s = getchdir (getchdir s) in
if Filename.is_relative p then
match Sys.is_directory p with
| exception Sys_error _ -> p
| true -> normalize p
| false -> (
let dir = normalize (Filename.dirname p) in
match Filename.basename p with
| "." -> dir
| base -> Filename.concat dir base)
else p

View file

@ -0,0 +1 @@
let realpath = Unix.realpath

View file

@ -0,0 +1 @@
/t1/** text eol=lf

View file

@ -0,0 +1 @@
*.expected.*

View file

@ -0,0 +1,42 @@
open Lwt.Infix
let key s = Mirage_kv.Key.v s
let size t1 key =
T1.get t1 key >|= function Ok r -> Ok (String.length r) | Error e -> Error e
let main =
T1.connect () >>= fun src ->
(T1.get src (key "a.ext") >|= function
| Ok res ->
if res = "foo\n" then print_endline "read a.ext successfully"
else Fmt.failwith "unexpected read value, expecting foo, read: %s" res
| Error e -> Fmt.failwith "error while reading 'a.ext': %a" T1.pp_error e)
>>= fun () ->
(size src (key "c") >>= function
| Error _ -> Fmt.failwith "error while calling size on 'c'"
| Ok l ->
if l = 4100 then
T1.get src (key "c") >|= function
| Error e -> Fmt.failwith "error while reading 'c': %a" T1.pp_error e
| Ok _ -> print_endline "read 'c' successfully"
else failwith "invalid size while reading 'c'")
>>= fun () ->
(size src (key "d") >>= function
| Error e -> Fmt.failwith "error while calling size on 'd': %a" T1.pp_error e
| Ok l ->
if l = 12300 then
T1.get src (key "d") >|= function
| Error e -> Fmt.failwith "error while reading 'd': %a" T1.pp_error e
| Ok _ -> print_endline "read 'd' successfully"
else Fmt.failwith "invalid size while reading 'd'")
>>= fun () ->
T1.get src (key "e/f") >|= function
| Error e -> Fmt.failwith "error while reading 'd': %a" T1.pp_error e
| Ok data ->
if data = "hallohallo\n" then print_endline "read e/f successfully"
else
Fmt.failwith "unexpected read value, expecting hallohallo, read: %s"
data
let () = Lwt_main.run main

View file

@ -0,0 +1,37 @@
(rule
(targets t1.ml t1.mli t1_plain.ml t1_plain_ext.ml)
(deps
(source_tree t1))
(action
(setenv
SOURCE_DATE_EPOCH
0
(progn
(run %{bin:ocaml-crunch} --mode=lwt -o t1.ml t1)
(run %{bin:ocaml-crunch} --mode=plain -o t1_plain.ml t1)
(run %{bin:ocaml-crunch} --mode=plain -e ext -o t1_plain_ext.ml t1)))))
(rule
(alias runtest)
(action
(diff t1.expected.ml t1.ml)))
(rule
(alias runtest)
(action
(diff t1.expected.mli t1.mli)))
(rule
(alias runtest)
(action
(diff t1_plain.expected.ml t1_plain.ml)))
(rule
(alias runtest)
(action
(diff t1_plain_ext.expected.ml t1_plain_ext.ml)))
(test
(name consumer)
(libraries lwt.unix mirage-kv lwt mirage-kv-mem)
(modules t1 consumer))

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,6 @@
(* Generated by: ocaml-crunch
Creation date: Thu, 1 Jan 1970 00:00:00 GMT *)
include Mirage_kv.RO
val connect : unit -> t Lwt.t

View file

@ -0,0 +1 @@
foo

View file

@ -0,0 +1 @@
bar

View file

@ -0,0 +1 @@
01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789

Binary file not shown.

View file

@ -0,0 +1 @@
hallohallo

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,27 @@
(* Generated by: ocaml-crunch
Creation date: Thu, 1 Jan 1970 00:00:00 GMT *)
module Internal = struct
let d_d3b07384d113edec49eaa6238ad5ff00 = "foo\n"
let file_chunks = function
| "a.ext" | "/a.ext" -> Some [ d_d3b07384d113edec49eaa6238ad5ff00; ]
| _ -> None
let file_list = [ "a.ext"; ]
end
let file_list = Internal.file_list
let read name =
match Internal.file_chunks name with
| None -> None
| Some c -> Some (String.concat "" c)
let hash = function
| "a.ext" | "/a.ext" -> Some "d3b07384d113edec49eaa6238ad5ff00"
| _ -> None
let size = function
| "a.ext" | "/a.ext" -> Some 4
| _ -> None