stagit

[fork] HTML git frontend
git clone https://hhvn.uk/stagit
git clone git://hhvn.uk/stagit
Log | Files | Refs | README | LICENSE

commit 7046dc44d406c7e24393a4279fea4eacc78c5d96
parent 0239cfc11a696eb8888dcf47e8316d58ecd9e073
Author: hhvn <dev@hhvn.uk>
Date:   Thu, 31 Aug 2023 11:26:17 +0100

Handle go modules and multiple clone urls via -G and -g

Diffstat:
Mstagit.c | 103++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
1 file changed, 66 insertions(+), 37 deletions(-)

diff --git a/stagit.c b/stagit.c @@ -65,7 +65,10 @@ static const char *repodir; static char *name = ""; static char *strippedname = ""; static char description[255]; -static char cloneurl[1024]; +static char *cloneurls[16]; +static int cloneurlsi = 0; +static char *gomodurl = NULL; +static int isgomod = 0; static char *submodules; static char *licensefiles[] = { "HEAD:LICENSE", "HEAD:LICENSE.md", "HEAD:COPYING" }; static char *license; @@ -497,13 +500,33 @@ printtimeshort(FILE *fp, const git_time *intime) } void +writeurl(FILE *fp, const char *txt, const char *url) +{ + fprintf(fp, "<tr class=\"url\"><td></td><td>%s <a href=\"", txt); + xmlencode(fp, url, strlen(url)); /* not percent-encoded */ + fputs("\">", fp); + xmlencode(fp, url, strlen(url)); + fputs("</a></td></tr>", fp); +} + +void writeheader(FILE *fp, const char *title) { + int go; + int i; + fputs("<!DOCTYPE html>\n" "<html>\n<head>\n" "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" - "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n" - "<title>", fp); + "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n", fp); + + go = isgomod && gomodurl && cloneurlsi && strcmp(title, "Log") == 0; + + if (go) + fprintf(fp, "<meta name=\"go-import\" content=\"%s git %s\">\n", + gomodurl, cloneurls[0]); + + fputs("<title>", fp); xmlencode(fp, title, strlen(title)); if (title[0] && strippedname[0]) fputs(" - ", fp); @@ -527,13 +550,13 @@ writeheader(FILE *fp, const char *title) fputs("</h1><span class=\"desc\">", fp); xmlencode(fp, description, strlen(description)); fputs("</span></td></tr>", fp); - if (cloneurl[0]) { - fputs("<tr class=\"url\"><td></td><td>git clone <a href=\"", fp); - xmlencode(fp, cloneurl, strlen(cloneurl)); /* not percent-encoded */ - fputs("\">", fp); - xmlencode(fp, cloneurl, strlen(cloneurl)); - fputs("</a></td></tr>", fp); - } + + for (i = 0; i < cloneurlsi; i++) + writeurl(fp, "git clone", cloneurls[i]); + + if (go) + writeurl(fp, "go get", gomodurl); + fputs("<tr><td></td><td>\n", fp); fprintf(fp, "<a href=\"%slog.html\">Log</a> | ", relpath); fprintf(fp, "<a href=\"%sfiles.html\">Files</a> | ", relpath); @@ -1181,6 +1204,18 @@ writerefs(FILE *fp) return 0; } +int +gitfileexists(git_repository *repo, const char *file) { + git_object *obj; + int ret; + + ret = !git_revparse_single(&obj, repo, file) && + git_object_type(obj) == GIT_OBJ_BLOB; + + git_object_free(obj); + return ret; +} + void usage(char *argv0) { @@ -1222,6 +1257,19 @@ main(int argc, char *argv[]) if (i + 1 >= argc) usage(argv[0]); baseurl = argv[++i]; + } else if (argv[i][1] == 'g') { + if (i + 1 >= argc) + usage(argv[0]); + + i++; + if (cloneurlsi == LEN(cloneurls)) + fprintf(stderr, "ignoring excess git clone URL\n"); + else + cloneurls[cloneurlsi++] = argv[i]; + } else if (argv[i][1] == 'G') { + if (i + 1 >= argc) + usage(argv[0]); + gomodurl = argv[++i]; } } if (!repodir) @@ -1292,40 +1340,21 @@ main(int argc, char *argv[]) fclose(fpread); } - /* read url or .git/url */ - joinpath(path, sizeof(path), repodir, "url"); - if (!(fpread = fopen(path, "r"))) { - joinpath(path, sizeof(path), repodir, ".git/url"); - fpread = fopen(path, "r"); - } - if (fpread) { - if (!fgets(cloneurl, sizeof(cloneurl), fpread)) - cloneurl[0] = '\0'; - checkfileerror(fpread, path, 'r'); - fclose(fpread); - cloneurl[strcspn(cloneurl, "\n")] = '\0'; - } - /* check LICENSE */ - for (i = 0; i < LEN(licensefiles) && !license; i++) { - if (!git_revparse_single(&obj, repo, licensefiles[i]) && - git_object_type(obj) == GIT_OBJ_BLOB) + for (i = 0; i < LEN(licensefiles) && !license; i++) + if (gitfileexists(repo, licensefiles[i])) license = licensefiles[i] + strlen("HEAD:"); - git_object_free(obj); - } /* check README */ - for (i = 0; i < LEN(readmefiles) && !readme; i++) { - if (!git_revparse_single(&obj, repo, readmefiles[i]) && - git_object_type(obj) == GIT_OBJ_BLOB) + for (i = 0; i < LEN(readmefiles) && !readme; i++) + if (gitfileexists(repo, readmefiles[i])) readme = readmefiles[i] + strlen("HEAD:"); - git_object_free(obj); - } - if (!git_revparse_single(&obj, repo, "HEAD:.gitmodules") && - git_object_type(obj) == GIT_OBJ_BLOB) + if (gitfileexists(repo, "HEAD:.gitmodules")) submodules = ".gitmodules"; - git_object_free(obj); + + /* check for go.mod file */ + isgomod = gitfileexists(repo, "HEAD:go.mod"); /* log for HEAD */ fp = efopen("log.html", "w");