commit 298f95fb39537cc43237be56aeb86ffbc21e38f0 from: Omar Polo date: Thu Jan 05 08:25:48 2023 UTC gotwebd: render BLOB inline, add BLOBRAW for serving raw blobs binary blobs are automatically redirected to the BLOBRAW page (which is the old BLOB.) ok jamske commit - 389a68d86df4adffefba4050e86cd6a8fe6de36d commit + 298f95fb39537cc43237be56aeb86ffbc21e38f0 blob - d7d581b830dd549f2e3d19757290d8539f83618d blob + c83793f9a486da3fff129c76d2b915edd05b7c40 --- gotwebd/files/htdocs/gotwebd/gotweb.css +++ gotwebd/files/htdocs/gotwebd/gotweb.css @@ -527,36 +527,36 @@ body { white-space: pre-wrap; } -#blame_title_wrapper { +#blame_title_wrapper, #blob_title_wrapper { clear: left; float: left; width: 100%; background-color: LightSlateGray; color: #ffffff; } -#blame_title { +#blame_title, #blob_title_wrapper { padding-left: 10px; padding-top: 5px; padding-bottom: 5px; } -#blame_content { +#blame_content, #blob_content { clear: left; float: left; width: 100%; } -#blame_header_wrapper { +#blame_header_wrapper, #blob_header_wrapper { float: left; background-color: #f5fcfb; width: 100%; } -#blame_header { +#blame_header, #blob_header { float: left; padding-left: 10px; padding-top: 5px; padding-bottom: 2px; width: 80%; } -#blame { +#blame, #blob { clear: left; float: left; margin-left: 20px; @@ -565,12 +565,15 @@ body { white-space: pre; overflow: auto; } -.blame_wrapper { +.blame_wrapper, .blob_line { clear: left; float: left; width: 100%; } -.blame_number { +.blame_wrapper:target, .blob_line:target { + background-color: Khaki; +} +.blame_number, .blob_number { float: left; width: 6em; overflow: hidden; @@ -590,7 +593,7 @@ body { width: 6em; overflow: hidden; } -.blame_code { +.blame_code, .blob_code { float:left; width: 50%; overflow: visible; blob - d4196649f19af83bb7448f6007b5db724a9b3866 blob + 9d187ce1e16a66d113377842fd55ccbd016fd2e3 --- gotwebd/got_operations.c +++ gotwebd/got_operations.c @@ -960,7 +960,8 @@ done: } const struct got_error * -got_output_file_blob(struct request *c) +got_open_blob_for_output(struct got_blob_object **blob, int *fd, + int *binary, struct request *c) { const struct got_error *error = NULL; struct transport *t = c->t; @@ -969,14 +970,15 @@ got_output_file_blob(struct request *c) struct got_commit_object *commit = NULL; struct got_object_id *commit_id = NULL; struct got_reflist_head refs; - struct got_blob_object *blob = NULL; char *path = NULL, *in_repo_path = NULL; - int bin, obj_type, fd = -1; - size_t len; - const uint8_t *buf; + int obj_type; TAILQ_INIT(&refs); + *blob = NULL; + *fd = -1; + *binary = 0; + if (asprintf(&path, "%s%s%s", qs->folder ? qs->folder : "", qs->folder ? "/" : "", qs->file) == -1) { error = got_error_from_errno("asprintf"); @@ -1014,19 +1016,52 @@ got_output_file_blob(struct request *c) goto done; } - error = got_gotweb_dupfd(&c->priv_fd[BLOB_FD_1], &fd); + error = got_gotweb_dupfd(&c->priv_fd[BLOB_FD_1], fd); if (error) goto done; - error = got_object_open_as_blob(&blob, repo, commit_id, BUF, fd); + error = got_object_open_as_blob(blob, repo, commit_id, BUF, *fd); if (error) goto done; - error = got_object_blob_is_binary(&bin, blob); + error = got_object_blob_is_binary(binary, *blob); if (error) goto done; - if (bin) + done: + if (commit) + got_object_commit_close(commit); + + if (error) { + if (*fd != -1) + close(*fd); + if (*blob) + got_object_blob_close(*blob); + *fd = -1; + *blob = NULL; + } + + free(in_repo_path); + free(commit_id); + free(path); + return error; +} + +const struct got_error * +got_output_file_blob(struct request *c) +{ + const struct got_error *error = NULL; + struct querystring *qs = c->t->qs; + struct got_blob_object *blob = NULL; + size_t len; + int binary, fd = -1; + const uint8_t *buf; + + error = got_open_blob_for_output(&blob, &fd, &binary, c); + if (error) + return error; + + if (binary) error = gotweb_render_content_type_file(c, "application/octet-stream", qs->file, NULL); else @@ -1046,17 +1081,42 @@ got_output_file_blob(struct request *c) buf = got_object_blob_get_read_buf(blob); fcgi_gen_binary_response(c, buf, len); } -done: - if (commit) - got_object_commit_close(commit); - if (fd != -1 && close(fd) == -1 && error == NULL) + done: + if (close(fd) == -1 && error == NULL) error = got_error_from_errno("close"); if (blob) got_object_blob_close(blob); - free(in_repo_path); - free(commit_id); - free(path); return error; +} + +int +got_output_blob_by_lines(struct template *tp, struct got_blob_object *blob, + int (*cb)(struct template *, const char *, size_t)) +{ + const struct got_error *err; + char *line = NULL; + size_t linesize = 0; + size_t lineno = 0; + ssize_t linelen = 0; + + for (;;) { + err = got_object_blob_getline(&line, &linelen, &linesize, + blob); + if (err || linelen == -1) + break; + lineno++; + if (cb(tp, line, lineno) == -1) + break; + } + + free(line); + + if (err) { + log_warnx("%s: got_object_blob_getline failed: %s", + __func__, err->msg); + return -1; + } + return 0; } struct blame_line { blob - 39453efb256d54ee495702a9fef915782dec76ef blob + 37d8624ec792d91e8f7438d5cc3682be3a54d179 --- gotwebd/gotweb.c +++ gotwebd/gotweb.c @@ -66,6 +66,7 @@ static const struct querystring_keys querystring_keys[ static const struct action_keys action_keys[] = { { "blame", BLAME }, { "blob", BLOB }, + { "blobraw", BLOBRAW }, { "briefs", BRIEFS }, { "commits", COMMITS }, { "diff", DIFF }, @@ -109,11 +110,12 @@ void gotweb_process_request(struct request *c) { const struct got_error *error = NULL, *error2 = NULL; + struct got_blob_object *blob = NULL; struct server *srv = NULL; struct querystring *qs = NULL; struct repo_dir *repo_dir = NULL; uint8_t err[] = "gotwebd experienced an error: "; - int r, html = 0; + int r, html = 0, fd = -1; /* init the transport */ error = gotweb_init_transport(&c->t); @@ -150,10 +152,12 @@ gotweb_process_request(struct request *c) * querystring. */ - if (qs->commit == NULL && (qs->action == BLAME || qs->action == BLOB || - qs->action == DIFF)) { - error2 = got_error(GOT_ERR_QUERYSTRING); - goto render; + if (qs->action == BLAME || qs->action == BLOB || + qs->action == BLOBRAW || qs->action == DIFF) { + if (qs->commit == NULL) { + error2 = got_error(GOT_ERR_QUERYSTRING); + goto render; + } } if (qs->action != INDEX) { @@ -166,7 +170,7 @@ gotweb_process_request(struct request *c) goto err; } - if (qs->action == BLOB) { + if (qs->action == BLOBRAW) { error = got_get_repo_commits(c, 1); if (error) goto done; @@ -176,6 +180,34 @@ gotweb_process_request(struct request *c) goto err; } goto done; + } + + if (qs->action == BLOB) { + int binary; + struct gotweb_url url = { + .index_page = -1, + .page = -1, + .action = BLOBRAW, + .path = qs->path, + .commit = qs->commit, + .folder = qs->folder, + .file = qs->file, + }; + + error = got_get_repo_commits(c, 1); + if (error) + goto done; + + error2 = got_open_blob_for_output(&blob, &fd, &binary, c); + if (error2) + goto render; + if (binary) { + fcgi_puts(c->tp, "Status: 302\r\n"); + fcgi_puts(c->tp, "Location: "); + gotweb_render_url(c, &url); + fcgi_puts(c->tp, "\r\n\r\n"); + goto done; + } } if (qs->action == RSS) { @@ -220,6 +252,10 @@ render: log_warnx("%s: %s", __func__, error->msg); goto err; } + break; + case BLOB: + if (gotweb_render_blob(c->tp, blob) == -1) + goto err; break; case BRIEFS: if (gotweb_render_briefs(c->tp) == -1) @@ -301,6 +337,10 @@ err: if (html && fcgi_printf(c, "\n") == -1) return; done: + if (blob) + got_object_blob_close(blob); + if (fd != -1) + close(fd); if (html && srv != NULL) gotweb_render_footer(c->tp); } @@ -1626,6 +1666,8 @@ gotweb_action_name(int action) return "blame"; case BLOB: return "blob"; + case BLOBRAW: + return "blobraw"; case BRIEFS: return "briefs"; case COMMITS: blob - f3c092bd9402f47b404b596072606dfc3196fce8 blob + e4e23bf9c198a25c2338660068796cd385a8498c --- gotwebd/gotwebd.h +++ gotwebd/gotwebd.h @@ -115,6 +115,9 @@ #define GOTWEB_PACK_NUM_TEMPFILES 32 +/* Forward declaration */ +struct got_blob_object; + enum imsg_type { IMSG_CFG_SRV = IMSG_PROC_MAX, IMSG_CFG_SOCK, @@ -404,6 +407,7 @@ enum querystring_elements { enum query_actions { BLAME, BLOB, + BLOBRAW, BRIEFS, COMMITS, DIFF, @@ -462,6 +466,7 @@ int gotweb_render_repo_fragment(struct template *, str int gotweb_render_briefs(struct template *); int gotweb_render_navs(struct template *); int gotweb_render_commits(struct template *); +int gotweb_render_blob(struct template *, struct got_blob_object *); int gotweb_render_rss(struct template *); /* parse.y */ @@ -491,7 +496,11 @@ const struct got_error *got_get_repo_tags(struct reque const struct got_error *got_get_repo_heads(struct request *); const struct got_error *got_output_repo_diff(struct request *); const struct got_error *got_output_repo_tree(struct request *); +const struct got_error *got_open_blob_for_output(struct got_blob_object **, + int *, int *, struct request *); const struct got_error *got_output_file_blob(struct request *); +int got_output_blob_by_lines(struct template *, struct got_blob_object *, + int (*)(struct template *, const char *, size_t)); const struct got_error *got_output_file_blame(struct request *); /* config.c */ blob - 31d9c2b76e13b67d88a33db6d31ba3ce49398422 blob + 5dac668e8a6c3b5de586bc8484746a6397e29dfb --- gotwebd/pages.tmpl +++ gotwebd/pages.tmpl @@ -31,6 +31,8 @@ #include "gotwebd.h" #include "tmpl.h" +static int gotweb_render_blob_line(struct template *, const char *, size_t); + static inline int rss_tag_item(struct template *, struct repo_tag *); static inline int rss_author(struct template *, char *); @@ -403,9 +405,57 @@ gotweb_render_age(struct template *tp, time_t time, in {{ if t->next_id || t->prev_id }} {{ render gotweb_render_navs(tp) }} {{ end }} + +{{ end }} + +{{ define gotweb_render_blob(struct template *tp, + struct got_blob_object *blob) }} +{! + struct request *c = tp->tp_arg; + struct transport *t = c->t; + struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); +!} +
+
Blob
+
+
+
+
+
Date:
+
+ {{ render gotweb_render_age(tp, rc->committer_time, TM_LONG) }} +
+
Message:
+
{{ rc->commit_msg }}
+
+
+
+
+
+      {{ render got_output_blob_by_lines(tp, blob, gotweb_render_blob_line) }}
+    
+
{{ end }} +{{ define gotweb_render_blob_line(struct template *tp, const char *line, + size_t no) }} +{! + char lineno[16]; + int r; + + r = snprintf(lineno, sizeof(lineno), "%zu", no); + if (r < 0 || (size_t)r >= sizeof(lineno)) + return -1; +!} +
+ +
{{ line }}
+
+{{ end }} + {{ define gotweb_render_rss(struct template *tp) }} {! struct request *c = tp->tp_arg;