implement recursive mode for 'got tree'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
diff --git a/got/got.1 b/got/got.1
index b85c7d4..5e8952c 100644
--- a/got/got.1
+++ b/got/got.1
@@ -176,7 +176,7 @@ Use the repository at the specified path.
If not specified, assume the repository is located at or above the current
working directory.
.El
-.It Cm tree [ Fl c Ar commit ] [ Fl r Ar repository-path ] [ Fl i ] [ Ar path ]
+.It Cm tree [ Fl c Ar commit ] [ Fl r Ar repository-path ] [ Fl i ] [ Fl R] [ Ar path ]
Display a listing of files and directories at the specified
directory path in the repository.
If no path is specified, the root directory is listed.
@@ -196,6 +196,8 @@ If not specified, assume the repository is located at or above the current
working directory.
.It Fl i
Show object IDs of files (blob objects) and directories (tree objects).
+.It Fl R
+Recurse into sub-directories.
.El
.Sh EXIT STATUS
.Ex -std got
diff --git a/got/got.c b/got/got.c
index bb5861b..9344bf9 100644
--- a/got/got.c
+++ b/got/got.c
@@ -1065,15 +1065,31 @@ done:
__dead static void
usage_tree(void)
{
- fprintf(stderr, "usage: %s tree [-c commit] [-r repository-path] [-i] path\n",
+ fprintf(stderr,
+ "usage: %s tree [-c commit] [-r repository-path] [-iR] path\n",
getprogname());
exit(1);
}
+static void
+print_entry(struct got_tree_entry *te, const char *id, const char *path,
+ const char *root_path)
+{
+ int is_root_path = (strcmp(path, root_path) == 0);
+
+ path += strlen(root_path);
+ while (path[0] == '/')
+ path++;
+
+ printf("%s%s%s%s%s\n", id ? id : "", path,
+ is_root_path ? "" : "/",
+ te->name, S_ISDIR(te->mode) ? "/" : "");
+}
static const struct got_error *
print_tree(const char *path, struct got_object_id *commit_id,
- int show_ids, struct got_repository *repo)
+ int show_ids, int recurse, const char *root_path,
+ struct got_repository *repo)
{
const struct got_error *err = NULL;
struct got_object_id *tree_id = NULL;
@@ -1108,10 +1124,25 @@ print_tree(const char *path, struct got_object_id *commit_id,
}
free(id_str);
}
- printf("%s%s%s\n", id ? id : "",
- te->name, S_ISDIR(te->mode) ? "/" : "");
- te = SIMPLEQ_NEXT(te, entry);
+ print_entry(te, id, path, root_path);
free(id);
+
+ if (recurse && S_ISDIR(te->mode)) {
+ char *child_path;
+ if (asprintf(&child_path, "%s%s%s", path,
+ path[0] == '/' && path[1] == '\0' ? "" : "/",
+ te->name) == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ err = print_tree(child_path, commit_id, show_ids, 1,
+ root_path, repo);
+ free(child_path);
+ if (err)
+ goto done;
+ }
+
+ te = SIMPLEQ_NEXT(te, entry);
}
done:
if (tree)
@@ -1128,7 +1159,7 @@ cmd_tree(int argc, char *argv[])
char *path, *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL;
struct got_object_id *commit_id = NULL;
char *commit_id_str = NULL;
- int show_ids = 0;
+ int show_ids = 0, recurse = 0;
int ch;
#ifndef PROFILE
@@ -1137,7 +1168,7 @@ cmd_tree(int argc, char *argv[])
err(1, "pledge");
#endif
- while ((ch = getopt(argc, argv, "c:r:i")) != -1) {
+ while ((ch = getopt(argc, argv, "c:r:iR")) != -1) {
switch (ch) {
case 'c':
commit_id_str = optarg;
@@ -1150,6 +1181,9 @@ cmd_tree(int argc, char *argv[])
case 'i':
show_ids = 1;
break;
+ case 'R':
+ recurse = 1;
+ break;
default:
usage();
/* NOTREACHED */
@@ -1207,7 +1241,8 @@ cmd_tree(int argc, char *argv[])
goto done;
}
- error = print_tree(in_repo_path, commit_id, show_ids, repo);
+ error = print_tree(in_repo_path, commit_id, show_ids, recurse,
+ in_repo_path, repo);
done:
free(in_repo_path);
free(repo_path);