class Repobrowse::GitCommitHTML
Constants
- CMT_CMD
rugged doesn't seem to have a way to show diffstats, decorations or combined diffs (–cc/–combined) for merges, so use git-show here
Public Instance Methods
close()
click to toggle source
# File lib/repobrowse/git_commit_html.rb, line 316 def close @rd = @rd&.close end
commit_header(env, repo, cmt)
click to toggle source
# File lib/repobrowse/git_commit_html.rb, line 12 def commit_header(env, repo, cmt) msg = Rugged.prettify_message(cmt.message) subject, body = msg.split(/\r?\n\r?\n/, 2) subject.strip! ht(subject) start(subject, repo) parents = cmt.parents oid = @commit = cmt.oid @buf << ' commit ' + oid @mhelp = nil case parents.size when 0 when 1 @buf << %Q[ (<a\nhref="#{oid}.patch">patch</a>)] pfx = ' parent' else @mhelp = "\n This is a merge, showing combined diff:\n\n" pfx = ' parents' end @buf << "\n " @buf << %Q(tree <a\nrel=nofollow\nhref="src/#{oid}">#{cmt.tree_oid}</a>\n) pad = 0 idents = [ ' author', 'committer' ].map do |field| x = cmt.__send__(field.strip) name_email = ht(+"#{x[:name]} <#{x[:email]}>") len = name_email.size pad = len if len > pad [ field, name_email, x[:time].strftime('%Y-%m-%d %k:%M:%S %z') ] end idents.each do |field, name_email, time| @buf << "#{field} #{[name_email].pack("A#{pad}")}\t#{time}\n" end @repo = repo cmd = CMT_CMD.dup cmd << @commit cmd << '--' @rd = repo.driver.popen(cmd, encoding: Encoding::UTF_8) abbr = @rd.gets(chomp: true).split(' ') parents.each_with_index do |pt, i| title = Rugged.prettify_message(pt.summary) title.strip! @buf << %Q(#{pfx} <a id=P#{i}\nhref="#{pt.oid}">#{abbr[i]}</a> #{ht(title)}\n) pfx = ' ' end refnames = @rd.gets("\0", chomp: true) @buf << "\n<b>#{subject}</b>#{ht(refnames)}\n\n" @buf << ht(body) if body @buf << "<a\nid=D>---</a>\n" @anchors = {} @parents = parents @nchg = @nadd = @ndel = 0 @state = :stat_begin end
die(msg)
click to toggle source
# File lib/repobrowse/git_commit_html.rb, line 147 def die(msg) raise RuntimeError, "#{msg} (#@commit)", [] end
diff_done()
click to toggle source
# File lib/repobrowse/git_commit_html.rb, line 269 def diff_done buf, @mhelp = @mhelp, nil @state = :done "#{buf}#{show_unchanged}</pre></body></html>" end
diff_line(line)
click to toggle source
# File lib/repobrowse/git_commit_html.rb, line 243 def diff_line(line) # dfa and dfb class names match public-inbox search term prefix case line when /\A\+/ %Q{<span\nclass="dfa">#{ht(line.chomp!)}</span>\n} when /\A\-/ %Q{<span\nclass="dfb">#{ht(line.chomp!)}</span>\n} when %r{\Adiff --git ("?a/.+) ("?b/.+)\n\z} # regular git_diff_ab_hdr($1, $2) when /\Adiff --(cc|combined) (.+)\n\z/ # merge git_diff_cc_hdr($1, $2) when /\Aindex ([a-f0-9]+)\.\.([a-f0-9]+)(.*)\n\z/ # regular git_diff_ab_index($1, $2, $3) when /\A@@ ([\d,\+\-]+) ([\d,\+\-]+) @@(.*)\n\z/ # regular git_diff_ab_hunk($1, $2, $3) when /\Aindex ([a-f0-9]+,[^\.]+)\.\.([a-f0-9]+)(.*)\n\z/ # --cc git_diff_cc_index($1, $2, $3) when /\A(@@@+) (\S+.*\S+) @@@+(.*)\n\z/ # --cc git_diff_cc_hunk($1, $2, $3) when nil diff_done else ht(line) end end
diffstat_end()
click to toggle source
# File lib/repobrowse/git_commit_html.rb, line 138 def diffstat_end ret = +"\n #@nchg " ret << (@nchg == 1 ? 'file changed, ' : 'files changed, ') ret << @nadd.to_s ret << (@nadd == 1 ? ' insertion(+), ' : ' insertions(+), ') ret << @ndel.to_s ret << (@ndel == 1 ? " deletion(-)\n\n" : " deletions(-)\n\n") end
diffstat_line(line)
click to toggle source
# File lib/repobrowse/git_commit_html.rb, line 109 def diffstat_line(line) line =~ /\A(\S+)\t+(\S+)\t+(.*)/ or die("bad stat line: #{line.inspect}") add = -$1 del = -$2 fn = -$3 if fn != '' # normal modification anchor = -to_anchor(fn) @anchors[anchor] = -fn line = %Q(<a\nhref="##{anchor}">#{ht(fn.dup)}</a>) else # rename from = @rd.gets("\0", chomp: true) or die('EOF rename (from)') to = @rd.gets("\0", chomp: true) or die('EOF rename (to)') line = diffstat_rename_line(from, to); end # text changes show numerically, Binary does not if add =~ /\A\d+\z/ && del =~ /\A\d+\z/ @nadd += add.to_i @ndel += del.to_i add = "+#{add}" del = "-#{del}" else # just in case... ht(add) ht(del) end @nchg += 1 " #{sprintf('% 6s/%-6s', del, add)}\t#{line}\n" end
diffstat_rename_line(from, to)
click to toggle source
# File lib/repobrowse/git_commit_html.rb, line 88 def diffstat_rename_line(from, to) anchor = -to_anchor(to) @anchors[anchor] = to from_parts = from.split('/') to_parts = to.split('/') base = [] while to_parts[0] && to_parts[0] == from_parts[0] base << to_parts.shift from_parts.shift end from = from_parts.join('/') to = to_parts.join('/') to = %Q(<a\nhref="##{anchor}">#{ht(to)}</a>) if base[0] base = ht(base.join('/')) "#{base}/{#{from} => #{to}}" else "#{from} => #{to}" end end
each() { |buf| ... }
click to toggle source
called by the Rack server
# File lib/repobrowse/git_commit_html.rb, line 276 def each buf = @buf @buf = nil yield buf buf.clear while buf = each_i yield buf buf.clear unless buf.frozen? end end
each_i()
click to toggle source
# File lib/repobrowse/git_commit_html.rb, line 287 def each_i case @state when :stat_begin # merges start with an extra '\0' before the diffstat # non-merge commits start with an extra '\n', instead sep = @mhelp ? "\0" : "\n" @rd.gets(sep) == sep or die('diffstat line not empty') @state = :stat when :stat case line = @rd.gets("\0", chomp: true) when nil if @mhelp @mhelp = "\n This is a merge, and the combined diff is empty.\n" return diff_done end die('premature EOF') when '' @state = :diff return diffstat_end else return diffstat_line(line) end when :diff return diff_line(@rd.gets) when :done return end while true end
git_diff_ab_hdr(fa, fb)
click to toggle source
diff –git a/foo.c b/bar.c
# File lib/repobrowse/git_commit_html.rb, line 152 def git_diff_ab_hdr(fa, fb) html_a = ht(fa.dup) html_b = ht(fb.dup) fa = @repo.driver.git_unquote(fa) fb = @repo.driver.git_unquote(fb) fa.sub!(%r{\Aa/}, '') fb.sub!(%r{\Ab/}, '') anchor = -to_anchor(fb) @anchors.delete(anchor) @fa = fa @fb = fb # not wasting bandwidth on links here # links in hunk headers are far more useful with line offsets %Q(<a\nid="#{anchor}">diff</a> --git #{html_a} #{html_b}\n) end
git_diff_ab_hunk(ca, cb, ctx)
click to toggle source
@@ -1,2 +3,4 @@ (regular diff)
# File lib/repobrowse/git_commit_html.rb, line 192 def git_diff_ab_hunk(ca, cb, ctx) na = ca.match(/\A-(\d+)/)[1] nb = cb.match(/\A\+(\d+)/)[1] # we add "rel=nofollow" here to reduce load on search engines, here rv = +'@@ ' rv << (na == '0' ? ca : git_diff_src_link(@parents[0], @fa, na, ca)) rv << ' ' rv << (nb == '0' ? cb : git_diff_src_link(@commit, @fb, nb, cb)) rv << " @@#{ht(ctx)}\n" end
git_diff_ab_index(da, db, tail)
click to toggle source
index abcdef89..01234567
# File lib/repobrowse/git_commit_html.rb, line 179 def git_diff_ab_index(da, db, tail) # not wasting bandwidth on links here, yet # links in hunk headers are far more useful with line offsets "index #{da}..#{db}#{ht(tail)}\n" end
git_diff_cc_hdr(combined, path)
click to toggle source
diff (–cc|–combined)
# File lib/repobrowse/git_commit_html.rb, line 169 def git_diff_cc_hdr(combined, path) html_path = ht(path.dup) path = @repo.driver.git_unquote(path) anchor = to_anchor(path) @anchors.delete(anchor) @path_cc = path %Q(<a\nid="#{anchor}">diff</a> --#{combined} #{html_path}\n) end
git_diff_cc_hunk(at, offs, ctx)
click to toggle source
@@@ -1,2 -3,4 +5,6 @@@ (combined diff)
# File lib/repobrowse/git_commit_html.rb, line 215 def git_diff_cc_hunk(at, offs, ctx) offs = offs.split(' ') last = offs.pop rv = at.dup offs.each_with_index do |off, i| parent = @parents[i] blob = @parent_objs_cc[i] lineno = off.match(/\A-(\d+)/)[1] if lineno == '0' # new file (does this happen with --cc?) rv << " #{off}" else href = ha(+"src/#{parent}?id=#{blob}#n#{lineno}") rv << %Q( <a\nhref=#{href}>#{off}</a>) end end lineno = last.match(/\A\+(\d+)/)[1] rv << ' ' if lineno == '0' # deleted file (does this happen with --cc?) rv << last else rv << git_diff_src_link(@commit, @path_cc, lineno, last) end rv << " #{at}#{ht(ctx)}\n" end
git_diff_cc_index(before, last, tail)
click to toggle source
index abcdef09,01234567..76543210
# File lib/repobrowse/git_commit_html.rb, line 205 def git_diff_cc_index(before, last, tail) ht(tail) @parent_objs_cc = before.split(',') # not wasting bandwidth on links here, yet # links in hunk headers are far more useful with line offsets "index #{before}..#{last}#{tail}\n" end
git_diff_src_link(ref, file, lineno, text)
click to toggle source
# File lib/repobrowse/git_commit_html.rb, line 185 def git_diff_src_link(ref, file, lineno, text) fragment = lineno ? "#n#{lineno}" : '' href = ha(+"src/#{ref}:#{file}#{fragment}") %Q(<a\nrel=nofollow\nhref=#{href}>#{text}</a>) end
show_unchanged()
click to toggle source
do not break anchor links if the combined diff doesn't show changes:
# File lib/repobrowse/git_commit_html.rb, line 68 def show_unchanged unchanged = @anchors.keys.sort! unchanged[0] or return '' buf = +<<EOS There are uninteresting changes from this merge. See the <a\nhref="#P0">parents</a>, or view final state(s) below: EOS unchanged.each do |anchor| fn = @repo.driver.git_unquote(@anchors[anchor]) href = ha(+"src/#@commit:#{fn}") buf << "\t<a\nrel=nofollow\nid=#{ anchor} }\nhref=#{href}>#{ht(+fn)}</a>\n" end buf end