Embed static assets into binary using ocaml-crunch

- Add dune rule to generate Static_assets module from lib/static/ (plain mode) - Create Static_handler module to serve embedded CSS/SVG with correct Content-Type - Replace Dream.static filesystem handler with embedded asset handler - Add crunch (>= 4.0.0) as a build dependency - Add tests verifying embedded assets are readable

Commit
74038913d7af9d8a8d85c71a98cf36b0a0a8cf0f
Author
Marius Peter <dev@marius-peter.com>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
dune-project
index 0e9a7f09..de9ee19f 100644..100644
@@ -22,6 +22,7 @@
22 22 (dream-html (>= 3.11.2))
23 23 (git (>= 3.18.0))
24 24 (git-unix (>= 3.18.0))
25 Added: (crunch (>= 4.0.0))
25 26 (ocamlformat (and :with-dev-setup (= 0.29.0)))
26 27 (toml (>= 7.1.0)))
27 28 (tags
lib/dune
index d0112353..fc9e2198 100644..100644
@@ -5,3 +5,10 @@
5 5 (libraries dream dream-html git-unix toml)
6 6 (preprocess
7 7 (pps dream-html.ppx)))
8 Added:
9 Added: (rule
10 Added: (target static_assets.ml)
11 Added: (deps
12 Added: (source_tree static))
13 Added: (action
14 Added: (run ocaml-crunch -m plain -s -o %{target} static)))
lib/handlers.ml
index 39597dfb..c9b3653a 100644..100644
@@ -77,5 +77,5 @@
77 77 get "/tags/" (handle tags);
78 78 get "/README" (handle readme);
79 79 ];
80 Removed: get "/static/**" (static "./lib/static");
80 Added: get "/static/**" @@ Static_handler.handler;
81 81 ]
lib/static_handler.ml
index 00000000..c5aea7d5 000000..100644
@@ -0,0 +1,24 @@
1 Added: (* -*- mode: tuareg; -*- *)
2 Added:
3 Added: let content_type_of_ext = function
4 Added: | ".css" -> "text/css; charset=utf-8"
5 Added: | ".svg" -> "image/svg+xml"
6 Added: | ".html" -> "text/html; charset=utf-8"
7 Added: | ".js" -> "application/javascript"
8 Added: | ".png" -> "image/png"
9 Added: | ".ico" -> "image/x-icon"
10 Added: | _ -> "application/octet-stream"
11 Added:
12 Added: let handler req =
13 Added: let target = Dream.target req in
14 Added: let path =
15 Added: match String.split_on_char '/' target with
16 Added: | "" :: "static" :: rest -> String.concat "/" rest
17 Added: | _ -> ""
18 Added: in
19 Added: match Static_assets.read path with
20 Added: | Some content ->
21 Added: let ext = Filename.extension path in
22 Added: let content_type = content_type_of_ext ext in
23 Added: Dream.respond ~headers:[ ("Content-Type", content_type) ] content
24 Added: | None -> Dream.respond ~status:`Not_Found "Not found"
test/test_ogit.ml
index 0feb098b..5210b90f 100644..100644
@@ -121,6 +121,15 @@
121 121 assert (hunk.new_count = 7)
122 122 | _ -> failwith "expected one diff hunk"
123 123
124 Added: let test_static_assets () =
125 Added: (match Ogit.Static_assets.read "styles.css" with
126 Added: | Some content -> assert (String.length content > 0)
127 Added: | None -> failwith "styles.css should be embedded");
128 Added: (match Ogit.Static_assets.read "git_icon.svg" with
129 Added: | Some content -> assert (String.length content > 0)
130 Added: | None -> failwith "git_icon.svg should be embedded");
131 Added: assert (Ogit.Static_assets.read "nonexistent" = None)
132 Added:
124 133 let () =
125 134 assert (Ogit.Resolvers.is_valid_repo_name "project.git");
126 135 assert (Ogit.Resolvers.is_valid_repo_name "project");
@@ -151,4 +160,5 @@
151 160 test_repository_layout ();
152 161 test_fallback_branch_candidates ();
153 162 test_line_diff ();
154 Removed: test_diff_hunks ()
163 Added: test_diff_hunks ();
164 Added: test_static_assets ()