Commit bcbc97d8dd5a7e35291a7be58ebe9700a328c976

Tracey Emery 2020-01-15T22:10:30

start tree

diff --git a/gotweb/files/htdocs/gotweb/gotweb.css b/gotweb/files/htdocs/gotweb/gotweb.css
index ae00ec1..2355d9a 100644
--- a/gotweb/files/htdocs/gotweb/gotweb.css
+++ b/gotweb/files/htdocs/gotweb/gotweb.css
@@ -559,6 +559,19 @@ body {
 	padding: 20px;
 	font-family: monospace;
 }
+#tree_wrapper {
+	clear: left;
+	float: left;
+	width: 100%;
+}
+#tree_id {
+	float: left;
+	padding: 2px;
+}
+#tree {
+	float:left ;
+	padding: 2px;
+}
 
 /* commit.tmpl */
 
diff --git a/gotweb/gotweb.c b/gotweb/gotweb.c
index cf39095..3cc5a9a 100644
--- a/gotweb/gotweb.c
+++ b/gotweb/gotweb.c
@@ -162,6 +162,7 @@ static char			*gw_get_repo_age(struct trans *,
 				    char *, char *, int);
 static char			*gw_get_repo_log(struct trans *, const char *,
 				    char *, int, int);
+static char			*gw_get_repo_tree(struct trans *, 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 *);
@@ -180,6 +181,8 @@ static const struct got_error*	 apply_unveil(const char *, const char *);
 static const struct got_error*	 cmp_tags(void *, int *,
 				    struct got_reference *,
 				    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*	 gw_load_got_paths(struct trans *);
 static const struct got_error*	 gw_load_got_path(struct trans *,
 				    struct gw_dir *);
@@ -320,6 +323,39 @@ done:
 	return err;
 }
 
+static const struct got_error *
+resolve_commit_arg(struct got_object_id **commit_id,
+    const char *commit_id_arg, struct got_repository *repo)
+{
+	const struct got_error *err;
+	struct got_reference *ref;
+	struct got_tag_object *tag;
+
+	err = got_repo_object_match_tag(&tag, commit_id_arg,
+	    GOT_OBJ_TYPE_COMMIT, repo);
+	if (err == NULL) {
+		*commit_id = got_object_id_dup(
+		    got_object_tag_get_object_id(tag));
+		if (*commit_id == NULL)
+			err = got_error_from_errno("got_object_id_dup");
+		got_object_tag_close(tag);
+		return err;
+	} else if (err->code != GOT_ERR_NO_OBJ)
+		return err;
+
+	err = got_ref_open(&ref, repo, commit_id_arg, 0);
+	if (err == NULL) {
+		err = got_ref_resolve(commit_id, repo, ref);
+		got_ref_close(ref);
+	} else {
+		if (err->code != GOT_ERR_NOT_REF)
+			return err;
+		err = got_repo_match_object_id_prefix(commit_id,
+		    commit_id_arg, GOT_OBJ_TYPE_COMMIT, repo);
+	}
+	return err;
+}
+
 int
 gw_get_repo_log_count(struct trans *gw_trans, char *start_commit)
 {
@@ -1817,7 +1853,8 @@ gw_get_repo_log(struct trans *gw_trans, const char *search_pattern,
 			free(log_tag_html);
 			break;
 		case (LOGTREE):
-			log_tree_html = strdup("log tree here");
+			log_tree_html = gw_get_repo_tree(gw_trans,
+			    start_commit);
 
 			if ((asprintf(&commit_row, log_tree_row,
 			    gw_html_escape(commit_log), log_tree_html)) == -1) {
@@ -2060,6 +2097,106 @@ done:
 		return tags;
 }
 
+static char*
+gw_get_repo_tree(struct trans *gw_trans, char *start_commit)
+{
+	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)
+		return NULL;
+
+	error = got_repo_open(&repo, gw_trans->repo_path, NULL);
+	if (error != NULL)
+		goto done;
+
+	error = got_repo_map_path(&in_repo_path, repo, gw_trans->repo_path, 1);
+	if (error != NULL)
+		goto done;
+
+	if (in_repo_path) {
+		free(path);
+		path = in_repo_path;
+	}
+
+	error = resolve_commit_arg(&commit_id, start_commit, repo);
+	if (error)
+		goto done;
+
+	error = got_object_id_by_path(&tree_id, repo, commit_id, in_repo_path);
+	if (error)
+		goto done;
+
+	error = got_object_open_as_tree(&tree, repo, tree_id);
+	if (error)
+		goto done;
+
+	nentries = got_object_tree_get_nentries(tree);
+
+	for (i = 0; i < nentries; i++) {
+		struct got_tree_entry *te;
+		char *id = NULL;
+
+		te = got_object_tree_get_entry(tree, i);
+
+		error = got_object_id_str(&id_str, got_tree_entry_get_id(te));
+		if (error)
+			goto done;
+
+		if (asprintf(&id, "%s", id_str) == -1) {
+			error = got_error_from_errno("asprintf");
+			free(id_str);
+			goto done;
+		}
+
+		mode_t mode = got_tree_entry_get_mode(te);
+
+		if (got_object_tree_entry_is_submodule(te))
+			modestr = "$";
+		else if (S_ISLNK(mode))
+			modestr = "@";
+		else if (S_ISDIR(mode))
+			modestr = "/";
+		else if (mode & S_IXUSR)
+			modestr = "*";
+
+		if ((asprintf(&tree_row, trees_row, id_str,
+		    got_tree_entry_get_name(te), modestr)) == -1) {
+			error = got_error_from_errno("asprintf");
+			goto done;
+		}
+		error = buf_puts(&newsize, diffbuf, tree_row);
+		free(id);
+		free(id_str);
+
+	}
+
+	if (buf_len(diffbuf) > 0) {
+		error = buf_putc(diffbuf, '\0');
+		tree_html = strdup(buf_get(diffbuf));
+	}
+done:
+	if (tree)
+		got_object_tree_close(tree);
+
+	free(tree_id);
+	free(diffbuf);
+	if (error)
+		return NULL;
+	else
+		return tree_html;
+
+}
+
 static char *
 gw_get_repo_heads(struct trans *gw_trans)
 {
diff --git a/gotweb/gotweb_ui.h b/gotweb/gotweb_ui.h
index a709ec3..cf1fa03 100644
--- a/gotweb/gotweb_ui.h
+++ b/gotweb/gotweb_ui.h
@@ -125,6 +125,12 @@ char *tags_navs =
 	"<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>";
+
 char *heads_row =
 	"<div id='heads_wrapper'>" \
 	"<div id='heads_age'>%s</div>" \