Class: Ask::Tools::ApplyPatch

Inherits:
Ask::Tool
  • Object
show all
Defined in:
lib/ask/tools/shell/apply_patch.rb

Overview

Apply a patch to files using a unified diff format. Supports creating, updating, and deleting files within a “*** Begin Patch” / “*** End Patch” envelope.

Constant Summary collapse

MAX_FILE_SIZE =
10_000_000

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#operationsObject



59
60
61
# File 'lib/ask/tools/shell/apply_patch.rb', line 59

def operations
  @operations ||= Shell::DefaultApplyPatchOperations.new
end

Instance Method Details

#execute(patchText:) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/ask/tools/shell/apply_patch.rb', line 65

def execute(patchText:)
  patches = parse_patch(patchText)
  return Ask::Result.error(message: "No valid patch sections found") if patches.empty?

  results = []
  patches.each do |entry|
    path = operations.expand_path(entry[:path])

    case entry[:type]
    when :add
      if operations.file_exist?(path)
        return Ask::Result.error(message: "File already exists: #{path}")
      end
      operations.mkdir_p(path)
      content = entry[:lines].join("\n")
      content += "\n" unless content.end_with?("\n")
      operations.write_file(path, content)
      results << { action: "add", path: entry[:path], lines: entry[:lines].size }

    when :update
      unless operations.file_exist?(path)
        return Ask::Result.error(message: "File does not exist: #{path}")
      end
      unless operations.file?(path)
        return Ask::Result.error(message: "Not a file: #{path}")
      end

      raw = operations.read_file(path)
      size = raw.bytesize
      if size > MAX_FILE_SIZE
        return Ask::Result.error(message: "File too large (#{size} bytes)")
      end

      new_content = apply_chunks(raw, entry[:chunks])
      operations.write_file(path, new_content)
      results << { action: "update", path: entry[:path] }

    when :delete
      unless operations.file_exist?(path)
        return Ask::Result.error(message: "File does not exist: #{path}")
      end
      operations.delete_file(path)
      results << { action: "delete", path: entry[:path] }
    end
  end

  summary = results.map { |r| "#{r[:action].upcase_first} #{r[:path]}" }.join("\n")
  Ask::Result.ok(data: { summary: summary, results: results }, metadata: { results: results })
end