commit - 5d58be1291225e7e6b5febddb818535c9907fd09
commit + 0d6c6ee302022b4b2746cd5a85df1f34f8891b9c
blob - 37523a3f4cb248caf256b0e5a47510f04058befc
blob + 170dd8d78a6e6113a9d9057dfc445245e87596bd
--- got/got.1
+++ got/got.1
.It $ Ta entry is a Git submodule
.El
.Pp
+Symbolic link entries are also annotated with the target path of the link.
+.Pp
If no
.Ar path
is specified, list the repository path corresponding to the current
blob - e8ed8348332436dcca1dd2effed1494c89d79ecd
blob + f14e875454e17d7c6012447918fec9a697f40c10
--- got/got.c
+++ got/got.c
exit(1);
}
-static void
+static const struct got_error *
print_entry(struct got_tree_entry *te, const char *id, const char *path,
- const char *root_path)
+ const char *root_path, struct got_repository *repo)
{
+ const struct got_error *err = NULL;
int is_root_path = (strcmp(path, root_path) == 0);
const char *modestr = "";
mode_t mode = got_tree_entry_get_mode(te);
+ char *link_target = NULL;
path += strlen(root_path);
while (path[0] == '/')
if (got_object_tree_entry_is_submodule(te))
modestr = "$";
- else if (S_ISLNK(mode))
+ else if (S_ISLNK(mode)) {
+ int i;
+
+ err = got_tree_entry_get_symlink_target(&link_target, te, repo);
+ if (err)
+ return err;
+ for (i = 0; i < strlen(link_target); i++) {
+ if (!isprint((unsigned char)link_target[i]))
+ link_target[i] = '?';
+ }
+
modestr = "@";
+ }
else if (S_ISDIR(mode))
modestr = "/";
else if (mode & S_IXUSR)
modestr = "*";
- printf("%s%s%s%s%s\n", id ? id : "", path,
- is_root_path ? "" : "/", got_tree_entry_get_name(te), modestr);
+ printf("%s%s%s%s%s%s%s\n", id ? id : "", path,
+ is_root_path ? "" : "/", got_tree_entry_get_name(te), modestr,
+ link_target ? " -> ": "", link_target ? link_target : "");
+
+ free(link_target);
+ return NULL;
}
static const struct got_error *
}
free(id_str);
}
- print_entry(te, id, path, root_path);
+ err = print_entry(te, id, path, root_path, repo);
free(id);
+ if (err)
+ goto done;
if (recurse && S_ISDIR(got_tree_entry_get_mode(te))) {
char *child_path;
blob - d17ff2d8455425992dbcd98fe8e0d53acfd2c208
blob + 50fe098796823909a7aa2c98d1b90d66536e434c
--- include/got_error.h
+++ include/got_error.h
#define GOT_ERR_NO_REMOTE 123
#define GOT_ERR_FETCH_NO_BRANCH 124
#define GOT_ERR_FETCH_BAD_REF 125
+#define GOT_ERR_TREE_ENTRY_TYPE 126
static const struct got_error {
int code;
{ GOT_ERR_NO_REMOTE, "remote repository not found" },
{ GOT_ERR_FETCH_NO_BRANCH, "could not find any branches to fetch" },
{ GOT_ERR_FETCH_BAD_REF, "reference cannot be fetched" },
+ { GOT_ERR_TREE_ENTRY_TYPE, "unexpected tree entry type" },
};
/*
blob - 461975117c98f1bb74df15d9317223d1940e4c6d
blob + 54c7093a4d0bc68cfd3ef1939b7c80f71106e777
--- include/got_object.h
+++ include/got_object.h
/* Get the object ID of a tree entry. */
struct got_object_id *got_tree_entry_get_id(struct got_tree_entry *);
+/*
+ * Get a string containing the target path of a given a symlink tree entry.
+ * The caller should dispose of it with free(3).
+ */
+const struct got_error *got_tree_entry_get_symlink_target(char **,
+ struct got_tree_entry *, struct got_repository *);
+
/* Get the index of a tree entry. */
int got_tree_entry_get_index(struct got_tree_entry *);
blob - 60884259fffeeadac52f16b3ef8d210656e4c539
blob + 9a3beff5204483df08335c4ff3dfe9f49015cf50
--- lib/object.c
+++ lib/object.c
return &te->id;
}
+const struct got_error *
+got_tree_entry_get_symlink_target(char **link_target, struct got_tree_entry *te,
+ struct got_repository *repo)
+{
+ const struct got_error *err = NULL;
+ struct got_blob_object *blob = NULL;
+ size_t len;
+
+ *link_target = NULL;
+
+ /* S_IFDIR check avoids confusing symlinks with submodules. */
+ if ((te->mode & (S_IFDIR | S_IFLNK)) != S_IFLNK)
+ return got_error(GOT_ERR_TREE_ENTRY_TYPE);
+
+ err = got_object_open_as_blob(&blob, repo,
+ got_tree_entry_get_id(te), PATH_MAX);
+ if (err)
+ return err;
+
+ err = got_object_blob_read_block(&len, blob);
+ if (err)
+ goto done;
+
+ *link_target = malloc(len + 1);
+ if (*link_target == NULL) {
+ err = got_error_from_errno("malloc");
+ goto done;
+ }
+ memcpy(*link_target, got_object_blob_get_read_buf(blob), len);
+ (*link_target)[len] = '\0';
+done:
+ if (blob)
+ got_object_blob_close(blob);
+ return err;
+}
+
int
got_tree_entry_get_index(struct got_tree_entry *te)
{
blob - 1b3bc07688dabd1f64ab5796add19f17d307dfc1
blob + 93119866bfc2b30573ae6680ae8c5a0ea8bd5e5b
--- tog/tog.1
+++ tog/tog.1
.It $ Ta entry is a Git submodule
.El
.Pp
+Symbolic link entries are also annotated with the target path of the link.
+.Pp
The key bindings for
.Cm tog tree
are as follows:
blob - de21c04b04cf92a585fa3fd019dce29f5c235ff7
blob + 37110e98ad018c151bf660c62fd637570da2df3a
--- tog/tog.c
+++ tog/tog.c
#include <sys/stat.h>
#include <sys/ioctl.h>
+#include <ctype.h>
#include <errno.h>
#define _XOPEN_SOURCE_EXTENDED
#include <curses.h>
struct got_tree_entry **selected_entry, int *ndisplayed,
const char *label, int show_ids, const char *parent_path,
struct got_tree_object *tree, int selected, int limit,
- int isroot, struct tog_colors *colors)
+ int isroot, struct tog_colors *colors, struct got_repository *repo)
{
const struct got_error *err = NULL;
struct got_tree_entry *te;
nentries = got_object_tree_get_nentries(tree);
for (i = got_tree_entry_get_index(te); i < nentries; i++) {
- char *line = NULL, *id_str = NULL;
+ char *line = NULL, *id_str = NULL, *link_target = NULL;
const char *modestr = "";
mode_t mode;
}
if (got_object_tree_entry_is_submodule(te))
modestr = "$";
- else if (S_ISLNK(mode))
+ else if (S_ISLNK(mode)) {
+ int i;
+
+ err = got_tree_entry_get_symlink_target(&link_target,
+ te, repo);
+ if (err) {
+ free(id_str);
+ return err;
+ }
+ for (i = 0; i < strlen(link_target); i++) {
+ if (!isprint((unsigned char)link_target[i]))
+ link_target[i] = '?';
+ }
modestr = "@";
+ }
else if (S_ISDIR(mode))
modestr = "/";
else if (mode & S_IXUSR)
modestr = "*";
- if (asprintf(&line, "%s %s%s", id_str ? id_str : "",
- got_tree_entry_get_name(te), modestr) == -1) {
+ if (asprintf(&line, "%s %s%s%s%s", id_str ? id_str : "",
+ got_tree_entry_get_name(te), modestr,
+ link_target ? " -> ": "",
+ link_target ? link_target : "") == -1) {
free(id_str);
+ free(link_target);
return got_error_from_errno("asprintf");
}
free(id_str);
+ free(link_target);
err = format_line(&wline, &width, line, view->ncols, 0);
if (err) {
free(line);
&s->last_displayed_entry, &s->selected_entry,
&s->ndisplayed, s->tree_label, s->show_ids, parent_path,
s->tree, s->selected, view->nlines, s->tree == s->root,
- &s->colors);
+ &s->colors, s->repo);
free(parent_path);
view_vborder(view);