diff --git a/patch_ng.py b/patch_ng.py index f64311b..b46f532 100755 --- a/patch_ng.py +++ b/patch_ng.py @@ -707,7 +707,9 @@ def _detect_type(self, p): break if p.header[idx].startswith(b'diff --git a/'): if (idx+1 < len(p.header) - and re.match(b'(?:index \\w{7}..\\w{7} \\d{6}|new file mode \\d*)', p.header[idx+1])): + and re.match( + b'(?:index \\w{4,40}\\.\\.\\w{4,40}(?: \\d{6})?|new file mode \\d+|deleted file mode \\d+)', + p.header[idx+1])): if DVCS: return GIT diff --git a/tests/patchformat/create.patch b/tests/patchformat/create.patch new file mode 100644 index 0000000..c054aa0 --- /dev/null +++ b/tests/patchformat/create.patch @@ -0,0 +1,20 @@ +From 8cacee878aff9a79603c87366d3eeefa68d80cf3 Mon Sep 17 00:00:00 2001 +From: John Doe +Date: Wed, 1 Oct 2025 10:59:19 +0200 +Subject: [PATCH] Add quotes.txt + +Signed-off-by: John Doe +--- + quotes.txt | 1 + + 1 file changed, 1 insertion(+) + create mode 100644 quotes.txt + +diff --git a/quotes.txt b/quotes.txt +new file mode 100644 +index 0000000000000000000000000000000000000000..edcfcc5846847fffa4986b8437f1d7a3bd8aa8cf +--- /dev/null ++++ b/quotes.txt +@@ -0,0 +1 @@ ++habita fides ipsam plerumque obligat fidem. +-- +2.51.0 diff --git a/tests/patchformat/remove.patch b/tests/patchformat/remove.patch new file mode 100644 index 0000000..609109b --- /dev/null +++ b/tests/patchformat/remove.patch @@ -0,0 +1,20 @@ +From 22751ffae72c0b955b55e68ec0e25a80e434e890 Mon Sep 17 00:00:00 2001 +From: John Doe +Date: Wed, 1 Oct 2025 10:59:47 +0200 +Subject: [PATCH] Remove quotes.txt + +Signed-off-by: John Doe +--- + quotes.txt | 1 - + 1 file changed, 1 deletion(-) + delete mode 100644 quotes.txt + +diff --git a/quotes.txt b/quotes.txt +deleted file mode 100644 +index 22174d6b96bbdd674d38f8be446d22758f996aba..0000000000000000000000000000000000000000 +--- a/quotes.txt ++++ /dev/null +@@ -1 +0,0 @@ +-Si vis pacem cole justitiam. +-- +2.51.0 diff --git a/tests/patchformat/update.patch b/tests/patchformat/update.patch new file mode 100644 index 0000000..a6a7da9 --- /dev/null +++ b/tests/patchformat/update.patch @@ -0,0 +1,19 @@ +From 3360e00554544de3a68a227ac9eff5bb687da723 Mon Sep 17 00:00:00 2001 +From: John Doe +Date: Wed, 1 Oct 2025 10:59:37 +0200 +Subject: [PATCH] Update quote + +Signed-off-by: John Doe +--- + quotes.txt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/quotes.txt b/quotes.txt +index edcfcc5846847fffa4986b8437f1d7a3bd8aa8cf..22174d6b96bbdd674d38f8be446d22758f996aba 100644 +--- a/quotes.txt ++++ b/quotes.txt +@@ -1 +1 @@ +-habita fides ipsam plerumque obligat fidem. ++Si vis pacem cole justitiam. +-- +2.51.0 diff --git a/tests/run_tests.py b/tests/run_tests.py index cc1814b..4145d29 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -518,6 +518,47 @@ def test_pathstrip(self): self.assertEqual(patch_ng.pathstrip(b'path/name.diff', 1), b'name.diff') self.assertEqual(patch_ng.pathstrip(b'path/name.diff', 0), b'path/name.diff') + +class TestPatchFormat(unittest.TestCase): + def setUp(self): + self.save_cwd = os.getcwd() + self.tmpdir = mkdtemp(prefix=self.__class__.__name__) + shutil.copytree(join(TESTS, 'patchformat'), join(self.tmpdir, 'patchformat')) + + def tearDown(self): + os.chdir(self.save_cwd) + remove_tree_force(self.tmpdir) + + def test_handle_full_index_patch_format(self): + """Test that a full index patch format is handled correctly + + When parsing a git patch with a full index line (40 hex chars), + the patch type should be detected as GIT and the patch should be + applied correctly (create, update, remove a file). + """ + + os.chdir(self.tmpdir) + pto = patch_ng.fromfile(join(self.tmpdir, 'patchformat', 'create.patch')) + self.assertEqual(len(pto), 1) + self.assertEqual(pto.items[0].type, patch_ng.GIT) + self.assertTrue(pto.apply()) + self.assertTrue(os.path.exists(join(self.tmpdir, 'quotes.txt'))) + + pto = patch_ng.fromfile(join(self.tmpdir, 'patchformat', 'update.patch')) + self.assertEqual(len(pto), 1) + self.assertEqual(pto.items[0].type, patch_ng.GIT) + self.assertTrue(pto.apply()) + with open(join(self.tmpdir, 'quotes.txt'), 'rb') as f: + content = f.read() + self.assertTrue(b'Si vis pacem cole justitiam.' in content) + + pto = patch_ng.fromfile(join(self.tmpdir, 'patchformat', 'remove.patch')) + self.assertEqual(len(pto), 1) + self.assertEqual(pto.items[0].type, patch_ng.GIT) + self.assertTrue(pto.apply()) + self.assertFalse(os.path.exists(join(self.tmpdir, 'quotes.txt'))) + + def remove_tree_force(folder): for root, _, files in os.walk(folder): for it in files: