commit 899fcfdf4534887848844329dae7327bd810a432 from: Omar Polo date: Sun Mar 13 20:31:44 2022 UTC add a dry-run/nop mode for got patch with lots of help from stsp for the manpage bits! commit - 986288a659290f72e774dcf0cb43ba76b2c23c72 commit + 899fcfdf4534887848844329dae7327bd810a432 blob - 6ecd586ce8e361dfca580081aea01c71ea59b531 blob + 1109e3c97f334540e101df641fdfc3423cedb552 --- got/got.1 +++ got/got.1 @@ -1285,7 +1285,7 @@ option) .El .El .Tg pa -.It Cm patch Op Ar patchfile +.It Cm patch Oo Fl n Oc Op Ar patchfile .Dl Pq alias: Cm pa Apply changes from .Ar patchfile @@ -1338,6 +1338,19 @@ Such changes can be viewed with and can be reverted with .Cm got revert if needed. +.Pp +The options for +.Cm got patch +are as follows: +.Bl -tag -width Ds +.It Fl n +Do not make any modifications to the work tree. +This can be used to check whether a patch would apply without issues. +If the +.Ar patchfile +contains diffs that affect the same file multiple times the results +displayed may be incorrect. +.El .Tg rv .It Cm revert Oo Fl p Oc Oo Fl F Ar response-script Oc Oo Fl R Oc Ar path ... .Dl Pq alias: Cm rv blob - 4bcea52af617043cda2fa50d87f21effce198199 blob + d595de198f4880c3458bb395b994e889acf68df3 --- got/got.c +++ got/got.c @@ -7132,7 +7132,7 @@ done: __dead static void usage_patch(void) { - fprintf(stderr, "usage: %s patch [patchfile]\n", + fprintf(stderr, "usage: %s patch [-n] [patchfile]\n", getprogname()); exit(1); } @@ -7192,11 +7192,14 @@ cmd_patch(int argc, char *argv[]) struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; char *cwd = NULL; - int ch; + int ch, nop = 0; int patchfd; - while ((ch = getopt(argc, argv, "")) != -1) { + while ((ch = getopt(argc, argv, "n")) != -1) { switch (ch) { + case 'n': + nop = 1; + break; default: usage_patch(); /* NOTREACHED */ @@ -7244,7 +7247,7 @@ cmd_patch(int argc, char *argv[]) err(1, "pledge"); #endif - error = got_patch(patchfd, worktree, repo, &print_remove_status, + error = got_patch(patchfd, worktree, repo, nop, &print_remove_status, NULL, &add_progress, NULL, check_cancelled, NULL); done: blob - 448bb17e65d75d8d5ba94bd577f5cde4fef566bf blob + 5f28ffc619f1b4e32ba37ff8e5361c636009ba74 --- include/got_patch.h +++ include/got_patch.h @@ -21,6 +21,6 @@ * The patch file descriptor *must* be seekable. */ const struct got_error * -got_patch(int, struct got_worktree *, struct got_repository *, +got_patch(int, struct got_worktree *, struct got_repository *, int, got_worktree_delete_cb, void *, got_worktree_checkout_cb, void *, got_cancel_cb, void *); blob - 71695e64b89d1a1b07daab61fb55d3c1883760ec blob + 6e5ec0f2143d39ff9eeca89060522c5155706a77 --- lib/patch.c +++ lib/patch.c @@ -66,6 +66,7 @@ struct got_patch_hunk { }; struct got_patch { + int nop; char *old; char *new; STAILQ_HEAD(, got_patch_hunk) head; @@ -399,6 +400,8 @@ patch_file(struct got_patch *p, const char *path, FILE 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"); @@ -420,7 +423,8 @@ patch_file(struct got_patch *p, const char *path, FILE err = locate_hunk(orig, h, &pos, &lineno); if (err != NULL) goto done; - err = copy(tmp, orig, copypos, pos); + if (!p->nop) + err = copy(tmp, orig, copypos, pos); if (err != NULL) goto done; copypos = pos; @@ -446,7 +450,8 @@ patch_file(struct got_patch *p, const char *path, FILE if (err != NULL) goto done; - err = apply_hunk(tmp, h, &lineno); + if (!p->nop) + err = apply_hunk(tmp, h, &lineno); if (err != NULL) goto done; @@ -465,7 +470,7 @@ patch_file(struct got_patch *p, const char *path, FILE err = got_error_from_errno("fstat"); else if (sb.st_size != copypos) err = got_error(GOT_ERR_PATCH_DONT_APPLY); - } else if (!feof(orig)) + } else if (!p->nop && !feof(orig)) err = copy(tmp, orig, copypos, -1); done: @@ -599,13 +604,17 @@ apply_patch(struct got_worktree *worktree, struct got_ goto done; } - err = got_opentemp_named(&tmppath, &tmp, template); + if (!p->nop) + 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); @@ -645,7 +654,7 @@ done: const struct got_error * got_patch(int fd, struct got_worktree *worktree, struct got_repository *repo, - got_worktree_delete_cb delete_cb, void *delete_arg, + int nop, 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) { @@ -695,6 +704,7 @@ got_patch(int fd, struct got_worktree *worktree, struc if (err || done) break; + p.nop = nop; err = apply_patch(worktree, repo, &p, delete_cb, delete_arg, add_cb, add_arg, cancel_cb, cancel_arg); patch_free(&p); blob - 9a300a816a79b7eacef07263e7bd7cbce706ae25 blob + 41f290c529e09c20b73b0a6752c3351664a9559d --- regress/cmdline/patch.sh +++ regress/cmdline/patch.sh @@ -910,7 +910,60 @@ EOF 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 < $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 } @@ -928,3 +981,4 @@ 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