"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Dhruvin Gandhi <contact@dhruvin.dev>
Subject:
show_repo_category
To:
gameoftrees@openbsd.org
Date:
Mon, 27 Nov 2023 13:00:35 +0530

Download raw body.

Thread
  • Dhruvin Gandhi:

    show_repo_category

Gitweb supports these per-repository configuration files [1]:

[x] description
[ ] category
[x] cloneurl
[x] gitweb.owner (or gotweb.owner)

Note: x means the feature is present in gotwebd.

This diff adds support for labeling repos with a category. Currently, category is shown
wherever the description is shown.

Rationale behind using a category column in index:

gotwebd list pages have pagination implemented. When introducting categories
web can employ below approaches:

1. Paginate first, and then group <per-page> entries by category:
	This works in practice, but each page has varying number of categories
	at various indices. To me, it looks a bit out of place.

2. Categorize first, and then paginate <all> entries starting from
alphabetically sorted categories:
	This brings up all repos under "archived" category to the first page. I
	believe this is undesirable.

3. No grouping, just label repositories with category metadata:
	This is quite simple to implement. We can, in a later commit, allow filtering 
	repositories by category.

These ideas are subject to my understanding of how the user inteface should look like
and I'm open to change them.

[1] https://git-scm.com/docs/gitweb#_per_repository_gitweb_configuration

PS: This is my first contribution to gameoftrees. Let me know if I got anything
wrong while sending a diff to mailing list.

diff refs/heads/main refs/heads/show_repo_category
commit - 2bde3e78a5bd6619af838df19eec530e23783c0b
commit + 99fcb0c39edde5fec8b7752c079e8c9fe878b802
blob - 2980f56caa8182e5f1e54b32e8d915bf78dd1308
blob + 36383a7197171f46fcd2358275424b2d00c76c7e
--- TODO
+++ TODO
@@ -55,8 +55,6 @@ gotwebd:
   page.
 - add a "rawdiff" page to serve a diff as text/plain (or text/x-patch),
   or maybe "rawcommit" that includes the commentary too.
-- support category grouping a-la gitweb/cgit with the gitweb.category
-  config option or via the "category" file in the root of the repo.
 - consider changing the URL scheme to avoid so many query parameters
 
 gotd:
blob - 67b8328cafa8a92842599b49698d625a536119bd
blob + bb4866199b15665bf92bfa9dd7b13a86205f1c20
--- gotwebd/files/htdocs/gotwebd/gotweb.css
+++ gotwebd/files/htdocs/gotwebd/gotweb.css
@@ -255,24 +255,27 @@ header.subtitle h2 {
 #index_header {
 	background-color: Khaki;
 }
-.index_project, .index_project_description, .index_project_owner,
-.index_project_age {
+.index_project, .index_project_description, .index_project_category,
+.index_project_owner, .index_project_age {
 	display: inline-block;
 	padding: 10px;
 	overflow: hidden;
 	vertical-align: middle;
 }
 .index_project {
-	width: 20%;
+	width: 15%;
 }
 .index_project_description {
-	width: 30%;
+	width: 25%;
 }
+.index_project_category {
+	width: 20%;
+}
 .index_project_owner {
-	width: 25%;
+	width: 20%;
 }
 .index_project_age {
-	width: 25%;
+	width: 20%;
 }
 .index_project a {
 	color: #444444;
blob - af7ddea86d0f5f5e689b53e6aa57e44387ec4a1c
blob + dd33c6f9937687236160a4084565fda7361e3cb9
--- gotwebd/gotweb.c
+++ gotwebd/gotweb.c
@@ -91,6 +91,8 @@ static const struct got_error *gotweb_load_got_path(st
     struct repo_dir *);
 static const struct got_error *gotweb_get_repo_description(char **,
     struct server *, const char *, int);
+static const struct got_error *gotweb_get_repo_category(char **,
+    struct server *, const char *, int);
 static const struct got_error *gotweb_get_clone_url(char **, struct server *,
     const char *, int);
 
@@ -701,6 +703,7 @@ gotweb_free_repo_dir(struct repo_dir *repo_dir)
 	if (repo_dir != NULL) {
 		free(repo_dir->name);
 		free(repo_dir->owner);
+		free(repo_dir->category);
 		free(repo_dir->description);
 		free(repo_dir->url);
 		free(repo_dir->path);
@@ -1161,6 +1164,10 @@ open_repo:
 	    repo_dir->path, dirfd(dt));
 	if (error)
 		goto err;
+	error = gotweb_get_repo_category(&repo_dir->category, srv,
+	    repo_dir->path, dirfd(dt));
+	if (error)
+		goto err;
 	error = got_get_repo_owner(&repo_dir->owner, c);
 	if (error)
 		goto err;
@@ -1252,6 +1259,52 @@ done:
 }
 
 static const struct got_error *
+gotweb_get_repo_category(char **category, struct server *srv,
+    const char *dirpath, int dir)
+{
+	const struct got_error *error = NULL;
+	struct stat sb;
+	int fd = -1;
+	off_t len;
+
+	*category = NULL;
+	if (srv->show_repo_category == 0)
+		return NULL;
+
+	fd = openat(dir, "category", O_RDONLY);
+	if (fd == -1) {
+		if (errno != ENOENT && errno != EACCES) {
+			error = got_error_from_errno_fmt("openat %s/%s",
+			    dirpath, "category");
+		}
+		goto done;
+	}
+
+	if (fstat(fd, &sb) == -1) {
+		error = got_error_from_errno_fmt("fstat %s/%s",
+		    dirpath, "category");
+		goto done;
+	}
+
+	len = sb.st_size;
+	if (len > GOTWEBD_MAXCATSZ - 1)
+		len = GOTWEBD_MAXCATSZ - 1;
+
+	*category = calloc(len + 1, sizeof(**category));
+	if (*category == NULL) {
+		error = got_error_from_errno("calloc");
+		goto done;
+	}
+
+	if (read(fd, *category, len) == -1)
+		error = got_error_from_errno("read");
+done:
+	if (fd != -1 && close(fd) == -1 && error == NULL)
+		error = got_error_from_errno("close");
+	return error;
+}
+
+static const struct got_error *
 gotweb_get_clone_url(char **url, struct server *srv, const char *dirpath,
     int dir)
 {
blob - 0a41fb98df13059fc8f142e386a1d099a8d24de9
blob + 464ebbe06ba7bb41e36302a46b948e7a6308391b
--- gotwebd/gotwebd.conf.5
+++ gotwebd/gotwebd.conf.5
@@ -136,6 +136,11 @@ Toggle display of the repository description.
 The
 .Pa description
 file in the repository should be updated with an appropriate description.
+.It Ic show_repo_category Ar on | off
+Toggle display of the repository category.
+This requires the creation of a
+.Pa category
+file inside the repository.
 .It Ic show_repo_owner Ar on | off
 Set whether to display the repository owner.
 Displaying the owner requires owner information to be added to the
@@ -192,6 +197,7 @@ server "localhost-unix" {
 	#show_repo_owner  on
 	#show_repo_age  on
 	#show_repo_description on
+	#show_repo_category  on
 	#show_repo_cloneurl  on
 	#respect_exportok off
 
blob - 8005d4db4e8e1da67b226c26b8e1640b5c42645d
blob + 3d2de659bcce54a65d534cc39223102ba3f571d0
--- gotwebd/gotwebd.h
+++ gotwebd/gotwebd.h
@@ -40,6 +40,7 @@
 #define GOTWEBD_USER		 "www"
 
 #define GOTWEBD_MAXDESCRSZ	 1024
+#define GOTWEBD_MAXCATSZ	 64
 #define GOTWEBD_MAXCLONEURLSZ	 1024
 #define GOTWEBD_CACHESIZE	 1024
 #define GOTWEBD_MAXCLIENTS	 1024
@@ -73,6 +74,7 @@
 #define D_SHOWSOWNER		 1
 #define D_SHOWAGE		 1
 #define D_SHOWDESC		 1
+#define D_SHOWCAT		 1
 #define D_SHOWURL		 1
 #define D_RESPECTEXPORTOK	 0
 #define D_MAXREPO		 0
@@ -165,6 +167,7 @@ struct repo_dir {
 	char			*name;
 	char			*owner;
 	char			*description;
+	char			*category;
 	char			*url;
 	time_t			 age;
 	char			*path;
@@ -306,6 +309,7 @@ struct server {
 	int		 show_repo_owner;
 	int		 show_repo_age;
 	int		 show_repo_description;
+	int		 show_repo_category;
 	int		 show_repo_cloneurl;
 	int		 respect_exportok;
 
blob - d04e49122cc951bb2815072249af493a694624f3
blob + 32831eb25c20a494bf0dccf6670049b248d29f0c
--- gotwebd/pages.tmpl
+++ gotwebd/pages.tmpl
@@ -174,6 +174,11 @@ static inline int rss_author(struct template *, char *
   <div class="index_project">
     Project
   </div>
+  {{ if srv->show_repo_category }}
+    <div class="index_project_category">
+      Category
+    </div>
+  {{ end }}
   {{ if srv->show_repo_description }}
     <div class="index_project_description">
       Description
@@ -232,6 +237,11 @@ static inline int rss_author(struct template *, char *
   <div class="index_project">
     <a href="{{ render gotweb_render_url(tp->tp_arg, &summary) }}">{{ repo_dir->name }}</a>
   </div>
+  {{ if srv->show_repo_category }}
+    <div class="index_project_category">
+      {{ repo_dir->category }}
+    </div>
+  {{ end }}
   {{ if srv->show_repo_description }}
     <div class="index_project_description">
       {{ repo_dir->description }}
@@ -885,6 +895,10 @@ static inline int rss_author(struct template *, char *
 	struct got_reflist_head	*refs = &t->refs;
 !}
 <dl id="summary_wrapper">
+  {{ if srv->show_repo_category }}
+    <dt>Category:</dt>
+    <dd>{{ t->repo_dir->category }}</dd>
+  {{ end }}
   {{ if srv->show_repo_description }}
     <dt>Description:</dt>
     <dd>{{ t->repo_dir->description }}</dd>
blob - 207d9f20026688bdc8849f0125e73b94a285504e
blob + dfed531e40bc3b2b0d3b5103b2e9b4c19943d972
--- gotwebd/parse.y
+++ gotwebd/parse.y
@@ -386,6 +386,9 @@ serveropts1	: REPOS_PATH STRING {
 		| SHOW_REPO_DESCRIPTION boolean {
 			new_srv->show_repo_description = $2;
 		}
+		| SHOW_REPO_CATEGORY boolean {
+			new_srv->show_repo_category = $2;
+		}
 		| SHOW_REPO_CLONEURL boolean {
 			new_srv->show_repo_cloneurl = $2;
 		}
@@ -470,6 +473,7 @@ lookup(char *s)
 		{ "respect_exportok",		RESPECT_EXPORTOK },
 		{ "server",			SERVER },
 		{ "show_repo_age",		SHOW_REPO_AGE },
+		{ "show_repo_category",		SHOW_REPO_CATEGORY },
 		{ "show_repo_cloneurl",		SHOW_REPO_CLONEURL },
 		{ "show_repo_description",	SHOW_REPO_DESCRIPTION },
 		{ "show_repo_owner",		SHOW_REPO_OWNER },
@@ -904,6 +908,7 @@ conf_new_server(const char *name)
 	srv->show_repo_owner = D_SHOWROWNER;
 	srv->show_repo_age = D_SHOWAGE;
 	srv->show_repo_description = D_SHOWDESC;
+	srv->show_repo_category = D_SHOWCAT;
 	srv->show_repo_cloneurl = D_SHOWURL;
 	srv->respect_exportok = D_RESPECTEXPORTOK;