9

This is touched on in two questions, 'Check if a file or folder has been patched already' and 'Make patch return 0 when skipping an already applied patch' however neither had a satisfying answer.

I am writing a script and want to test the following for a patch:

Fully applied: continue

Partially applied: exit

Not applied: if it can be applied successfully do it and continue, otherwise exit

The problem is handling the partially applied case:

mkdir test && cd test

cat << EOF > foobar.patch
--- /dev/null
+++ foo
@@ -0,0 +1 @@
+foo
--- /dev/null
+++ bar
@@ -0,0 +1 @@
+bar
EOF

patch --forward -i foobar.patch
rm foo

So bar exists but foo doesn't because at some point it was removed. Now if I apply the patch forward in a dry-run the exit code is 1 since it's not applied successfully.

$ patch --dry-run --forward --force -i foobar.patch
checking file foo
The next patch would create the file bar,
which already exists!  Skipping patch.
1 out of 1 hunk ignored
$ echo $?
1

That does not tell me whether the patch is fully applied though, just that it failed the dry-run. I don't know why that's marked correct as the stackoverflow answer. I tried reversing but since it's a non-interactive script it only worked with force:

$ patch --dry-run --reverse --force -i foobar.patch
The next patch, when reversed, would delete the file foo,
which does not exist!  Applying it anyway.
checking file foo
Hunk #1 FAILED at 1.
1 out of 1 hunk FAILED
checking file bar
$ echo $?
1

So does it always hold that if I try to forcibly reverse a patch in a dry-run and it succeeds that the patch is fully applied, and if it fails that it's not fully applied (or applied at all)? Because if so then I can do something like

patch --dry-run --reverse --force -i foobar.patch ||
(patch --dry-run --forward --force -i foobar.patch &&
 patch --forward --force -i foobar.patch) ||
exit 1
  • Is the source code under your control, ie can you guarantee that all patches will always apply exactly once? – roaima Sep 19 '16 at 7:23
  • 1
    @roamia well the patch and script are under my control. only my script would be applying the patch. – Jay Sep 19 '16 at 16:46
  • I think it's possible to contrive a starting point and a patch that would succeed fully in both forward and reverse directions. – Jasen Dec 25 '16 at 12:01
1

With this diff:

diff --git a/bar b/bar
new file mode 100644
index 0000000..e69de29
diff --git a/foo b/foo
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/foo
@@ -0,0 +1 @@
+foo

this happens:

$ cd /tmp/test
$ patch --forward -i foobar.patch
patching file bar
patching file foo
$ echo $?
0
$ rm bar
$ patch --dry-run --reverse --force -i foobar.patch
The next patch, when reversed, would delete the file bar,
which does not exist!  Applying it anyway.
checking file bar
checking file foo
$ echo $?
0

So the answer to your question is no.

  • Thank you for pointing that out. I've found I can fix for that case by using --posix since it will set an error when there's no file to patch. However using POSIX mode will not set an error if a file to be deleted contains content that differs from the patch. For example if I run that reverse command with --posix and the bar file contains some data then in POSIX mode the file will not be deleted and no error occurs. Therefore my fix is run it both with and without posix mode and if both are ok then I assume the patch was successfully applied. I will update my question to reflect this. – Jay Jan 22 '17 at 23:47
  • It appears --posix may not be the cure-all I thought it was. If a file is deleted by a patch and I run --posix --reverse then it errors that the file does not exist. I'll have to look into this more tomorrow. – Jay Jan 23 '17 at 7:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.