commit - 122e16119c68804932abae9efbce7cad48a85a24
commit + 46e6bdd46c729dfc7e89384a8df8f9153ada0557
blob - d89b541d0dedd769040cf62df12ad6582091b1d0
blob + 4f71ec07169550c3193e28bb9ff1ffb746d4f3e1
--- lib/patch.c
+++ lib/patch.c
}
}
return NULL;
+}
+
+static const struct got_error *
+schedule_add(const char *path, struct got_worktree *worktree,
+ struct got_repository *repo, got_worktree_checkout_cb add_cb,
+ void *add_arg)
+{
+ static const struct got_error *err = NULL;
+ struct got_pathlist_head paths;
+ struct got_pathlist_entry *pe;
+
+ TAILQ_INIT(&paths);
+
+ err = got_pathlist_insert(&pe, &paths, path, NULL);
+ if (err == NULL)
+ err = got_worktree_schedule_add(worktree, &paths,
+ add_cb, add_arg, repo, 1);
+ got_pathlist_free(&paths);
+ return err;
+}
+
+static const struct got_error *
+schedule_del(const char *path, struct got_worktree *worktree,
+ struct got_repository *repo, got_worktree_delete_cb delete_cb,
+ void *delete_arg)
+{
+ static const struct got_error *err = NULL;
+ struct got_pathlist_head paths;
+ struct got_pathlist_entry *pe;
+
+ TAILQ_INIT(&paths);
+
+ err = got_pathlist_insert(&pe, &paths, path, NULL);
+ if (err == NULL)
+ err = got_worktree_schedule_delete(worktree, &paths,
+ 0, NULL, delete_cb, delete_arg, repo, 0, 0);
+ got_pathlist_free(&paths);
+ return err;
}
static const struct got_error *
h = STAILQ_FIRST(&p->head);
if (h == NULL || STAILQ_NEXT(h, entries) != NULL)
return got_error(GOT_ERR_PATCH_MALFORMED);
- if (p->nop)
- return NULL;
for (i = 0; i < h->len; ++i) {
if (fprintf(tmp, "%s", h->lines[i]+1) < 0)
return got_error_from_errno("fprintf");
}
}
-
- if (p->new == NULL) {
- struct stat sb;
-
- if (fstat(fileno(orig), &sb) == -1)
- err = got_error_from_errno("fstat");
- else if (sb.st_size != copypos)
- err = got_error(GOT_ERR_PATCH_DONT_APPLY);
- } else if (!p->nop && !feof(orig))
+ if (!feof(orig))
err = copy(tmp, orig, copypos, -1);
done:
}
static const struct got_error *
-build_pathlist(const char *p, char **path, struct got_pathlist_head *head,
- struct got_worktree *worktree)
-{
- const struct got_error *err;
- struct got_pathlist_entry *pe;
-
- err = got_worktree_resolve_path(path, worktree, p);
- if (err == NULL)
- err = got_pathlist_insert(&pe, head, *path, NULL);
- return err;
-}
-
-static const struct got_error *
-can_rm(void *arg, unsigned char status, unsigned char staged_status,
- const char *path, struct got_object_id *blob_id,
- struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
- int dirfd, const char *de_name)
-{
- if (status == GOT_STATUS_NONEXISTENT)
- return got_error_set_errno(ENOENT, path);
- if (status != GOT_STATUS_NO_CHANGE &&
- status != GOT_STATUS_ADD &&
- status != GOT_STATUS_MODIFY &&
- status != GOT_STATUS_MODE_CHANGE)
- return got_error_path(path, GOT_ERR_FILE_STATUS);
- if (staged_status == GOT_STATUS_DELETE)
- return got_error_path(path, GOT_ERR_FILE_STATUS);
- return NULL;
-}
-
-static const struct got_error *
-can_add(void *arg, unsigned char status, unsigned char staged_status,
- const char *path, struct got_object_id *blob_id,
- struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
- int dirfd, const char *de_name)
-{
- if (status != GOT_STATUS_NONEXISTENT)
- return got_error_path(path, GOT_ERR_FILE_STATUS);
- return NULL;
-}
-
-static const struct got_error *
-can_edit(void *arg, unsigned char status, unsigned char staged_status,
- const char *path, struct got_object_id *blob_id,
- struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
- int dirfd, const char *de_name)
-{
- if (status == GOT_STATUS_NONEXISTENT)
- return got_error_set_errno(ENOENT, path);
- if (status != GOT_STATUS_NO_CHANGE &&
- status != GOT_STATUS_ADD &&
- status != GOT_STATUS_MODIFY)
- return got_error_path(path, GOT_ERR_FILE_STATUS);
- if (staged_status == GOT_STATUS_DELETE)
- return got_error_path(path, GOT_ERR_FILE_STATUS);
- return NULL;
-}
-
-static const struct got_error *
-check_file_status(struct got_patch *p, int file_renamed,
- struct got_worktree *worktree, struct got_repository *repo,
- struct got_pathlist_head *old, struct got_pathlist_head *new,
- got_cancel_cb cancel_cb, void *cancel_arg)
-{
- static const struct got_error *err;
-
- if (p->old != NULL && p->new == NULL)
- return got_worktree_status(worktree, old, repo, 0,
- can_rm, NULL, cancel_cb, cancel_arg);
- else if (file_renamed) {
- err = got_worktree_status(worktree, old, repo, 0,
- can_rm, NULL, cancel_cb, cancel_arg);
- if (err)
- return err;
- return got_worktree_status(worktree, new, repo, 0,
- can_add, NULL, cancel_cb, cancel_arg);
- } else if (p->old == NULL)
- return got_worktree_status(worktree, new, repo, 0,
- can_add, NULL, cancel_cb, cancel_arg);
- else
- return got_worktree_status(worktree, new, repo, 0,
- can_edit, NULL, cancel_cb, cancel_arg);
-}
-
-static const struct got_error *
apply_patch(struct got_worktree *worktree, struct got_repository *repo,
struct got_patch *p, got_worktree_delete_cb delete_cb, void *delete_arg,
- got_worktree_checkout_cb add_cb, void *add_arg, got_cancel_cb cancel_cb,
- void *cancel_arg)
+ got_worktree_checkout_cb add_cb, void *add_arg)
{
const struct got_error *err = NULL;
- struct got_pathlist_head oldpaths, newpaths;
int file_renamed = 0;
char *oldpath = NULL, *newpath = NULL;
char *tmppath = NULL, *template = NULL;
FILE *tmp = NULL;
- TAILQ_INIT(&oldpaths);
- TAILQ_INIT(&newpaths);
-
- err = build_pathlist(p->old != NULL ? p->old : p->new, &oldpath,
- &oldpaths, worktree);
+ err = got_worktree_resolve_path(&oldpath, worktree,
+ p->old != NULL ? p->old : p->new);
if (err)
goto done;
- err = build_pathlist(p->new != NULL ? p->new : p->old, &newpath,
- &newpaths, worktree);
+ err = got_worktree_resolve_path(&newpath, worktree,
+ p->new != NULL ? p->new : p->old);
if (err)
goto done;
- if (p->old != NULL && p->new != NULL && strcmp(p->old, p->new))
- file_renamed = 1;
-
- err = check_file_status(p, file_renamed, worktree, repo, &oldpaths,
- &newpaths, cancel_cb, cancel_arg);
- if (err)
+ if (p->old != NULL && p->new == NULL) {
+ /*
+ * special case: delete a file. don't try to match
+ * the lines but just schedule the removal.
+ */
+ err = schedule_del(p->old, worktree, repo, delete_cb,
+ delete_arg);
goto done;
+ }
if (asprintf(&template, "%s/got-patch",
got_worktree_get_root_path(worktree)) == -1) {
goto done;
}
- if (!p->nop)
- err = got_opentemp_named(&tmppath, &tmp, template);
+ err = got_opentemp_named(&tmppath, &tmp, template);
if (err)
goto done;
err = patch_file(p, oldpath, tmp);
if (err)
goto done;
- if (p->nop)
- goto done;
-
- if (p->old != NULL && p->new == NULL) {
- err = got_worktree_schedule_delete(worktree, &oldpaths,
- 0, NULL, delete_cb, delete_arg, repo, 0, 0);
- goto done;
- }
-
if (rename(tmppath, newpath) == -1) {
err = got_error_from_errno3("rename", tmppath, newpath);
goto done;
}
+ file_renamed = p->old != NULL && strcmp(p->old, p->new);
if (file_renamed) {
- err = got_worktree_schedule_delete(worktree, &oldpaths,
- 0, NULL, delete_cb, delete_arg, repo, 0, 0);
+ err = schedule_del(oldpath, worktree, repo, delete_cb,
+ delete_arg);
if (err == NULL)
- err = got_worktree_schedule_add(worktree, &newpaths,
- add_cb, add_arg, repo, 1);
+ err = schedule_add(newpath, worktree, repo,
+ add_cb, add_arg);
} else if (p->old == NULL)
- err = got_worktree_schedule_add(worktree, &newpaths,
- add_cb, add_arg, repo, 1);
+ err = schedule_add(newpath, worktree, repo, add_cb,
+ add_arg);
else
printf("M %s\n", oldpath); /* XXX */
done:
- if (err != NULL && newpath != NULL && (file_renamed || p->old == NULL))
+ if (err != NULL && (file_renamed || p->old == NULL))
unlink(newpath);
free(template);
if (tmppath != NULL)
unlink(tmppath);
free(tmppath);
- got_pathlist_free(&oldpaths);
- got_pathlist_free(&newpaths);
free(oldpath);
free(newpath);
return err;
blob - 41f290c529e09c20b73b0a6752c3351664a9559d
blob + 3c32d4b102c5f846f81ff306d31409388f56973a
--- regress/cmdline/patch.sh
+++ regress/cmdline/patch.sh
test_done $testroot $ret
return 1
fi
- rm $testroot/wt/eta
cat <<EOF > $testroot/wt/patch
--- alpha
fi
test_done $testroot $ret
}
-
-test_patch_illegal_status() {
- local testroot=`test_init patch_illegal_status`
-
- got checkout $testroot/repo $testroot/wt > /dev/null
- ret=$?
- if [ $ret -ne 0 ]; then
- test_done $testroot $ret
- return 1
- fi
-
- # edit an non-existent and unknown file
- cat <<EOF > $testroot/wt/patch
---- iota
-+++ iota
-@@ -1 +1 @@
-- iota
-+ IOTA
-EOF
-
- (cd $testroot/wt && got patch patch) > /dev/null \
- 2> $testroot/stderr
- ret=$?
- if [ $ret -eq 0 ]; then
- echo "edited a missing file" >&2
- test_done $testroot $ret
- return 1
- fi
-
- echo "got: iota: No such file or directory" \
- > $testroot/stderr.expected
- cmp -s $testroot/stderr.expected $testroot/stderr
- ret=$?
- if [ $ret -ne 0 ]; then
- diff -u $testroot/stderr.expected $testroot/stderr
- test_done $testroot $ret
- return 1
- fi
-
- # create iota and re-try
- echo iota > $testroot/wt/iota
-
- (cd $testroot/wt && got patch patch) > /dev/null \
- 2> $testroot/stderr
- ret=$?
- if [ $ret -eq 0 ]; then
- echo "patched an unknown file" >&2
- test_done $testroot $ret
- return 1
- fi
- echo "got: iota: file has unexpected status" \
- > $testroot/stderr.expected
- cmp -s $testroot/stderr.expected $testroot/stderr
- ret=$?
- if [ $ret -ne 0 ]; then
- diff -u $testroot/stderr.expected $testroot/stderr
- test_done $testroot $ret
- return 1
- fi
-
- rm $testroot/wt/iota
- ret=$?
- if [ $ret -ne 0 ]; then
- test_done $testroot $ret
- return 1
- fi
-
- # edit obstructed file
- rm $testroot/wt/alpha
- mkdir $testroot/wt/alpha
- cat <<EOF > $testroot/wt/patch
---- alpha
-+++ alpha
-@@ -1 +1,2 @@
- alpha
-+was edited
-EOF
-
- (cd $testroot/wt && got patch patch) > /dev/null \
- 2> $testroot/stderr
- ret=$?
- if [ $ret -eq 0 ]; then
- echo "edited a missing file" >&2
- test_done $testroot $ret
- return 1
- fi
-
- echo "got: alpha: file has unexpected status" \
- > $testroot/stderr.expected
- cmp -s $testroot/stderr.expected $testroot/stderr
- ret=$?
- if [ $ret -ne 0 ]; then
- diff -u $testroot/stderr.expected $testroot/stderr
- test_done $testroot $ret
- return 1
- fi
-
- # delete an unknown file
- cat <<EOF > $testroot/wt/patch
---- iota
-+++ /dev/null
-@@ -1 +0,0 @@
--iota
-EOF
-
- (cd $testroot/wt && got patch patch) > /dev/null \
- 2> $testroot/stderr
- ret=$?
- if [ $ret -eq 0 ]; then
- echo "deleted a missing file?" >&2
- test_done $testroot $ret
- return 1
- fi
-
- echo "got: iota: No such file or directory" \
- > $testroot/stderr.expected
- cmp -s $testroot/stderr.expected $testroot/stderr
- ret=$?
- if [ $ret -eq 0 ]; then
- diff -u $testroot/stderr.expected $testroot/stderr
- test_done $testroot $ret
- return 1
- fi
-
- # try again with iota in place but still not registered
- echo iota > $testroot/wt/iota
- (cd $testroot/wt && got patch patch) > /dev/null \
- 2> $testroot/stderr
- ret=$?
- if [ $ret -eq 0 ]; then
- echo "deleted an unversioned file?" >&2
- test_done $testroot $ret
- return 1
- fi
-
- echo "got: iota: file has unexpected status" \
- > $testroot/stderr.expected
- cmp -s $testroot/stderr.expected $testroot/stderr
- ret=$?
- if [ $ret -eq 0 ]; then
- diff -u $testroot/stderr.expected $testroot/stderr
- fi
- test_done $testroot $ret
-}
-
-test_patch_nop() {
- local testroot=`test_init patch_nop`
-
- got checkout $testroot/repo $testroot/wt > /dev/null
- ret=$?
- if [ $ret -ne 0 ]; then
- test_done $testroot $ret
- return 1
- fi
-
- cat <<EOF > $testroot/wt/patch
---- alpha
-+++ alpha
-@@ -1 +1 @@
--alpha
-+cafe alpha
---- beta
-+++ /dev/null
-@@ -1 +0,0 @@
--beta
---- gamma/delta
-+++ gamma/delta.new
-@@ -1 +1 @@
--delta
-+delta updated and renamed!
-EOF
-
- (cd $testroot/wt && got patch -n patch)
- ret=$?
- if [ $ret -ne 0 ]; then
- test_done $testroot $ret
- return 1
- fi
-
- # remove the patch to avoid the ? entry
- rm $testroot/wt/patch
-
- (cd $testroot/wt && got status) > $testroot/stdout
- ret=$?
- if [ $ret -ne 0 ]; then
- test_done $testroot $ret
- return 1
- fi
-
- echo -n > $testroot/stdout.expected
- cmp -s $testroot/stdout.expected $testroot/stdout
- ret=$?
- if [ $ret -ne 0 ]; then
- diff -u $testroot/stdout.expected $testroot/stdout
- fi
- test_done $testroot $ret
-}
-
test_parseargs "$@"
run_test test_patch_simple_add_file
run_test test_patch_simple_rm_file
run_test test_patch_no_patch
run_test test_patch_equals_for_context
run_test test_patch_rename
-run_test test_patch_illegal_status
-run_test test_patch_nop