commit 72ea6654e747de4879e06bd45e50ea7d9f5b7ed6 from: Stefan Sperling date: Sat Jul 27 09:21:56 2019 UTC add support for multiple path arguments to 'got status' commit - 3f17dee4f66ddd410b6ab5a184e3a8c3608d3892 commit + 72ea6654e747de4879e06bd45e50ea7d9f5b7ed6 blob - cb00a11ad2f7c41e4c84673e981173ed0592308e blob + d3e564d4699851132f9a64ad9d11d4e5f5bc7643 --- got/got.1 +++ got/got.1 @@ -212,7 +212,7 @@ branch will be used. .It Cm up Short alias for .Cm update . -.It Cm status [ Ar path ] +.It Cm status [ Ar path ... ] Show the current modification status of files in a work tree, using the following status codes: .Bl -column YXZ description @@ -226,9 +226,10 @@ using the following status codes: .Nm .El .Pp -If a +If no .Ar path -is specified, only show modifications within this path. +is specified, show modifications in the entire work tree. +Otherwise, show modifications at or within the specified paths. .It Cm st Short alias for .Cm status . blob - 3e915e8dfa84371b3c80fdb1394bf157c98299e7 blob + 90f2c5558432c2c95b5ee07a924b9fb1bacb2c90 --- got/got.c +++ got/got.c @@ -1802,7 +1802,11 @@ cmd_diff(int argc, char *argv[]) if (argc <= 1) { struct print_diff_arg arg; + struct got_pathlist_head paths; char *id_str; + + TAILQ_INIT(&paths); + error = got_object_id_str(&id_str, got_worktree_get_base_commit_id(worktree)); if (error) @@ -1813,9 +1817,14 @@ cmd_diff(int argc, char *argv[]) arg.id_str = id_str; arg.header_shown = 0; - error = got_worktree_status(worktree, path, repo, print_diff, + error = got_pathlist_append(NULL, &paths, path, NULL); + if (error) + goto done; + + error = got_worktree_status(worktree, &paths, repo, print_diff, &arg, check_cancelled, NULL); free(id_str); + got_pathlist_free(&paths); goto done; } @@ -2291,7 +2300,7 @@ done: __dead static void usage_status(void) { - fprintf(stderr, "usage: %s status [path]\n", getprogname()); + fprintf(stderr, "usage: %s status [path ...]\n", getprogname()); exit(1); } @@ -2310,8 +2319,11 @@ cmd_status(int argc, char *argv[]) struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *path = NULL; - int ch; + struct got_pathlist_head paths; + int ch, i; + TAILQ_INIT(&paths); + while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { default: @@ -2339,15 +2351,21 @@ cmd_status(int argc, char *argv[]) goto done; if (argc == 0) { - path = strdup(""); - if (path == NULL) { - error = got_error_from_errno("strdup"); - goto done; - } - } else if (argc == 1) { - error = got_worktree_resolve_path(&path, worktree, argv[0]); + error = got_pathlist_append(NULL, &paths, "", NULL); if (error) goto done; + } else if (argc >= 1) { + for (i = 0; i < argc; i++) { + error = got_worktree_resolve_path(&path, worktree, + argv[i]); + if (error) + goto done; + error = got_pathlist_append(NULL, &paths, path, NULL); + if (error) { + free(path); + goto done; + } + } } else usage_status(); @@ -2360,9 +2378,10 @@ cmd_status(int argc, char *argv[]) if (error) goto done; - error = got_worktree_status(worktree, path, repo, print_status, NULL, + error = got_worktree_status(worktree, &paths, repo, print_status, NULL, check_cancelled, NULL); done: + got_pathlist_free(&paths); free(cwd); free(path); return error; blob - 588e227a26ee5dff0066f6f1dd4dbf7581b3f5ec blob + c5070b49c1c0ade4b575d6fa753b6b239b460635 --- include/got_path.h +++ include/got_path.h @@ -78,6 +78,17 @@ TAILQ_HEAD(got_pathlist_head, got_pathlist_entry); const struct got_error *got_pathlist_insert(struct got_pathlist_entry **, struct got_pathlist_head *, const char *, void *); +/* + * Append a path to the list of paths. + * The caller should already have initialized the list head. This list stores + * the pointer to the path as-is, i.e. the path is not copied internally and + * must remain available until the list is freed with got_pathlist_free(). + * If the first argument is not NULL, set it to a pointer to the newly inserted + * element, or to a NULL pointer in case the path was already on the list. + */ +const struct got_error *got_pathlist_append(struct got_pathlist_entry **, + struct got_pathlist_head *, const char *, void *); + /* Free resources allocated for a path list. */ void got_pathlist_free(struct got_pathlist_head *); blob - e9f5a6c90d4b5185ce58d45c93a4c57a850306a3 blob + e98f4eefa2ca47670e414b5ece91a68d435e66d0 --- include/got_worktree.h +++ include/got_worktree.h @@ -148,8 +148,8 @@ typedef const struct got_error *(*got_worktree_status_ * a path, and a corresponding status code. */ const struct got_error *got_worktree_status(struct got_worktree *, - const char *, struct got_repository *, got_worktree_status_cb, void *, - got_worktree_cancel_cb cancel_cb, void *); + struct got_pathlist_head *, struct got_repository *, + got_worktree_status_cb, void *, got_worktree_cancel_cb cancel_cb, void *); /* * Try to resolve a user-provided path to an on-disk path in the work tree. blob - 8d2ef334e7a05632a8884779d1d12b8dbf60bdc0 blob + f3e258fea9747229b54c77f3ec2be3c804b0f38c --- lib/path.c +++ lib/path.c @@ -252,7 +252,24 @@ got_pathlist_insert(struct got_pathlist_entry **insert *inserted = new; return NULL; } + +const struct got_error * +got_pathlist_append(struct got_pathlist_entry **pe, + struct got_pathlist_head *pathlist, const char *path, void *data) +{ + struct got_pathlist_entry *new; + new = malloc(sizeof(*new)); + if (new == NULL) + return got_error_from_errno("malloc"); + new->path = path; + new->data = data; + TAILQ_INSERT_TAIL(pathlist, new, entry); + if (pe) + *pe = new; + return NULL; +} + void got_pathlist_free(struct got_pathlist_head *pathlist) { blob - c15d384d2c146fcd939be25190f8eb596b845ca2 blob + 4101d79ebd4fde3380f09ac29feed253aa25c1ec --- lib/worktree.c +++ lib/worktree.c @@ -2265,10 +2265,14 @@ worktree_status(struct got_worktree *worktree, const c if (errno == ENOTDIR || errno == ENOENT) { struct got_fileindex_entry *ie; ie = got_fileindex_entry_get(fileindex, path); - if (ie == NULL) { - err = got_error(GOT_ERR_BAD_PATH); + if (ie == NULL) + err = (*status_cb)(status_arg, + GOT_STATUS_UNVERSIONED, path, NULL, NULL); + else + err = report_file_status(ie, ondisk_path, + status_cb, status_arg, repo); + if (err) goto done; - } err = report_file_status(ie, ondisk_path, status_cb, status_arg, repo); goto done; @@ -2299,20 +2303,26 @@ done: } const struct got_error * -got_worktree_status(struct got_worktree *worktree, const char *path, - struct got_repository *repo, got_worktree_status_cb status_cb, - void *status_arg, got_worktree_cancel_cb cancel_cb, void *cancel_arg) +got_worktree_status(struct got_worktree *worktree, + struct got_pathlist_head *paths, struct got_repository *repo, + got_worktree_status_cb status_cb, void *status_arg, + got_worktree_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; char *fileindex_path = NULL; struct got_fileindex *fileindex = NULL; + struct got_pathlist_entry *pe; err = open_fileindex(&fileindex, &fileindex_path, worktree); if (err) return err; - err = worktree_status(worktree, path, fileindex, repo, - status_cb, status_arg, cancel_cb, cancel_arg); + TAILQ_FOREACH(pe, paths, entry) { + err = worktree_status(worktree, pe->path, fileindex, repo, + status_cb, status_arg, cancel_cb, cancel_arg); + if (err) + break; + } free(fileindex_path); got_fileindex_free(fileindex); return err; blob - caf49bac02e4804db8079107c17f7b157837f688 blob + b77e1d3aed4da758cdd72648e410e4a105ebac25 --- regress/cmdline/status.sh +++ regress/cmdline/status.sh @@ -441,7 +441,45 @@ function test_status_empty_dir_unversioned_file { fi test_done "$testroot" "$ret" } + +function test_status_many_paths { + local testroot=`test_init status_many_paths` + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + echo "modified alpha" > $testroot/wt/alpha + (cd $testroot/wt && got rm beta >/dev/null) + echo "unversioned file" > $testroot/wt/foo + rm $testroot/wt/epsilon/zeta + touch $testroot/wt/beta + echo "new file" > $testroot/wt/new + mkdir $testroot/wt/newdir + (cd $testroot/wt && got add new >/dev/null) + + (cd $testroot/wt && got status newdir > $testroot/stdout.expected) + (cd $testroot/wt && got status alpha >> $testroot/stdout.expected) + (cd $testroot/wt && got status epsilon >> $testroot/stdout.expected) + (cd $testroot/wt && got status foo >> $testroot/stdout.expected) + (cd $testroot/wt && got status new >> $testroot/stdout.expected) + (cd $testroot/wt && got status beta >> $testroot/stdout.expected) + (cd $testroot/wt && got status . >> $testroot/stdout.expected) + + (cd $testroot/wt && got status newdir alpha epsilon foo new beta . \ + > $testroot/stdout) + + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi + test_done "$testroot" "$ret" +} + run_test test_status_basic run_test test_status_subdir_no_mods run_test test_status_subdir_no_mods2 @@ -453,3 +491,4 @@ run_test test_status_shows_no_mods_after_complete_merg run_test test_status_shows_conflict run_test test_status_empty_dir run_test test_status_empty_dir_unversioned_file +run_test test_status_many_paths