sgw | Static git web (fork of stagit) |
| download: https://git.y1.nz/archives/sgw.tar.gz | |
| README | Files | Log | Refs | LICENSE |
commit c9de381e978e64e4d40e93948a1b784ce12aa364 parent 2976b0675172e5a69caffeb120a14f885bc2309d Author: Emma Weaver <emma@waeaves.com> Date: Wed, 17 Jun 2026 21:53:25 -0400 Merged accidentally divergent work, tweaked formatting Diffstat:
| M | Makefile | 7 | +++++-- |
| M | README | 13 | ++++++++----- |
| M | TODO | 1 | - |
| M | config.h | 7 | ++++--- |
| M | index.c | 53 | +++++++++++++++++------------------------------------ |
| M | main.c | 292 | ++++++++++++++++--------------------------------------------------------------- |
| A | repo.c | 223 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | repo.h | 18 | ++++++++++++++++++ |
| M | style.css | 4 | ++-- |
9 files changed, 336 insertions(+), 282 deletions(-)
diff --git a/Makefile b/Makefile @@ -1,12 +1,15 @@ include config.mk -sgw: main.c opt.o files.o index.o config.h config.mk - $(CC) main.c opt.o files.o index.o -o sgw $(LDFLAGS) +sgw: main.c opt.o files.o repo.o index.o config.h config.mk + $(CC) main.c opt.o files.o repo.o index.o -o sgw $(LDFLAGS) opt.o: opt.c opt.h config.mk $(CC) -c opt.c -o opt.o $(CFLAGS) +repo.o: repo.c repo.h config.mk + $(CC) -c repo.c -o repo.o $(CFLAGS) + files.o: files.c files.h config.mk $(CC) -c files.c -o files.o $(CFLAGS) diff --git a/README b/README @@ -1,9 +1,12 @@ -┌─────┐ -│~sgw~│ -└─────┘ + ____ ___ + // \ // \\ // + \\__ // ____\ / // + \\\ // \ //\ // + \___// \__// \/ \/ -Static Git Webpage (Generator). -Fork of Hiltjo Posthuma's Stagit: www.codemadness.org/git/stagit/ +Static Git Web (Generator) + +Fork/refactor of Hiltjo Posthuma's Stagit (www.codemadness.org/git/stagit) Build: Run "make" to create the sgw binary. Then, run "make install" as root diff --git a/TODO b/TODO @@ -4,7 +4,6 @@ - allow creation of both dir pages, and "all files" page? [ ] enforce lack of trailing/leading slashes in -o and -b options [ ] Remove globals / replace them with passed structs -[ ] Rewrite man page [ ] Caching - but it needs to also not increase complexity. - it's ok to duplicate storage diff --git a/config.h b/config.h @@ -17,7 +17,8 @@ /* the relative path to save to index page to */ #define INDEX_DEST "index.html" /* what projects' titles link to */ -#define INDEX_REPO_LINK readme == NULL ? "files.html" : "files/%s.html", readme +#define INDEX_REPO_LINK data->readme == NULL ? "files.html" : "files/%s.html", data->readme +/* used for index page title, otherwise not displayed. */ #define INDEX_TITLE "Emma's Code" /* shown at the top of index page */ #define INDEX_HEADER "<p>" \ @@ -28,9 +29,9 @@ /********* repository page configurations ************/ /* the relative path to save each repository's page to */ -#define PAGE_DEST "%s", repo_name +#define PAGE_DEST "%s", data->repo_name /* shown at the top of each repo page */ -#define PAGE_HEADER "<span> <a href=\"/\">git.y1.nz</a> </span>" +#define PAGE_HEADER "<p> <a href=\"/\">git.y1.nz</a> </p>" /* label shown before download/clone link */ #define PAGE_ACCESS_LABEL "download" /* shown at the bottom of each repo page */ diff --git a/index.c b/index.c @@ -9,13 +9,13 @@ #include <git2.h> #include "config.h" +#include "repo.h" // TODO extract these to a shared location (index.h) #define SPUTF(f, s) fputs((s), (f)) #define put_xml(fp, s) put_xml_len((fp), (s), strlen(s)) -static char owner[255]; - +// TODO improve this... yuck..... FILE * git_fopen(char *path, size_t path_size, const char *name); void put_xml_len(FILE *fp, const char *data, size_t len); void put_percent_encoded(FILE *fp, const char *data); @@ -42,10 +42,7 @@ put_index_header(FILE *fp) "</head>" "\n" "<body>" "\n" ); fprintf(fp, INDEX_HEADER); - SPUTF( - fp, - "<div id=\"content\">" "\n" - ); + SPUTF(fp, "<p id=\"content\">" "\n"); } void @@ -53,7 +50,7 @@ put_index_footer(FILE *fp) { SPUTF( fp, - "</tbody></table>" "\n" "</div>" "\n" + "</tbody></table>" "\n" "</p>" "\n" "</body>" "\n" "</html>" "\n" ); } @@ -61,9 +58,11 @@ put_index_footer(FILE *fp) void put_index_category(FILE *fp, const char *category, int first) { + if (!first && category == NULL) return; + if (!first) SPUTF(fp, "</tbody></table><br>" "\n"); - SPUTF(fp, "<table><tbody>" "\n"); + SPUTF(fp, "<table class=\"index\"><tbody>" "\n"); if (category != NULL) { SPUTF(fp, "<tr></tr>" "<tr><td colspan=3><b>"); @@ -75,10 +74,7 @@ put_index_category(FILE *fp, const char *category, int first) int put_index_log( FILE *fp, - git_repository *repo, - const char *description, - const char *repo_name, - const char *readme + RepoData *data ) { git_commit *commit = NULL; const git_signature *author; @@ -86,49 +82,34 @@ put_index_log( git_oid id; int ret = 0; - git_revwalk_new(&w, repo); + git_revwalk_new(&w, data->repo); git_revwalk_push_head(w); - if (git_revwalk_next(&id, w) || - git_commit_lookup(&commit, repo, &id)) { + if ( + git_revwalk_next(&id, w) || + git_commit_lookup(&commit, data->repo, &id) + ) { ret = -1; goto err; } author = git_commit_author(commit); + // TODO make this link reflect the repo page configuration SPUTF(fp, "<tr><td><a href=\""); put_absolute_path(fp, ""); fprintf(fp, INDEX_REPO_LINK); SPUTF(fp, "\">"); - put_xml(fp, repo_name); + put_xml(fp, data->repo_name); SPUTF(fp, "</a></td><td>"); - put_xml(fp, description); + put_xml(fp, data->description); SPUTF(fp, "</td><td>"); if (author) printtimeshort(fp, &(author->when)); - SPUTF(fp, "</td></tr>"); + SPUTF(fp, "</td></tr>"); git_commit_free(commit); err: git_revwalk_free(w); - return ret; } - -void -find_owner() -{ - FILE *fp; - char path[PATH_MAX]; - fp = git_fopen(path, sizeof(path), ".git/owner"); - - owner[0] = '\0'; - if (fp) { - if (!fgets(owner, sizeof(owner), fp)) - owner[0] = '\0'; - check_file_error(fp, path, 'r'); - fclose(fp); - owner[strcspn(owner, "\n")] = '\0'; - } -} diff --git a/main.c b/main.c @@ -17,11 +17,11 @@ #include "compat.h" #include "opt.h" #include "files.h" +#include "repo.h" #define CPUT(f, c) putc((c), (f)) #define put_xml(fp, s) put_xml_len((fp), (s), strlen(s)) #define SPUTF(f, s) fputs((s), (f)) -#define LENGTH(s) (sizeof(s)/sizeof(*s)) #include "config.h" @@ -68,39 +68,20 @@ struct Weight { size_t lines; }; +/* miscellaneous constants */ static const char orders[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E' }; static const char tab[] = "0123456789ABCDEF"; /* GLOBALS */ -// TODO untangle these, pass them around instead... - -static git_repository *repo; - -/* flags + arguments */ static Opt opt; -static const char *repo_dir; - -static const char *license_files[] = { LICENSE_FILES }; -static const char *readme_files[] = { README_FILES }; - -// TODO extract these into a struct. LMFAO -static char *name = ""; -static char *repo_name = ""; -static char description[255]; -static char clone_url[1024]; -static char *submodules; -static const char *license; -static const char *readme; - -/* bad globals for index.... */ -// TODO move this stuff to index.h? +static RepoData *data; static FILE *index_fp; -static char index_fname[255] = "index.html"; +static char index_fname[PATH_MAX]; -void find_owner(); -int put_index_log(FILE *fp, git_repository *repo, const char *description, const char *repo_name, const char *readme); +// TODO reorganize so that this ugliness isn't necessary... void put_index_header(FILE *fp); void put_index_category(FILE *fp, const char *category, int first); +int put_index_log(FILE *fp, RepoData *data); void put_index_footer(FILE *fp); void @@ -154,52 +135,6 @@ page_path_err: errx(1, "page path truncated! '%s' / '%s'" "\n", dir, name); } -FILE * -git_fopen(char *path, int path_size, const char *file) -{ - FILE *ret; - - /* try dir/(whatever), */ - /* (+5 removes the leading '.git/'.) */ - join_path(path, path_size, repo_dir, file + 5); - if ((ret = fopen(path, "r"))) return ret; - - /* then try dir/.git/(whatever). */ - join_path(path, path_size, repo_dir, file); - return fopen(path, "r"); -} - -void -find_license() -{ - git_object *obj = NULL; - int i; - for (i = 0; i < LENGTH(license_files) && !license; i++) { - if ( - !git_revparse_single(&obj, repo, license_files[i]) && - git_object_type(obj) == GIT_OBJ_BLOB - ) - license = license_files[i] + strlen("HEAD:"); - git_object_free(obj); - } -} - -void -find_readme() -{ - git_object *obj = NULL; - int i; - readme = NULL; - for (i = 0; i < LENGTH(readme_files) && !readme; i++) { - if ( - !git_revparse_single(&obj, repo, readme_files[i]) && - git_object_type(obj) == GIT_OBJ_BLOB - ) - readme = readme_files[i] + strlen("HEAD:"); - git_object_free(obj); - } -} - void delta_info_free(struct DeltaInfo *di) { @@ -223,10 +158,10 @@ commit_info_get_stats(struct CommitInfo *ci) size_t ndeltas, nhunks, nhunklines; size_t i, j, k; - if (git_tree_lookup(&(ci->commit_tree), repo, git_commit_tree_id(ci->commit))) + if (git_tree_lookup(&(ci->commit_tree), data->repo, git_commit_tree_id(ci->commit))) goto err; if (!git_commit_parent(&(ci->parent), ci->commit, 0)) { - if (git_tree_lookup(&(ci->parent_tree), repo, git_commit_tree_id(ci->parent))) { + if (git_tree_lookup(&(ci->parent_tree), data->repo, git_commit_tree_id(ci->parent))) { ci->parent = NULL; ci->parent_tree = NULL; } @@ -236,7 +171,7 @@ commit_info_get_stats(struct CommitInfo *ci) opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH | GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_INCLUDE_TYPECHANGE; - if (git_diff_tree_to_tree(&(ci->diff), repo, ci->parent_tree, ci->commit_tree, &opts)) + if (git_diff_tree_to_tree(&(ci->diff), data->repo, ci->parent_tree, ci->commit_tree, &opts)) goto err; if (git_diff_find_init_options(&fopts, GIT_DIFF_FIND_OPTIONS_VERSION)) @@ -341,7 +276,7 @@ commit_info_get_by_oid(const git_oid *id) if (!(ci = calloc(1, sizeof(struct CommitInfo)))) err(1, "calloc"); - if (git_commit_lookup(&(ci->commit), repo, id)) + if (git_commit_lookup(&(ci->commit), data->repo, id)) goto err; ci->id = id; @@ -396,7 +331,7 @@ get_refs(struct ReferenceInfo **pris, size_t *prefcount) *pris = NULL; *prefcount = 0; - if (git_reference_iterator_new(&it, repo)) + if (git_reference_iterator_new(&it, data->repo)) return -1; for (refcount = 0; !git_reference_next(&ref, it); ) { @@ -605,27 +540,25 @@ put_header(FILE *fp, const char *title) "<title>", fp ); - put_xml(fp, title); - if (title[0] && repo_name[0]) - fputs(" - ", fp); - put_xml(fp, repo_name); - if (description[0]) - fputs(" - ", fp); - put_xml(fp, description); - SPUTF(fp, "</title>" "\n"); - - SPUTF(fp, "<link rel=\"icon\" type=\"image/png\" href=\""); + if (title[0]) { + put_xml(fp, title); + SPUTF(fp, " - "); + put_xml(fp, data->repo_name); + } else { + put_xml(fp, data->repo_name); + } + SPUTF(fp, "</title>" "\n" "<link rel=\"icon\" type=\"image/png\" href=\""); put_absolute_path(fp, "favicon.png"); SPUTF(fp, "\" />" "\n"); SPUTF(fp, "<link rel=\"alternate\" type=\"application/atom+xml\" title=\""); - put_xml(fp, name); + put_xml(fp, data->name); SPUTF(fp, " Atom Feed\" href=\""); put_absolute_path(fp, "atom.xml"); SPUTF(fp, "\" />" "\n"); SPUTF(fp, "<link rel=\"alternate\" type=\"application/atom+xml\" title=\""); - put_xml(fp, name); + put_xml(fp, data->name); SPUTF(fp, " Atom Feed (tags)\" href=\""); put_absolute_path(fp, "tags.xml"); SPUTF(fp, "\" />" "\n"); @@ -638,25 +571,25 @@ put_header(FILE *fp, const char *title) fprintf(fp, PAGE_HEADER); SPUTF(fp, "<table>" "<tr>" "<td><h1>"); - put_xml(fp, repo_name); + put_xml(fp, data->repo_name); SPUTF(fp, "</h1></td>" "<td><span class=\"desc\">"); - put_xml(fp, description); + put_xml(fp, data->description); SPUTF(fp, "</span></td>" "</tr>"); - if (clone_url[0]) { + if (data->url[0]) { SPUTF(fp, "<tr class=\"url\">" "<td></td>" "<td>"); fprintf(fp, PAGE_ACCESS_LABEL); SPUTF(fp, ": <a href=\""); - put_xml(fp, clone_url); /* not percent encoded */ + put_xml(fp, data->url); /* not percent encoded */ SPUTF(fp, "\">"); - put_xml(fp, clone_url); + put_xml(fp, data->url); SPUTF(fp, "</a></td></tr>"); } SPUTF(fp, "<tr>" "<td></td>" "<td>" "\n"); - if (readme) { + if (data->readme) { SPUTF(fp, "<a href=\""); put_absolute_path(fp, "files/"); - fprintf(fp, "%s.html", readme); + fprintf(fp, "%s.html", data->readme); SPUTF(fp, "\">README</a> | "); } @@ -672,30 +605,29 @@ put_header(FILE *fp, const char *title) put_absolute_path(fp, "refs.html"); SPUTF(fp, "\">Refs</a>"); - if (submodules) { + if (data->submodules) { SPUTF(fp, " | <a href=\""); put_absolute_path(fp, "files/"); - fprintf(fp, "%s.html", submodules); + fprintf(fp, "%s.html", data->submodules); SPUTF(fp, "\">Submodules</a>"); } - if (license) { + if (data->license) { SPUTF(fp, " | <a href=\""); put_absolute_path(fp, "files/"); - fprintf(fp, "%s.html", license); + fprintf(fp, "%s.html", data->license); SPUTF(fp, "\">LICENSE</a>"); } SPUTF(fp, "</td></tr></table>" "\n"); - SPUTF(fp, "<hr/>" "\n"); - SPUTF(fp, "<div id=\"content\">" "\n"); + SPUTF(fp, "<p id=\"content\">" "\n"); } void put_footer(FILE *fp) { - SPUTF(fp, "</div>" "\n"); + SPUTF(fp, "</p>" "\n"); fprintf(fp, PAGE_FOOTER); SPUTF(fp, "</body>" "\n" "</html>" "\n"); } @@ -938,9 +870,8 @@ write_commit_page(char *name, struct CommitInfo *ci) char fname[PATH_MAX]; get_page_path(fname, sizeof(fname), opt.out_dir, name); FILE *fp = fopen_w(fname); - // [old] fpfile = efopen(path, "w"); - put_header(fp, ci->summary); + put_header(fp, ci->oid); SPUTF(fp, "<pre>"); put_show_file(fp, ci); @@ -962,7 +893,7 @@ put_log(FILE *fp, const git_oid *oid) int r; int commits_left = MAX_COMMITS; - git_revwalk_new(&w, repo); + git_revwalk_new(&w, data->repo); git_revwalk_push(w, oid); // TODO avoid processing very large commits @@ -1014,7 +945,7 @@ err: } void -put_log_html(FILE *fp, const git_oid *head) +put_log_html(FILE *fp) { put_header(fp, "Log"); fputs( @@ -1031,7 +962,7 @@ put_log_html(FILE *fp, const git_oid *head) fp ); - if (head) put_log(fp, head); + if (data->head) put_log(fp, data->head); fputs("</tbody></table>", fp); put_footer(fp); @@ -1110,14 +1041,14 @@ write_atom(FILE *fp, int all) "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" "\n" "<feed xmlns=\"http://www.w3.org/2005/Atom\">" "\n" "<title>" ); - put_xml(fp, repo_name); + put_xml(fp, data->repo_name); SPUTF(fp, ", branch HEAD</title>" "\n" "<subtitle>"); - put_xml(fp, description); + put_xml(fp, data->description); SPUTF(fp, "</subtitle>" "\n"); /* all commits or only tags? */ if (all) { - git_revwalk_new(&w, repo); + git_revwalk_new(&w, data->repo); git_revwalk_push_head(w); for (i = 0; i < m && !git_revwalk_next(&id, w); i++) { if (!(ci = commit_info_get_by_oid(&id))) @@ -1467,7 +1398,7 @@ put_file_list(FILE *fp, git_tree *tree, const char *path) combine_paths(entrypath, path, name); - if (!git_tree_entry_to_object(&obj, repo, entry)) { + if (!git_tree_entry_to_object(&obj, data->repo, entry)) { struct Weight weight = put_entry_obj(fp, obj, entry, entrypath, name); ret.bytes += weight.bytes; @@ -1534,15 +1465,15 @@ write_filetree(const char *path, const char *filename, git_tree *tree) } void -walk_git_tree(const git_oid *id) +walk_git_tree() { git_tree *tree = NULL; git_commit *commit = NULL; int has_files; - if (!id) return; + if (!data->head) return; - has_files = !git_commit_lookup(&commit, repo, id) && + has_files = !git_commit_lookup(&commit, data->repo, data->head) && !git_commit_tree(&tree, commit); write_filetree("", "files.html", has_files ? tree : NULL); @@ -1612,7 +1543,7 @@ put_refs(FILE *fp) } void -write_log_page(const git_oid *head) +write_log_page() { FILE *fp; char fname[PATH_MAX]; @@ -1620,7 +1551,7 @@ write_log_page(const git_oid *head) get_page_path(fname, sizeof(fname), opt.out_dir, "log.html"); fp = fopen_w(fname); - put_log_html(fp, head); + put_log_html(fp); check_file_error(fp, fname, 'w'); fclose(fp); @@ -1673,131 +1604,25 @@ write_releases_feed() fclose(fp); } -void -find_submodules() -{ - git_object *obj = NULL; - if ( - !git_revparse_single(&obj, repo, "HEAD:.gitmodules") && - git_object_type(obj) == GIT_OBJ_BLOB - ) - submodules = ".gitmodules"; - git_object_free(obj); -} - -void -find_description() -{ - char path[PATH_MAX]; - FILE *fp; - if ((fp = git_fopen(path, sizeof(path), ".git/description"))) { - if (!fgets(description, sizeof(description), fp)) - description[0] = '\0'; - check_file_error(fp, path, 'r'); - fclose(fp); - } -} - -void -find_clone_url() -{ - char path[PATH_MAX]; - FILE *fp; - if ((fp = git_fopen(path, sizeof(path), ".git/url"))) { - if (!fgets(clone_url, sizeof(clone_url), fp)) - clone_url[0] = '\0'; - check_file_error(fp, path, 'r'); - fclose(fp); - - // TODO ??? - clone_url[strcspn(clone_url, "\n")] = '\0'; - } -} - -void -find_repo_name() -{ - char abs_dir[PATH_MAX + 1]; - char *p; - - /* set abs_dir */ - if (!realpath(repo_dir, abs_dir)) - err(1, "realpath"); - - if ((name = strrchr(abs_dir, '/'))) name++; - else name = ""; - - if (!(repo_name = strdup(name))) err(1, "strdup"); - if ((p = strrchr(repo_name, '.'))) - if (!strcmp(p, ".git")) - *p = '\0'; - - if (repo_name[0] == '\0') - repo_name = "untitled"; -} - int write_repo_pages(const char* dir) { - - // TODO fully stop using globals like this.... - repo_dir = dir; - -#ifdef __OpenBSD__ - if (unveil(repo_dir, "r") == -1) err(1, "unveil: %s", repo_dir); - if (unveil(".", "rwc") == -1) err(1, "unveil: ."); - - /* - if (cachefile) { - if (unveil(cachefile, "rwc") == -1) err(1, "unveil: %s", cachefile); - if (pledge("stdio rpath wpath cpath fattr", NULL) == -1) err(1, "pledge"); - } else { - if (pledge("stdio rpath wpath cpath", NULL) == -1) err(1, "pledge"); - } - */ -#endif - - /* open the git repo */ - int result = git_repository_open_ext( - &repo, repo_dir, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL - ); - if (result < 0) { - fprintf(stderr, "fatal: cannot open repository '%s'" "\n", dir); - return 1; - } - - /* find HEAD */ - const git_oid *head = NULL; - git_object *obj = NULL; - if (!git_revparse_single(&obj, repo, "HEAD")) - head = git_object_id(obj); - git_object_free(obj); - - /* set global vars... */ - // TODO repo = open_repo(); - find_repo_name(); - find_description(); - find_clone_url(); - find_license(); - find_readme(); - find_submodules(); - if (opt.index) find_owner(); + data = alloc_repo_data(dir); + if (data == NULL) return 1; if (opt.index) { - put_index_log(index_fp, repo, description, repo_name, readme); + put_index_log(index_fp, data); } if (opt.pages) { - write_log_page(head); - walk_git_tree(head); - write_refs_page(); - write_feed(); - write_releases_feed(); + write_log_page(data); + walk_git_tree(data); + write_refs_page(data); + write_feed(data); + write_releases_feed(data); } - /* clean up */ - // TODO close_repo(); - git_repository_free(repo); + free_repo_data(data); return 0; } @@ -1813,6 +1638,8 @@ begin_index() ); index_fp = fopen_w(index_fname); put_index_header(index_fp); + index_fp = fopen_w(index_fname); + put_index_header(index_fp); } void @@ -1858,8 +1685,7 @@ main(int argc, const char *argv[]) if (opt.index) begin_index(); for (i = 0; i < opt.repo_count; i++) { - if (opt.categories[i] != NULL) - put_index_category(index_fp, opt.categories[i], i == 0); + put_index_category(index_fp, opt.categories[i], i == 0); result = write_repo_pages(opt.repo_dirs[i]); if(result > 0) return 1; } diff --git a/repo.c b/repo.c @@ -0,0 +1,223 @@ +#include <git2.h> +#include <stdio.h> +#include <limits.h> /* for PATH_MAX */ +#include <string.h> /* for strcspn */ // TODO remove this dep +#include <err.h> /* for err */ + +#include "config.h" /* for LICENSE_FILES and README_FILES */ +#include "files.h" /* for check_file_error */ +#include "repo.h" + +#define LENGTH(s) (sizeof(s)/sizeof(*s)) +#define URL_SIZE 255 +#define DESCRIPTION_SIZE 1024 +#define OWNER_SIZE 255 + +static const char *license_files[] = { LICENSE_FILES }; +static const char *readme_files[] = { README_FILES }; + +/* helper for find_readme, find_url, find_license, etc. */ +FILE * +git_fopen(RepoData *data, char *path, int path_size, const char *file) +{ + FILE *ret; + + /* Try dir/<whatever> (the +5 removes the leading '.git/') */ + join_path(path, path_size, data->dir, file + 5); + if ((ret = fopen(path, "r"))) return ret; + + /* then try dir/.git/<whatever. */ + join_path(path, path_size, data->dir, file); + return fopen(path, "r"); +} + +void +find_head(RepoData *data) +{ + data->head = NULL; + git_object *obj = NULL; + if (!git_revparse_single(&obj, data->repo, "HEAD")) + data->head = git_object_id(obj); + git_object_free(obj); +} + +void +find_submodules(RepoData *data) +{ + git_object *obj = NULL; + data->submodules = NULL; + if ( + !git_revparse_single(&obj, data->repo, "HEAD:.gitmodules") && + git_object_type(obj) == GIT_OBJ_BLOB + ) + data->submodules = ".gitmodules"; + git_object_free(obj); +} + +void +find_description(RepoData *data) +{ + char path[PATH_MAX]; + FILE *fp; + data->description = malloc(DESCRIPTION_SIZE * sizeof(char)); + data->description[0] = '\0'; + + if (!(fp = git_fopen(data, path, sizeof(path), ".git/description"))) + return; + + if (!fgets(data->description, DESCRIPTION_SIZE, fp)) + data->description[0] = '\0'; + + check_file_error(fp, path, 'r'); + fclose(fp); +} + +void +find_url(RepoData *data) +{ + char path[PATH_MAX]; + FILE *fp; + + data->url = malloc(URL_SIZE * sizeof(char)); + data->url[0] = '\0'; + + if (!(fp = git_fopen(data, path, sizeof(path), ".git/url"))) + return; + + if (!fgets(data->url, URL_SIZE, fp)) + data->url[0] = '\0'; + + check_file_error(fp, path, 'r'); + fclose(fp); + + // TODO ??? + data->url[strcspn(data->url, "\n")] = '\0'; +} + +void +find_repo_name(RepoData *data) +{ + char abs_dir[PATH_MAX + 1]; + char *p; + + data->name = data->repo_name = ""; + + /* set abs_dir */ + if (!realpath(data->dir, abs_dir)) + err(1, "realpath"); + + if ((data->name = strrchr(abs_dir, '/'))) data->name++; + else data->name = ""; + + if (!(data->repo_name = strdup(data->name))) err(1, "strdup"); + if ((p = strrchr(data->repo_name, '.'))) + if (!strcmp(p, ".git")) + *p = '\0'; + + if (data->repo_name[0] == '\0') + data->repo_name = "untitled"; +} + +void +find_license(RepoData *data) +{ + git_object *obj = NULL; + int i; + data->license = NULL; + for (i = 0; i < LENGTH(license_files) && data->license == NULL; i++) { + if ( + !git_revparse_single(&obj, data->repo, license_files[i]) && + git_object_type(obj) == GIT_OBJ_BLOB + ) + data->license = license_files[i] + strlen("HEAD:"); + git_object_free(obj); + } +} + +void +find_readme(RepoData *data) +{ + git_object *obj = NULL; + int i; + data->readme = NULL; + for (i = 0; i < LENGTH(readme_files) && data->readme == NULL; i++) { + if ( + !git_revparse_single(&obj, data->repo, readme_files[i]) && + git_object_type(obj) == GIT_OBJ_BLOB + ) + data->readme = readme_files[i] + strlen("HEAD:"); + git_object_free(obj); + } +} + +void +find_owner(RepoData *data) +{ + FILE *fp; + char path[PATH_MAX]; + + data->owner = malloc(OWNER_SIZE * sizeof(char)); + data->owner[0] = '\0'; + + fp = git_fopen(data, path, sizeof(path), ".git/owner"); + + if (!fp) return; + + if (!fgets(data->owner, OWNER_SIZE, fp)) + data->owner[0] = '\0'; + check_file_error(fp, path, 'r'); + fclose(fp); + data->owner[strcspn(data->owner, "\n")] = '\0'; +} + +RepoData * +alloc_repo_data(const char *dir) +{ + RepoData *data = malloc(sizeof(RepoData)); + + data->dir = dir; + +#ifdef __OpenBSD__ + if (unveil(data->dir, "r") == -1) err(1, "unveil: %s", data->dir); + if (unveil(".", "rwc") == -1) err(1, "unveil: ."); + + /* + if (cachefile) { + if (unveil(cachefile, "rwc") == -1) err(1, "unveil: %s", cachefile); + if (pledge("stdio rpath wpath cpath fattr", NULL) == -1) err(1, "pledge"); + } else { + if (pledge("stdio rpath wpath cpath", NULL) == -1) err(1, "pledge"); + } + */ +#endif + + /* open the git repo */ + int result = git_repository_open_ext( + &(data->repo), data->dir, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL + ); + if (result < 0) { + fprintf(stderr, "fatal: cannot open repository '%s'" "\n", dir); + return NULL; + } + + find_head(data); + find_repo_name(data); + find_description(data); + find_url(data); + find_license(data); + find_readme(data); + find_submodules(data); + find_owner(data); + + return data; +} + +void +free_repo_data(RepoData *data) +{ + git_repository_free(data->repo); + free(data->url); + free(data->owner); + free(data->description); + free(data); +} diff --git a/repo.h b/repo.h @@ -0,0 +1,18 @@ +/* This module contains all sgw's logic for extracting repo data. */ + +typedef struct _rd { + const char *dir; + git_repository *repo; + const git_oid *head; + char *name; + char *repo_name; + char *description; + char *url; + const char *submodules; + const char *license; + const char *readme; + char *owner; /* currently set, but not used */ +} RepoData; + +RepoData *alloc_repo_data(const char *repo_dir); +void free_repo_data(RepoData *repo); diff --git a/style.css b/style.css @@ -55,13 +55,13 @@ table td { #branches tr:hover td, #tags tr:hover td, -#index tr:hover td, +.index tr:hover td, #log tr:hover td, #files tr:hover td { background-color: #fee; } -#index tr td:nth-child(2), +.index tr td:nth-child(2), #tags tr td:nth-child(3), #branches tr td:nth-child(3), #log tr td:nth-child(2) {
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.