30

I have a build tool that runs a patch command and if the patch command returns non-zero, it will cause the build to fail. I am applying a patch that may or may not already be applied, so I use the -N option to patch, which skips as it should. However, when it does skip, patch is returning non-zero. Is there a way to force it to return 0 even if it skips applying patches? I couldn't find any such capability from the man page.

6 Answers 6

9

Accepted answer did not work for me because patch was returning 1 also on other types of errors (maybe different version or sth). So instead, in case of error I am checking output for "Skipping patch" message to ignore such but return error on other issues.

OUT="$(patch -p0 --forward < FILENAME)" || echo "${OUT}" | grep "Skipping patch" -q || (echo "$OUT" && false);
Sign up to request clarification or add additional context in comments.

Comments

4

I believe that the following recipe should do the trick, it is what I am using in the same situation;

patches: $(wildcard $(SOMEWHERE)/patches/*.patch)
    for patch_file in $^; do \
        patch --strip=2 --unified --backup --forward --directory=<somewhere> --input=$$patch_file; \
        retCode=$$?; \
        [[ $$retCode -gt 1 ]] && exit $$retCode; \
    done; \
    exit 0

This recipe loops over the dependencies (in my case the patch files) and calls patch for each one. The "trick" on which I am relying is that patch returns 1 if the patch has already been applied and other higher numbers for other errors (such as a non existent patch file). The DIAGNOSTICS section of the patch manual entry describes the return code situation. YMMV

1 Comment

This strikes me as a head-scratching deficiency in the CLI of patch. The reason I ran into this at all is because I have another tool than runs patch and uses its return code (0 vs. nonzero) to determine whether it succeeded or failed. Thank you for your answer, I will use this script instead of patch as the patch command. Still, it's just odd that they don't have a switch for this.
3

You can also do that as a one line only

patch -p0 --forward < patches/patch-babylonjs.diff || true

So if you want to apply the patch and make sure that's it's working:

(patch -p0 --forward < patches/patch-babylonjs.diff || true) && echo OK

No matter whether the patch has already been applied or not, you'll always get "OK" displayed here.

2 Comments

This will say still say OK if the patch hasn't already been applied and also fails to apply.
But the first example works well. Exit code is 0, and if patch has already been applied it says "Reversed (or previously applied) patch detected! Skipping patch."
1

Below is a script that iterates on the above idea from @fsw and handles removal of .rej files as necessary.

#! /bin/sh

set +x
set -euo pipefail

bn=$(basename "$0")

patch="$1"; shift

r=$(mktemp /tmp/"$bn".XXXX)

if ! out=$(patch -p1 -N -r "$r" < "$patch")
then
    echo "$out" | grep -q "Reversed (or previously applied) patch detected!  Skipping patch."
    test -s "$r" # Make sure we have rejects.
else
    test -f "$r" && ! test -s "$r" # Make sure we have no rejects.
fi

rm -f "$r"

Comments

1

set -e
patch --batch --reverse --unified --strip=0 --input=xxx.patch
patch --forward --unified --strip=0 --input=xxx.patch

why:
--batch --reverse return 0 even if it already reversed
then --forward return 0 only if it really success

And you can just generate your patch in reversed diection. (diff new old)

1 Comment

Doesn't work. If patch wasn't already applied, the --reverse command applies it (Unreversed patch detected! Ignoring -R.). Then the next command fails.
0
# Unfortunately the --forward flag detects that a patch is reversed but still exits with code 1 and this
# stops the script, so we do not use the --forward flag.
if patch -p1 --dry-run < "${p}" 2>&1 | grep -q "Reversed (or previously applied)"; then
  echo "Already applied, skipping."
else
  patch -p1 < "$p"
fi

I believe this version is simpler and propagates patches errors beside the reversed one.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.