Modularize everything.

Commit
6658535cf610d6c1d99dae20e98ced14a920dbb2
Author
Marius Peter <marius.peter@tutanota.com>
Author date
Committer
Marius Peter <marius.peter@tutanota.com>
Committer date
Changed files
lib/git_helpers.ml
index 5e5d4cd1..ed917a8a 100644..100644
@@ -4,13 +4,6 @@
4 4
5 5 type user_record = { name : string; email : string }
6 6
7 Removed: type commit_record = {
8 Removed: hash : string;
9 Removed: parents : string list;
10 Removed: author : Git.User.t;
11 Removed: message : string option;
12 Removed: }
13 Removed:
14 7 let full_path path = Filename.concat Config.git_directory path
15 8
16 9 let store repo_path =
@@ -23,39 +16,51 @@
23 16 let description_path = Filename.concat (full_path repo_path) "description" in
24 17 In_channel.with_open_text description_path In_channel.input_all
25 18
26 Removed: (* Read a Git object and turn it into our [commit_record], or propagate an error. *)
27 Removed: let get_commit_record store h =
28 Removed: Store.read store h >>= function
29 Removed: | Ok (Value.Commit c) ->
30 Removed: Lwt.return_ok
31 Removed: {
32 Removed: hash = Store.Hash.to_hex h;
33 Removed: parents = Store.Value.Commit.parents c |> List.map Store.Hash.to_hex;
34 Removed: author = Store.Value.Commit.author c;
35 Removed: message = Store.Value.Commit.message c;
36 Removed: }
37 Removed: | Ok _ -> Lwt.return_error (`Msg "object is not a commit")
38 Removed: | Error e -> Lwt.return_error e
19 Added: module Commit = struct
20 Added: type t = {
21 Added: hash : string;
22 Added: parents : string list;
23 Added: author : Git.User.t;
24 Added: message : string option;
25 Added: }
39 26
40 Removed: let recent_commits repo_path n =
41 Removed: let open Lwt_result.Syntax in
42 Removed: let* store = store repo_path in
43 Removed: let* head = Store.Ref.resolve store Git.Reference.head in
44 Removed: let rec walk acc hash count =
45 Removed: if count = 0 then Lwt.return_ok (List.rev acc)
46 Removed: else
47 Removed: get_commit_record store hash >>= function
48 Removed: | Error e -> Lwt.return_error e
49 Removed: | Ok commit -> (
50 Removed: match commit.parents with
51 Removed: | parent :: _ ->
52 Removed: walk (commit :: acc) (Store.Hash.of_hex parent) (count - 1)
53 Removed: | [] -> Lwt.return_ok (List.rev (commit :: acc)))
54 Removed: in
55 Removed: walk [] head n
27 Added: let of_hash store h =
28 Added: Store.read store h >>= function
29 Added: | Ok (Value.Commit c) ->
30 Added: Lwt_result.return
31 Added: {
32 Added: hash = Store.Hash.to_hex h;
33 Added: parents = Store.Value.Commit.parents c |> List.map Store.Hash.to_hex;
34 Added: author = Store.Value.Commit.author c;
35 Added: message = Store.Value.Commit.message c;
36 Added: }
37 Added: | Ok _ -> Lwt.return_error (`Msg "object is not a commit")
38 Added: | Error e -> Lwt.return_error e
56 39
57 Removed: let get_commit repo_path id =
58 Removed: let open Lwt_result.Syntax in
59 Removed: let* store = store repo_path in
60 Removed: let id = Store.Hash.of_hex id in
61 Removed: get_commit_record store id
40 Added: let recent_commits repo_path n =
41 Added: let open Lwt_result.Syntax in
42 Added: let* store = store repo_path in
43 Added: let* head = Store.Ref.resolve store Git.Reference.head in
44 Added: let rec walk acc hash count =
45 Added: if count = 0 then Lwt_result.return (List.rev acc)
46 Added: else
47 Added: of_hash store hash >>= function
48 Added: | Error e -> Lwt.return_error e
49 Added: | Ok commit -> (
50 Added: match commit.parents with
51 Added: | parent :: _ ->
52 Added: walk (commit :: acc) (Store.Hash.of_hex parent) (count - 1)
53 Added: | [] -> Lwt_result.return (List.rev (commit :: acc)))
54 Added: in
55 Added: walk [] head n
56 Added:
57 Added: let of_id repo_path id =
58 Added: let open Lwt_result.Syntax in
59 Added: let* store = store repo_path in
60 Added: let id = Store.Hash.of_hex id in
61 Added: of_hash store id
62 Added: end
63 Added:
64 Added: module Branch = struct
65 Added: let all_branches repo_path = [ "foo"; "bar"; repo_path ]
66 Added: end
lib/handlers.ml
index 95aecd32..321c6936 100644..100644
@@ -6,41 +6,39 @@
6 6 let msg = Format.asprintf "%a" Git_unix.Store.pp_error e in
7 7 Views.error_page msg |> Dream_html.respond
8 8
9 Removed: let ogit_root _req = Views.ogit_root () |> Dream_html.respond
9 Added: let root _req = Views.root () |> Dream_html.respond
10 10
11 Removed: let repo_summary req =
12 Removed: let repo_path = Dream.param req "repo_name" in
13 Removed: let branches = [ "bing"; "bong" ] in
14 Removed: let* commits = Git_helpers.recent_commits repo_path 10 in
15 Removed: Views.repo_summary repo_path branches commits |> Dream_html.respond
11 Added: module Repo = struct
12 Added: let repo_path req = Dream.param req "repo_name"
16 13
17 Removed: let repo_commit req =
18 Removed: let repo_path = Dream.param req "repo_name" in
19 Removed: let id = match Dream.query req "id" with Some id -> id | None -> "" in
20 Removed: let* commit = Git_helpers.get_commit repo_path id in
21 Removed: Views.repo_commit repo_path commit |> Dream_html.respond
14 Added: let summary req =
15 Added: let branches = Git_helpers.Branch.all_branches (repo_path req) in
16 Added: let* commits = Git_helpers.Commit.recent_commits (repo_path req) 10 in
17 Added: let authors = [ "John Pork"; "Sebastian Jellybean" ] in
18 Added: Views.Repo.summary (repo_path req) branches commits authors
19 Added: |> Dream_html.respond
22 20
23 Removed: (* let repo_tree req = *)
24 Removed: (* let repo_name = Dream.param req "repo_name" in *)
25 Removed: (* let path = Git_helpers.full_path repo_name in *)
26 Removed: (* let dir_path = Dream.target req in *)
27 Removed: (* Views.repo_tree ~repo_path:path dir_path |> Dream_html.respond *)
21 Added: let refs req = Views.Repo.refs (repo_path req) |> Dream_html.respond
22 Added: let log req = Views.Repo.log (repo_path req) |> Dream_html.respond
23 Added: let tree req = Views.Repo.tree (repo_path req) |> Dream_html.respond
28 24
29 Removed: (* let repo_blob req = *)
30 Removed: (* let repo_name = Dream.param req "repo_name" in *)
31 Removed: (* let path = Git_helpers.full_path repo_name in *)
32 Removed: (* let blob_path = Dream.query req "path" |> Option.value ~default:"" in *)
33 Removed: (* Views.repo_blob repo_name blob_path |> Dream_html.respond *)
25 Added: let commit req =
26 Added: let id = match Dream.query req "id" with Some id -> id | None -> "" in
27 Added: let* commit = Git_helpers.Commit.of_id (repo_path req) id in
28 Added: Views.Repo.commit (repo_path req) commit |> Dream_html.respond
29 Added: end
34 30
35 31 let all_handlers =
36 32 [
37 Removed: Dream.get "/" ogit_root;
33 Added: Dream.get "/" root;
38 34 Dream.scope "/:repo_name" []
39 Removed: [
40 Removed: Dream.get "/" repo_summary;
41 Removed: Dream.get "/commit/" repo_commit;
42 Removed: (* Dream.get "/tree" repo_tree; *)
43 Removed: (* Dream.get "/blob" repo_blob; *)
44 Removed: ];
35 Added: Repo.
36 Added: [
37 Added: Dream.get "/" summary;
38 Added: Dream.get "/refs/" refs;
39 Added: Dream.get "/log/" log;
40 Added: Dream.get "/tree/" tree;
41 Added: Dream.get "/commit/" commit;
42 Added: ];
45 43 Dream.get "/static/**" (Dream.static "./lib/static");
46 44 ]
lib/static/styles.css
index de2c3dbf..ae8a86c4 100644..100644
@@ -69,3 +69,10 @@
69 69 color: black;
70 70 text-decoration: revert;
71 71 }
72 Added:
73 Added: h1 {
74 Added: position: sticky;
75 Added: top: 0;
76 Added: background: inherit;
77 Added: padding: 0.5em 0;
78 Added: }
lib/views.ml
index 3c1330ef..e023236f 100644..100644
@@ -3,12 +3,40 @@
3 3 type body_data = {
4 4 title : string;
5 5 subtitle : string;
6 Removed: topnav : Dream_html.node;
7 6 content : Dream_html.node list;
8 7 }
9 8
10 Removed: module Layout = struct
9 Added: module Components = struct
11 10 open Dream_html
11 Added:
12 Added: let topnav current_path =
13 Added: let open HTML in
14 Added: let li_of_a (path, text) =
15 Added: let is_active = path = current_path in
16 Added: let attrs = if is_active then [ id "active" ] else [] in
17 Added: let url =
18 Added: if String.equal path "/" then Printf.sprintf "/%s/" current_path
19 Added: else Printf.sprintf "/%s/%s" current_path path
20 Added: in
21 Added: li attrs [ a [ href "%s" url ] [ txt text ] ]
22 Added: in
23 Added: nav
24 Added: [ id "top" ]
25 Added: [
26 Added: ul []
27 Added: @@ List.map li_of_a
28 Added: [
29 Added: ("/", "summary");
30 Added: ("refs/", "refs");
31 Added: ("log/", "log");
32 Added: ("tree/", "tree");
33 Added: ("commit/", "commit");
34 Added: ];
35 Added: ]
36 Added: end
37 Added:
38 Added: module Page = struct
39 Added: open Dream_html
12 40 open HTML
13 41
14 42 let header title subtitle =
@@ -22,7 +50,7 @@
22 50
23 51 let default_head_data = { page_title = "Ogit" }
24 52
25 Removed: let application ?(head_data = default_head_data) body_data =
53 Added: let render ?(head_data = default_head_data) body_data =
26 54 html []
27 55 [
28 56 head []
@@ -35,44 +63,14 @@
35 63 body []
36 64 [
37 65 header body_data.title body_data.subtitle;
38 Removed: body_data.topnav;
66 Added: Components.topnav body_data.title;
39 67 div [ id "main" ] body_data.content;
40 68 footer ();
41 69 ];
42 70 ]
43 71 end
44 72
45 Removed: module Components = struct
46 Removed: open Dream_html
47 Removed:
48 Removed: let topnav repo_path current_path =
49 Removed: let open HTML in
50 Removed: let li_of_a (path, text) =
51 Removed: let is_active = path = current_path in
52 Removed: let attrs = if is_active then [ id "active" ] else [] in
53 Removed: let url =
54 Removed: if String.equal path "/" then Printf.sprintf "/%s/" repo_path
55 Removed: else Printf.sprintf "/%s/%s" repo_path path
56 Removed: in
57 Removed: li attrs [ a [ href "%s" url ] [ txt text ] ]
58 Removed: in
59 Removed: nav
60 Removed: [ id "top" ]
61 Removed: [
62 Removed: ul []
63 Removed: @@ List.map li_of_a
64 Removed: [
65 Removed: ("/", "summary");
66 Removed: ("refs", "refs");
67 Removed: ("log", "log");
68 Removed: ("tree", "tree");
69 Removed: ("commit", "commit");
70 Removed: ("diff", "diff");
71 Removed: ];
72 Removed: ]
73 Removed: end
74 Removed:
75 Removed: let ogit_root () =
73 Added: let root () =
76 74 let open Dream_html in
77 75 let repositories_in directory =
78 76 let repos =
@@ -87,61 +85,89 @@
87 85 {
88 86 title = "Ogit";
89 87 subtitle = "Repositories for " ^ Config.author;
90 Removed: topnav = HTML.(null []);
91 88 content = [ repositories_in Config.git_directory ];
92 89 }
93 90 in
94 Removed: Layout.application body_data
91 Added: Page.render body_data
95 92
96 Removed: let repo_summary repo_path branches commits =
97 Removed: let open Git_helpers in
98 Removed: let open Dream_html in
99 Removed: let li_of_branch branch =
100 Removed: HTML.(li [] [ a [ href "%s" branch ] [ txt "%s" branch ] ])
101 Removed: in
102 Removed: let li_of_commit commit =
103 Removed: match commit.message with
104 Removed: | Some msg ->
105 Removed: HTML.(
106 Removed: li []
107 Removed: [
108 Removed: a
109 Removed: [ href "commit/?id=%s" commit.hash ]
110 Removed: [ txt "%s %s" (short_hash commit.hash) msg ];
111 Removed: ])
112 Removed: | None -> HTML.(li [] [ a [ href "" ] [ txt "caca!!" ] ])
113 Removed: in
114 Removed: let content =
115 Removed: HTML.
116 Removed: [
117 Removed: h3 [] [ txt "Branches" ];
118 Removed: ul [] (List.map li_of_branch branches);
119 Removed: h3 [] [ txt "Recent commits" ];
120 Removed: ul [] (List.map li_of_commit commits);
121 Removed: ]
122 Removed: in
123 Removed: Layout.application
124 Removed: {
125 Removed: title = repo_path;
126 Removed: subtitle = repo_description repo_path;
127 Removed: topnav = Components.topnav repo_path "";
128 Removed: content;
129 Removed: }
93 Added: module Repo = struct
94 Added: let summary repo_path branches commits authors =
95 Added: let open Dream_html in
96 Added: let li_of_branch branch =
97 Added: HTML.(li [] [ a [ href "%s" branch ] [ txt "%s" branch ] ])
98 Added: in
99 Added: let li_of_commit (commit : Git_helpers.Commit.t) =
100 Added: match commit.message with
101 Added: | Some msg ->
102 Added: HTML.(
103 Added: li []
104 Added: [
105 Added: a
106 Added: [ href "commit/?id=%s" commit.hash ]
107 Added: [ txt "%s %s" (Git_helpers.short_hash commit.hash) msg ];
108 Added: ])
109 Added: | None -> HTML.(li [] [ a [ href "" ] [ txt "caca!!" ] ])
110 Added: in
111 Added: let li_of_author author =
112 Added: HTML.(li [] [ a [ href "" ] [ txt "%s" author ] ])
113 Added: in
114 Added: let content =
115 Added: HTML.
116 Added: [
117 Added: h3 [] [ txt "Branches" ];
118 Added: ul [] (List.map li_of_branch branches);
119 Added: h3 [] [ txt "Recent commits" ];
120 Added: ul [] (List.map li_of_commit commits);
121 Added: h3 [] [ txt "Authors" ];
122 Added: ul [] (List.map li_of_author authors);
123 Added: ]
124 Added: in
125 Added: Page.render
126 Added: {
127 Added: title = repo_path;
128 Added: subtitle = Git_helpers.repo_description repo_path;
129 Added: content;
130 Added: }
130 131
131 Removed: let repo_commit repo_path commit =
132 Removed: let open Git_helpers in
133 Removed: let open Dream_html in
134 Removed: let message = match commit.message with Some msg -> msg | None -> "" in
135 Removed: let content = HTML.[ h3 [] [ txt "%s" message ] ] in
136 Removed: let title = Printf.sprintf "%s : %s" repo_path (short_hash commit.hash) in
137 Removed: Layout.application
138 Removed: {
139 Removed: title;
140 Removed: subtitle = "";
141 Removed: topnav = Components.topnav repo_path "";
142 Removed: content;
143 Removed: }
132 Added: let refs repo_path =
133 Added: let open Dream_html in
134 Added: Page.render
135 Added: HTML.
136 Added: {
137 Added: title = repo_path;
138 Added: subtitle = Git_helpers.repo_description repo_path;
139 Added: content = [ null [] ];
140 Added: }
144 141
142 Added: let log repo_path =
143 Added: let open Dream_html in
144 Added: Page.render
145 Added: HTML.
146 Added: {
147 Added: title = repo_path;
148 Added: subtitle = Git_helpers.repo_description repo_path;
149 Added: content = [ null [] ];
150 Added: }
151 Added:
152 Added: let tree repo_path =
153 Added: let open Dream_html in
154 Added: Page.render
155 Added: HTML.
156 Added: {
157 Added: title = repo_path;
158 Added: subtitle = Git_helpers.repo_description repo_path;
159 Added: content = [ null [] ];
160 Added: }
161 Added:
162 Added: let commit repo_path (commit : Git_helpers.Commit.t) =
163 Added: let open Dream_html in
164 Added: let open Git_helpers in
165 Added: let message = match commit.message with Some msg -> msg | None -> "" in
166 Added: let content = HTML.[ h3 [] [ txt "%s" message ] ] in
167 Added: let title = Printf.sprintf "%s : %s" repo_path (short_hash commit.hash) in
168 Added: Page.render { title; subtitle = ""; content }
169 Added: end
170 Added:
145 171 let error_page message =
146 172 let open Dream_html in
147 173 HTML.(
@@ -149,19 +175,24 @@
149 175 [
150 176 head []
151 177 [
152 Removed: title [] "Big error";
178 Added: title [] "Fatal Error";
153 179 link [ rel "stylesheet"; href "/static/styles.css" ];
154 180 link
155 181 [ rel "icon"; type_ "image/x-icon"; href "/static/git_icon.svg" ];
156 182 ];
157 183 body []
158 184 [
159 Removed: h1 [] [ txt "Major error alert" ];
160 Removed: h2 [] [ txt "Major alert subtitle" ];
161 Removed: (* Components.topnav; *)
162 Removed: div [ id "main" ] [ txt "%s" message ];
185 Added: h1 [] [ txt "Fatal Error" ];
186 Added: div
187 Added: [ id "main" ]
188 Added: [
189 Added: p [] [ b [] [ txt "%s" message ] ];
190 Added: p []
191 Added: [
192 Added: txt
193 Added: "Your best course of action is to press the 'back' \
194 Added: button in your browser.";
195 Added: ];
196 Added: ];
163 197 ];
164 198 ])
165 Removed:
166 Removed: let repo_tree repo_path = repo_summary repo_path
167 Removed: let repo_blob repo_path = repo_summary repo_path