diff --git a/Tests/Utilities/TestPatch.cpp b/Tests/Utilities/TestPatch.cpp index fd1a0511543..e39c02f28fc 100644 --- a/Tests/Utilities/TestPatch.cpp +++ b/Tests/Utilities/TestPatch.cpp @@ -165,3 +165,25 @@ TEST_CASE(add_file_from_scratch) EXPECT_FILE_EQ(MUST(String::formatted("{}/file_to_add", s_test_dir)), "Hello, friends!\n"); } + +TEST_CASE(two_patches_in_single_patch_file) +{ + PatchSetup setup; + + auto patch = R"( +--- /dev/null ++++ a/first_file_to_add +@@ -0,0 +1 @@ ++Hello, friends! +--- /dev/null ++++ a/second_file_to_add +@@ -0,0 +1 @@ ++Hello, friends! +)"sv; + + run_patch({}, patch, "patching file first_file_to_add\n" + "patching file second_file_to_add\n"sv); + + EXPECT_FILE_EQ(MUST(String::formatted("{}/first_file_to_add", s_test_dir)), "Hello, friends!\n"); + EXPECT_FILE_EQ(MUST(String::formatted("{}/second_file_to_add", s_test_dir)), "Hello, friends!\n"); +} diff --git a/Userland/Libraries/LibDiff/Hunks.cpp b/Userland/Libraries/LibDiff/Hunks.cpp index af88fa6e4b6..205b3d67783 100644 --- a/Userland/Libraries/LibDiff/Hunks.cpp +++ b/Userland/Libraries/LibDiff/Hunks.cpp @@ -87,6 +87,14 @@ ErrorOr Parser::parse_file_line(Optional const& strip_count) return stripped_path.to_string(); } +ErrorOr Parser::parse_patch(Optional const& strip_count) +{ + Patch patch; + patch.header = TRY(parse_header(strip_count)); + patch.hunks = TRY(parse_hunks()); + return patch; +} + ErrorOr
Parser::parse_header(Optional const& strip_count) { Header header; @@ -111,20 +119,20 @@ ErrorOr
Parser::parse_header(Optional const& strip_count) consume_line(); } - return Error::from_string_literal("Unable to find any patch"); + return header; } ErrorOr> Parser::parse_hunks() { Vector hunks; - while (!is_eof()) { + while (next_is("@@ ")) { // Try an locate a hunk location in this hunk. It may be prefixed with information. auto maybe_location = consume_unified_location(); consume_line(); if (!maybe_location.has_value()) - continue; + break; Hunk hunk { *maybe_location, {} }; @@ -178,6 +186,8 @@ ErrorOr> Parser::parse_hunks() ErrorOr> parse_hunks(StringView diff) { Parser lexer(diff); + while (!lexer.next_is("@@ ") && !lexer.is_eof()) + lexer.consume_line(); return lexer.parse_hunks(); } } diff --git a/Userland/Libraries/LibDiff/Hunks.h b/Userland/Libraries/LibDiff/Hunks.h index 51c0d7d46b7..fa919abeda7 100644 --- a/Userland/Libraries/LibDiff/Hunks.h +++ b/Userland/Libraries/LibDiff/Hunks.h @@ -80,11 +80,13 @@ class Parser : public GenericLexer { public: using GenericLexer::GenericLexer; + ErrorOr parse_patch(Optional const& strip_count = {}); + ErrorOr> parse_hunks(); +private: ErrorOr
parse_header(Optional const& strip_count); -private: ErrorOr parse_file_line(Optional const& strip_count); Optional consume_unified_location(); bool consume_line_number(size_t& number); diff --git a/Userland/Utilities/patch.cpp b/Userland/Utilities/patch.cpp index 0ce7c37557e..cebe38942b1 100644 --- a/Userland/Utilities/patch.cpp +++ b/Userland/Utilities/patch.cpp @@ -65,25 +65,28 @@ ErrorOr serenity_main(Main::Arguments arguments) auto patch_content = TRY(input->read_until_eof()); - // FIXME: Support multiple patches in the patch file. Diff::Parser parser(patch_content); - Diff::Patch patch; - patch.header = TRY(parser.parse_header(strip_count)); - patch.hunks = TRY(parser.parse_hunks()); - // FIXME: Support adding/removing a file, and asking for file to patch as fallback otherwise. - StringView to_patch; - if (FileSystem::is_regular_file(patch.header.old_file_path)) { - to_patch = patch.header.old_file_path; - } else if (is_adding_file(patch) || FileSystem::is_regular_file(patch.header.new_file_path)) { - to_patch = patch.header.new_file_path; - } else { - warnln("Unable to determine file to patch"); - return 1; + while (!parser.is_eof()) { + Diff::Patch patch = TRY(parser.parse_patch(strip_count)); + + if (patch.header.format == Diff::Format::Unknown) + break; + + // FIXME: Support adding/removing a file, and asking for file to patch as fallback otherwise. + StringView to_patch; + if (FileSystem::is_regular_file(patch.header.old_file_path)) { + to_patch = patch.header.old_file_path; + } else if (is_adding_file(patch) || FileSystem::is_regular_file(patch.header.new_file_path)) { + to_patch = patch.header.new_file_path; + } else { + warnln("Unable to determine file to patch"); + return 1; + } + + outln("patching file {}", to_patch); + TRY(do_patch(to_patch, patch)); } - outln("patching file {}", to_patch); - TRY(do_patch(to_patch, patch)); - return 0; }