summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarius Peter <marius.peter@tutanota.com>2025-03-02 19:23:19 +0100
committerMarius Peter <marius.peter@tutanota.com>2025-03-02 19:23:19 +0100
commit55993c4d0857aec8a372aee989aaeef61ea37b3c (patch)
treea6da37b5fda45d80f84251633426dee51db87575
parentc67581470cbdf2a1c8efabce78afffb2e3a2a2c6 (diff)
Great work today! 🔥
-rw-r--r--bin/main.ml3
-rw-r--r--lib/git_unhelpers.ml35
-rw-r--r--lib/handlers.ml7
-rw-r--r--lib/views.ml145
4 files changed, 146 insertions, 44 deletions
diff --git a/bin/main.ml b/bin/main.ml
index c30e4fc..74712e1 100644
--- a/bin/main.ml
+++ b/bin/main.ml
@@ -6,5 +6,8 @@ let () =
Dream.get "/:repo_name" (fun req ->
let repo_name = Dream.param req "repo_name" in
Ogit.Handlers.repo_root repo_name);
+ Dream.get "/:repo_name/tree" (fun req ->
+ let repo_name = Dream.param req "repo_name" in
+ Ogit.Handlers.repo_tree repo_name);
Dream.get "/static/**" (Dream.static "./lib/static");
]
diff --git a/lib/git_unhelpers.ml b/lib/git_unhelpers.ml
index 28d4d3a..5b55c16 100644
--- a/lib/git_unhelpers.ml
+++ b/lib/git_unhelpers.ml
@@ -1,11 +1,17 @@
(* These will be reimplemented using OCaml's Git library, one day... *)
-let get_git_log repo_path =
+let get_latest_commits repo_path count =
+ let open Printf in
let full_path = Filename.concat Config.git_directory repo_path in
let full_cmd =
- let cmd = Printf.sprintf "git -C %s log" full_path in
- let options = [ "--pretty=format:'%ad %s'"; "--date=short"; "-n 10" ] in
- String.concat " " (cmd :: options)
+ let command = sprintf "git -C %s log" full_path in
+ let options =
+ let format = "--pretty=format:'%ad %s'" in
+ let date = "--date=short" in
+ let count = sprintf "-n %s" (string_of_int count) in
+ [ format; date; count ]
+ in
+ String.concat " " (command :: options)
in
let ic = Unix.open_process_in full_cmd in
let rec read_lines acc =
@@ -17,3 +23,24 @@ let get_git_log repo_path =
List.rev acc
in
read_lines []
+
+let get_all_branches repo_path =
+ let open Printf in
+ let full_path = Filename.concat Config.git_directory repo_path in
+ let full_cmd = sprintf "git -C %s branch" full_path in
+ let ic = Unix.open_process_in full_cmd in
+ let rec read_lines acc =
+ try
+ let line = input_line ic |> String.trim in
+ let clean_line =
+ if String.length line > 2 && String.sub line 0 2 = "* " then
+ String.sub line 2 (String.length line - 2)
+ (* Remove "* " from active branch *)
+ else line
+ in
+ read_lines (clean_line :: acc)
+ with End_of_file ->
+ ignore (Unix.close_process_in ic);
+ List.rev acc
+ in
+ read_lines []
diff --git a/lib/handlers.ml b/lib/handlers.ml
index 4a6e0ca..46df354 100644
--- a/lib/handlers.ml
+++ b/lib/handlers.ml
@@ -1,6 +1,3 @@
-open Lwt.Infix
-
let ogit_root _ = Views.Ogit_root.render () |> Dream_html.respond
-
-let repo_root repo_name =
- Views.Repo_root.render repo_name >>= Dream_html.respond
+let repo_root repo_name = Views.Repo_root.render repo_name |> Dream_html.respond
+let repo_tree repo_name = Views.Repo_tree.render repo_name |> Dream_html.respond
diff --git a/lib/views.ml b/lib/views.ml
index 446d601..2d11674 100644
--- a/lib/views.ml
+++ b/lib/views.ml
@@ -32,7 +32,7 @@ module Layout = struct
];
body []
[
- header "Ogit" body_data.subtitle;
+ header body_data.title body_data.subtitle;
body_data.topnav;
div [ id "main" ] body_data.content;
footer;
@@ -40,6 +40,60 @@ module Layout = struct
]
end
+module Topnav = struct
+ open Dream_html
+ open HTML
+
+ let repo repo_path current_path =
+ let li_of_a (path, text) =
+ let is_active = path = current_path in
+ let attrs = if is_active then [ id "active" ] else [] in
+ let url =
+ if String.length path = 0 then Printf.sprintf "/%s" repo_path
+ else Printf.sprintf "/%s/%s" repo_path path
+ in
+ li attrs [ a [ href "%s" url ] [ txt text ] ]
+ in
+ nav
+ [ id "top" ]
+ [
+ ul []
+ @@ List.map li_of_a
+ [
+ ("", "summary");
+ ("refs", "refs");
+ ("log", "log");
+ ("tree", "tree");
+ ("commit", "commit");
+ ("diff", "diff");
+ ];
+ ]
+
+ (* let li_of_a (path, text) = *)
+ (* let is_active = path = current_path in *)
+ (* li (if is_active then [ id "active" ] else []) in *)
+ (* let link_of_path = *)
+ (* if String.length path = 0 then Printf.sprintf "/%s" repo_path *)
+ (* else Printf.sprintf "/%s/%s" repo_path path *)
+ (* in *)
+ (* li [ id "active" ] [ a [ href "%s" link_of_path ] [ txt text ] ] *)
+ (* in *)
+ (* nav *)
+ (* [ id "top" ] *)
+ (* [ *)
+ (* ul [] *)
+ (* @@ List.map li_of_a *)
+ (* [ *)
+ (* ("", "summary"); *)
+ (* ("refs", "refs"); *)
+ (* ("log", "log"); *)
+ (* ("tree", "tree"); *)
+ (* ("commit", "commit"); *)
+ (* ("diff", "diff"); *)
+ (* ]; *)
+ (* ] *)
+end
+
module Ogit_root = struct
open Dream_html
open HTML
@@ -56,7 +110,7 @@ module Ogit_root = struct
let body_data =
{
- title = "My repositories";
+ title = "Ogit";
subtitle = "Repositories for " ^ Config.author;
topnav = null [];
content = [ repositories_in Config.git_directory ];
@@ -68,57 +122,78 @@ end
module Repo_root = struct
open Dream_html
open HTML
- (* open Lwt.Syntax *)
+
+ (* let href_for_git_object kind identifier = *)
+ (* let open Printf in *)
+ (* href "%s" @@ *)
+ (* match kind with *)
+ (* | `Branch -> sprintf "/tree/%s" identifier *)
+ (* | `Commit -> sprintf "/commit/%s" identifier *)
let render repo_path =
- (* let* title_result = Git_helpers.get_head_commit_hash repo_path in *)
- (* let title = *)
- (* match title_result with Ok hash -> hash | Error msg -> "Error: " ^ msg *)
- (* in *)
- let title = "Finble" in
+ let title = repo_path in
let subtitle = Filename.concat Config.git_directory repo_path in
- let topnav =
- nav
- [ id "top" ]
- [
- ul []
- [
- li [] [ a [ href "/" ] [ txt "summary" ] ];
- li [] [ a [ href "/" ] [ txt "refs" ] ];
- li [] [ a [ href "/" ] [ txt "log" ] ];
- li [] [ a [ href "/" ] [ txt "tree" ] ];
- li [] [ a [ href "/" ] [ txt "commit" ] ];
- li [] [ a [ href "/" ] [ txt "diff" ] ];
- ];
- ]
+ let all_branches = Git_unhelpers.get_all_branches repo_path in
+ let li_of_branch branch =
+ li [] [ a [ href "%s" branch ] [ txt "%s" branch ] ]
in
- let recent_commits = Git_unhelpers.get_git_log repo_path in
+ let recent_commits = Git_unhelpers.get_latest_commits repo_path 10 in
let li_of_commit commit =
li [] [ a [ href "%s" commit ] [ txt "%s" commit ] ]
in
let content =
[
+ h3 [] [ txt "Branches" ];
+ ul [] (List.map li_of_branch all_branches);
h3 [] [ txt "Recent commits" ];
- ul [] @@ List.map li_of_commit recent_commits;
+ ul [] (List.map li_of_commit recent_commits);
]
in
- let body_data = { title; subtitle; topnav; content } in
- Lwt.return @@ Layout.application body_data
+ let body_data =
+ { title; subtitle; topnav = Topnav.repo repo_path ""; content }
+ in
+ Layout.application body_data
end
module Repo_tree = struct
open Dream_html
open HTML
- open Lwt.Syntax
+ let full_path repo_path = Filename.concat Config.git_directory repo_path
+
+ (* Helper function to list top-level files and directories *)
+ let ls_repo repo_path =
+ try
+ Sys.readdir (full_path repo_path)
+ |> Array.to_list
+ |> List.filter (fun name -> name <> ".git") (* Exclude .git *)
+ |> List.sort String.compare
+ with Sys_error _ -> []
+
+ (* Function to create a link based on file type *)
+ let link_for_entry repo_path entry =
+ let entry_path = Filename.concat (full_path repo_path) entry in
+ if Sys.is_directory entry_path then
+ a
+ [ href "%s" @@ Printf.sprintf "/%s/tree/%s" repo_path entry ]
+ [ txt "%s" (entry ^ "/") ]
+ else
+ a
+ [ href "%s" @@ Printf.sprintf "/%s/blob/%s" repo_path entry ]
+ [ txt "%s" entry ]
+
+ let li_of_entry repo_path entry = li [] [ link_for_entry repo_path entry ]
+
+ (* Render function *)
let render repo_path =
- let* title_result = Git_helpers.get_head_commit_hash repo_path in
- let title =
- match title_result with Ok hash -> hash | Error msg -> "Error: " ^ msg
+ let title = repo_path in
+ let subtitle = "Files" in
+
+ let repo_entries = ls_repo repo_path in
+ let content = [ ul [] (List.map (li_of_entry repo_path) repo_entries) ] in
+
+ let body_data =
+ { title; subtitle; topnav = Topnav.repo repo_path "tree"; content }
in
- let subtitle = "Dinglefops" in
- let topnav = null [] in
- let content = [ txt "foobar" ] in
- let body_data = { title; subtitle; topnav; content } in
- Lwt.return @@ Layout.application body_data
+ Layout.application body_data
end
Copyright 2019--2025 Marius PETER