2022-02-27 12:28:57 (UTC-03:00)
Marcel Rodrigues <marcelgmr@gmail.com>
add tree browsing
diff --git a/app.lua b/app.lua index 32f21ef..fb1ef47 100644 --- a/app.lua +++ b/app.lua @@ -101,6 +101,28 @@ local routes = { } return lud.template.render_file("view/commit.html", env) end}, + {"GET", "/group/([%w_-]+)/repo/([%w_-]+)/commit/([%w_-]+)/tree/(.*)", + function (req, gname, rname, cid, path) + local repo = groups[gname][rname] + local commit = repo:commit(cid) + local node = commit:tree_entry(path) + if node == nil then + return "File not found", 404, "Not found" + end + local parts = {} + for part in path:gmatch("[^/]+") do + table.insert(parts, part) + end + local env = { + gname=gname, rname=rname, cid=cid, path=path, + base=req.path, parts=parts, node=node, + } + if node.type_ == "dir" then + return lud.template.render_file("view/dir.html", env) + elseif node.type_ == "file" then + return lud.template.render_file("view/file.html", env) + end + end}, } local app = lud.app.new_app(routes) diff --git a/git.lua b/git.lua index c444cc3..5b7e399 100644 --- a/git.lua +++ b/git.lua @@ -133,6 +133,13 @@ int git_commit_tree(git_tree **tree_out, const git_commit *commit); size_t git_tree_entrycount(const git_tree *tree); const git_tree_entry * git_tree_entry_byindex(const git_tree *tree, size_t idx); git_object_t git_tree_entry_type(const git_tree_entry *entry); +const char * git_tree_entry_name(const git_tree_entry *entry); +int git_tree_entry_bypath(git_tree_entry **out, const git_tree *root, const char *path); +int git_tree_entry_to_object(git_object **object_out, git_repository *repo, const git_tree_entry *entry); +void git_tree_entry_free(git_tree_entry *entry); + +git_object_size_t git_blob_rawsize(const git_blob *blob); +const void * git_blob_rawcontent(const git_blob *blob); int git_diff_tree_to_tree(git_diff **diff, git_repository *repo, git_tree *old_tree, git_tree *new_tree, const git_diff_options *opts); int git_diff_print(git_diff *diff, git_diff_format_t format, git_diff_line_cb print_cb, void *payload); @@ -151,8 +158,8 @@ end local Commit = {} Commit.__index = Commit -local function get_commit(commit) - return setmetatable({commit=commit}, Commit) +local function get_commit(commit, repo) + return setmetatable({commit=commit, repo=repo}, Commit) end function Commit:id(len) @@ -185,7 +192,7 @@ function Commit:parent(n) local pcommit = ffi.new("git_commit *[1]") local ret = C.git_commit_parent(pcommit, self.commit, n-1) if ret == 0 then - return get_commit(pcommit[0]) + return get_commit(pcommit[0], self.repo) else return nil end @@ -201,6 +208,60 @@ function Commit:tree() end end +function Commit:children(tree) + local n = tonumber(C.git_tree_entrycount(tree)) + local children = {} + for i = 1, n do + local entry = C.git_tree_entry_byindex(tree, i-1) + local entry_type = C.git_tree_entry_type(entry) + local entry_name = ffi.string(C.git_tree_entry_name(entry)) + local child + if entry_type == 2 then + child = entry_name.."/" + elseif entry_type == 3 then + child = entry_name + end + table.insert(children, child) + end + return children +end + +function Commit:node(entry) + local entry_type = C.git_tree_entry_type(entry) + local entry_name = C.git_tree_entry_name(entry) + local pobj = ffi.new("git_object *[1]") + C.git_tree_entry_to_object(pobj, self.repo, entry) + if entry_type == 2 then + local tree = ffi.cast("git_tree *", pobj[0]) + local children = self:children(tree) + return {type_="dir", name=name, children=children} + elseif entry_type == 3 then + local blob = ffi.cast("git_blob *", pobj[0]) + local data = ffi.string(C.git_blob_rawcontent(blob), C.git_blob_rawsize(blob)) + return {type_="file", name=name, data=data} + else + return nil + end +end + +function Commit:tree_entry(path) + local tree = self:tree() + if tree == nil then + return nil + end + if path == "" then + local children = self:children(tree) + return {type_="dir", name="", children=children} + end + local pentry = ffi.new("git_tree_entry *[1]") + local ret = C.git_tree_entry_bypath(pentry, tree, path) + if ret == 0 then + return self:node(pentry[0]) + else + return nil + end +end + local Repo = {} Repo.__index = Repo @@ -240,7 +301,7 @@ function Repo:commit(rev) C.git_commit_lookup(pcommit, self.repo, oid) local commit = pcommit[0] C.git_object_free(obj) - return get_commit(commit) + return get_commit(commit, self.repo) end function Repo:find_prev(cid, dist) diff --git a/view/dir.html b/view/dir.html new file mode 100644 index 0000000..8a1ee2f --- /dev/null +++ b/view/dir.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>cogit - {{$gname}} - {{$rname}} - {{$cid}} - {{path}}</title> +</head> +<body> + <p> + <a href="/">home</a> + > + <a href="/group/{{$gname}}">{{$gname}}</a> + > + <a href="/group/{{$gname}}/repo/{{$rname}}">{{$rname}}</a> + > + <a href="/group/{{$gname}}/repo/{{$rname}}/commit/{{$cid}}">{{$cid}}</a> + > + % set partial = "/group/"..$gname.."/repo/"..$rname.."/commit/"..$cid.."/tree" + <a href="{{$partial}}/">tree</a> + % for part in $parts do + % set partial = $partial .. "/" .. $part + > + <a href="{{$partial}}">{{$part}}</a> + % end + </p> + <ul> + % for child in $node.children do + <li><a href="{{$base..$child}}">{{$child}}</a></li> + % end + </ul> +</body> +</html> diff --git a/view/file.html b/view/file.html new file mode 100644 index 0000000..eaf79e0 --- /dev/null +++ b/view/file.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>cogit - {{$gname}} - {{$rname}} - {{$cid}} - {{path}}</title> +</head> +<body> + <p> + <a href="/">home</a> + > + <a href="/group/{{$gname}}">{{$gname}}</a> + > + <a href="/group/{{$gname}}/repo/{{$rname}}">{{$rname}}</a> + > + <a href="/group/{{$gname}}/repo/{{$rname}}/commit/{{$cid}}">{{$cid}}</a> + > + % set partial = "/group/"..$gname.."/repo/"..$rname.."/commit/"..$cid.."/tree" + <a href="{{$partial}}">tree</a> + % for part in $parts do + % set partial = $partial .. "/" .. $part + > + <a href="{{$partial}}">{{$part}}</a> + % end + </p> + <pre>{{!$node.data}}</pre> +</body> +</html>