| 1 | -- resty-gitweb@pages/log.lua |
| 2 | -- Log page builder |
| 3 |
|
| 4 | -- Copyright (c) 2020 Joshua 'joshuas3' Stockin |
| 5 | -- <https://git.joshstock.in/resty-gitweb> |
| 6 | -- This software is licensed under the MIT License. |
| 7 |
|
| 8 | local utils = require("utils/utils") |
| 9 | local git = require("git/git") |
| 10 |
|
| 11 | local builder = require("utils/builder") |
| 12 | local tabulate = require("utils/tabulate") |
| 13 | local nav = require("utils/nav") |
| 14 |
|
| 15 | local _M = function(repo, repo_dir, branch, n, skip) |
| 16 | n = tonumber(n or 20) |
| 17 | skip = tonumber(skip or 0) |
| 18 |
|
| 19 | local build = builder:new() |
| 20 |
|
| 21 | -- Breadcrumb navigation and repository description |
| 22 | local breadcrumb_nav = { |
| 23 | {string.format("/%s", repo.name), repo.name}, |
| 24 | {string.format("/%s/tree/%s", repo.name, branch.name), branch.name}, |
| 25 | {string.format("/%s/log/%s", repo.name, branch.name), "log"} |
| 26 | } |
| 27 | build:add("<h2>"..nav(breadcrumb_nav, " / ").."</h2>") |
| 28 | build:add("<p>"..repo.description.."</p>") |
| 29 |
|
| 30 | -- Navigation links |
| 31 | local navlinks = { |
| 32 | {string.format("/%s/download", repo.name), "Download"}, |
| 33 | {string.format("/%s/refs", repo.name), "Refs"}, |
| 34 | {string.format("/%s/log/%s", repo.name, branch.name), "<b>Commit Log</b>"}, |
| 35 | {string.format("/%s/tree/%s", repo.name, branch.name), "Files"} |
| 36 | } |
| 37 |
|
| 38 | for _, special in pairs(repo.specialfiles) do -- create nav items for special files |
| 39 | local split = string.split(special, " ") |
| 40 | table.insert(navlinks, { |
| 41 | string.format("/%s/blob/%s/%s", repo.name, branch.name, split[2]), |
| 42 | split[1] |
| 43 | }) |
| 44 | end |
| 45 |
|
| 46 | build:add([[<div class="nav">]]) |
| 47 | build:add(nav(navlinks)) |
| 48 | build:add("</div>") |
| 49 |
|
| 50 | -- Commits table |
| 51 | build:add("<h3>Commits</h3>") |
| 52 |
|
| 53 | local commits_head = git.log(repo_dir, branch.name, path, n, skip, true) |
| 54 |
|
| 55 | local this_page = string.format("/%s/log/%s", repo.name, branch.name) |
| 56 |
|
| 57 | -- Build controls |
| 58 | local controls = [[<div class="controls">]] |
| 59 | local prev = false |
| 60 | if skip ~= 0 then -- previous page? |
| 61 | local params = "" |
| 62 | if skip - n > 0 then |
| 63 | params = params.."?skip="..tostring(tonumber(skip) - tonumber(n)) |
| 64 | end |
| 65 | if n ~= 20 then |
| 66 | if params ~= "" then |
| 67 | params = params.."&" |
| 68 | else |
| 69 | params = params.."?" |
| 70 | end |
| 71 | params = params.."n="..tostring(n) |
| 72 | end |
| 73 | controls = controls..[[<span><a href="]]..this_page..params..[["><< Previous Page</a></span>]] |
| 74 | prev = true |
| 75 | end |
| 76 | if git.count(repo_dir, commits_head[#commits_head].hash) ~= 1 then -- check if last commit in this list is actually the last |
| 77 | -- it's not the last, create a "next page" button |
| 78 | local params = "" |
| 79 | params = params.."?skip="..tostring(skip+n) |
| 80 | if n ~= 20 then |
| 81 | params = params.."&n="..tostring(n) |
| 82 | end |
| 83 | if prev then |
| 84 | controls = controls..[[<span style="margin:0 5px">|</span>]] |
| 85 | end |
| 86 | controls = controls..[[<span><a href="]]..this_page..params..[[">Next Page >></a></span>]] |
| 87 | end |
| 88 | controls = controls..[[<span float="right"> |
| 89 | <form class="control-form" method="GET" style="display:inline;margin:0;float:right"> |
| 90 | <input type="hidden" name="skip" value="]]..tostring(skip)..[["> |
| 91 | <label for="n">Results</label> |
| 92 | <select id="n" name="n" onchange="if (this.value != 0){this.form.submit();}"> |
| 93 | <option disabled selected value style="display:none">]]..tostring(n)..[[</option> |
| 94 | <option>10</option> |
| 95 | <option>20</option> |
| 96 | <option>50</option> |
| 97 | <option>100</option> |
| 98 | </select> |
| 99 | </form> |
| 100 | </span>]] |
| 101 | controls = controls.."</div>" |
| 102 |
|
| 103 | build:add(controls) |
| 104 |
|
| 105 | -- Build commit table |
| 106 | local commits_table_data = {} |
| 107 | commits_table_data.class = "log" |
| 108 | commits_table_data.headers = { |
| 109 | {"count", [[<span class="q" title="Commit number/count">{#}</span>]]}, |
| 110 | {"timestamp", "Time"}, |
| 111 | {"shorthash", "Hash"}, |
| 112 | {"subject", "Subject"}, |
| 113 | {"author", "Author"}, |
| 114 | {"changed_files", [[<span class="q" title="# of files changed">#</span>]]}, |
| 115 | {"changed_plus", [[<span class="q" title="Insertions">(+)</span>]]}, |
| 116 | {"changed_minus", [[<span class="q" title="Deletions">(-)</span>]]}, |
| 117 | {"gpggood", [[<span class="q" title="GPG signature status |
| 118 | |
| 119 | G: Good (valid) signature |
| 120 | B: Bad signature |
| 121 | U: Good signature with unknown validity |
| 122 | X: Good signature that has expired |
| 123 | Y: Good signature made by an expired key |
| 124 | R: Good signature made by a revoked key |
| 125 | E: Signature can't be checked (e.g. missing key) |
| 126 | N: No signature">GPG?</span>]]} |
| 127 | } |
| 128 | commits_table_data.rows = {} |
| 129 |
|
| 130 | for i, commit in pairs(commits_head) do |
| 131 | table.insert(commits_table_data.rows, { |
| 132 | git.count(repo_dir, commit.hash), |
| 133 | utils.iso8601(commit.timestamp), |
| 134 | string.format([[<a href="/%s/commit/%s">%s</a>]], repo.name, commit.hash, commit.shorthash), |
| 135 | utils.html_sanitize(commit.subject), |
| 136 | string.format([[<a href="mailto:%s">%s</a>]], commit.email, utils.html_sanitize(commit.author)), |
| 137 | commit.diff.num, |
| 138 | commit.diff.plus, |
| 139 | commit.diff.minus, |
| 140 | commit.gpggood |
| 141 | }) |
| 142 | end |
| 143 |
|
| 144 | -- Add |
| 145 | build:add(tabulate(commits_table_data)) |
| 146 | build:add(controls) |
| 147 |
|
| 148 | return build |
| 149 | end |
| 150 |
|
| 151 | return _M |
| 152 |
|