Class PatchApplier

java.lang.Object
org.machanism.machai.gw.tools.PatchApplier

public final class PatchApplier extends Object
Applies unified and simplified search-and-replace diff patches to text files.

The utility parses patch hunks, locates their original context near the position indicated by a unified-diff header, and writes the resulting lines using the caller-supplied character set. It rejects patches that cannot be matched, make no changes, or would erase a nonempty file. This class has no mutable shared state and exposes only static operations.

Since:
1.2.0
Author:
Viktor Tovstyi
  • Constructor Details

    • PatchApplier

      private PatchApplier()
      Prevents instantiation of this static utility class.
  • Method Details

    • parsePatchLine

      private static PatchApplier.PatchLine parsePatchLine(String hunkLine)
      Parses one hunk line into its operation and unprefixed content.
      Parameters:
      hunkLine - raw patch line
      Returns:
      parsed patch line; unprefixed input is treated as context
    • advancePastContext

      private static int advancePastContext(List<String> lines, String content, int index)
      Advances beyond a context line, searching forward when its expected position no longer matches exactly.
      Parameters:
      lines - modified file lines
      content - expected context content
      index - current line index
      Returns:
      index immediately after the matching or expected context line
    • removeLine

      private static void removeLine(List<String> lines, int index) throws IOException
      Removes a line at the current patch position.
      Parameters:
      lines - modified file lines
      index - index of the line to remove
      Throws:
      IOException - if the removal is beyond the available file context
    • applyPatch

      public static void applyPatch(File file, List<String> patchLines, Charset charset) throws IOException
      Applies a unified or simplified diff patch to a file.

      Standard unified-diff headers, such as @@ -1,5 +1,6 @@, and simplified @@ headers are supported.

      Parameters:
      file - target file to patch; it is created when absent
      patchLines - ordered lines from the patch file
      charset - character set used to read and write the target file
      Throws:
      IOException - if file operations fail, a hunk cannot be applied, or validation rejects the resulting content
    • readHunk

      private static PatchApplier.Hunk readHunk(List<String> patchLines, int headerIndex, int offsetDelta)
      Reads the hunk beginning at a patch header.
      Parameters:
      patchLines - complete patch lines
      headerIndex - index of the header
      offsetDelta - cumulative line-count delta from preceding hunks
      Returns:
      parsed hunk
    • isHunkBoundary

      private static boolean isHunkBoundary(String line)
      Determines whether a line begins another hunk or file section.
      Parameters:
      line - candidate patch line
      Returns:
      true when the line is a recognized boundary
    • getExpectedStart

      private static int getExpectedStart(String header, int offsetDelta)
      Calculates the preferred result-file position from a unified-diff header.
      Parameters:
      header - hunk header
      offsetDelta - cumulative prior line-count delta
      Returns:
      zero-based preferred position, or zero for a simplified or invalid header
    • applyHunk

      private static void applyHunk(List<String> resultLines, PatchApplier.Hunk hunk, String header) throws IOException
      Locates and applies a hunk to the mutable result lines.
      Parameters:
      resultLines - mutable result file lines
      hunk - parsed hunk
      header - original hunk header for diagnostics
      Throws:
      IOException - if no matching hunk context is found
    • applyPatchLine

      private static int applyPatchLine(List<String> lines, PatchApplier.PatchLine patchLine, int index) throws IOException
      Applies one parsed hunk line at the current result-file index.
      Parameters:
      lines - mutable result lines
      patchLine - parsed operation and content
      index - current result-file index
      Returns:
      index at which the next operation should occur
      Throws:
      IOException - if a removal exceeds available context
    • countAdded

      private static int countAdded(List<String> lines)
      Counts addition lines in a hunk.
      Parameters:
      lines - raw hunk lines
      Returns:
      number of additions
    • countRemoved

      private static int countRemoved(List<String> lines)
      Counts removal lines in a hunk.
      Parameters:
      lines - raw hunk lines
      Returns:
      number of removals
    • createParentDirectory

      private static void createParentDirectory(Path path) throws IOException
      Creates the target file's parent directory when it does not exist.
      Parameters:
      path - target path
      Throws:
      IOException - if the directory cannot be created
    • validatePatchResult

      private static void validatePatchResult(List<String> original, List<String> modified, String fileName) throws IOException
      Rejects unsafe or ineffective patch results.
      Parameters:
      original - original file lines
      modified - patched file lines
      fileName - file name for diagnostics
      Throws:
      IOException - if the patch erases a nonempty file or makes no change
    • findHunkStart

      private static int findHunkStart(List<String> fileLines, List<String> hunkLines, int expectedStart)
      Finds the first complete original-context match nearest the expected start.
      Parameters:
      fileLines - candidate file lines
      hunkLines - raw hunk lines
      expectedStart - preferred zero-based position
      Returns:
      matching index, or -1 when no match exists
    • expectedOriginalLines

      private static List<String> expectedOriginalLines(List<String> hunkLines)
      Extracts the original-file lines required by a hunk.
      Parameters:
      hunkLines - raw hunk lines
      Returns:
      context and removal content in original-file order
    • matchesAt

      private static boolean matchesAt(List<String> fileLines, List<String> expectedLines, int startOffset)
      Checks whether expected lines match the file at an index.
      Parameters:
      fileLines - file lines
      expectedLines - expected consecutive lines
      startOffset - candidate start index
      Returns:
      true if all expected lines match in bounds
    • matchLines

      private static boolean matchLines(List<String> fileLines, List<String> expectedLines, int startOffset)
      Compares expected lines to a consecutive segment of file lines.
      Parameters:
      fileLines - file lines
      expectedLines - expected lines
      startOffset - start of the candidate segment
      Returns:
      true if every line matches
    • indexOfLine

      private static int indexOfLine(List<String> lines, String expectedLine, int startIndex)
      Finds a line at or after the supplied index.
      Parameters:
      lines - lines to search
      expectedLine - line to locate
      startIndex - first index to examine
      Returns:
      matching index, or -1 when absent