diff options
| author | Marius Peter <marius.peter@tutanota.com> | 2025-06-08 01:37:48 +0200 | 
|---|---|---|
| committer | Marius Peter <marius.peter@tutanota.com> | 2025-06-08 01:37:48 +0200 | 
| commit | ef89b655e942603605d0d94837ba2407f86352bf (patch) | |
| tree | 2094062f4a6cb7ea95a736815d3a05488cba9027 /lib | |
| parent | 0647fb79dea80219ea0b0be2b315163d9a5d3ae2 (diff) | |
Implement Tree and Blob views.
Getting real close to something good now!
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/git_presenters.ml | 62 | ||||
| -rw-r--r-- | lib/handlers.ml | 8 | ||||
| -rw-r--r-- | lib/routes.ml | 32 | ||||
| -rw-r--r-- | lib/views.ml | 56 | 
4 files changed, 101 insertions, 57 deletions
| diff --git a/lib/git_presenters.ml b/lib/git_presenters.ml index f0a0317..215e9c5 100644 --- a/lib/git_presenters.ml +++ b/lib/git_presenters.ml @@ -3,6 +3,7 @@  module Store = Git_unix.Store  open Lwt_result.Syntax  open Config +open Lwt_result.Infix  let full_path path = Filename.concat config.git_project_root path @@ -69,8 +70,10 @@ let all_branches repo =    let* refs = Store.Ref.list store in    let branches =      List.map -      (fun (ref, hash) -> -        { name = Git.Reference.to_string ref; hash = Store.Hash.to_hex hash }) +      (fun (reference, hash) -> +        let name = Git.Reference.to_string reference in +        let hash = Store.Hash.to_hex hash in +        { name; hash })        refs    in    Lwt_result.return branches @@ -83,37 +86,45 @@ type tree_entry = {  }  type tree = { hash : string; short_hash : string; entries : tree_entry list } - -let to_entry _ = -  { -    hash = "foo"; -    short_hash = String.sub "foobar" 0 8; -    name = "foobarbino"; -    perm = 122; -  } +type blob = { content : string } + +let to_entry (entry : Store.Value.Tree.entry) = +  let perm = +    match entry.perm with +    | `Commit -> 0o160000 +    | `Dir -> 0o040000 +    | `Everybody -> 0o100664 +    | `Exec -> 0o100755 +    | `Link -> 0o120000 +    | `Normal -> 0o100644 +  in +  let hash = Store.Hash.to_hex entry.node in +  let short_hash = String.sub hash 0 8 in +  { hash; short_hash; name = entry.name; perm }  let present_tree tree = Store.Value.Tree.to_list tree |> List.map to_entry  let to_tree store hash = -  let* v = Store.read store hash in -  match v with +  Store.read store hash >>= function    | Git.Value.Tree tree ->        let hash = Store.Hash.to_hex hash in -      Lwt_result.return -        { hash; short_hash = String.sub hash 0 8; entries = present_tree tree } -  | _ -> -      Dream.log "Value is not a tree"; -      Lwt_result.fail (`Msg "value is not a tree") +      let short_hash = String.sub hash 0 8 in +      let entries = present_tree tree in +      Lwt_result.return { hash; short_hash; entries } +  | _ -> Lwt_result.fail (`Msg "value is not a tree") + +let to_blob store hash = +  Store.read store hash >>= function +  | Git.Value.Blob blob -> +      let content = Store.Value.Blob.to_string blob in +      Lwt_result.return { content } +  | _ -> Lwt_result.fail (`Msg "value is not a tree")  let head_tree_id store = -  let* commit_hash = Store.Ref.resolve store Git.Reference.head in -  let* v = Store.read store commit_hash in -  match v with +  Store.Ref.resolve store Git.Reference.head >>= Store.read store >>= function    | Git.Value.Commit commit ->        Store.Value.Commit.tree commit |> Lwt_result.return -  | _ -> -      Dream.log "no head tree id"; -      Lwt_result.fail (`Msg "") +  | _ -> `Msg "no head tree id" |> Lwt_result.fail  let head_tree repo =    let* store = store repo in @@ -124,3 +135,8 @@ let tree_of_id repo id =    let* store = store repo in    let* hash = Lwt_result.return (Store.Hash.of_hex id) in    to_tree store hash + +let blob_of_id repo id = +  let* store = store repo in +  let* hash = Lwt_result.return (Store.Hash.of_hex id) in +  to_blob store hash diff --git a/lib/handlers.ml b/lib/handlers.ml index 17f3ac0..21d3ea8 100644 --- a/lib/handlers.ml +++ b/lib/handlers.ml @@ -31,16 +31,19 @@ module Repo = struct      Views.Repo.log (repo req) commits |> Dream_html.respond    let tree_head req = -    Dream.log "Tree head";      let* tree = head_tree (repo req) in      Views.Repo.tree (repo req) tree |> Dream_html.respond    let tree_id req = -    Dream.log "Tree id";      let id = id_of_req req in      let* tree = tree_of_id (repo req) id in      Views.Repo.tree (repo req) tree |> Dream_html.respond +  let blob_id req = +    let id = id_of_req req in +    let* blob = blob_of_id (repo req) id in +    Views.Repo.blob (repo req) blob |> Dream_html.respond +    let commit req =      let id = id_of_req req in      let* commit = commit_of_id (repo req) id in @@ -59,6 +62,7 @@ let all_handlers =              get "/log/" log;              get "/tree/" tree_head;              get "/tree/:id" tree_id; +            get "/blob/:id" blob_id;              get "/commit/:id" commit;            ];        get "/static/**" (static "./lib/static"); diff --git a/lib/routes.ml b/lib/routes.ml index c136152..84c2851 100644 --- a/lib/routes.ml +++ b/lib/routes.ml @@ -1,29 +1,29 @@  (* -*- mode: tuareg; -*- *) -open Dream_html -open HTML -  type t =    | Root    | Repo of string    | Tag of string * string    | Commit of string * string -  | Tree of string * string * string -  | Blob of string * string * string +  | Tree of string * string +  | Blob of string * string  let%path root_path = "/"  let%path repo_path = "/%s/"  let%path tag_path = "/%s/refs/%s"  let%path commit_path = "/%s/commit/%s" -let%path tree_path = "/%s/tree/%s/%s" -let%path blob_path = "/%s/blob/%s/%s" - -let path_attr = function -  | Root -> path_attr href root_path -  | Repo repo -> path_attr href repo_path repo -  | Tag (repo, branch) -> path_attr href tag_path repo branch -  | Commit (repo, commit) -> path_attr href commit_path repo commit -  | Tree (repo, commit, path) -> path_attr href tree_path repo commit path -  | Blob (repo, commit, path) -> path_attr href blob_path repo commit path +let%path tree_path = "/%s/tree/%s" +let%path blob_path = "/%s/blob/%s" -let link_to route content = a [ path_attr route ] [ content ] +let link_to route contents = +  let open Dream_html in +  let open HTML in +  let path = function +    | Root -> path_attr href root_path +    | Repo repo -> path_attr href repo_path repo +    | Tag (repo, branch) -> path_attr href tag_path repo branch +    | Commit (repo, commit) -> path_attr href commit_path repo commit +    | Tree (repo, hash) -> path_attr href tree_path repo hash +    | Blob (repo, hash) -> path_attr href blob_path repo hash +  in +  a [ path route ] [ contents ] diff --git a/lib/views.ml b/lib/views.ml index b6cf617..e1056b7 100644 --- a/lib/views.ml +++ b/lib/views.ml @@ -1,7 +1,6 @@  (* -*- mode: tuareg; -*- *)  open Dream_html -open Git_presenters  open Config  type body_data = { @@ -16,9 +15,7 @@ module Components = struct    let topnav repo =      let open HTML in -    let () = Dream.log "%s" ("current path is: " ^ repo) in      let li_of_a (path, text) = -      let () = Dream.log "%s" ("and path is: " ^ path) in        let is_active = String.ends_with ~suffix:path repo in        let attrs = if is_active then [ id "active" ] else [] in        let url = Printf.sprintf "/%s/%s" repo path in @@ -98,7 +95,10 @@ let root () =    Page.render body_data  module Repo = struct +  open Git_presenters +    let page_title repo = Printf.sprintf "%s — %s" repo (repo_description repo) +  let li_of_author author = HTML.(li [] [ txt "%s" author ])    let li_of_branch repo (branch : branch) =      HTML.( @@ -120,17 +120,24 @@ module Repo = struct                   ]);            ] +  let li_of_entry repo entry = +    let display_name = +      if entry.perm = 0o040000 then entry.name ^ "/" else entry.name +    in +    let route = +      if entry.perm = 0o040000 then Routes.Tree (repo, entry.hash) +      else Routes.Blob (repo, entry.hash) +    in +    HTML.(li [] [ Routes.link_to route @@ txt "%s" display_name ]) +    let summary repo branches commits authors = -    let li_of_branch = li_of_branch repo in -    let li_of_commit = li_of_commit repo in -    let li_of_author author = HTML.(li [] [ txt "%s" author ]) in      let content =        HTML.          [            h3 [] [ txt "Branches" ]; -          ul [] (List.map li_of_branch branches); +          ul [] (List.map (li_of_branch repo) branches);            h3 [] [ txt "Recent commits" ]; -          ul [] (List.map li_of_commit commits); +          ul [] (List.map (li_of_commit repo) commits);            h3 [] [ txt "Authors" ];            ul [] (List.map li_of_author authors);          ] @@ -144,9 +151,12 @@ module Repo = struct        }    let refs repo branches = -    let li_of_branch = li_of_branch repo in      let content = -      HTML.[ h3 [] [ txt "Branches" ]; ul [] (List.map li_of_branch branches) ] +      HTML. +        [ +          h3 [] [ txt "Branches" ]; +          ul [] (List.map (li_of_branch repo) branches); +        ]      in      Page.render ~page_title:(page_title repo)        { @@ -157,10 +167,12 @@ module Repo = struct        }    let log repo commits = -    let li_of_commit = li_of_commit repo in      let content =        HTML. -        [ h3 [] [ txt "All commits" ]; ul [] (List.map li_of_commit commits) ] +        [ +          h3 [] [ txt "All commits" ]; +          ul [] (List.map (li_of_commit repo) commits); +        ]      in      Page.render ~page_title:(page_title repo)        { @@ -171,13 +183,12 @@ module Repo = struct        }    let tree repo tree = -    let title = Printf.sprintf "%s : %s" repo tree.short_hash in -    let li_of_entry entry = HTML.(li [] [ txt "%s" entry.name ]) in +    let title = Printf.sprintf "%s" repo in      let content =        HTML.          [            h3 [] [ txt "Tree %s" tree.short_hash ]; -          ul [] (List.map li_of_entry tree.entries); +          ul [] (List.map (li_of_entry repo) tree.entries);          ]      in      Page.render ~page_title:(page_title repo) @@ -188,6 +199,19 @@ module Repo = struct          content;        } +  let blob repo blob = +    let title = Printf.sprintf "%s" repo in +    let content = +      HTML.[ h3 [] [ txt "Blob" ]; p [] [ txt "%s" blob.content ] ] +    in +    Page.render ~page_title:(page_title repo) +      { +        title; +        subtitle = repo_description repo; +        topnav = Components.topnav repo; +        content; +      } +    let commit repo commit =      let message = match commit.message with Some msg -> msg | None -> "" in      let title = Printf.sprintf "%s : %s" repo commit.short_hash in @@ -207,7 +231,7 @@ let error_page message =        [          head []            [ -            title [] "Fatal Error"; +            title [] "Fatal error";              link [ rel "stylesheet"; href "/static/styles.css" ];              link                [ rel "icon"; type_ "image/x-icon"; href "/static/git_icon.svg" ]; | 
