Check-in by ben on 2025-11-12 03:37:15 Initial commit for coprolit version 1 INSERTED DELETED 982 0 coprolit.awk 18 0 geomyidae.sh 23 0 map2gph.awk 31 0 readme.txt 1054 0 TOTAL over 4 changed files ADDED coprolit.awk Index: coprolit.awk ================================================================== --- /dev/null +++ coprolit.awk @@ -0,0 +1,982 @@ +#!/usr/bin/awk -f +# coprolit.awk version 1 by Ben Collver +# +# Static page generator for gopher and fossil SCM. +# Usage: awk -f coprolit.awk +# Requirements: fossil webdump + +function exists(filename, result, retval) { + result = getline < filename + close(filename) + if (result == -1) { + retval = 0 + } else { + retval = 1 + } + return retval +} + +function fossil_configuration(arr, cmd, fsout, k, v) { + fsout = gettemp() + cmd = sprintf("fossil configuration export project %s -R %s", + fsout, _repo) + system(cmd) + while ((getline 0) { + if (/^#/ || /^config/) { + # ignore comments & config lines + } else { + k = $2 + v = $4 + sub(/^'/, "", k) + sub(/'$/, "", k) + sub(/^'/, "", v) + sub(/'$/, "", v) + arr[k] = v + } + } + close(fsout) + unlink(fsout) + return +} + +function fossil_remote( cmd, retval) { + # get remote repository URL + retval = "unknown" + cmd = sprintf("fossil remote -R %s 2>&1", _repo) + while ((cmd | getline) > 0) { + # remove user name from the remote repository URL + sub(/\/[^/]*@/, "/") + retval = $0 + } + close(cmd) + return retval +} + +function generate_branches( branches, cmd, commits, fsout, i, m, + out, refs, sel) +{ + mkdir(_work "/branches") + out = _work "/branches/gophermap" + unlink(out) + fsout = gettemp() + cmd = sprintf("fossil branch ls -R %s >%s 2>&1", _repo, fsout) + system(cmd) + refs["count"] = 1 + refs[1] = "fossil branch ls" + info(out, sprintf("# %s / Branches", _conf["project-name"])) + menu(out, "Branches") + m = 0 + while ((getline < fsout) > 0) { + m++ + branches[m] = $1 + sel = _root "/timeline/" $1 + item(out, 1, $1, sel, _server, _port) + } + close(fsout) + unlink(fsout) + + reference(out, refs) + close(out) + + for (i = 1; i <= m; i++) { + generate_timeline(branches[i]) + } + return +} + +function generate_commit(commit, branch, cmd, comment, file, + fsout, has_downloads, hash, is_checkin, m, out, parents, refs, + slug, type) +{ + out = sprintf("%s/info/%s/gophermap", _work, commit) + if (exists(out)) { + # This has already been generated, don't do again + return + } + + mkdir(_work "/info/" commit) + mkdir(_work "/patch") + + fsout = gettemp() + cmd = sprintf("fossil timeline %s -n 1 --full -R %s >%s 2>&1", + commit, _repo, fsout) + system(cmd) + m = 1 + refs[m] = sprintf("fossil timeline %s -n 1 --full", commit) + info(out, sprintf("# %s / Check-in [%s]", + _conf["project-name"], commit)) + menu(out, "Commit") + while ((getline < fsout) > 0) { + if ($1 == "Commit:") { + hash = $2 + } else if ($1 == "Comment:") { + comment = $0 + sub(/^Comment: */, "", comment) + } else if ($1 == "Branch") { + branch = $2 + } + } + close(fsout) + unlink(fsout) + + cmd = sprintf("fossil whatis %s -R %s >%s 2>&1", commit, _repo, fsout) + system(cmd) + m++ + refs[m] = sprintf("fossil whatis %s", commit) + + type = "unknown" + while ((getline < fsout) > 0) { + if (/^type:/) { + sub(/^type: */, "") + type = $0 + } + } + close(fsout) + unlink(fsout) + + if (type ~ /^Check-in/) { + is_checkin = 1 + } else { + is_checkin = 0 + } + + has_downloads = 0 + parents = 0 + + if (is_checkin) { + if (_download_count < _download_max || _download_max == 0) { + has_downloads = 1 + _download_count++ + + # export tarball + m++ + refs[m] = generate_tarball(commit) + + # export zip + m++ + refs[m] = generate_zip(commit) + } + + cmd = sprintf("fossil timeline parents %s -n 0 --oneline -R %s >%s", + commit, _repo, fsout) + system(cmd) + while ((getline 0) { + if (/^... end of timeline/) { + sub(/^\(/, "", $5) + sub(/\)$/, "", $5) + parents = $5 + } + } + close(fsout) + unlink(fsout) + + if (parents > 1) { + # export patch + file = sprintf("%s/patch/%s.txt", _work, commit) + printf "%s\n\n", type >file + if (length(comment) < 66) { + println(file, comment) + } else { + print_wrap(file, comment, 65) + } + printf "\n" >>file + close(file) + + cmd = sprintf("fossil diff -v --checkin %s --numstat -R %s >>%s", + commit, _repo, file) + system(cmd) + + printf "\n" >>file + close(file) + + cmd = sprintf("fossil diff -v --checkin %s -R %s >>%s", + commit, _repo, file) + system(cmd) + + m++ + refs[m] = sprintf("fossil diff -v --checkin %s --numstat", + commit) + m++ + refs[m] = sprintf("fossil diff -v --checkin %s", commit) + } + } + + info(out, "# Overview") + info(out, "") + if (length(comment) < 66) { + info(out, sprintf("Comment: %s", comment)) + } else { + info(out, "Comment:") + info_wrap(out, comment, 65) + } + if (is_checkin && has_downloads) { + info(out, "") + info(out, "Downloads:") + slug = sprintf("%s/tarball/%s/%s-%s.tar.gz", + _root, commit, _conf["short-project-name"], commit) + item(out, "9", "Tarball", slug, _server, _port) + slug = sprintf("%s/zip/%s/%s-%s.zip", + _root, commit, _conf["short-project-name"], commit) + item(out, "9", "Zip archive", slug, _server, _port) + } + + info(out, "") + info(out, "SHA3-256:") + info(out, " " hash) + info(out, sprintf("Type: %s", type)) + + if (is_checkin && parents > 1) { + info(out, "") + info(out, "# Changes") + info(out, "") + file = sprintf("%s/patch/%s.txt", _root, commit) + item(out, 0, "Patch", file, _server, _port) + } + + refs["count"] = m + reference(out, refs) + close(out) + return +} + +function generate_files( cmd, file) { + # export tip tarball & zip + generate_tarball("tip") + generate_zip("tip") + + # extract tip tarball + file = sprintf("%s/tarball/tip/%s-tip.tar.gz", + _work, _conf["short-project-name"]) + cmd = sprintf("tar zxf %s -C %s --transform 's,%s,files,'", + file, _work, _conf["short-project-name"]) + system(cmd) + return +} + +function generate_home( cmd, fsout, out) { + out = _work "/gophermap" + unlink(out) + fsout = gettemp() + cmd = sprintf("fossil wiki export -h %s -R %s >%s 2>&1", + _conf["project-name"], _repo, fsout) + system(cmd) + info(out, "# Home - " _conf["project-name"]) + menu(out, "Home") + cmd = sprintf("webdump -ilr -w 60 <%s", fsout) + while ((cmd | getline) > 0) { + info(out, $0) + } + close(fsout) + unlink(fsout) + close(out) + return +} + +function generate_tarball(commit, cmd, file, name, retval) { + mkdir(_work "/tarball/" commit) + + name = _conf["short-project-name"] + file = sprintf("%s/tarball/%s/%s-%s.tar.gz", + _work, commit, name, commit) + cmd = sprintf("fossil tarball %s %s --name %s -R %s", + commit, file, name, _repo) + system(cmd) + retval = sprintf("fossil tarball %s %s-%s.tar.gz --name %s", + commit, name, commit, name) + return retval +} + +function generate_tags( tags, cmd, commits, fsout, i, m, out, + query, refs, sel) +{ + mkdir(_work "/tags") + out = _work "/tags/gophermap" + unlink(out) + fsout = gettemp() + + query = "SELECT " \ + " substr(tag.tagname, 5) AS tagname, " \ + " datetime(MAX(tagxref.mtime)) AS mtime " \ + "FROM repository.tag " \ + "JOIN repository.tagxref ON tagxref.tagid=tag.tagid " \ + "WHERE " \ + " tag.tagname LIKE 'sym-%%' AND " \ + " tagxref.tagtype = 1 " \ + "GROUP BY tag.tagid, tag.tagname " \ + "ORDER BY MAX(tagxref.mtime) DESC" + + # cmd = sprintf("fossil tag ls -R %s >%s 2>&1", _repo, fsout) + cmd = sprintf("fossil sql --readonly -R %s >%s 2>&1", _repo, fsout) + printf ".mode tabs\n%s\n", query | cmd + close(cmd) + + refs["count"] = 3 + refs[1] = "fossil tag ls" + refs[1] = "fossil sql --readonly" + refs[3] = query + + info(out, sprintf("# %s / Tags", _conf["project-name"])) + menu(out, "Tags") + m = 0 + while ((getline < fsout) > 0) { + m++ + tags[m] = $1 + sel = _root "/tags/" $1 + item(out, 1, $1 " -- " $2, sel, _server, _port) + } + close(fsout) + unlink(fsout) + + reference(out, refs) + close(out) + + for (i = 1; i <= m; i++) { + generate_tag_timeline(tags[i]) + } + return +} + +function generate_tag_timeline(tag, author, authors, cmd, + comment_abbrev, commit, commits, date, dates, fsout, i, label, + line, lines, m, out, refs, sel, time, total_commits) +{ + out = sprintf("%s/tags/%s/gophermap", _work, tag) + if (exists(out)) { + # This has already been generated, don't do again. + return + } + + _download_count = 0 + _download_max = _download + + mkdir(_work "/tags/" tag) + fsout = gettemp() + cmd = sprintf("fossil tag find -n 0 -t ci %s -R %s >%s 2>&1", + tag, _repo, fsout) + system(cmd) + refs["count"] = 1 + refs[1] = sprintf("fossil tag find -n 0 -t ci %s", tag) + + total_commits = 0 + line = "" + while ((getline < fsout) > 0) { + if ($1 == "===") { + date = $2 + } else if (/^[0-9]/) { + # check whether line buffer is present from prior iterations + if (length(line) > 0) { + if (match(line, /user: [^ ]*/)) { + author = substr(line, RSTART + 7, RLENGTH - 6) + } else { + author = "unknown" + } + sub(/ \(user:.*\)/, "", line) + if (m < _timeline) { + m++ + authors[m] = author + commits[m] = commit + lines[m] = line + dates[m] = date " " time + } + } + time = $1 + commit = $2 + sub(/^\[/, "", commit) + sub(/\]$/, "", commit) + line = $0 + sub(/^[^ ]* [^ ]* /, "", line) + } else if (/^ /) { + sub(/^ */, "") + line = line $0 + } else if (/^... end of timeline /) { + sub(/^\(/, "", $5) + sub(/\)$/, "", $5) + total_commits = $5 + } + } + if (length(line) > 0 && m < _timeline) { + if (match(line, /user: [^ ]*/)) { + author = substr(line, RSTART + 6, RLENGTH - 6) + } else { + author = "unknown" + } + sub(/ \(user:.*\)/, "", line) + m++ + authors[m] = author + commits[m] = commit + lines[m] = line + dates[m] = date " " time + } + close(fsout) + unlink(fsout) + + info(out, sprintf("# %s / Timeline / Tag %s", + _conf["project-name"], tag)) + menu(out, "Timeline") + for (i = 1; i <= m; i++) { + if (length(comment) < 42) { + comment_abbrev = comment + } else { + comment_abbrev = substr(comment, 1, 37) "..." + } + label = sprintf("%-17s %-41s %s", + substr(dates[i], 1, 16), comment_abbrev, authors[i]) + sel = _root "/info/" commits[i] + item(out, 1, label, sel, _server, _port) + } + + if (m < total_commits) { + info(out, " " total_commits - m \ + " more commits remaining, fetch the repository") + } + + reference(out, refs) + close(out) + + for (i = 1; i <= m; i++) { + generate_commit(commits[i]) + } + return +} + +function generate_ticket(ticket, ctime, foundin, mtime, priority, + resolution, severity, status, title, uuid, type, cmd, out) +{ + out = sprintf("%s/tickets/%s.txt", _work, ticket) + unlink(out) + printf "# %s\n\n", _conf["project-name"] >out + printf "## View Ticket\n\n" >>out + printf "Ticket Hash: %s\n", uuid >>out + if (length(title) < 66) { + printf "Title: %s\n", title >>out + } else { + printf "Title:\n" >>out + print_wrap(out, title, 65) + } + printf "Status: %s\n", status >>out + printf "Type: %s\n", type >>out + printf "Severity: %s\n", severity >>out + printf "Priority: %s\n", priority >>out + printf "Resolution: %s\n", resolution >>out + printf "Modified: %s\n", mtime >>out + printf "Created: %s\n", ctime >>out + printf "Found In: %s\n", foundin >>out + cmd = sprintf("fossil ticket history %s -R %s 2>&1", ticket, _repo) + while ((cmd | getline) > 0) { + if (/^Ticket Change/) { + printf "\n" >>out + } + print $0 >>out + } + close(cmd) + printf "\nReference:\n\n" >>out + printf "fossil ticket history %s\n", ticket >>out + close(out) + return +} + +function generate_tickets( ctime, cmd, count, field, fnr, fsout, + i, label, mtime, oldfs, out, query, refs, sel, tags, ticket) +{ + mkdir(_work "/tickets") + out = _work "/tickets/gophermap" + unlink(out) + fsout = gettemp() + + query = "SELECT " \ + " tkt_id, " \ + " tkt_uuid, " \ + " datetime(tkt_mtime) AS mtime, " \ + " datetime(tkt_ctime) AS ctime, " \ + " type, " \ + " status, " \ + " subsystem, " \ + " priority, " \ + " severity, " \ + " foundin, " \ + " resolution, " \ + " title, " \ + " comment " \ + "FROM repository.ticket" + + # cmd = sprintf("fossil ticket show 0 -R %s >%s 2>&1", _repo, fsout) + cmd = sprintf("fossil sql --readonly -R %s >%s 2>&1", _repo, fsout) + printf ".headers on\n.mode tabs\n%s\n", query | cmd + close(cmd) + + refs["count"] = 3 + refs[1] = "fossil ticket show 0" + refs[2] = "fossil sql --readonly" + refs[3] = query + + info(out, sprintf("# %s / Tickets", _conf["project-name"])) + menu(out, "Tickets") + oldfs = FS + FS = "\t" + while ((getline < fsout) > 0) { + fnr++ + if (fnr == 1) { + count = NF + for (i = 1; i <= count; i++) { + field[$i] = i + } + } else { + ticket = substr($field["tkt_uuid"], 1, 10) + + label = "Ticket: " ticket + sel = sprintf("%s/tickets/%s.txt", _root, ticket) + item(out, 0, label, sel, _server, _port) + info(out, "Mtime: " $field["mtime"]) + info(out, "Type: " $field["type"]) + info(out, "Status: " $field["status"]) + if (length($field["title"]) < 61) { + info(out, "Title: " $field["title"]) + } else { + info(out, "Title:") + info_wrap(out, $field["title"], 65) + } + info(out, "") + generate_ticket(ticket, + $field["ctime"], + $field["foundin"], + $field["mtime"], + $field["priority"], + $field["resolution"], + $field["severity"], + $field["status"], + $field["title"], + $field["tkt_uuid"], + $field["type"]) + } + } + FS = oldfs + close(fsout) + unlink(fsout) + + reference(out, refs) + close(out) + + return +} + +function generate_timeline(branch, author, branch_opt, cmd, + comment, comment_abbrev, commit, commits, date, download_count, + download_max, fsout, i, label, m, out, refs, sel, total_commits) +{ + _download_count = 0 + if (length(branch) > 0) { + _download_max = -1 + branch_opt = "-b " branch " " + out = sprintf("%s/timeline/%s/gophermap", _work, branch) + } else { + _download_max = _download + branch_opt = "" + out = sprintf("%s/timeline/gophermap", _work) + } + if (exists(out)) { + # This has already been generated, don't do again. + return + } + + if (length(branch) > 0) { + mkdir(_work "/timeline/" branch) + } else { + mkdir(_work "/timeline") + } + fsout = gettemp() + + cmd = sprintf("fossil timeline -n 0 %s-t ci --oneline -R %s >%s 2>&1", + branch_opt, _repo, fsout) + system(cmd) + total_commits = 0 + while ((getline 0) { + if (/^... end of timeline /) { + sub(/^\(/, "", $5) + sub(/\)$/, "", $5) + total_commits = $5 + } + } + close(fsout) + unlink(fsout) + + refs["count"] = 1 + refs[1] = sprintf("fossil timeline %s%s-t ci --medium", + branch_opt, _timeline_opt) + + cmd = sprintf("fossil timeline %s%s-t ci --medium -R %s >%s 2>&1", + branch_opt, _timeline_opt, _repo, fsout) + system(cmd) + if (length(branch) > 0) { + info(out, sprintf("# %s / Timeline / Branch %s", + _conf["project-name"], branch)) + } else { + info(out, sprintf("# %s / Timeline", _conf["project-name"])) + } + menu(out, "Timeline") + author = "unknown" + commit = "" + date = "unknown" + comment = "" + while ((getline < fsout) > 0) { + if ($1 == "Commit:") { + commit = $2 + m++ + commits[m] = commit + } else if ($1 == "Date:") { + sub(/^Date: */, "") + date = $0 + } else if ($1 == "Author:") { + sub(/^Author: */, "") + author = $0 + } else if ($1 == "Comment:") { + sub(/^Comment: */, "") + comment = $0 + } else if (length($0) == 0) { + if (length(comment) < 42) { + comment_abbrev = comment + } else { + comment_abbrev = substr(comment, 1, 37) "..." + } + label = sprintf("%-17s %-41s %s", + substr(date, 1, 16), comment_abbrev, author) + sel = _root "/info/" commit + item(out, 1, label, sel, _server, _port) + } + } + close(fsout) + unlink(fsout) + + if (m < total_commits) { + info(out, " " total_commits - m \ + " more commits remaining, fetch the repository") + } + + reference(out, refs) + close(out) + + for (i = 1; i <= m; i++) { + generate_commit(commits[i]) + } + return +} + +function generate_wiki( cmd, fsout, i, m, out, pages, refs, sel) { + mkdir(_work "/wiki") + out = _work "/wiki/gophermap" + unlink(out) + fsout = gettemp() + cmd = sprintf("fossil wiki ls -R %s >%s 2>&1", _repo, fsout) + system(cmd) + refs["count"] = 1 + refs[1] = "fossil wiki ls" + info(out, sprintf("# %s / Wiki", _conf["project-name"])) + menu(out, "Wiki") + m = 0 + while ((getline < fsout) > 0) { + m++ + pages[m] = $0 + sel = _root "/wiki/" safe_filename($0) ".txt" + item(out, 0, $0, sel, _server, _port) + } + close(fsout) + unlink(fsout) + + reference(out, refs) + close(out) + + for (i = 1; i <= m; i++) { + generate_wiki_page(pages[i]) + } + + return +} + +function generate_wiki_page(page, cmd, fsout, out) { + out = sprintf("%s/wiki/%s.txt", _work, safe_filename(page)) + unlink(out) + fsout = gettemp() + cmd = sprintf("fossil wiki export -h \"%s\" -R %s >%s 2>&1", + page, _repo, fsout) + system(cmd) + printf "# %s\n\n", page >out + cmd = sprintf("webdump -ilr -w 60 <%s", fsout) + while ((cmd | getline) > 0) { + print >>out + } + printf "\nReference:\n\n" >>out + printf "fossil wiki export -h \"%s\"\n", page >>out + close(out) + close(fsout) + unlink(fsout) + return +} + +function generate_zip(commit, cmd, file, name, retval) { + mkdir(_work "/zip/" commit) + + name = _conf["short-project-name"] + file = sprintf("%s/zip/%s/%s-%s.zip", _work, commit, name, commit) + cmd = sprintf("fossil zip %s %s --name %s -R %s", + commit, file, name, _repo) + system(cmd) + retval = sprintf("fossil zip %s %s-%s.zip --name %s", + commit, name, commit, name) + return retval +} + +function gettemp( cmd, result, retval) { + cmd = "mktemp" + while ((cmd | getline) > 0) { + retval = $0 + } + result = close(cmd) + if (result != 0) { + print "Error: mktemp failed exit status: " result + exit + } + if (length(retval) == 0) { + print "Error: mktemp failed, no tmpfile" + exit + } + return retval +} + +function info(out, str) { + if (length(out) == 0) { + printf "i%s\tErr\t%s\t%s\r\n", str, _server, _port + } else { + printf "i%s\tErr\t%s\t%s\r\n", str, _server, _port >>out + } + return +} + +# info_wrap() will break long lines into line continuations + +function info_wrap(out, str, len) { + line = 1 + buf = str + while (length(buf) > len) { + chunk = substr(buf, 1, len) + if (match(chunk, / [^ ]*$/)) { + before = substr(buf, 1, RSTART-1) + after = substr(buf, RSTART+1) + info(out, " " before) + buf = after + } else if (match(chunk, /-[^-]*$/)) { + before = substr(buf, 1, RSTART) + after = substr(buf, RSTART+1) + info(out, " " before) + buf = after + } else { + break + } + line++ + } + info(out, " " buf) + return +} + +function item(out, type, label, sel, host, port, line) { + line = item_str(type, label, sel, host, port) + if (length(out) == 0) { + printf "%s\r\n", line + } else { + printf "%s\r\n", line >>out + } + return +} + +function item_str(type, label, sel, host, port) { + retval = sprintf("%s%s\t%s\t%s\t%s", type, label, sel, host, port) + return retval +} + +function main( cmd, format) { + if (ARGC < 3) { + usage() + exit 0 + } + _repo = ARGV[1] + _root = ARGV[2] + + _download = 5 + _port = 70 + _server = "localhost" + _timeline = 100 + _work = "output" + format = "gopher" + + for (i = 3; i < ARGC; i++) { + if (ARGV[i] == "--dir") { + _work = ARGV[i + 1] + i++ + } else if (ARGV[i] == "--download") { + _download = ARGV[i + 1] + i++ + } else if (ARGV[i] == "--format") { + format = ARGV[i + 1] + i++ + if (format != "geomyidae" && format != "gopher") { + print "Error: Unknown format: " format + exit 1 + } + } else if (ARGV[i] == "--port") { + _port = ARGV[i + 1] + i++ + } else if (ARGV[i] == "--server") { + _server = ARGV[i + 1] + i++ + } else if (ARGV[i] == "--timeline") { + _timeline = ARGV[i + 1] + i++ + } else { + print "Error: Unrecognized option: " ARGV[i] + exit 1 + } + } + if (_timeline > 0) { + _timeline_opt = "-n " _timeline " " + } else { + _timeline_opt = "" + } + _download_count = 0 + + fossil_configuration(_conf) + if ($_conf["project-name"] == "unknown") { + print "Error: Could not find fossil project name" + exit 1 + } + _remote = fossil_remote() + + mkdir(_work) + generate_home() + generate_timeline("") + generate_files() + generate_branches() + generate_tags() + generate_tickets() + generate_wiki() + + if (format == "geomyidae") { + cmd = sprintf("./geomyidae.sh \"%s\"", _work) + system(cmd) + } + return +} + +function menu(out, cur, i, label, opts, path) { + opts[1] = "Timeline" + opts[2] = "Files" + opts[3] = "Branches" + opts[4] = "Tags" + opts[5] = "Tickets" + opts[6] = "Wiki" + path[1] = "timeline" + path[2] = "files" + path[3] = "branches" + path[4] = "tags" + path[5] = "tickets" + path[6] = "wiki" + item(out, "h", "fossil clone " _remote, "URL:" _remote, _server, _port) + for (i = 1; i < 7; i++) { + if (cur == opts[i]) { + label = sprintf("(%s)", opts[i]) + } else { + label = sprintf(" %s ", opts[i]) + } + item(out, 1, label, _root "/" path[i], _server, _port) + } + info(out, "---") + return +} + +function mkdir(dir) { + system("mkdir -p " dir) + return +} + +function println(out, str) { + if (length(out) == 0) { + print str + } else { + print str >>out + } + return +} + +# print_wrap() will break long lines into line continuations + +function print_wrap(out, str, len) { + line = 1 + buf = str + while (length(buf) > len) { + chunk = substr(buf, 1, len) + if (match(chunk, / [^ ]*$/)) { + before = substr(buf, 1, RSTART-1) + after = substr(buf, RSTART+1) + println(out, " " before) + buf = after + } else if (match(chunk, /-[^-]*$/)) { + before = substr(buf, 1, RSTART) + after = substr(buf, RSTART+1) + println(out, " " before) + buf = after + } else { + break + } + line++ + } + println(out, " " buf) + return +} + +function reference(out, refs, i) { + info(out, "") + info(out, "# Reference") + info(out, "") + for (i = 1; i <= refs["count"]; i++) { + if (length(refs[i]) > 65) { + info_wrap(out, refs[i], 65) + } else { + info(out, refs[i]) + } + } + return +} + +function safe_filename(name) { + gsub(/:/, "_", name) + gsub(/\\/, "_", name) + gsub(/\//, "_", name) + gsub(/ /, "_", name) + return name +} + +function unlink(filename, cmd) { + cmd = sprintf("rm %s 2>/dev/null", filename) + system(cmd) + return +} + +function usage() { + print "Usage: coprolit.awk REPO ROOT options" + print "" + print "REPO = file.fossil" + print "ROOT = Gopher root selector" + print "" + print "Options:" + print "--dir (default: output)" + print "--download (default: 5)" + print " limit number of tarballs per section" + print "--format (geomyidae | gopher)" + print "--port portnum" + print "--server hostname" + print "--timeline (default: 100)" + print " limit number of items in timeline" + print "" + return +} + +BEGIN { + main() +} ADDED geomyidae.sh Index: geomyidae.sh ================================================================== --- /dev/null +++ geomyidae.sh @@ -0,0 +1,18 @@ +#!/bin/sh +dir="$1" +if [ -z "$dir" ] +then + echo "Usage: geomyidae.sh DIR" + echo "" + echo "Converts all gophermap files in DIR to index.gph for geomyidae." + echo "" + exit 0 +fi + +find "$dir" -type f -name gophermap | while read f +do + d=$(dirname $f) + awk -f map2gph "$f" >"$d/index.gph" +done + +find "$dir" -type f -name gophermap -print0 | xargs -0 rm ADDED map2gph.awk Index: map2gph.awk ================================================================== --- /dev/null +++ map2gph.awk @@ -0,0 +1,23 @@ +#!/usr/bin/awk -f +# map2gph.awk version 1 by Ben Collver +# Convert gophernicus to geomyidae gophermap +# usage: awk -f map2gph.awk gophermap >index.gph + +BEGIN { + FS = "\t" +} + +/^i/ { + sub(/\r$/, "") + sub(/^i/, "", $1) + print $1 + next +} + +{ + sub(/\r$/, "") + type = substr($1, 1, 1) + userstr = substr($1, 2) + gsub(/\|/, "\\|", userstr) + printf "[%s|%s|%s|%s|%s]\n", type, userstr, $2, $3, $4 +} ADDED readme.txt Index: readme.txt ================================================================== --- /dev/null +++ readme.txt @@ -0,0 +1,31 @@ +Coprolit +======== + +Static page generator for gopher and fossil SCM. + +Requires: + +* awk & unix +* fossil SCM +* webdump + +Usage: + +First clone the fossil repository locally, then run coprolit.awk. + + $ awk -f coprolit.awk + + Usage: coprolit.awk REPO ROOT options + + REPO = file.fossil + ROOT = Gopher root selector + + Options: + --dir (default: output) + --download (default: 5) + limit number of tarballs per section + --format (geomyidae | gopher) + --port portnum + --server hostname + --timeline (default: 100) + limit number of items in timeline