commit - 054041d073d5af5bb32b7c3299af9cf2bf85c426
commit + 3143d852d788e42c45a61252acb935a698efed2f
blob - f2f5a3cbeb857a547e2c1bb1e3c13aba9479efa2
blob + 656685591bdfde81e5346507229c0bd87d2fa18c
--- lib/fileindex.c
+++ lib/fileindex.c
struct dirent *de = NULL;
size_t path_len = strlen(path);
struct got_pathlist_entry *dle;
+
+ if (cb->diff_traverse) {
+ err = cb->diff_traverse(cb_arg, path, dirfd);
+ if (err)
+ return err;
+ }
dle = TAILQ_FIRST(dirlist);
while ((*ie && got_path_is_child((*ie)->path, path, path_len)) || dle) {
blob - 88f07eccfa3c94fd5c1e4b81985cf5b7558c9ef2
blob + aff771b0551ee8d209acba24e8ce1cfe8383392d
--- lib/got_lib_fileindex.h
+++ lib/got_lib_fileindex.h
struct got_fileindex_entry *, const char *);
typedef const struct got_error *(*got_fileindex_diff_dir_new_cb)(void *,
struct dirent *, const char *, int);
+typedef const struct got_error *(*got_fileindex_diff_dir_traverse)(void *,
+ const char *, int);
struct got_fileindex_diff_dir_cb {
got_fileindex_diff_dir_old_new_cb diff_old_new;
got_fileindex_diff_dir_old_cb diff_old;
got_fileindex_diff_dir_new_cb diff_new;
+ got_fileindex_diff_dir_traverse diff_traverse;
};
const struct got_error *got_fileindex_diff_dir(struct got_fileindex *, int,
const char *, const char *, struct got_repository *,
blob - a0cbc48d4e120a8765536e6bee2ab03cd00d4adc
blob + 82a6b4b7b9e073c4d26c6e63e14032229c1784e1
--- lib/worktree.c
+++ lib/worktree.c
/* A pathlist containing per-directory pathlists of ignore patterns. */
struct got_pathlist_head ignores;
int report_unchanged;
+ int no_ignores;
};
static const struct got_error *
path = de->d_name;
}
- if (de->d_type == DT_DIR) {
- int subdirfd = openat(dirfd, de->d_name,
- O_RDONLY | O_NOFOLLOW | O_DIRECTORY);
- if (subdirfd == -1) {
- if (errno != ENOENT && errno != EACCES)
- err = got_error_from_errno2("openat", path);
- } else {
- err = add_ignores(&a->ignores, a->worktree->root_path,
- path, subdirfd, ".cvsignore");
- if (err == NULL)
- err = add_ignores(&a->ignores,
- a->worktree->root_path, path,
- subdirfd, ".gitignore");
- if (close(subdirfd) == -1 && err == NULL)
- err = got_error_from_errno2("close", path);
- }
- } else if (got_path_is_child(path, a->status_path, a->status_path_len)
+ if (de->d_type != DT_DIR &&
+ got_path_is_child(path, a->status_path, a->status_path_len)
&& !match_ignores(&a->ignores, path))
err = (*a->status_cb)(a->status_arg, GOT_STATUS_UNVERSIONED,
GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL);
}
static const struct got_error *
+status_traverse(void *arg, const char *path, int dirfd)
+{
+ const struct got_error *err = NULL;
+ struct diff_dir_cb_arg *a = arg;
+
+ if (a->no_ignores)
+ return NULL;
+
+ err = add_ignores(&a->ignores, a->worktree->root_path,
+ path, dirfd, ".cvsignore");
+ if (err)
+ return err;
+
+ err = add_ignores(&a->ignores, a->worktree->root_path, path,
+ dirfd, ".gitignore");
+
+ return err;
+}
+
+static const struct got_error *
report_single_file_status(const char *path, const char *ondisk_path,
struct got_fileindex *fileindex, got_worktree_status_cb status_cb,
void *status_arg, struct got_repository *repo, int report_unchanged)
GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL, -1, NULL);
return NULL;
+}
+
+static const struct got_error *
+add_ignores_from_parent_paths(struct got_pathlist_head *ignores,
+ const char *root_path, const char *path)
+{
+ const struct got_error *err;
+ char *parent_path, *next_parent_path;
+
+ err = add_ignores(ignores, root_path, "", -1,
+ ".cvsignore");
+ if (err)
+ return err;
+
+ err = add_ignores(ignores, root_path, "", -1,
+ ".gitignore");
+ if (err)
+ return err;
+
+ err = got_path_dirname(&parent_path, path);
+ if (err) {
+ if (err->code == GOT_ERR_BAD_PATH)
+ return NULL; /* cannot traverse parent */
+ return err;
+ }
+ for (;;) {
+ err = add_ignores(ignores, root_path, parent_path, -1,
+ ".cvsignore");
+ if (err)
+ break;
+ err = add_ignores(ignores, root_path, parent_path, -1,
+ ".gitignore");
+ if (err)
+ break;
+ err = got_path_dirname(&next_parent_path, parent_path);
+ if (err) {
+ if (err->code != GOT_ERR_BAD_PATH)
+ return err;
+ err = NULL; /* traversed everything */
+ break;
+ }
+ }
+
+ return err;
}
static const struct got_error *
struct got_fileindex_diff_dir_cb fdiff_cb;
struct diff_dir_cb_arg arg;
char *ondisk_path = NULL;
+
+ TAILQ_INIT(&arg.ignores);
if (asprintf(&ondisk_path, "%s%s%s",
worktree->root_path, path[0] ? "/" : "", path) == -1)
fdiff_cb.diff_old_new = status_old_new;
fdiff_cb.diff_old = status_old;
fdiff_cb.diff_new = status_new;
+ fdiff_cb.diff_traverse = status_traverse;
arg.fileindex = fileindex;
arg.worktree = worktree;
arg.status_path = path;
arg.cancel_cb = cancel_cb;
arg.cancel_arg = cancel_arg;
arg.report_unchanged = report_unchanged;
- TAILQ_INIT(&arg.ignores);
+ arg.no_ignores = no_ignores;
if (!no_ignores) {
- err = add_ignores(&arg.ignores, worktree->root_path,
- path, fd, ".cvsignore");
- if (err == NULL)
- err = add_ignores(&arg.ignores,
- worktree->root_path, path, fd,
- ".gitignore");
+ err = add_ignores_from_parent_paths(&arg.ignores,
+ worktree->root_path, path);
+ if (err)
+ goto done;
}
- if (err == NULL)
- err = got_fileindex_diff_dir(fileindex, fd,
- worktree->root_path, path, repo, &fdiff_cb, &arg);
- free_ignores(&arg.ignores);
+ err = got_fileindex_diff_dir(fileindex, fd,
+ worktree->root_path, path, repo, &fdiff_cb, &arg);
}
-
+done:
+ free_ignores(&arg.ignores);
if (fd != -1 && close(fd) != 0 && err == NULL)
err = got_error_from_errno("close");
free(ondisk_path);
blob - 5abbce9475bb8bd2f1cbb3e33113883173026f03
blob + bf27874f97a3459375523f37a2f63d9a83168936
--- regress/cmdline/status.sh
+++ regress/cmdline/status.sh
echo "unversioned file" > $testroot/wt/foo
echo "unversioned file" > $testroot/wt/foop
+ echo "unversioned file" > $testroot/wt/epsilon/foo
echo "unversioned file" > $testroot/wt/epsilon/bar
echo "unversioned file" > $testroot/wt/epsilon/boo
echo "unversioned file" > $testroot/wt/epsilon/moo
- echo "foo" > $testroot/wt/.cvsignore
+ mkdir -p $testroot/wt/epsilon/new/
+ echo "unversioned file" > $testroot/wt/epsilon/new/foo
+ echo "**/foo" > $testroot/wt/.cvsignore
echo "bar" > $testroot/wt/epsilon/.cvsignore
echo "moo" >> $testroot/wt/epsilon/.cvsignore
echo '? epsilon/boo' >> $testroot/stdout.expected
echo '? foop' >> $testroot/stdout.expected
(cd $testroot/wt && got status > $testroot/stdout)
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo '? epsilon/.cvsignore' > $testroot/stdout.expected
+ echo '? epsilon/boo' >> $testroot/stdout.expected
+ (cd $testroot/wt && got status epsilon > $testroot/stdout)
cmp -s $testroot/stdout.expected $testroot/stdout
ret="$?"
test_done "$testroot" "$ret"
return 1
fi
+
+ echo -n '' > $testroot/stdout.expected
+ (cd $testroot/wt && got status epsilon/new > $testroot/stdout)
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
echo '? .cvsignore' > $testroot/stdout.expected
echo '? epsilon/.cvsignore' >> $testroot/stdout.expected
echo '? epsilon/boo' >> $testroot/stdout.expected