/* * Copyright (c) 2023, Shannon Booth * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include static ErrorOr do_patch(StringView path_of_file_to_patch, Diff::Patch const& patch) { auto file_to_patch = TRY(Core::File::open(path_of_file_to_patch, Core::File::OpenMode::Read)); auto content = TRY(file_to_patch->read_until_eof()); auto lines = StringView(content).lines(); // Apply patch to a temporary file in case one or more of the hunks fails. char tmp_output[] = "/tmp/patch.XXXXXX"; auto tmp_file = TRY(Core::File::adopt_fd(TRY(Core::System::mkstemp(tmp_output)), Core::File::OpenMode::ReadWrite)); TRY(Diff::apply_patch(*tmp_file, lines, patch)); return FileSystem::move_file(path_of_file_to_patch, StringView { tmp_output, sizeof(tmp_output) }); } ErrorOr serenity_main(Main::Arguments arguments) { Core::ArgsParser args_parser; args_parser.parse(arguments); auto input = TRY(Core::File::standard_input()); 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()); 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 (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)); return 0; }