commit - bcbc97d8dd5a7e35291a7be58ebe9700a328c976
commit + ec46ccd7d7f1b541c5409aef045c57985fdecfe8
blob - 8f9b2cf6f568f007f0e1d1cce187828cc667f290
blob + 36e91d38a462f406fa51d2311ffd2601ef72ded1
--- Makefile.inc
+++ Makefile.inc
CPPFLAGS += -DGOT_LIBEXECDIR=${LIBEXECDIR} -DGOT_VERSION=${GOT_VERSION}
-CFLAGS += -Werror -Wall -Wstrict-prototypes -Wunused-variable
+#CFLAGS += -Werror -Wall -Wstrict-prototypes -Wunused-variable
#CFLAGS += -DGOT_PACK_NO_MMAP
#CFLAGS += -DGOT_NO_OBJ_CACHE
#CFLAGS += -DGOT_OBJ_CACHE_DEBUG
ETC_DIR = ${CHROOT_DIR}/etc
EXPL_DIR = ${ETC_DIR}/examples
HTTPD_DIR = ${CHROOT_DIR}/htdocs
+TMP_DIR = ${CHROOT_DIR}/tmp
PROG_DIR = ${HTTPD_DIR}/${PROG}
CGI_DIR = ${CHROOT_DIR}${GOTWEB_DIR}
TMPL_DIR = ${CGI_DIR}/gw_tmpl
blob - 4ea3fdf6856195211f469ede4bc0b6c70d0ad0e1
blob + 8a884d85583952006e7224a3fa6fdecfa61d08a2
--- gotweb/Makefile
+++ gotweb/Makefile
if [ ! -d ${HTTPD_DIR}/. ]; then \
${INSTALL} -d -o root -g daemon -m 755 ${HTTPD_DIR}; \
fi
+ if [ ! -d ${TMP_DIR}/. ]; then \
+ ${INSTALL} -d -o www -g www -m 755 ${TMP_DIR}; \
+ fi
if [ ! -d ${PROG_DIR}/. ]; then \
${INSTALL} -d -o root -g daemon -m 755 ${PROG_DIR}; \
fi
blob - 2355d9a8a685cc149633d1b0cac030c0f292319a
blob + d034c425417c6cda05766a1f32148715e40cec27
--- gotweb/files/htdocs/gotweb/gotweb.css
+++ gotweb/files/htdocs/gotweb/gotweb.css
padding: 0;
font-family: Arial, sans-serif;
}
+
+.diff_minus, .diff_submodule {
+ color: magenta;
+}
+.diff_plus, .diff_symlink, .diff_author {
+ color: darkcyan;
+}
+.diff_chunk_header, .diff_date {
+ background-color: LightSlateGray;
+ color: yellow;
+}
+.diff_meta, .diff_executable, .diff_commit {
+ color: green;
+}
+.diff_directory {
+ color: blue;
+}
+
#dotted_line {
clear: left;
float: left;
font-family: monospace;
}
+/* blame.tmpl */
+
+#log_blame_title_wrapper {
+ clear: left;
+ float: left;
+ width: 100%;
+ background-color: LightSlateGray;
+ color: #ffffff;
+}
+#log_blame_title {
+ padding-left: 10px;
+ padding-top: 5px;
+ padding-bottom: 5px;
+}
+#log_blame_content {
+ clear: left;
+ float: left;
+ width: 100%;
+}
+#log_blame_row_wrapper {
+ clear: left;
+ float: left;
+ background-color: #f5fcfb;
+ width: 100%;
+}
+#log_blame_commit {
+ clear: left;
+ float: left;
+ padding-left: 10px;
+ padding-top: 5px;
+ padding-bottom: 2px;
+}
+#log_blame {
+ clear: left;
+ float: left;
+ padding: 20px;
+ font-family: monospace;
+}
+#blame_wrapper {
+ clear: left;
+ float: left;
+ width: 100%;
+}
+#blame_id {
+ float: left;
+ padding: 2px;
+}
+#blame {
+ float:left ;
+ padding: 2px;
+}
+
/* tree.tmpl */
#log_tree_title_wrapper {
float: left;
padding: 20px;
font-family: monospace;
+ white-space: pre;
}
/* summary.tmpl */
blob - 3cc5a9a7e4edc98ef9cead27a933493239362af6
blob + ed0caaef099bbac42c1fb21e0d9165082e23a0d2
--- gotweb/gotweb.c
+++ gotweb/gotweb.c
/*
* Copyright (c) 2019, 2020 Tracey Emery <tracey@traceyemery.net>
* Copyright (c) 2018, 2019 Stefan Sperling <stsp@openbsd.org>
- * Copyright (c) 2014, 2015, 2017 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
char *repo_path;
char *commit;
char *repo_file;
+ char *repo_folder;
char *action_name;
char *headref;
unsigned int action;
};
enum gw_key {
- KEY_PATH,
KEY_ACTION,
KEY_COMMIT_ID,
KEY_FILE,
- KEY_PAGE,
+ KEY_FOLDER,
KEY_HEADREF,
- KEY__MAX
+ KEY_PAGE,
+ KEY_PATH,
+ KEY__ZMAX
};
struct gw_dir {
"content",
};
-static const struct kvalid gw_keys[KEY__MAX] = {
- { kvalid_stringne, "path" },
+static const struct kvalid gw_keys[KEY__ZMAX] = {
{ kvalid_stringne, "action" },
{ kvalid_stringne, "commit" },
{ kvalid_stringne, "file" },
- { kvalid_int, "page" },
+ { kvalid_stringne, "folder" },
{ kvalid_stringne, "headref" },
+ { kvalid_int, "page" },
+ { kvalid_stringne, "path" },
};
int gw_get_repo_log_count(struct trans *, char *);
char *, char *, int);
static char *gw_get_repo_log(struct trans *, const char *,
char *, int, int);
+static char *gw_get_file_blame(struct trans *, char *);
static char *gw_get_repo_tree(struct trans *, char *);
+static char *gw_get_repo_diff(struct trans *, char *,
+ char *);
static char *gw_get_repo_tags(struct trans *, int, int);
static char *gw_get_repo_heads(struct trans *);
static char *gw_get_clone_url(struct trans *, char *);
static char *gw_get_got_link(struct trans *);
static char *gw_get_site_link(struct trans *);
static char *gw_html_escape(const char *);
+static char *color_diff_line(char *);
static void gw_display_open(struct trans *, enum khttp,
enum kmime);
struct got_reference *);
static const struct got_error* resolve_commit_arg(struct got_object_id **,
const char *, struct got_repository *);
+static const struct got_error* match_object_id(struct got_object_id **,
+ char **, const char *r, int, int,
+ struct got_repository *);
+static const struct got_error* blame_cb(void *, int, int,
+ struct got_object_id *);
static const struct got_error* gw_load_got_paths(struct trans *);
static const struct got_error* gw_load_got_path(struct trans *,
struct gw_dir *);
return err;
}
+static const struct got_error *
+match_object_id(struct got_object_id **id, char **label,
+ const char *id_str, int obj_type, int resolve_tags,
+ struct got_repository *repo)
+{
+ const struct got_error *err;
+ struct got_tag_object *tag;
+ struct got_reference *ref = NULL;
+
+ *id = NULL;
+ *label = NULL;
+
+ if (resolve_tags) {
+ err = got_repo_object_match_tag(&tag, id_str, GOT_OBJ_TYPE_ANY,
+ repo);
+ if (err == NULL) {
+ *id = got_object_id_dup(
+ got_object_tag_get_object_id(tag));
+ if (*id == NULL)
+ err = got_error_from_errno("got_object_id_dup");
+ else if (asprintf(label, "refs/tags/%s",
+ got_object_tag_get_name(tag)) == -1) {
+ err = got_error_from_errno("asprintf");
+ free(*id);
+ *id = NULL;
+ }
+ got_object_tag_close(tag);
+ return err;
+ } else if (err->code != GOT_ERR_NO_OBJ)
+ return err;
+ }
+
+ err = got_repo_match_object_id_prefix(id, id_str, obj_type, repo);
+ if (err) {
+ if (err->code != GOT_ERR_BAD_OBJ_ID_STR)
+ return err;
+ err = got_ref_open(&ref, repo, id_str, 0);
+ if (err != NULL)
+ goto done;
+ *label = strdup(got_ref_get_name(ref));
+ if (*label == NULL) {
+ err = got_error_from_errno("strdup");
+ goto done;
+ }
+ err = got_ref_resolve(id, repo, ref);
+ } else {
+ err = got_object_id_str(label, *id);
+ if (*label == NULL) {
+ err = got_error_from_errno("strdup");
+ goto done;
+ }
+ }
+done:
+ if (ref)
+ got_ref_close(ref);
+ return err;
+}
+
int
gw_get_repo_log_count(struct trans *gw_trans, char *start_commit)
{
int log_count = 0;
error = got_repo_open(&repo, gw_trans->repo_path, NULL);
- if (error != NULL)
+ if (error)
return 0;
SIMPLEQ_INIT(&refs);
if (start_commit == NULL) {
struct got_reference *head_ref;
error = got_ref_open(&head_ref, repo, gw_trans->headref, 0);
- if (error != NULL)
+ if (error)
goto done;
error = got_ref_resolve(&id, repo, head_ref);
got_ref_close(head_ref);
- if (error != NULL)
+ if (error)
goto done;
error = got_object_open_as_commit(&commit, repo, id);
int obj_type;
error = got_ref_resolve(&id, repo, ref);
got_ref_close(ref);
- if (error != NULL)
+ if (error)
goto done;
error = got_object_get_type(&obj_type, repo, id);
- if (error != NULL)
+ if (error)
goto done;
if (obj_type == GOT_OBJ_TYPE_TAG) {
struct got_tag_object *tag;
error = got_object_open_as_tag(&tag, repo, id);
- if (error != NULL)
+ if (error)
goto done;
if (got_object_tag_get_object_type(tag) !=
GOT_OBJ_TYPE_COMMIT) {
goto done;
}
error = got_object_open_as_commit(&commit, repo, id);
- if (error != NULL)
+ if (error)
goto done;
}
if (commit == NULL) {
error = got_repo_match_object_id_prefix(&id,
start_commit, GOT_OBJ_TYPE_COMMIT, repo);
- if (error != NULL)
+ if (error)
goto done;
}
error = got_repo_match_object_id_prefix(&id,
start_commit, GOT_OBJ_TYPE_COMMIT, repo);
- if (error != NULL)
+ if (error)
goto done;
}
error = got_object_open_as_commit(&commit, repo, id);
- if (error != NULL)
+ if (error)
goto done;
error = got_repo_map_path(&in_repo_path, repo, gw_trans->repo_path, 1);
- if (error != NULL)
+ if (error)
goto done;
if (in_repo_path) {
got_commit_graph_close(graph);
if (repo) {
error = got_repo_close(repo);
- if (error != NULL)
+ if (error)
return 0;
}
if (error) {
{
const struct got_error *error = NULL;
+ char *log, *log_html;
+
+ error = apply_unveil(gw_trans->gw_dir->path, NULL);
+ if (error)
+ return error;
+
+ log = gw_get_repo_log(gw_trans, NULL, gw_trans->commit, 1, LOGBLAME);
+
+ if (log != NULL && strcmp(log, "") != 0) {
+ if ((asprintf(&log_html, log_tree, log)) == -1)
+ return got_error_from_errno("asprintf");
+ khttp_puts(gw_trans->gw_req, log_html);
+ free(log_html);
+ free(log);
+ }
return error;
}
if ((asprintf(&gw_trans->repo_path, "%s/%s",
gw_trans->gw_conf->got_repos_path, p->parsed.s)) == -1)
return got_error_from_errno("asprintf");
-
- if ((p = gw_trans->gw_req->fieldmap[KEY_COMMIT_ID]))
- if ((asprintf(&gw_trans->commit, "%s",
- p->parsed.s)) == -1)
- return got_error_from_errno("asprintf");
/* get action and set function */
if ((p = gw_trans->gw_req->fieldmap[KEY_ACTION]))
action = NULL;
}
+
+ if ((p = gw_trans->gw_req->fieldmap[KEY_COMMIT_ID]))
+ if ((asprintf(&gw_trans->commit, "%s",
+ p->parsed.s)) == -1)
+ return got_error_from_errno("asprintf");
if ((p = gw_trans->gw_req->fieldmap[KEY_FILE]))
if ((asprintf(&gw_trans->repo_file, "%s",
p->parsed.s)) == -1)
return got_error_from_errno("asprintf");
+ if ((p = gw_trans->gw_req->fieldmap[KEY_FOLDER]))
+ if ((asprintf(&gw_trans->repo_folder, "%s",
+ p->parsed.s)) == -1)
+ return got_error_from_errno("asprintf");
+
if ((p = gw_trans->gw_req->fieldmap[KEY_HEADREF]))
if ((asprintf(&gw_trans->headref, "%s",
p->parsed.s)) == -1)
}
error = got_repo_open(&repo, dir, NULL);
- if (error != NULL)
+ if (error)
goto err;
if (is_head)
else
error = got_ref_list(&refs, repo, repo_ref,
got_ref_cmp_by_name, NULL);
- if (error != NULL)
+ if (error)
goto err;
SIMPLEQ_FOREACH(re, &refs, entry) {
else
refname = got_ref_get_name(re->ref);
error = got_ref_open(&head_ref, repo, refname, 0);
- if (error != NULL)
+ if (error)
goto err;
error = got_ref_resolve(&id, repo, head_ref);
got_ref_close(head_ref);
- if (error != NULL)
+ if (error)
goto err;
error = got_object_open_as_commit(&commit, repo, id);
- if (error != NULL)
+ if (error)
goto err;
committer_time =
return NULL;
return repo_age;
+}
+
+static char *
+gw_get_repo_diff(struct trans *gw_trans, char *id_str1, char *id_str2)
+{
+ const struct got_error *error;
+ FILE *f = NULL;
+ struct got_object_id *id1 = NULL, *id2 = NULL;
+ struct got_repository *repo = NULL;
+ struct buf *diffbuf = NULL;
+ char *label1 = NULL, *label2 = NULL, *diff_html = NULL, *buf = NULL,
+ *buf_color = NULL;
+ int type1, type2;
+ size_t newsize;
+
+ f = got_opentemp();
+ if (f == NULL)
+ return NULL;
+
+ error = buf_alloc(&diffbuf, 0);
+ if (error)
+ return NULL;
+
+ error = got_repo_open(&repo, gw_trans->repo_path, NULL);
+ if (error)
+ goto done;
+
+ error = match_object_id(&id1, &label1, id_str1, GOT_OBJ_TYPE_ANY, 1,
+ repo);
+ if (error)
+ goto done;
+
+ if (id_str2) {
+ error = match_object_id(&id2, &label2, id_str2,
+ GOT_OBJ_TYPE_ANY, 1, repo);
+ if (error)
+ goto done;
+
+ error = got_object_get_type(&type2, repo, id2);
+ if (error)
+ goto done;
+ }
+
+ error = got_object_get_type(&type1, repo, id1);
+ if (error)
+ goto done;
+
+ if (id_str2 && type1 != type2) {
+ error = got_error(GOT_ERR_OBJ_TYPE);
+ goto done;
+ }
+
+ switch (type1) {
+ case GOT_OBJ_TYPE_BLOB:
+ error = got_diff_objects_as_blobs(id2, id1, NULL, NULL, 3, 0,
+ repo, f);
+ break;
+ case GOT_OBJ_TYPE_TREE:
+ error = got_diff_objects_as_trees(id2, id1, "", "", 3, 0, repo,
+ f);
+ break;
+ case GOT_OBJ_TYPE_COMMIT:
+ error = got_diff_objects_as_commits(id2, id1, 3, 0, repo, f);
+ break;
+ default:
+ error = got_error(GOT_ERR_OBJ_TYPE);
+ }
+
+ if ((buf = calloc(128, sizeof(char *))) == NULL)
+ goto done;
+
+ fseek(f, 0, SEEK_SET);
+
+ while ((fgets(buf, 128, f)) != NULL) {
+ buf_color = color_diff_line(buf);
+ error = buf_puts(&newsize, diffbuf, buf_color);
+ if (error)
+ return NULL;
+
+ error = buf_puts(&newsize, diffbuf, div_end);
+ if (error)
+ return NULL;
+ }
+
+ if (buf_len(diffbuf) > 0) {
+ error = buf_putc(diffbuf, '\0');
+ diff_html = strdup(buf_get(diffbuf));
+ }
+done:
+ fclose(f);
+ free(buf_color);
+ free(buf);
+ free(diffbuf);
+ free(label1);
+ free(label2);
+ free(id1);
+ free(id2);
+ if (repo)
+ got_repo_close(repo);
+
+ if (error)
+ return NULL;
+ else
+ return diff_html;
}
static char *
*commit_diff_disp = NULL, *logbriefs_navs_html = NULL,
*log_tree_html = NULL, *log_commit_html = NULL,
*log_diff_html = NULL, *commit_tree = NULL,
- *commit_tree_disp = NULL, *log_tag_html = NULL;
+ *commit_tree_disp = NULL, *log_tag_html = NULL,
+ *log_blame_html = NULL;
char *commit_log0, *newline;
regex_t regex;
- int have_match, log_count = 0;
+ int have_match, log_count = 0, has_parent = 1;
size_t newsize;
struct buf *diffbuf = NULL;
time_t committer_time;
log_count = gw_get_repo_log_count(gw_trans, start_commit);
error = buf_alloc(&diffbuf, 0);
- if (error != NULL)
+ if (error)
return NULL;
if (search_pattern &&
return NULL;
error = got_repo_open(&repo, gw_trans->repo_path, NULL);
- if (error != NULL)
+ if (error)
return NULL;
SIMPLEQ_INIT(&refs);
if (start_commit == NULL) {
struct got_reference *head_ref;
error = got_ref_open(&head_ref, repo, gw_trans->headref, 0);
- if (error != NULL)
+ if (error)
goto done;
error = got_ref_resolve(&id1, repo, head_ref);
got_ref_close(head_ref);
- if (error != NULL)
+ if (error)
goto done;
error = got_object_open_as_commit(&commit, repo, id1);
int obj_type;
error = got_ref_resolve(&id1, repo, ref);
got_ref_close(ref);
- if (error != NULL)
+ if (error)
goto done;
error = got_object_get_type(&obj_type, repo, id1);
- if (error != NULL)
+ if (error)
goto done;
if (obj_type == GOT_OBJ_TYPE_TAG) {
struct got_tag_object *tag;
error = got_object_open_as_tag(&tag, repo, id1);
- if (error != NULL)
+ if (error)
goto done;
if (got_object_tag_get_object_type(tag) !=
GOT_OBJ_TYPE_COMMIT) {
goto done;
}
error = got_object_open_as_commit(&commit, repo, id1);
- if (error != NULL)
+ if (error)
goto done;
}
if (commit == NULL) {
error = got_repo_match_object_id_prefix(&id1,
start_commit, GOT_OBJ_TYPE_COMMIT, repo);
- if (error != NULL)
+ if (error)
goto done;
}
error = got_repo_match_object_id_prefix(&id1,
start_commit, GOT_OBJ_TYPE_COMMIT, repo);
}
- if (error != NULL)
+ if (error)
goto done;
error = got_repo_map_path(&in_repo_path, repo, gw_trans->repo_path, 1);
- if (error != NULL)
+ if (error)
goto done;
if (in_repo_path) {
if (error)
goto done;
free(id2);
- } else
+ } else {
+ has_parent = 0;
id_str2 = strdup("/dev/null");
+ }
}
committer_time =
free(log_tag_html);
break;
+ case (LOGBLAME):
+ log_blame_html = gw_get_file_blame(gw_trans,
+ start_commit);
+
+ if ((asprintf(&commit_row, log_blame_row,
+ gw_html_escape(commit_log), log_blame_html)) == -1) {
+ error = got_error_from_errno("asprintf");
+ goto done;
+ }
+
+ free(log_blame_html);
+ break;
case (LOGTREE):
log_tree_html = gw_get_repo_tree(gw_trans,
start_commit);
goto done;
}
- log_diff_html = strdup("diff here");
+ if (has_parent)
+ log_diff_html = gw_get_repo_diff(gw_trans,
+ commit_commit, commit_parent);
+ else
+ log_diff_html = gw_get_repo_diff(gw_trans,
+ commit_commit, NULL);
if ((asprintf(&commit_row, log_diff_row,
commit_diff_disp, commit_commit_disp,
got_commit_graph_close(graph);
if (repo) {
error = got_repo_close(repo);
- if (error != NULL)
+ if (error)
return NULL;
}
if (error) {
size_t newsize;
error = buf_alloc(&diffbuf, 0);
- if (error != NULL)
+ if (error)
return NULL;
SIMPLEQ_INIT(&refs);
error = got_repo_open(&repo, gw_trans->repo_path, NULL);
- if (error != NULL)
+ if (error)
goto done;
error = got_ref_list(&refs, repo, "refs/tags", cmp_tags, repo);
return NULL;
else
return tags;
+}
+
+struct blame_line {
+ int annotated;
+ char *id_str;
+ char *committer;
+ char datebuf[11]; /* YYYY-MM-DD + NUL */
+};
+
+struct blame_cb_args {
+ struct blame_line *lines;
+ int nlines;
+ int nlines_prec;
+ int lineno_cur;
+ off_t *line_offsets;
+ FILE *f;
+ struct got_repository *repo;
+};
+
+static const struct got_error *
+blame_cb(void *arg, int nlines, int lineno, struct got_object_id *id)
+{
+ const struct got_error *err = NULL;
+ struct blame_cb_args *a = arg;
+ struct blame_line *bline;
+ char *line = NULL;
+ size_t linesize = 0;
+ struct got_commit_object *commit = NULL;
+ off_t offset;
+ struct tm tm;
+ time_t committer_time;
+
+ if (nlines != a->nlines ||
+ (lineno != -1 && lineno < 1) || lineno > a->nlines)
+ return got_error(GOT_ERR_RANGE);
+
+ if (lineno == -1)
+ return NULL; /* no change in this commit */
+
+ /* Annotate this line. */
+ bline = &a->lines[lineno - 1];
+ if (bline->annotated)
+ return NULL;
+ err = got_object_id_str(&bline->id_str, id);
+ if (err)
+ return err;
+
+ err = got_object_open_as_commit(&commit, a->repo, id);
+ if (err)
+ goto done;
+
+ bline->committer = strdup(got_object_commit_get_committer(commit));
+ if (bline->committer == NULL) {
+ err = got_error_from_errno("strdup");
+ goto done;
+ }
+
+ committer_time = got_object_commit_get_committer_time(commit);
+ if (localtime_r(&committer_time, &tm) == NULL)
+ return got_error_from_errno("localtime_r");
+ if (strftime(bline->datebuf, sizeof(bline->datebuf), "%G-%m-%d",
+ &tm) >= sizeof(bline->datebuf)) {
+ err = got_error(GOT_ERR_NO_SPACE);
+ goto done;
+ }
+ bline->annotated = 1;
+
+ /* Print lines annotated so far. */
+ bline = &a->lines[a->lineno_cur - 1];
+ if (!bline->annotated)
+ goto done;
+
+ offset = a->line_offsets[a->lineno_cur - 1];
+ if (fseeko(a->f, offset, SEEK_SET) == -1) {
+ err = got_error_from_errno("fseeko");
+ goto done;
+ }
+
+ while (bline->annotated) {
+ char *smallerthan, *at, *nl, *committer;
+ size_t len;
+
+ if (getline(&line, &linesize, a->f) == -1) {
+ if (ferror(a->f))
+ err = got_error_from_errno("getline");
+ break;
+ }
+
+ committer = bline->committer;
+ smallerthan = strchr(committer, '<');
+ if (smallerthan && smallerthan[1] != '\0')
+ committer = smallerthan + 1;
+ at = strchr(committer, '@');
+ if (at)
+ *at = '\0';
+ len = strlen(committer);
+ if (len >= 9)
+ committer[8] = '\0';
+
+ nl = strchr(line, '\n');
+ if (nl)
+ *nl = '\0';
+ printf("%.*d) %.8s %s %-8s %s\n", a->nlines_prec, a->lineno_cur,
+ bline->id_str, bline->datebuf, committer, line);
+
+ a->lineno_cur++;
+ bline = &a->lines[a->lineno_cur - 1];
+ }
+done:
+ if (commit)
+ got_object_commit_close(commit);
+ free(line);
+ return err;
}
static char*
-gw_get_repo_tree(struct trans *gw_trans, char *start_commit)
+gw_get_file_blame(struct trans *gw_trans, char *commit_str)
{
const struct got_error *error = NULL;
struct got_repository *repo = NULL;
+ struct got_object_id *obj_id = NULL;
+ struct got_object_id *commit_id = NULL;
+ struct got_blob_object *blob = NULL;
+ struct buf *diffbuf = NULL;
+ size_t newsize;
+ char *blame_html = NULL, *path = NULL, *in_repo_path = NULL,
+ *blame_row = NULL, *id_str;
+ struct blame_cb_args bca;
+ int nentries, i, obj_type;
+ size_t filesize;
+
+ error = buf_alloc(&diffbuf, 0);
+ if (error)
+ return NULL;
+
+ error = got_repo_open(&repo, gw_trans->repo_path, NULL);
+ if (error)
+ goto done;
+
+ error = got_repo_map_path(&in_repo_path, repo, gw_trans->repo_path, 1);
+ if (error)
+ goto done;
+
+ error = resolve_commit_arg(&commit_id, commit_str, repo);
+ if (error)
+ goto done;
+
+ error = got_object_id_by_path(&obj_id, repo, commit_id, in_repo_path);
+ if (error)
+ goto done;
+ if (obj_id == NULL) {
+ error = got_error(GOT_ERR_NO_OBJ);
+ goto done;
+ }
+
+ error = got_object_get_type(&obj_type, repo, obj_id);
+ if (error)
+ goto done;
+
+ if (obj_type != GOT_OBJ_TYPE_BLOB) {
+ error = got_error(GOT_ERR_OBJ_TYPE);
+ goto done;
+ }
+
+ error = got_object_open_as_blob(&blob, repo, obj_id, 8192);
+ if (error)
+ goto done;
+
+ bca.f = got_opentemp();
+ if (bca.f == NULL) {
+ error = got_error_from_errno("got_opentemp");
+ goto done;
+ }
+ error = got_object_blob_dump_to_file(&filesize, &bca.nlines,
+ &bca.line_offsets, bca.f, blob);
+ if (error || bca.nlines == 0)
+ goto done;
+
+ /* Don't include \n at EOF in the blame line count. */
+ if (bca.line_offsets[bca.nlines - 1] == filesize)
+ bca.nlines--;
+
+ bca.lines = calloc(bca.nlines, sizeof(*bca.lines));
+ if (bca.lines == NULL) {
+ error = got_error_from_errno("calloc");
+ goto done;
+ }
+ bca.lineno_cur = 1;
+ bca.nlines_prec = 0;
+ i = bca.nlines;
+ while (i > 0) {
+ i /= 10;
+ bca.nlines_prec++;
+ }
+ bca.repo = repo;
+
+ error = got_blame(in_repo_path, commit_id, repo, blame_cb, &bca, NULL,
+ NULL);
+ blame_html = strdup("blame");
+done:
+ free(diffbuf);
+ if (error)
+ return NULL;
+ else
+ return blame_html;
+}
+
+static char*
+gw_get_repo_tree(struct trans *gw_trans, char *commit_str)
+{
+ const struct got_error *error = NULL;
+ struct got_repository *repo = NULL;
struct got_object_id *tree_id = NULL, *commit_id = NULL;
struct got_tree_object *tree = NULL;
struct buf *diffbuf = NULL;
size_t newsize;
char *tree_html = NULL, *path = NULL, *in_repo_path = NULL,
*tree_row = NULL, *id_str;
- const char *modestr = "";
int nentries, i;
error = buf_alloc(&diffbuf, 0);
- if (error != NULL)
+ if (error)
return NULL;
error = got_repo_open(&repo, gw_trans->repo_path, NULL);
- if (error != NULL)
+ if (error)
goto done;
error = got_repo_map_path(&in_repo_path, repo, gw_trans->repo_path, 1);
- if (error != NULL)
+ if (error)
goto done;
- if (in_repo_path) {
+ if (gw_trans->repo_folder != NULL)
+ path = strdup(gw_trans->repo_folder);
+ else if (in_repo_path) {
free(path);
path = in_repo_path;
}
- error = resolve_commit_arg(&commit_id, start_commit, repo);
+ if (commit_str == NULL) {
+ struct got_reference *head_ref;
+ error = got_ref_open(&head_ref, repo, gw_trans->headref, 0);
+ if (error)
+ goto done;
+
+ error = got_ref_resolve(&commit_id, repo, head_ref);
+ got_ref_close(head_ref);
+
+ } else
+ error = resolve_commit_arg(&commit_id, commit_str, repo);
if (error)
goto done;
- error = got_object_id_by_path(&tree_id, repo, commit_id, in_repo_path);
+ error = got_object_id_by_path(&tree_id, repo, commit_id, path);
if (error)
goto done;
for (i = 0; i < nentries; i++) {
struct got_tree_entry *te;
- char *id = NULL;
+ const char *modestr = "";
+ char *id = NULL, *url_html = NULL;
te = got_object_tree_get_entry(tree, i);
if (error)
goto done;
- if (asprintf(&id, "%s", id_str) == -1) {
+ if ((asprintf(&id, "%s", id_str)) == -1) {
error = got_error_from_errno("asprintf");
free(id_str);
goto done;
else if (mode & S_IXUSR)
modestr = "*";
- if ((asprintf(&tree_row, trees_row, id_str,
- got_tree_entry_get_name(te), modestr)) == -1) {
+ char *build_folder = NULL;
+ if (S_ISDIR(got_tree_entry_get_mode(te))) {
+ if (gw_trans->repo_folder != NULL) {
+ if ((asprintf(&build_folder, "%s/%s",
+ gw_trans->repo_folder,
+ got_tree_entry_get_name(te))) == -1) {
+ error =
+ got_error_from_errno("asprintf");
+ goto done;
+ }
+ } else {
+ if (asprintf(&build_folder, "%s",
+ got_tree_entry_get_name(te)) == -1)
+ goto done;
+ }
+
+ if ((asprintf(&url_html, folder_html,
+ gw_trans->repo_name, gw_trans->action_name,
+ gw_trans->commit, build_folder,
+ got_tree_entry_get_name(te), modestr)) == -1) {
+ error = got_error_from_errno("asprintf");
+ goto done;
+ }
+ } else {
+ if (gw_trans->repo_folder != NULL) {
+ if ((asprintf(&build_folder, "%s",
+ gw_trans->repo_folder)) == -1) {
+ error =
+ got_error_from_errno("asprintf");
+ goto done;
+ }
+ } else
+ build_folder = strdup("");
+
+ if ((asprintf(&url_html, file_html, gw_trans->repo_name,
+ "blame", gw_trans->commit,
+ got_tree_entry_get_name(te), build_folder,
+ got_tree_entry_get_name(te), modestr)) == -1) {
+ error = got_error_from_errno("asprintf");
+ goto done;
+ }
+ }
+ free(build_folder);
+
+ if (error)
+ goto done;
+
+ if ((asprintf(&tree_row, trees_row, "", url_html)) == -1) {
error = got_error_from_errno("asprintf");
goto done;
}
error = buf_puts(&newsize, diffbuf, tree_row);
+ if (error)
+ goto done;
+
free(id);
free(id_str);
-
+ free(url_html);
+ free(tree_row);
}
if (buf_len(diffbuf) > 0) {
return NULL;
else
return tree_html;
-
}
static char *
size_t newsize;
error = buf_alloc(&diffbuf, 0);
- if (error != NULL)
+ if (error)
return NULL;
error = got_repo_open(&repo, gw_trans->repo_path, NULL);
- if (error != NULL)
+ if (error)
goto done;
SIMPLEQ_INIT(&refs);
}
static char *
+color_diff_line(char *buf)
+{
+ const struct got_error *error = NULL;
+ char *colorized_line = NULL, *div_diff_line_div = NULL, *color = NULL;
+ struct buf *diffbuf = NULL;
+ size_t newsize;
+
+ error = buf_alloc(&diffbuf, 0);
+ if (error)
+ return NULL;
+
+ if (strncmp(buf, "-", 1) == 0)
+ color = "diff_minus";
+ if (strncmp(buf, "+", 1) == 0)
+ color = "diff_plus";
+ if (strncmp(buf, "@@", 2) == 0)
+ color = "diff_chunk_header";
+ if (strncmp(buf, "@@", 2) == 0)
+ color = "diff_chunk_header";
+ if (strncmp(buf, "commit +", 8) == 0)
+ color = "diff_meta";
+ if (strncmp(buf, "commit -", 8) == 0)
+ color = "diff_meta";
+ if (strncmp(buf, "blob +", 6) == 0)
+ color = "diff_meta";
+ if (strncmp(buf, "blob -", 6) == 0)
+ color = "diff_meta";
+ if (strncmp(buf, "file +", 6) == 0)
+ color = "diff_meta";
+ if (strncmp(buf, "file -", 6) == 0)
+ color = "diff_meta";
+ if (strncmp(buf, "from:", 5) == 0)
+ color = "diff_author";
+ if (strncmp(buf, "via:", 4) == 0)
+ color = "diff_author";
+ if (strncmp(buf, "date:", 5) == 0)
+ color = "diff_date";
+
+ if ((asprintf(&div_diff_line_div, div_diff_line, color)) == -1)
+ return NULL;
+
+ error = buf_puts(&newsize, diffbuf, div_diff_line_div);
+ if (error)
+ return NULL;
+
+ error = buf_puts(&newsize, diffbuf, buf);
+ if (error)
+ return NULL;
+
+ if (buf_len(diffbuf) > 0) {
+ error = buf_putc(diffbuf, '\0');
+ colorized_line = strdup(buf_get(diffbuf));
+ }
+
+ free(diffbuf);
+ free(div_diff_line_div);
+ return colorized_line;
+}
+
+static char *
gw_html_escape(const char *html)
{
char *escaped_str = NULL, *buf;
break;
case ('\n'):
strcat(buf, "<br />");
- case ('|'):
- strcat(buf, " ");
default:
strcat(buf, &c[0]);
break;
if ((gw_trans->gw_tmpl = malloc(sizeof(struct ktemplate))) == NULL)
errx(1, "malloc");
- if (KCGI_OK != khttp_parse(gw_trans->gw_req, gw_keys, KEY__MAX,
+ if (KCGI_OK != khttp_parse(gw_trans->gw_req, gw_keys, KEY__ZMAX,
&page, 1, 0))
errx(1, "khttp_parse");
goto err;
}
- if (pledge("stdio rpath proc exec sendfd unveil", NULL) == -1) {
+ if (pledge("stdio rpath wpath cpath proc exec sendfd unveil",
+ NULL) == -1) {
error = got_error_from_errno("pledge");
goto err;
}
blob - cf1fa039bd3b89188cc6c8c9f097ab657bb026c6
blob + 6bda1b0aba9e8e0f019baa7d653ea0c84c9f3f7e
--- gotweb/gotweb_ui.h
+++ gotweb/gotweb_ui.h
"<div id='np_wrapper'>" \
"<div id='nav_prev'>";
+char *div_diff_line =
+ "<div id='diff_line' class='%s'>";
+
char *div_end =
"</div>";
"<div id='dotted_line'></div>";
char *logbriefs_navs =
- "<a href='?path=%s&action=commit&commit=%s'>commit</a> | " \
+ /* "<a href='?path=%s&action=commit&commit=%s'>commit</a> | " \ */
"<a href='?path=%s&action=commitdiff&commit=%s'>diff</a> | " \
"<a href='?path=%s&action=tree&commit=%s'>tree</a><!--/* | " \
"<a href='?path=%s&action=snapshot&commit=%s'>snapshot</a> */-->";
char *tags_navs =
"<a href='?path=%s&action=tag&commit=%s'>tag</a> | " \
- "<a href='?path=%s&action=commit&commit=%s'>commit</a> | " \
+ /* "<a href='?path=%s&action=commit&commit=%s'>commit</a> | " \ */
"<a href='?path=%s&action=logbriefs&commit=%s'>log briefs</a> | " \
"<a href='?path=%s&action=log&commit=%s'>log</a>";
char *trees_row =
"<div id='tree_wrapper'>" \
"<div id='tree_id'>%s</div>" \
- "<div id='tree'>%s%s</div>" \
+ "<div id='tree'>%s</div>" \
"</div>";
char *heads_row =
char *heads_navs =
"<a href='?path=%s&action=summary&headref=%s'>summary</a> | " \
"<a href='?path=%s&action=logbriefs&headref=%s'>log briefs</a> | " \
- "<a href='?path=%s&action=log&headref=%s'>log</a> | " \
- "<a href='?path=%s&action=commit&headref=%s'>commit</a>";
+ "<a href='?path=%s&action=log&headref=%s'>log</a> | ";
+ /* "<a href='?path=%s&action=commit&headref=%s'>commit</a>"; */
char *commit_diff_html =
"<div id='commit_diff_title'>Diff:</div>" \
"<div id='commit_log_title'>Tree:</div>" \
"<div id='commit_log'>%s</div>";
+char *folder_html =
+ "<a href='?path=%s&action=%s&commit=%s&folder=%s' " \
+ "class='diff_directory'>%s%s</a>";
+
+char *file_html =
+ "<a href='?path=%s&action=%s&commit=%s&file=%s&folder=%s'>%s%s</a>";
+
/* log.tmpl */
char *logs =
"<div id='solid_line'></div>";
char *logs_navs =
- "<a href='?path=%s&action=commit&commit=%s'>commit</a> | " \
+ /* "<a href='?path=%s&action=commit&commit=%s'>commit</a> | " \ */
"<a href='?path=%s&action=commitdiff&commit=%s'>diff</a> | " \
"<a href='?path=%s&action=tree&commit=%s'>tree</a><!--/* | " \
"<a href='?path=%s&action=snapshot&commit=%s'>snapshot</a> */-->";
"<div id='log_tag'>%s</div>" \
"</div>";
+/* blame.tmpl */
+
+char *log_blame =
+ "<div id='log_blame_title_wrapper'>" \
+ "<div id='log_blame_title'>blame</div></div>" \
+ "<div id='log_blame_content'>%s</div>";
+
+char *log_blame_row =
+ "<div id='log_blame_row_wrapper'>" \
+ "<div id='log_blame_commit'>%s</div>" \
+ "</div>" \
+ "<div id='dotted_line'></div>" \
+ "<div id='log_blame'>%s</div>" \
+ "</div>";
+
+char *log_blame_navs =
+ /* "<a href='?path=%s&action=commit&commit=%s'>commit</a> | " \ */
+ "<a href='?path=%s&action=commitdiff&commit=%s'>diff</a> | " \
+ "<a href='?path=%s&action=blame&commit=%s'>blame</a><!--/* | " \
+ "<a href='?path=%s&action=snapshot&commit=%s'>snapshot</a> */-->";
+
/* tree.tmpl */
char *log_tree =
"</div>";
char *log_tree_navs =
- "<a href='?path=%s&action=commit&commit=%s'>commit</a> | " \
+ /* "<a href='?path=%s&action=commit&commit=%s'>commit</a> | " \ */
"<a href='?path=%s&action=commitdiff&commit=%s'>diff</a> | " \
"<a href='?path=%s&action=tree&commit=%s'>tree</a><!--/* | " \
"<a href='?path=%s&action=snapshot&commit=%s'>snapshot</a> */-->";