commit - 3f17dee4f66ddd410b6ab5a184e3a8c3608d3892
commit + 72ea6654e747de4879e06bd45e50ea7d9f5b7ed6
blob - cb00a11ad2f7c41e4c84673e981173ed0592308e
blob + d3e564d4699851132f9a64ad9d11d4e5f5bc7643
--- got/got.1
+++ got/got.1
.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
.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
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)
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;
}
__dead static void
usage_status(void)
{
- fprintf(stderr, "usage: %s status [path]\n", getprogname());
+ fprintf(stderr, "usage: %s status [path ...]\n", getprogname());
exit(1);
}
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:
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();
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
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
* 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
*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
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;
}
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
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
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