From: Stefan Sperling Subject: got patch stats about conflicts and rejects To: gameoftrees@openbsd.org Date: Thu, 11 May 2023 07:34:26 +0200 When 'got patch' sees merge conflicts it prints a final message saying the patch failed to apply. This behaviour seemed somewhat unclear to me in this particular case: $ got patch < umb3.diff G Makefile C commands.c G conf.c G ctl.c G externs.h G if.c G main.c C ppp.c G sqlite3.c A umb.c got: patch failed to apply $ This left me wondering where the problem was. Other commands treat conflicted files as an expected outcome rather than an error. So I did not immediately understand that merge conflicts were the reason for the error message. I see why patch does this differently but I would prefer the following output, as implemented below. $ got patch < umb3.diff G Makefile C commands.c G conf.c G ctl.c G externs.h G if.c G main.c C ppp.c G sqlite3.c A umb.c Files with merge conflicts: 2 got: patch failed to apply $ ok? ----------------------------------------------- make 'got patch' display statistics about files with conflicts and rejects diff e423877dd3fa76444ef448d4272a9f6d3ff32b54 923b751a6de843fe88951be34e6d8a7eec656101 commit - e423877dd3fa76444ef448d4272a9f6d3ff32b54 commit + 923b751a6de843fe88951be34e6d8a7eec656101 blob - 5b1264a0869935160185d8dbf60cfca23110939d blob + 8d34fc2c0463ba9b0482b97a427cd03c82b875d8 --- got/got.c +++ got/got.c @@ -8165,6 +8165,12 @@ static const struct got_error * return err; } +struct got_patch_progress_arg { + int did_something; + int conflicts; + int rejects; +}; + static const struct got_error * patch_progress(void *arg, const char *old, const char *new, unsigned char status, const struct got_error *error, int old_from, @@ -8172,13 +8178,24 @@ patch_progress(void *arg, const char *old, const char int ws_mangled, const struct got_error *hunk_err) { const char *path = new == NULL ? old : new; + struct got_patch_progress_arg *a = arg; while (*path == '/') path++; - if (status != 0) + if (status != GOT_STATUS_NO_CHANGE && + status != 0 /* per-hunk progress */) { printf("%c %s\n", status, path); + a->did_something = 1; + } + if (hunk_err == NULL) { + if (status == GOT_STATUS_CANNOT_UPDATE) + a->rejects++; + else if (status == GOT_STATUS_CONFLICT) + a->conflicts++; + } + if (error != NULL) fprintf(stderr, "%s: %s\n", getprogname(), error->msg); @@ -8196,6 +8213,21 @@ static const struct got_error * return NULL; } +static void +print_patch_progress_stats(struct got_patch_progress_arg *ppa) +{ + if (!ppa->did_something) + return; + + if (ppa->conflicts > 0) + printf("Files with merge conflicts: %d\n", ppa->conflicts); + + if (ppa->rejects > 0) { + printf("Files where patch failed to apply: %d\n", + ppa->rejects); + } +} + static const struct got_error * cmd_patch(int argc, char *argv[]) { @@ -8211,6 +8243,7 @@ cmd_patch(int argc, char *argv[]) int ch, nop = 0, strip = -1, reverse = 0; int patchfd; int *pack_fds = NULL; + struct got_patch_progress_arg ppa; TAILQ_INIT(&refs); @@ -8301,9 +8334,10 @@ cmd_patch(int argc, char *argv[]) goto done; } + memset(&ppa, 0, sizeof(ppa)); error = got_patch(patchfd, worktree, repo, nop, strip, reverse, - commit_id, &patch_progress, NULL, check_cancelled, NULL); - + commit_id, patch_progress, &ppa, check_cancelled, NULL); + print_patch_progress_stats(&ppa); done: got_ref_list_free(&refs); free(commit_id); blob - f8f96458bc264b17a74e776857380fbf625c03d2 blob + 17db471e5c3aa81e0eb9233b406861cdccd08fcd --- regress/cmdline/patch.sh +++ regress/cmdline/patch.sh @@ -202,6 +202,7 @@ EOF @@ -1,1 +1,2 @@ hunk failed to apply # numbers @@ -1,9 +0,0 @@ hunk failed to apply +Files where patch failed to apply: 2 EOF cmp -s $testroot/stdout.expected $testroot/stdout @@ -561,6 +562,7 @@ EOF # iota # kappa # lambda +Files where patch failed to apply: 5 EOF cat < $testroot/stderr.expected @@ -1528,6 +1530,7 @@ test_patch_merge_conflict() { echo 'C alpha' > $testroot/stdout.expected echo 'C numbers' >> $testroot/stdout.expected + echo 'Files with merge conflicts: 2' >> $testroot/stdout.expected cmp -s $testroot/stdout $testroot/stdout.expected ret=$? if [ $ret -ne 0 ]; then