commit c1669e2e5fb4f6007afe46318e82a4e0de689390 from: Stefan Sperling date: Wed Jan 09 18:20:52 2019 UTC implement recursive mode for 'got tree' commit - 80bd227c8266b1bdccfbaca37c2d9366e6e9ef67 commit + c1669e2e5fb4f6007afe46318e82a4e0de689390 blob - b85c7d4acf1dfb346061b17df8a3b3ba58d863cc blob + 5e8952c6e1329f6cee0405f65332a159c2395f7b --- got/got.1 +++ 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 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 blob - bb5861b87334a06680c1f45a5291002db4e8204f blob + 9344bf93767b2a5453c8f923e3ee059ef601e562 --- got/got.c +++ 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 *com } 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);