Skip to content

Commit f893e08

Browse files
shannonboothAtkinsSJ
authored andcommitted
patch: Support creation of a file
Previously patch would always expect the file that it was patching to exist (even it were empty). If we know that the patch is creating a file from nothing (i.e has a start line of '0'), then we treat a file that doesn't exist as if it has no content lines.
1 parent 0612e8e commit f893e08

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

Tests/Utilities/TestPatch.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,19 @@ TEST_CASE(strip_path_partially)
149149

150150
EXPECT_FILE_EQ(MUST(String::formatted("{}/to/basename", s_test_dir)), "Hello, friends!\n");
151151
}
152+
153+
TEST_CASE(add_file_from_scratch)
154+
{
155+
PatchSetup setup;
156+
157+
auto patch = R"(
158+
--- /dev/null
159+
+++ a/file_to_add
160+
@@ -0,0 +1 @@
161+
+Hello, friends!
162+
)"sv;
163+
164+
run_patch({}, patch, "patching file file_to_add\n"sv);
165+
166+
EXPECT_FILE_EQ(MUST(String::formatted("{}/file_to_add", s_test_dir)), "Hello, friends!\n");
167+
}

Userland/Utilities/patch.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,31 @@
1212
#include <LibFileSystem/FileSystem.h>
1313
#include <LibMain/Main.h>
1414

15+
static bool is_adding_file(Diff::Patch const& patch)
16+
{
17+
return patch.hunks[0].location.old_range.start_line == 0;
18+
}
19+
20+
static ErrorOr<ByteBuffer> read_content(StringView path_of_file_to_patch, Diff::Patch const& patch)
21+
{
22+
auto file_to_patch_or_error = Core::File::open(path_of_file_to_patch, Core::File::OpenMode::Read);
23+
24+
// Trivial case - no error reading the file.
25+
if (!file_to_patch_or_error.is_error())
26+
return TRY(file_to_patch_or_error.release_value()->read_until_eof());
27+
28+
auto const& error = file_to_patch_or_error.error();
29+
30+
// If the patch is adding a file then it is fine for opening the file to error out if it did not exist.
31+
if (!is_adding_file(patch) || !error.is_errno() || error.code() != ENOENT)
32+
return file_to_patch_or_error.release_error();
33+
34+
return ByteBuffer {};
35+
}
36+
1537
static ErrorOr<void> do_patch(StringView path_of_file_to_patch, Diff::Patch const& patch)
1638
{
17-
auto file_to_patch = TRY(Core::File::open(path_of_file_to_patch, Core::File::OpenMode::Read));
18-
auto content = TRY(file_to_patch->read_until_eof());
39+
ByteBuffer content = TRY(read_content(path_of_file_to_patch, patch));
1940
auto lines = StringView(content).lines();
2041

2142
// Apply patch to a temporary file in case one or more of the hunks fails.
@@ -54,7 +75,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
5475
StringView to_patch;
5576
if (FileSystem::is_regular_file(patch.header.old_file_path)) {
5677
to_patch = patch.header.old_file_path;
57-
} else if (FileSystem::is_regular_file(patch.header.new_file_path)) {
78+
} else if (is_adding_file(patch) || FileSystem::is_regular_file(patch.header.new_file_path)) {
5879
to_patch = patch.header.new_file_path;
5980
} else {
6081
warnln("Unable to determine file to patch");

0 commit comments

Comments
 (0)