summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/git_helpers.ml91
-rw-r--r--lib/handlers.ml54
-rw-r--r--lib/static/styles.css7
-rw-r--r--lib/views.ml215
4 files changed, 204 insertions, 163 deletions
diff --git a/lib/git_helpers.ml b/lib/git_helpers.ml
index 5e5d4cd..ed917a8 100644
--- a/lib/git_helpers.ml
+++ b/lib/git_helpers.ml
@@ -4,13 +4,6 @@ module Value = Git.Value
type user_record = { name : string; email : string }
-type commit_record = {
- hash : string;
- parents : string list;
- author : Git.User.t;
- message : string option;
-}
-
let full_path path = Filename.concat Config.git_directory path
let store repo_path =
@@ -23,39 +16,51 @@ let repo_description repo_path =
let description_path = Filename.concat (full_path repo_path) "description" in
In_channel.with_open_text description_path In_channel.input_all
-(* Read a Git object and turn it into our [commit_record], or propagate an error. *)
-let get_commit_record store h =
- Store.read store h >>= function
- | Ok (Value.Commit c) ->
- Lwt.return_ok
- {
- hash = Store.Hash.to_hex h;
- parents = Store.Value.Commit.parents c |> List.map Store.Hash.to_hex;
- author = Store.Value.Commit.author c;
- message = Store.Value.Commit.message c;
- }
- | Ok _ -> Lwt.return_error (`Msg "object is not a commit")
- | Error e -> Lwt.return_error e
-
-let recent_commits repo_path n =
- let open Lwt_result.Syntax in
- let* store = store repo_path in
- let* head = Store.Ref.resolve store Git.Reference.head in
- let rec walk acc hash count =
- if count = 0 then Lwt.return_ok (List.rev acc)
- else
- get_commit_record store hash >>= function
- | Error e -> Lwt.return_error e
- | Ok commit -> (
- match commit.parents with
- | parent :: _ ->
- walk (commit :: acc) (Store.Hash.of_hex parent) (count - 1)
- | [] -> Lwt.return_ok (List.rev (commit :: acc)))
- in
- walk [] head n
-
-let get_commit repo_path id =
- let open Lwt_result.Syntax in
- let* store = store repo_path in
- let id = Store.Hash.of_hex id in
- get_commit_record store id
+module Commit = struct
+ type t = {
+ hash : string;
+ parents : string list;
+ author : Git.User.t;
+ message : string option;
+ }
+
+ let of_hash store h =
+ Store.read store h >>= function
+ | Ok (Value.Commit c) ->
+ Lwt_result.return
+ {
+ hash = Store.Hash.to_hex h;
+ parents = Store.Value.Commit.parents c |> List.map Store.Hash.to_hex;
+ author = Store.Value.Commit.author c;
+ message = Store.Value.Commit.message c;
+ }
+ | Ok _ -> Lwt.return_error (`Msg "object is not a commit")
+ | Error e -> Lwt.return_error e
+
+ let recent_commits repo_path n =
+ let open Lwt_result.Syntax in
+ let* store = store repo_path in
+ let* head = Store.Ref.resolve store Git.Reference.head in
+ let rec walk acc hash count =
+ if count = 0 then Lwt_result.return (List.rev acc)
+ else
+ of_hash store hash >>= function
+ | Error e -> Lwt.return_error e
+ | Ok commit -> (
+ match commit.parents with
+ | parent :: _ ->
+ walk (commit :: acc) (Store.Hash.of_hex parent) (count - 1)
+ | [] -> Lwt_result.return (List.rev (commit :: acc)))
+ in
+ walk [] head n
+
+ let of_id repo_path id =
+ let open Lwt_result.Syntax in
+ let* store = store repo_path in
+ let id = Store.Hash.of_hex id in
+ of_hash store id
+end
+
+module Branch = struct
+ let all_branches repo_path = [ "foo"; "bar"; repo_path ]
+end
diff --git a/lib/handlers.ml b/lib/handlers.ml
index 95aecd3..321c693 100644
--- a/lib/handlers.ml
+++ b/lib/handlers.ml
@@ -6,41 +6,39 @@ let ( let* ) m f =
let msg = Format.asprintf "%a" Git_unix.Store.pp_error e in
Views.error_page msg |> Dream_html.respond
-let ogit_root _req = Views.ogit_root () |> Dream_html.respond
+let root _req = Views.root () |> Dream_html.respond
-let repo_summary req =
- let repo_path = Dream.param req "repo_name" in
- let branches = [ "bing"; "bong" ] in
- let* commits = Git_helpers.recent_commits repo_path 10 in
- Views.repo_summary repo_path branches commits |> Dream_html.respond
+module Repo = struct
+ let repo_path req = Dream.param req "repo_name"
-let repo_commit req =
- let repo_path = Dream.param req "repo_name" in
- let id = match Dream.query req "id" with Some id -> id | None -> "" in
- let* commit = Git_helpers.get_commit repo_path id in
- Views.repo_commit repo_path commit |> Dream_html.respond
+ let summary req =
+ let branches = Git_helpers.Branch.all_branches (repo_path req) in
+ let* commits = Git_helpers.Commit.recent_commits (repo_path req) 10 in
+ let authors = [ "John Pork"; "Sebastian Jellybean" ] in
+ Views.Repo.summary (repo_path req) branches commits authors
+ |> Dream_html.respond
-(* let repo_tree req = *)
-(* let repo_name = Dream.param req "repo_name" in *)
-(* let path = Git_helpers.full_path repo_name in *)
-(* let dir_path = Dream.target req in *)
-(* Views.repo_tree ~repo_path:path dir_path |> Dream_html.respond *)
+ let refs req = Views.Repo.refs (repo_path req) |> Dream_html.respond
+ let log req = Views.Repo.log (repo_path req) |> Dream_html.respond
+ let tree req = Views.Repo.tree (repo_path req) |> Dream_html.respond
-(* let repo_blob req = *)
-(* let repo_name = Dream.param req "repo_name" in *)
-(* let path = Git_helpers.full_path repo_name in *)
-(* let blob_path = Dream.query req "path" |> Option.value ~default:"" in *)
-(* Views.repo_blob repo_name blob_path |> Dream_html.respond *)
+ let commit req =
+ let id = match Dream.query req "id" with Some id -> id | None -> "" in
+ let* commit = Git_helpers.Commit.of_id (repo_path req) id in
+ Views.Repo.commit (repo_path req) commit |> Dream_html.respond
+end
let all_handlers =
[
- Dream.get "/" ogit_root;
+ Dream.get "/" root;
Dream.scope "/:repo_name" []
- [
- Dream.get "/" repo_summary;
- Dream.get "/commit/" repo_commit;
- (* Dream.get "/tree" repo_tree; *)
- (* Dream.get "/blob" repo_blob; *)
- ];
+ Repo.
+ [
+ Dream.get "/" summary;
+ Dream.get "/refs/" refs;
+ Dream.get "/log/" log;
+ Dream.get "/tree/" tree;
+ Dream.get "/commit/" commit;
+ ];
Dream.get "/static/**" (Dream.static "./lib/static");
]
diff --git a/lib/static/styles.css b/lib/static/styles.css
index de2c3db..ae8a86c 100644
--- a/lib/static/styles.css
+++ b/lib/static/styles.css
@@ -69,3 +69,10 @@ div#main a:hover {
color: black;
text-decoration: revert;
}
+
+h1 {
+ position: sticky;
+ top: 0;
+ background: inherit;
+ padding: 0.5em 0;
+}
diff --git a/lib/views.ml b/lib/views.ml
index 3c1330e..e023236 100644
--- a/lib/views.ml
+++ b/lib/views.ml
@@ -3,11 +3,39 @@ type head_data = { page_title : string }
type body_data = {
title : string;
subtitle : string;
- topnav : Dream_html.node;
content : Dream_html.node list;
}
-module Layout = struct
+module Components = struct
+ open Dream_html
+
+ let topnav current_path =
+ let open HTML in
+ 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.equal path "/" then Printf.sprintf "/%s/" current_path
+ else Printf.sprintf "/%s/%s" current_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");
+ ];
+ ]
+end
+
+module Page = struct
open Dream_html
open HTML
@@ -22,7 +50,7 @@ module Layout = struct
let default_head_data = { page_title = "Ogit" }
- let application ?(head_data = default_head_data) body_data =
+ let render ?(head_data = default_head_data) body_data =
html []
[
head []
@@ -35,44 +63,14 @@ module Layout = struct
body []
[
header body_data.title body_data.subtitle;
- body_data.topnav;
+ Components.topnav body_data.title;
div [ id "main" ] body_data.content;
footer ();
];
]
end
-module Components = struct
- open Dream_html
-
- let topnav repo_path current_path =
- let open HTML in
- 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.equal path "/" 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");
- ];
- ]
-end
-
-let ogit_root () =
+let root () =
let open Dream_html in
let repositories_in directory =
let repos =
@@ -87,60 +85,88 @@ let ogit_root () =
{
title = "Ogit";
subtitle = "Repositories for " ^ Config.author;
- topnav = HTML.(null []);
content = [ repositories_in Config.git_directory ];
}
in
- Layout.application body_data
+ Page.render body_data
-let repo_summary repo_path branches commits =
- let open Git_helpers in
- let open Dream_html in
- let li_of_branch branch =
- HTML.(li [] [ a [ href "%s" branch ] [ txt "%s" branch ] ])
- in
- let li_of_commit commit =
- match commit.message with
- | Some msg ->
- HTML.(
- li []
- [
- a
- [ href "commit/?id=%s" commit.hash ]
- [ txt "%s %s" (short_hash commit.hash) msg ];
- ])
- | None -> HTML.(li [] [ a [ href "" ] [ txt "caca!!" ] ])
- in
- let content =
- HTML.
- [
- h3 [] [ txt "Branches" ];
- ul [] (List.map li_of_branch branches);
- h3 [] [ txt "Recent commits" ];
- ul [] (List.map li_of_commit commits);
- ]
- in
- Layout.application
- {
- title = repo_path;
- subtitle = repo_description repo_path;
- topnav = Components.topnav repo_path "";
- content;
- }
+module Repo = struct
+ let summary repo_path branches commits authors =
+ let open Dream_html in
+ let li_of_branch branch =
+ HTML.(li [] [ a [ href "%s" branch ] [ txt "%s" branch ] ])
+ in
+ let li_of_commit (commit : Git_helpers.Commit.t) =
+ match commit.message with
+ | Some msg ->
+ HTML.(
+ li []
+ [
+ a
+ [ href "commit/?id=%s" commit.hash ]
+ [ txt "%s %s" (Git_helpers.short_hash commit.hash) msg ];
+ ])
+ | None -> HTML.(li [] [ a [ href "" ] [ txt "caca!!" ] ])
+ in
+ let li_of_author author =
+ HTML.(li [] [ a [ href "" ] [ txt "%s" author ] ])
+ in
+ let content =
+ HTML.
+ [
+ h3 [] [ txt "Branches" ];
+ ul [] (List.map li_of_branch branches);
+ h3 [] [ txt "Recent commits" ];
+ ul [] (List.map li_of_commit commits);
+ h3 [] [ txt "Authors" ];
+ ul [] (List.map li_of_author authors);
+ ]
+ in
+ Page.render
+ {
+ title = repo_path;
+ subtitle = Git_helpers.repo_description repo_path;
+ content;
+ }
-let repo_commit repo_path commit =
- let open Git_helpers in
- let open Dream_html in
- let message = match commit.message with Some msg -> msg | None -> "" in
- let content = HTML.[ h3 [] [ txt "%s" message ] ] in
- let title = Printf.sprintf "%s : %s" repo_path (short_hash commit.hash) in
- Layout.application
- {
- title;
- subtitle = "";
- topnav = Components.topnav repo_path "";
- content;
- }
+ let refs repo_path =
+ let open Dream_html in
+ Page.render
+ HTML.
+ {
+ title = repo_path;
+ subtitle = Git_helpers.repo_description repo_path;
+ content = [ null [] ];
+ }
+
+ let log repo_path =
+ let open Dream_html in
+ Page.render
+ HTML.
+ {
+ title = repo_path;
+ subtitle = Git_helpers.repo_description repo_path;
+ content = [ null [] ];
+ }
+
+ let tree repo_path =
+ let open Dream_html in
+ Page.render
+ HTML.
+ {
+ title = repo_path;
+ subtitle = Git_helpers.repo_description repo_path;
+ content = [ null [] ];
+ }
+
+ let commit repo_path (commit : Git_helpers.Commit.t) =
+ let open Dream_html in
+ let open Git_helpers in
+ let message = match commit.message with Some msg -> msg | None -> "" in
+ let content = HTML.[ h3 [] [ txt "%s" message ] ] in
+ let title = Printf.sprintf "%s : %s" repo_path (short_hash commit.hash) in
+ Page.render { title; subtitle = ""; content }
+end
let error_page message =
let open Dream_html in
@@ -149,19 +175,24 @@ let error_page message =
[
head []
[
- title [] "Big error";
+ title [] "Fatal Error";
link [ rel "stylesheet"; href "/static/styles.css" ];
link
[ rel "icon"; type_ "image/x-icon"; href "/static/git_icon.svg" ];
];
body []
[
- h1 [] [ txt "Major error alert" ];
- h2 [] [ txt "Major alert subtitle" ];
- (* Components.topnav; *)
- div [ id "main" ] [ txt "%s" message ];
+ h1 [] [ txt "Fatal Error" ];
+ div
+ [ id "main" ]
+ [
+ p [] [ b [] [ txt "%s" message ] ];
+ p []
+ [
+ txt
+ "Your best course of action is to press the 'back' \
+ button in your browser.";
+ ];
+ ];
];
])
-
-let repo_tree repo_path = repo_summary repo_path
-let repo_blob repo_path = repo_summary repo_path
Copyright 2019--2025 Marius PETER