Great work today! 🔥

Commit
55993c4d0857aec8a372aee989aaeef61ea37b3c
Author
Marius Peter <marius.peter@tutanota.com>
Author date
Committer
Marius Peter <marius.peter@tutanota.com>
Committer date
Changed files
bin/main.ml
index c30e4fc5..74712e1d 100644..100644
@@ -6,5 +6,8 @@
6 6 Dream.get "/:repo_name" (fun req ->
7 7 let repo_name = Dream.param req "repo_name" in
8 8 Ogit.Handlers.repo_root repo_name);
9 Added: Dream.get "/:repo_name/tree" (fun req ->
10 Added: let repo_name = Dream.param req "repo_name" in
11 Added: Ogit.Handlers.repo_tree repo_name);
9 12 Dream.get "/static/**" (Dream.static "./lib/static");
10 13 ]
lib/git_unhelpers.ml
index 28d4d3a8..5b55c168 100644..100644
@@ -1,17 +1,44 @@
1 1 (* These will be reimplemented using OCaml's Git library, one day... *)
2 2
3 Removed: let get_git_log repo_path =
3 Added: let get_latest_commits repo_path count =
4 Added: let open Printf in
4 5 let full_path = Filename.concat Config.git_directory repo_path in
5 6 let full_cmd =
6 Removed: let cmd = Printf.sprintf "git -C %s log" full_path in
7 Removed: let options = [ "--pretty=format:'%ad %s'"; "--date=short"; "-n 10" ] in
8 Removed: String.concat " " (cmd :: options)
7 Added: let command = sprintf "git -C %s log" full_path in
8 Added: let options =
9 Added: let format = "--pretty=format:'%ad %s'" in
10 Added: let date = "--date=short" in
11 Added: let count = sprintf "-n %s" (string_of_int count) in
12 Added: [ format; date; count ]
13 Added: in
14 Added: String.concat " " (command :: options)
9 15 in
10 16 let ic = Unix.open_process_in full_cmd in
11 17 let rec read_lines acc =
12 18 try
13 19 let line = input_line ic in
14 20 read_lines (line :: acc)
21 Added: with End_of_file ->
22 Added: ignore (Unix.close_process_in ic);
23 Added: List.rev acc
24 Added: in
25 Added: read_lines []
26 Added:
27 Added: let get_all_branches repo_path =
28 Added: let open Printf in
29 Added: let full_path = Filename.concat Config.git_directory repo_path in
30 Added: let full_cmd = sprintf "git -C %s branch" full_path in
31 Added: let ic = Unix.open_process_in full_cmd in
32 Added: let rec read_lines acc =
33 Added: try
34 Added: let line = input_line ic |> String.trim in
35 Added: let clean_line =
36 Added: if String.length line > 2 && String.sub line 0 2 = "* " then
37 Added: String.sub line 2 (String.length line - 2)
38 Added: (* Remove "* " from active branch *)
39 Added: else line
40 Added: in
41 Added: read_lines (clean_line :: acc)
15 42 with End_of_file ->
16 43 ignore (Unix.close_process_in ic);
17 44 List.rev acc
lib/handlers.ml
index 4a6e0ca5..46df3541 100644..100644
@@ -1,6 +1,3 @@
1 Removed: open Lwt.Infix
2 Removed:
3 1 let ogit_root _ = Views.Ogit_root.render () |> Dream_html.respond
4 Removed:
5 Removed: let repo_root repo_name =
6 Removed: Views.Repo_root.render repo_name >>= Dream_html.respond
2 Added: let repo_root repo_name = Views.Repo_root.render repo_name |> Dream_html.respond
3 Added: let repo_tree repo_name = Views.Repo_tree.render repo_name |> Dream_html.respond
lib/views.ml
index 446d6015..2d116745 100644..100644
@@ -32,7 +32,7 @@
32 32 ];
33 33 body []
34 34 [
35 Removed: header "Ogit" body_data.subtitle;
35 Added: header body_data.title body_data.subtitle;
36 36 body_data.topnav;
37 37 div [ id "main" ] body_data.content;
38 38 footer;
@@ -40,6 +40,60 @@
40 40 ]
41 41 end
42 42
43 Added: module Topnav = struct
44 Added: open Dream_html
45 Added: open HTML
46 Added:
47 Added: let repo repo_path current_path =
48 Added: let li_of_a (path, text) =
49 Added: let is_active = path = current_path in
50 Added: let attrs = if is_active then [ id "active" ] else [] in
51 Added: let url =
52 Added: if String.length path = 0 then Printf.sprintf "/%s" repo_path
53 Added: else Printf.sprintf "/%s/%s" repo_path path
54 Added: in
55 Added: li attrs [ a [ href "%s" url ] [ txt text ] ]
56 Added: in
57 Added: nav
58 Added: [ id "top" ]
59 Added: [
60 Added: ul []
61 Added: @@ List.map li_of_a
62 Added: [
63 Added: ("", "summary");
64 Added: ("refs", "refs");
65 Added: ("log", "log");
66 Added: ("tree", "tree");
67 Added: ("commit", "commit");
68 Added: ("diff", "diff");
69 Added: ];
70 Added: ]
71 Added:
72 Added: (* let li_of_a (path, text) = *)
73 Added: (* let is_active = path = current_path in *)
74 Added: (* li (if is_active then [ id "active" ] else []) in *)
75 Added: (* let link_of_path = *)
76 Added: (* if String.length path = 0 then Printf.sprintf "/%s" repo_path *)
77 Added: (* else Printf.sprintf "/%s/%s" repo_path path *)
78 Added: (* in *)
79 Added: (* li [ id "active" ] [ a [ href "%s" link_of_path ] [ txt text ] ] *)
80 Added: (* in *)
81 Added: (* nav *)
82 Added: (* [ id "top" ] *)
83 Added: (* [ *)
84 Added: (* ul [] *)
85 Added: (* @@ List.map li_of_a *)
86 Added: (* [ *)
87 Added: (* ("", "summary"); *)
88 Added: (* ("refs", "refs"); *)
89 Added: (* ("log", "log"); *)
90 Added: (* ("tree", "tree"); *)
91 Added: (* ("commit", "commit"); *)
92 Added: (* ("diff", "diff"); *)
93 Added: (* ]; *)
94 Added: (* ] *)
95 Added: end
96 Added:
43 97 module Ogit_root = struct
44 98 open Dream_html
45 99 open HTML
@@ -56,7 +110,7 @@
56 110
57 111 let body_data =
58 112 {
59 Removed: title = "My repositories";
113 Added: title = "Ogit";
60 114 subtitle = "Repositories for " ^ Config.author;
61 115 topnav = null [];
62 116 content = [ repositories_in Config.git_directory ];
@@ -68,57 +122,78 @@
68 122 module Repo_root = struct
69 123 open Dream_html
70 124 open HTML
71 Removed: (* open Lwt.Syntax *)
72 125
126 Added: (* let href_for_git_object kind identifier = *)
127 Added: (* let open Printf in *)
128 Added: (* href "%s" @@ *)
129 Added: (* match kind with *)
130 Added: (* | `Branch -> sprintf "/tree/%s" identifier *)
131 Added: (* | `Commit -> sprintf "/commit/%s" identifier *)
132 Added:
73 133 let render repo_path =
74 Removed: (* let* title_result = Git_helpers.get_head_commit_hash repo_path in *)
75 Removed: (* let title = *)
76 Removed: (* match title_result with Ok hash -> hash | Error msg -> "Error: " ^ msg *)
77 Removed: (* in *)
78 Removed: let title = "Finble" in
134 Added: let title = repo_path in
79 135 let subtitle = Filename.concat Config.git_directory repo_path in
80 Removed: let topnav =
81 Removed: nav
82 Removed: [ id "top" ]
83 Removed: [
84 Removed: ul []
85 Removed: [
86 Removed: li [] [ a [ href "/" ] [ txt "summary" ] ];
87 Removed: li [] [ a [ href "/" ] [ txt "refs" ] ];
88 Removed: li [] [ a [ href "/" ] [ txt "log" ] ];
89 Removed: li [] [ a [ href "/" ] [ txt "tree" ] ];
90 Removed: li [] [ a [ href "/" ] [ txt "commit" ] ];
91 Removed: li [] [ a [ href "/" ] [ txt "diff" ] ];
92 Removed: ];
93 Removed: ]
136 Added: let all_branches = Git_unhelpers.get_all_branches repo_path in
137 Added: let li_of_branch branch =
138 Added: li [] [ a [ href "%s" branch ] [ txt "%s" branch ] ]
94 139 in
95 Removed: let recent_commits = Git_unhelpers.get_git_log repo_path in
140 Added: let recent_commits = Git_unhelpers.get_latest_commits repo_path 10 in
96 141 let li_of_commit commit =
97 142 li [] [ a [ href "%s" commit ] [ txt "%s" commit ] ]
98 143 in
99 144 let content =
100 145 [
146 Added: h3 [] [ txt "Branches" ];
147 Added: ul [] (List.map li_of_branch all_branches);
101 148 h3 [] [ txt "Recent commits" ];
102 Removed: ul [] @@ List.map li_of_commit recent_commits;
149 Added: ul [] (List.map li_of_commit recent_commits);
103 150 ]
104 151 in
105 Removed: let body_data = { title; subtitle; topnav; content } in
106 Removed: Lwt.return @@ Layout.application body_data
152 Added: let body_data =
153 Added: { title; subtitle; topnav = Topnav.repo repo_path ""; content }
154 Added: in
155 Added: Layout.application body_data
107 156 end
108 157
109 158 module Repo_tree = struct
110 159 open Dream_html
111 160 open HTML
112 Removed: open Lwt.Syntax
113 161
162 Added: let full_path repo_path = Filename.concat Config.git_directory repo_path
163 Added:
164 Added: (* Helper function to list top-level files and directories *)
165 Added: let ls_repo repo_path =
166 Added: try
167 Added: Sys.readdir (full_path repo_path)
168 Added: |> Array.to_list
169 Added: |> List.filter (fun name -> name <> ".git") (* Exclude .git *)
170 Added: |> List.sort String.compare
171 Added: with Sys_error _ -> []
172 Added:
173 Added: (* Function to create a link based on file type *)
174 Added: let link_for_entry repo_path entry =
175 Added: let entry_path = Filename.concat (full_path repo_path) entry in
176 Added: if Sys.is_directory entry_path then
177 Added: a
178 Added: [ href "%s" @@ Printf.sprintf "/%s/tree/%s" repo_path entry ]
179 Added: [ txt "%s" (entry ^ "/") ]
180 Added: else
181 Added: a
182 Added: [ href "%s" @@ Printf.sprintf "/%s/blob/%s" repo_path entry ]
183 Added: [ txt "%s" entry ]
184 Added:
185 Added: let li_of_entry repo_path entry = li [] [ link_for_entry repo_path entry ]
186 Added:
187 Added: (* Render function *)
114 188 let render repo_path =
115 Removed: let* title_result = Git_helpers.get_head_commit_hash repo_path in
116 Removed: let title =
117 Removed: match title_result with Ok hash -> hash | Error msg -> "Error: " ^ msg
189 Added: let title = repo_path in
190 Added: let subtitle = "Files" in
191 Added:
192 Added: let repo_entries = ls_repo repo_path in
193 Added: let content = [ ul [] (List.map (li_of_entry repo_path) repo_entries) ] in
194 Added:
195 Added: let body_data =
196 Added: { title; subtitle; topnav = Topnav.repo repo_path "tree"; content }
118 197 in
119 Removed: let subtitle = "Dinglefops" in
120 Removed: let topnav = null [] in
121 Removed: let content = [ txt "foobar" ] in
122 Removed: let body_data = { title; subtitle; topnav; content } in
123 Removed: Lwt.return @@ Layout.application body_data
198 Added: Layout.application body_data
124 199 end