diff options
author | V1K1NGbg <victor@ilchev.com> | 2024-08-22 17:48:59 -0300 |
---|---|---|
committer | Hisham Muhammad <hisham@gobolinux.org> | 2024-10-21 13:30:51 -0300 |
commit | 55450f45af0eb730a679aa2c016a5282c22882eb (patch) | |
tree | 436cac6a03005b4cc5c7ad76d966e044072d0b87 /src | |
parent | bb80ad3ceaaaabc57d7a732a09d9052d0b26d72e (diff) | |
download | luarocks-55450f45af0eb730a679aa2c016a5282c22882eb.tar.gz luarocks-55450f45af0eb730a679aa2c016a5282c22882eb.tar.bz2 luarocks-55450f45af0eb730a679aa2c016a5282c22882eb.zip |
Teal: convert luarocks.tools.patch
Diffstat (limited to 'src')
-rw-r--r-- | src/luarocks/tools/patch.tl (renamed from src/luarocks/tools/patch.lua) | 233 |
1 files changed, 132 insertions, 101 deletions
diff --git a/src/luarocks/tools/patch.lua b/src/luarocks/tools/patch.tl index 10654e06..95715176 100644 --- a/src/luarocks/tools/patch.lua +++ b/src/luarocks/tools/patch.tl | |||
@@ -8,59 +8,88 @@ | |||
8 | -- Project home: http://code.google.com/p/python-patch/ . | 8 | -- Project home: http://code.google.com/p/python-patch/ . |
9 | -- Version 0.1 | 9 | -- Version 0.1 |
10 | 10 | ||
11 | local patch = {} | 11 | local record patch |
12 | record Lineends | ||
13 | lf: integer | ||
14 | crlf: integer | ||
15 | cr: integer | ||
16 | end | ||
17 | record Hunk | ||
18 | startsrc: integer | ||
19 | linessrc: integer | ||
20 | starttgt: integer | ||
21 | linestgt: integer | ||
22 | invalid: boolean | ||
23 | text: {string} | ||
24 | end | ||
25 | record File --! | ||
26 | at: integer | ||
27 | str: string | ||
28 | len: integer | ||
29 | eof: boolean | ||
30 | read: function(File, integer): string | ||
31 | close: function(File): boolean | ||
32 | end | ||
33 | record Files | ||
34 | source: {string} --! | ||
35 | target: {string} | ||
36 | epoch: {boolean} | ||
37 | hunks: {{Hunk}} | ||
38 | fileends: {Lineends} | ||
39 | hunkends: {Lineends} | ||
40 | end | ||
41 | end | ||
12 | 42 | ||
13 | local fs = require("luarocks.fs") | 43 | local fs = require("luarocks.fs") |
14 | 44 | ||
15 | local io = io | 45 | local type Lineends = patch.Lineends |
16 | local os = os | 46 | local type Hunk = patch.Hunk |
17 | local string = string | 47 | local type Files = patch.Files |
18 | local table = table | 48 | local type File = patch.File |
19 | local format = string.format | ||
20 | 49 | ||
21 | -- logging | 50 | -- logging |
22 | local debugmode = false | 51 | local debugmode = false |
23 | local function debug(_) end | 52 | local function debug(_: string) end --! |
24 | local function info(_) end | 53 | local function info(_: string) end |
25 | local function warning(s) io.stderr:write(s .. '\n') end | 54 | local function warning(s: string) io.stderr:write(s .. '\n') end |
26 | 55 | ||
27 | -- Returns boolean whether string s2 starts with string s. | 56 | -- Returns boolean whether string s2 starts with string s. |
28 | local function startswith(s, s2) | 57 | local function startswith(s: string, s2: string): boolean |
29 | return s:sub(1, #s2) == s2 | 58 | return s:sub(1, #s2) == s2 |
30 | end | 59 | end |
31 | 60 | ||
32 | -- Returns boolean whether string s2 ends with string s. | 61 | -- Returns boolean whether string s2 ends with string s. |
33 | local function endswith(s, s2) | 62 | local function endswith(s: string, s2: string): boolean |
34 | return #s >= #s2 and s:sub(#s-#s2+1) == s2 | 63 | return #s >= #s2 and s:sub(#s-#s2+1) == s2 |
35 | end | 64 | end |
36 | 65 | ||
37 | -- Returns string s after filtering out any new-line characters from end. | 66 | -- Returns string s after filtering out any new-line characters from end. |
38 | local function endlstrip(s) | 67 | local function endlstrip(s: string): string, integer |
39 | return s:gsub('[\r\n]+$', '') | 68 | return s:gsub('[\r\n]+$', '') |
40 | end | 69 | end |
41 | 70 | ||
42 | -- Returns shallow copy of table t. | 71 | -- Returns shallow copy of table t. |
43 | local function table_copy(t) | 72 | local function table_copy<K, V>(t: {K: V}): {K: V} |
44 | local t2 = {} | 73 | local t2 = {} |
45 | for k,v in pairs(t) do t2[k] = v end | 74 | for k,v in pairs(t) do t2[k] = v end |
46 | return t2 | 75 | return t2 |
47 | end | 76 | end |
48 | 77 | ||
49 | local function exists(filename) | 78 | local function exists(filename: string): boolean |
50 | local fh = io.open(filename) | 79 | local fh = io.open(filename) |
51 | local result = fh ~= nil | 80 | local result = fh ~= nil |
52 | if fh then fh:close() end | 81 | if fh then fh:close() end |
53 | return result | 82 | return result |
54 | end | 83 | end |
55 | local function isfile() return true end --FIX? | 84 | local function isfile(): boolean return true end --FIX? --! |
56 | 85 | ||
57 | local function string_as_file(s) | 86 | local function string_as_file(s: string): File --! |
58 | return { | 87 | return { |
59 | at = 0, | 88 | at = 0, |
60 | str = s, | 89 | str = s, |
61 | len = #s, | 90 | len = #s, |
62 | eof = false, | 91 | eof = false, |
63 | read = function(self, n) | 92 | read = function(self: File, n: integer): string |
64 | if self.eof then return nil end | 93 | if self.eof then return nil end |
65 | local chunk = self.str:sub(self.at, self.at + n - 1) | 94 | local chunk = self.str:sub(self.at, self.at + n - 1) |
66 | self.at = self.at + n | 95 | self.at = self.at + n |
@@ -69,10 +98,10 @@ local function string_as_file(s) | |||
69 | end | 98 | end |
70 | return chunk | 99 | return chunk |
71 | end, | 100 | end, |
72 | close = function(self) | 101 | close = function(self: File): boolean |
73 | self.eof = true | 102 | self.eof = true |
74 | end, | 103 | end, |
75 | } | 104 | } as File |
76 | end | 105 | end |
77 | 106 | ||
78 | -- | 107 | -- |
@@ -84,12 +113,12 @@ end | |||
84 | -- in binary or ASCII mode. | 113 | -- in binary or ASCII mode. |
85 | -- (file_lines - version 20080913) | 114 | -- (file_lines - version 20080913) |
86 | -- | 115 | -- |
87 | local function file_lines(f) | 116 | local function file_lines(f: FILE): function(): string |
88 | local CHUNK_SIZE = 1024 | 117 | local CHUNK_SIZE = 1024 |
89 | local buffer = "" | 118 | local buffer = "" |
90 | local pos_beg = 1 | 119 | local pos_beg = 1 |
91 | return function() | 120 | return function(): string |
92 | local pos, chars | 121 | local pos, chars: string, string |
93 | while 1 do | 122 | while 1 do |
94 | pos, chars = buffer:match('()([\r\n].)', pos_beg) | 123 | pos, chars = buffer:match('()([\r\n].)', pos_beg) |
95 | if pos or not f then | 124 | if pos or not f then |
@@ -97,27 +126,28 @@ local function file_lines(f) | |||
97 | elseif f then | 126 | elseif f then |
98 | local chunk = f:read(CHUNK_SIZE) | 127 | local chunk = f:read(CHUNK_SIZE) |
99 | if chunk then | 128 | if chunk then |
100 | buffer = buffer:sub(pos_beg) .. chunk | 129 | buffer = buffer:sub(pos_beg) .. chunk --! funcy stuff with pos |
101 | pos_beg = 1 | 130 | pos_beg = 1 |
102 | else | 131 | else |
103 | f = nil | 132 | f = nil |
104 | end | 133 | end |
105 | end | 134 | end |
106 | end | 135 | end |
107 | if not pos then | 136 | local posi = math.tointeger(pos) |
108 | pos = #buffer | 137 | if not posi then |
138 | posi = #buffer | ||
109 | elseif chars == '\r\n' then | 139 | elseif chars == '\r\n' then |
110 | pos = pos + 1 | 140 | posi = posi + 1 |
111 | end | 141 | end |
112 | local line = buffer:sub(pos_beg, pos) | 142 | local line = buffer:sub(pos_beg, posi) |
113 | pos_beg = pos + 1 | 143 | pos_beg = posi + 1 |
114 | if #line > 0 then | 144 | if #line > 0 then |
115 | return line | 145 | return line |
116 | end | 146 | end |
117 | end | 147 | end |
118 | end | 148 | end |
119 | 149 | ||
120 | local function match_linerange(line) | 150 | local function match_linerange(line: string): string, string, string, string |
121 | local m1, m2, m3, m4 = line:match("^@@ %-(%d+),(%d+) %+(%d+),(%d+)") | 151 | local m1, m2, m3, m4 = line:match("^@@ %-(%d+),(%d+) %+(%d+),(%d+)") |
122 | if not m1 then m1, m3, m4 = line:match("^@@ %-(%d+) %+(%d+),(%d+)") end | 152 | if not m1 then m1, m3, m4 = line:match("^@@ %-(%d+) %+(%d+),(%d+)") end |
123 | if not m1 then m1, m2, m3 = line:match("^@@ %-(%d+),(%d+) %+(%d+)") end | 153 | if not m1 then m1, m2, m3 = line:match("^@@ %-(%d+),(%d+) %+(%d+)") end |
@@ -125,11 +155,11 @@ local function match_linerange(line) | |||
125 | return m1, m2, m3, m4 | 155 | return m1, m2, m3, m4 |
126 | end | 156 | end |
127 | 157 | ||
128 | local function match_epoch(str) | 158 | local function match_epoch(str: string): string |
129 | return str:match("[^0-9]1969[^0-9]") or str:match("[^0-9]1970[^0-9]") | 159 | return str:match("[^0-9]1969[^0-9]") or str:match("[^0-9]1970[^0-9]") |
130 | end | 160 | end |
131 | 161 | ||
132 | function patch.read_patch(filename, data) | 162 | function patch.read_patch(filename: string, data: string): Files, boolean |
133 | -- define possible file regions that will direct the parser flow | 163 | -- define possible file regions that will direct the parser flow |
134 | local state = 'header' | 164 | local state = 'header' |
135 | -- 'header' - comments before the patch body | 165 | -- 'header' - comments before the patch body |
@@ -139,26 +169,26 @@ function patch.read_patch(filename, data) | |||
139 | -- 'hunkskip' - skipping invalid hunk mode | 169 | -- 'hunkskip' - skipping invalid hunk mode |
140 | 170 | ||
141 | local all_ok = true | 171 | local all_ok = true |
142 | local lineends = {lf=0, crlf=0, cr=0} | 172 | local lineends: Lineends = {lf=0, crlf=0, cr=0} |
143 | local files = {source={}, target={}, epoch={}, hunks={}, fileends={}, hunkends={}} | 173 | local files: Files = {source={}, target={}, epoch={}, hunks: {{Hunk}}={}, fileends={}, hunkends: {Lineends}={}} |
144 | local nextfileno = 0 | 174 | local nextfileno = 0 |
145 | local nexthunkno = 0 --: even if index starts with 0 user messages | 175 | local nexthunkno = 0 --: even if index starts with 0 user messages |
146 | -- number hunks from 1 | 176 | -- number hunks from 1 |
147 | 177 | ||
148 | -- hunkinfo holds parsed values, hunkactual - calculated | 178 | -- hunkinfo holds parsed values, hunkactual - calculated |
149 | local hunkinfo = { | 179 | local hunkinfo: Hunk = { |
150 | startsrc=nil, linessrc=nil, starttgt=nil, linestgt=nil, | 180 | startsrc=nil, linessrc=nil, starttgt=nil, linestgt=nil, |
151 | invalid=false, text={} | 181 | invalid=false, text={} |
152 | } | 182 | } |
153 | local hunkactual = {linessrc=nil, linestgt=nil} | 183 | local hunkactual: Hunk = {linessrc=nil, linestgt=nil} |
154 | 184 | ||
155 | info(format("reading patch %s", filename)) | 185 | info(string.format("reading patch %s", filename)) --! |
156 | 186 | ||
157 | local fp | 187 | local fp: FILE |
158 | if data then | 188 | if data then |
159 | fp = string_as_file(data) | 189 | fp = string_as_file(data) as FILE --! cast |
160 | else | 190 | else |
161 | fp = filename == '-' and io.stdin or assert(io.open(filename, "rb")) | 191 | fp = filename == '-' and io.stdin or assert(io.open(filename, "rb") as (FILE, string)) --! use of cast |
162 | end | 192 | end |
163 | local lineno = 0 | 193 | local lineno = 0 |
164 | 194 | ||
@@ -202,10 +232,10 @@ function patch.read_patch(filename, data) | |||
202 | table.insert(hunkinfo.text, line) | 232 | table.insert(hunkinfo.text, line) |
203 | -- todo: handle \ No newline cases | 233 | -- todo: handle \ No newline cases |
204 | else | 234 | else |
205 | warning(format("invalid hunk no.%d at %d for target file %s", | 235 | warning(string.format("invalid hunk no.%d at %d for target file %s", |
206 | nexthunkno, lineno, files.target[nextfileno])) | 236 | nexthunkno, lineno, files.target[nextfileno])) |
207 | -- add hunk status node | 237 | -- add hunk status node |
208 | table.insert(files.hunks[nextfileno], table_copy(hunkinfo)) | 238 | table.insert(files.hunks[nextfileno], table_copy(hunkinfo as {any: any}) as Hunk) |
209 | files.hunks[nextfileno][nexthunkno].invalid = true | 239 | files.hunks[nextfileno][nexthunkno].invalid = true |
210 | all_ok = false | 240 | all_ok = false |
211 | state = 'hunkskip' | 241 | state = 'hunkskip' |
@@ -215,16 +245,16 @@ function patch.read_patch(filename, data) | |||
215 | if hunkactual.linessrc > hunkinfo.linessrc or | 245 | if hunkactual.linessrc > hunkinfo.linessrc or |
216 | hunkactual.linestgt > hunkinfo.linestgt | 246 | hunkactual.linestgt > hunkinfo.linestgt |
217 | then | 247 | then |
218 | warning(format("extra hunk no.%d lines at %d for target %s", | 248 | warning(string.format("extra hunk no.%d lines at %d for target %s", |
219 | nexthunkno, lineno, files.target[nextfileno])) | 249 | nexthunkno, lineno, files.target[nextfileno])) |
220 | -- add hunk status node | 250 | -- add hunk status node |
221 | table.insert(files.hunks[nextfileno], table_copy(hunkinfo)) | 251 | table.insert(files.hunks[nextfileno], table_copy(hunkinfo as {any: any}) as Hunk) |
222 | files.hunks[nextfileno][nexthunkno].invalid = true | 252 | files.hunks[nextfileno][nexthunkno].invalid = true |
223 | state = 'hunkskip' | 253 | state = 'hunkskip' |
224 | elseif hunkinfo.linessrc == hunkactual.linessrc and | 254 | elseif hunkinfo.linessrc == hunkactual.linessrc and |
225 | hunkinfo.linestgt == hunkactual.linestgt | 255 | hunkinfo.linestgt == hunkactual.linestgt |
226 | then | 256 | then |
227 | table.insert(files.hunks[nextfileno], table_copy(hunkinfo)) | 257 | table.insert(files.hunks[nextfileno], table_copy(hunkinfo as {any: any}) as Hunk) |
228 | state = 'hunkskip' | 258 | state = 'hunkskip' |
229 | 259 | ||
230 | -- detect mixed window/unix line ends | 260 | -- detect mixed window/unix line ends |
@@ -232,7 +262,7 @@ function patch.read_patch(filename, data) | |||
232 | if (ends.cr~=0 and 1 or 0) + (ends.crlf~=0 and 1 or 0) + | 262 | if (ends.cr~=0 and 1 or 0) + (ends.crlf~=0 and 1 or 0) + |
233 | (ends.lf~=0 and 1 or 0) > 1 | 263 | (ends.lf~=0 and 1 or 0) > 1 |
234 | then | 264 | then |
235 | warning(format("inconsistent line ends in patch hunks for %s", | 265 | warning(string.format("inconsistent line ends in patch hunks for %s", |
236 | files.source[nextfileno])) | 266 | files.source[nextfileno])) |
237 | end | 267 | end |
238 | end | 268 | end |
@@ -245,18 +275,18 @@ function patch.read_patch(filename, data) | |||
245 | elseif startswith(line, "--- ") then | 275 | elseif startswith(line, "--- ") then |
246 | state = 'filenames' | 276 | state = 'filenames' |
247 | if debugmode and #files.source > 0 then | 277 | if debugmode and #files.source > 0 then |
248 | debug(format("- %2d hunks for %s", #files.hunks[nextfileno], | 278 | debug(string.format("- %2d hunks for %s", #files.hunks[nextfileno], |
249 | files.source[nextfileno])) | 279 | files.source[nextfileno])) |
250 | end | 280 | end |
251 | end | 281 | end |
252 | -- state is 'hunkskip', 'hunkhead', or 'filenames' | 282 | -- state is 'hunkskip', 'hunkhead', or 'filenames' |
253 | end | 283 | end |
254 | local advance | 284 | local advance: boolean |
255 | if state == 'filenames' then | 285 | if state == 'filenames' then |
256 | if startswith(line, "--- ") then | 286 | if startswith(line, "--- ") then |
257 | if files.source[nextfileno] then | 287 | if files.source[nextfileno] then |
258 | all_ok = false | 288 | all_ok = false |
259 | warning(format("skipping invalid patch for %s", | 289 | warning(string.format("skipping invalid patch for %s", |
260 | files.source[nextfileno+1])) | 290 | files.source[nextfileno+1])) |
261 | table.remove(files.source, nextfileno+1) | 291 | table.remove(files.source, nextfileno+1) |
262 | -- double source filename line is encountered | 292 | -- double source filename line is encountered |
@@ -268,7 +298,7 @@ function patch.read_patch(filename, data) | |||
268 | local match, rest = line:match("^%-%-%- ([^ \t\r\n]+)(.*)") | 298 | local match, rest = line:match("^%-%-%- ([^ \t\r\n]+)(.*)") |
269 | if not match then | 299 | if not match then |
270 | all_ok = false | 300 | all_ok = false |
271 | warning(format("skipping invalid filename at line %d", lineno+1)) | 301 | warning(string.format("skipping invalid filename at line %d", lineno+1)) |
272 | state = 'header' | 302 | state = 'header' |
273 | else | 303 | else |
274 | if match_epoch(rest) then | 304 | if match_epoch(rest) then |
@@ -279,7 +309,7 @@ function patch.read_patch(filename, data) | |||
279 | elseif not startswith(line, "+++ ") then | 309 | elseif not startswith(line, "+++ ") then |
280 | if files.source[nextfileno] then | 310 | if files.source[nextfileno] then |
281 | all_ok = false | 311 | all_ok = false |
282 | warning(format("skipping invalid patch with no target for %s", | 312 | warning(string.format("skipping invalid patch with no target for %s", |
283 | files.source[nextfileno+1])) | 313 | files.source[nextfileno+1])) |
284 | table.remove(files.source, nextfileno+1) | 314 | table.remove(files.source, nextfileno+1) |
285 | else | 315 | else |
@@ -290,7 +320,7 @@ function patch.read_patch(filename, data) | |||
290 | else | 320 | else |
291 | if files.target[nextfileno] then | 321 | if files.target[nextfileno] then |
292 | all_ok = false | 322 | all_ok = false |
293 | warning(format("skipping invalid patch - double target at line %d", | 323 | warning(string.format("skipping invalid patch - double target at line %d", |
294 | lineno+1)) | 324 | lineno+1)) |
295 | table.remove(files.source, nextfileno+1) | 325 | table.remove(files.source, nextfileno+1) |
296 | table.remove(files.target, nextfileno+1) | 326 | table.remove(files.target, nextfileno+1) |
@@ -306,7 +336,7 @@ function patch.read_patch(filename, data) | |||
306 | local match, rest = line:match(re_filename) | 336 | local match, rest = line:match(re_filename) |
307 | if not match then | 337 | if not match then |
308 | all_ok = false | 338 | all_ok = false |
309 | warning(format( | 339 | warning(string.format( |
310 | "skipping invalid patch - no target filename at line %d", | 340 | "skipping invalid patch - no target filename at line %d", |
311 | lineno+1)) | 341 | lineno+1)) |
312 | state = 'header' | 342 | state = 'header' |
@@ -318,8 +348,8 @@ function patch.read_patch(filename, data) | |||
318 | end | 348 | end |
319 | nexthunkno = 0 | 349 | nexthunkno = 0 |
320 | table.insert(files.hunks, {}) | 350 | table.insert(files.hunks, {}) |
321 | table.insert(files.hunkends, table_copy(lineends)) | 351 | table.insert(files.hunkends, table_copy(lineends as {any: any}) as Lineends) |
322 | table.insert(files.fileends, table_copy(lineends)) | 352 | table.insert(files.fileends, table_copy(lineends as {any: any}) as Lineends) |
323 | state = 'hunkhead' | 353 | state = 'hunkhead' |
324 | advance = true | 354 | advance = true |
325 | end | 355 | end |
@@ -330,17 +360,17 @@ function patch.read_patch(filename, data) | |||
330 | if not advance and state == 'hunkhead' then | 360 | if not advance and state == 'hunkhead' then |
331 | local m1, m2, m3, m4 = match_linerange(line) | 361 | local m1, m2, m3, m4 = match_linerange(line) |
332 | if not m1 then | 362 | if not m1 then |
333 | if not files.hunks[nextfileno-1] then | 363 | if not files.hunks[nextfileno - 1] then |
334 | all_ok = false | 364 | all_ok = false |
335 | warning(format("skipping invalid patch with no hunks for file %s", | 365 | warning(string.format("skipping invalid patch with no hunks for file %s", |
336 | files.target[nextfileno])) | 366 | files.target[nextfileno])) |
337 | end | 367 | end |
338 | state = 'header' | 368 | state = 'header' |
339 | else | 369 | else |
340 | hunkinfo.startsrc = tonumber(m1) | 370 | hunkinfo.startsrc = math.tointeger(m1) |
341 | hunkinfo.linessrc = tonumber(m2 or 1) | 371 | hunkinfo.linessrc = math.tointeger(m2) or 1 |
342 | hunkinfo.starttgt = tonumber(m3) | 372 | hunkinfo.starttgt = math.tointeger(m3) |
343 | hunkinfo.linestgt = tonumber(m4 or 1) | 373 | hunkinfo.linestgt = math.tointeger(m4) or 1 |
344 | hunkinfo.invalid = false | 374 | hunkinfo.invalid = false |
345 | hunkinfo.text = {} | 375 | hunkinfo.text = {} |
346 | 376 | ||
@@ -354,24 +384,24 @@ function patch.read_patch(filename, data) | |||
354 | end | 384 | end |
355 | end | 385 | end |
356 | if state ~= 'hunkskip' then | 386 | if state ~= 'hunkskip' then |
357 | warning(format("patch file incomplete - %s", filename)) | 387 | warning(string.format("patch file incomplete - %s", filename)) |
358 | all_ok = false | 388 | all_ok = false |
359 | -- os.exit(?) | 389 | -- os.exit(?) |
360 | else | 390 | else |
361 | -- duplicated message when an eof is reached | 391 | -- duplicated message when an eof is reached |
362 | if debugmode and #files.source > 0 then | 392 | if debugmode and #files.source > 0 then |
363 | debug(format("- %2d hunks for %s", #files.hunks[nextfileno], | 393 | debug(string.format("- %2d hunks for %s", #files.hunks[nextfileno], |
364 | files.source[nextfileno])) | 394 | files.source[nextfileno])) |
365 | end | 395 | end |
366 | end | 396 | end |
367 | 397 | ||
368 | local sum = 0; for _,hset in ipairs(files.hunks) do sum = sum + #hset end | 398 | local sum = 0; for _,hset in ipairs(files.hunks) do sum = sum + #hset end |
369 | info(format("total files: %d total hunks: %d", #files.source, sum)) | 399 | info(string.format("total files: %d total hunks: %d", #files.source, sum)) |
370 | fp:close() | 400 | fp:close() |
371 | return files, all_ok | 401 | return files, all_ok |
372 | end | 402 | end |
373 | 403 | ||
374 | local function find_hunk(file, h, hno) | 404 | local function find_hunk(file: {string}, h: Hunk, hno: integer): boolean |
375 | for fuzz=0,2 do | 405 | for fuzz=0,2 do |
376 | local lineno = h.startsrc | 406 | local lineno = h.startsrc |
377 | for i=0,#file do | 407 | for i=0,#file do |
@@ -381,7 +411,7 @@ local function find_hunk(file, h, hno) | |||
381 | if l > fuzz then | 411 | if l > fuzz then |
382 | -- todo: \ No newline at the end of file | 412 | -- todo: \ No newline at the end of file |
383 | if startswith(hline, " ") or startswith(hline, "-") then | 413 | if startswith(hline, " ") or startswith(hline, "-") then |
384 | local line = file[lineno] | 414 | local line = file[lineno] --! cast |
385 | lineno = lineno + 1 | 415 | lineno = lineno + 1 |
386 | if not line or #line == 0 then | 416 | if not line or #line == 0 then |
387 | found = false | 417 | found = false |
@@ -397,7 +427,7 @@ local function find_hunk(file, h, hno) | |||
397 | if found then | 427 | if found then |
398 | local offset = location - h.startsrc - fuzz | 428 | local offset = location - h.startsrc - fuzz |
399 | if offset ~= 0 then | 429 | if offset ~= 0 then |
400 | warning(format("Hunk %d found at offset %d%s...", hno, offset, fuzz == 0 and "" or format(" (fuzz %d)", fuzz))) | 430 | warning(string.format("Hunk %d found at offset %d%s...", hno, offset, fuzz == 0 and "" or string.format(" (fuzz %d)", fuzz))) |
401 | end | 431 | end |
402 | h.startsrc = location | 432 | h.startsrc = location |
403 | h.starttgt = h.starttgt + offset | 433 | h.starttgt = h.starttgt + offset |
@@ -413,8 +443,8 @@ local function find_hunk(file, h, hno) | |||
413 | return false | 443 | return false |
414 | end | 444 | end |
415 | 445 | ||
416 | local function load_file(filename) | 446 | local function load_file(filename: string): {string} |
417 | local fp = assert(io.open(filename)) | 447 | local fp = assert(io.open(filename) as (FILE, string)) --! cast |
418 | local file = {} | 448 | local file = {} |
419 | local readline = file_lines(fp) | 449 | local readline = file_lines(fp) |
420 | while true do | 450 | while true do |
@@ -426,15 +456,15 @@ local function load_file(filename) | |||
426 | return file | 456 | return file |
427 | end | 457 | end |
428 | 458 | ||
429 | local function find_hunks(file, hunks) | 459 | local function find_hunks(file: {string}, hunks: {Hunk}) |
430 | for hno, h in ipairs(hunks) do | 460 | for hno, h in ipairs(hunks) do |
431 | find_hunk(file, h, hno) | 461 | find_hunk(file, h, hno) |
432 | end | 462 | end |
433 | end | 463 | end |
434 | 464 | ||
435 | local function check_patched(file, hunks) | 465 | local function check_patched(file: {string}, hunks: {Hunk}): boolean |
436 | local lineno = 1 | 466 | local lineno: integer = 1 |
437 | local ok, err = pcall(function() | 467 | local _, err: boolean, string = pcall(function() |
438 | if #file == 0 then | 468 | if #file == 0 then |
439 | error('nomatch', 0) | 469 | error('nomatch', 0) |
440 | end | 470 | end |
@@ -443,7 +473,7 @@ local function check_patched(file, hunks) | |||
443 | if #file < h.starttgt then | 473 | if #file < h.starttgt then |
444 | error('nomatch', 0) | 474 | error('nomatch', 0) |
445 | end | 475 | end |
446 | lineno = h.starttgt | 476 | lineno = h.starttgt as integer --! cast |
447 | for _, hline in ipairs(h.text) do | 477 | for _, hline in ipairs(h.text) do |
448 | -- todo: \ No newline at the end of file | 478 | -- todo: \ No newline at the end of file |
449 | if not startswith(hline, "-") and not startswith(hline, "\\") then | 479 | if not startswith(hline, "-") and not startswith(hline, "\\") then |
@@ -453,7 +483,7 @@ local function check_patched(file, hunks) | |||
453 | error('nomatch', 0) | 483 | error('nomatch', 0) |
454 | end | 484 | end |
455 | if endlstrip(line) ~= endlstrip(hline:sub(2)) then | 485 | if endlstrip(line) ~= endlstrip(hline:sub(2)) then |
456 | warning(format("file is not patched - failed hunk: %d", hno)) | 486 | warning(string.format("file is not patched - failed hunk: %d", hno)) |
457 | error('nomatch', 0) | 487 | error('nomatch', 0) |
458 | end | 488 | end |
459 | end | 489 | end |
@@ -464,9 +494,9 @@ local function check_patched(file, hunks) | |||
464 | return err ~= 'nomatch' | 494 | return err ~= 'nomatch' |
465 | end | 495 | end |
466 | 496 | ||
467 | local function patch_hunks(srcname, tgtname, hunks) | 497 | local function patch_hunks(srcname: string, tgtname: string, hunks: {Hunk}): boolean |
468 | local src = assert(io.open(srcname, "rb")) | 498 | local src = assert(io.open(srcname, "rb") as (FILE, string)) --! cast |
469 | local tgt = assert(io.open(tgtname, "wb")) | 499 | local tgt = assert(io.open(tgtname, "wb") as (FILE, string)) --! cast |
470 | 500 | ||
471 | local src_readline = file_lines(src) | 501 | local src_readline = file_lines(src) |
472 | 502 | ||
@@ -479,7 +509,7 @@ local function patch_hunks(srcname, tgtname, hunks) | |||
479 | local srclineno = 1 | 509 | local srclineno = 1 |
480 | local lineends = {['\n']=0, ['\r\n']=0, ['\r']=0} | 510 | local lineends = {['\n']=0, ['\r\n']=0, ['\r']=0} |
481 | for hno, h in ipairs(hunks) do | 511 | for hno, h in ipairs(hunks) do |
482 | debug(format("processing hunk %d for file %s", hno, tgtname)) | 512 | debug(string.format("processing hunk %d for file %s", hno, tgtname)) |
483 | -- skip to line just before hunk starts | 513 | -- skip to line just before hunk starts |
484 | while srclineno < h.startsrc do | 514 | while srclineno < h.startsrc do |
485 | local line = src_readline() | 515 | local line = src_readline() |
@@ -508,10 +538,10 @@ local function patch_hunks(srcname, tgtname, hunks) | |||
508 | local line2write = hline:sub(2) | 538 | local line2write = hline:sub(2) |
509 | -- detect if line ends are consistent in source file | 539 | -- detect if line ends are consistent in source file |
510 | local sum = 0 | 540 | local sum = 0 |
511 | for _,v in pairs(lineends) do if v > 0 then sum=sum+1 end end | 541 | for _,v in pairs(lineends as {string:any}) do if v as integer > 0 then sum=sum+1 end end --! unchecked |
512 | if sum == 1 then | 542 | if sum == 1 then |
513 | local newline | 543 | local newline: string |
514 | for k,v in pairs(lineends) do if v ~= 0 then newline = k end end | 544 | for k,v in pairs(lineends as {string:any}) do if v ~= 0 then newline = k end end |
515 | tgt:write(endlstrip(line2write) .. newline) | 545 | tgt:write(endlstrip(line2write) .. newline) |
516 | else -- newlines are mixed or unknown | 546 | else -- newlines are mixed or unknown |
517 | tgt:write(line2write) | 547 | tgt:write(line2write) |
@@ -527,7 +557,7 @@ local function patch_hunks(srcname, tgtname, hunks) | |||
527 | return true | 557 | return true |
528 | end | 558 | end |
529 | 559 | ||
530 | local function strip_dirs(filename, strip) | 560 | local function strip_dirs(filename: string, strip: integer): string |
531 | if strip == nil then return filename end | 561 | if strip == nil then return filename end |
532 | for _=1,strip do | 562 | for _=1,strip do |
533 | filename=filename:gsub("^[^/]*/", "") | 563 | filename=filename:gsub("^[^/]*/", "") |
@@ -535,7 +565,7 @@ local function strip_dirs(filename, strip) | |||
535 | return filename | 565 | return filename |
536 | end | 566 | end |
537 | 567 | ||
538 | local function write_new_file(filename, hunk) | 568 | local function write_new_file(filename: string, hunk: Hunk): boolean, string |
539 | local fh = io.open(filename, "wb") | 569 | local fh = io.open(filename, "wb") |
540 | if not fh then return false end | 570 | if not fh then return false end |
541 | for _, hline in ipairs(hunk.text) do | 571 | for _, hline in ipairs(hunk.text) do |
@@ -549,12 +579,12 @@ local function write_new_file(filename, hunk) | |||
549 | return true | 579 | return true |
550 | end | 580 | end |
551 | 581 | ||
552 | local function patch_file(source, target, epoch, hunks, strip, create_delete) | 582 | local function patch_file(source: string, target: string, epoch: boolean, hunks: {Hunk}, strip: integer, create_delete: boolean): boolean, string |
553 | local create_file = false | 583 | local create_file = false |
554 | if create_delete then | 584 | if create_delete then |
555 | local is_src_epoch = epoch and #hunks == 1 and hunks[1].startsrc == 0 and hunks[1].linessrc == 0 | 585 | local is_src_epoch = epoch and #hunks == 1 and hunks[1].startsrc == 0 and hunks[1].linessrc == 0 |
556 | if is_src_epoch or source == "/dev/null" then | 586 | if is_src_epoch or source == "/dev/null" then |
557 | info(format("will create %s", target)) | 587 | info(string.format("will create %s", target)) |
558 | create_file = true | 588 | create_file = true |
559 | end | 589 | end |
560 | end | 590 | end |
@@ -567,13 +597,14 @@ local function patch_file(source, target, epoch, hunks, strip, create_delete) | |||
567 | f2patch = strip_dirs(target, strip) | 597 | f2patch = strip_dirs(target, strip) |
568 | f2patch = fs.absolute_name(f2patch) | 598 | f2patch = fs.absolute_name(f2patch) |
569 | if not exists(f2patch) then --FIX:if f2patch nil | 599 | if not exists(f2patch) then --FIX:if f2patch nil |
570 | warning(format("source/target file does not exist\n--- %s\n+++ %s", | 600 | warning(string.format("source/target file does not exist\n--- %s\n+++ %s", |
571 | source, f2patch)) | 601 | source, f2patch)) |
572 | return false | 602 | return false |
573 | end | 603 | end |
574 | end | 604 | end |
575 | if not isfile(f2patch) then | 605 | -- if not isfile(f2patch) then --! |
576 | warning(format("not a file - %s", f2patch)) | 606 | if not isfile() then --! |
607 | warning(string.format("not a file - %s", f2patch)) | ||
577 | return false | 608 | return false |
578 | end | 609 | end |
579 | 610 | ||
@@ -586,7 +617,7 @@ local function patch_file(source, target, epoch, hunks, strip, create_delete) | |||
586 | local hunkfind = {} | 617 | local hunkfind = {} |
587 | local validhunks = 0 | 618 | local validhunks = 0 |
588 | local canpatch = false | 619 | local canpatch = false |
589 | local hunklineno | 620 | local hunklineno: integer |
590 | if not file then | 621 | if not file then |
591 | return nil, "failed reading file " .. source | 622 | return nil, "failed reading file " .. source |
592 | end | 623 | end |
@@ -597,14 +628,14 @@ local function patch_file(source, target, epoch, hunks, strip, create_delete) | |||
597 | if not ok then | 628 | if not ok then |
598 | return false | 629 | return false |
599 | end | 630 | end |
600 | info(format("successfully removed %s", source)) | 631 | info(string.format("successfully removed %s", source)) |
601 | return true | 632 | return true |
602 | end | 633 | end |
603 | end | 634 | end |
604 | 635 | ||
605 | find_hunks(file, hunks) | 636 | find_hunks(file, hunks) |
606 | 637 | ||
607 | local function process_line(line, lineno) | 638 | local function process_line(line: string, lineno: integer): boolean |
608 | if not hunk or lineno < hunk.startsrc then | 639 | if not hunk or lineno < hunk.startsrc then |
609 | return false | 640 | return false |
610 | end | 641 | end |
@@ -624,7 +655,7 @@ local function patch_file(source, target, epoch, hunks, strip, create_delete) | |||
624 | if endlstrip(line) == hunkfind[hunklineno] then | 655 | if endlstrip(line) == hunkfind[hunklineno] then |
625 | hunklineno = hunklineno + 1 | 656 | hunklineno = hunklineno + 1 |
626 | else | 657 | else |
627 | debug(format("hunk no.%d doesn't match source file %s", | 658 | debug(string.format("hunk no.%d doesn't match source file %s", |
628 | hunkno, source)) | 659 | hunkno, source)) |
629 | -- file may be already patched, but check other hunks anyway | 660 | -- file may be already patched, but check other hunks anyway |
630 | hunkno = hunkno + 1 | 661 | hunkno = hunkno + 1 |
@@ -638,7 +669,7 @@ local function patch_file(source, target, epoch, hunks, strip, create_delete) | |||
638 | end | 669 | end |
639 | -- check if processed line is the last line | 670 | -- check if processed line is the last line |
640 | if lineno == hunk.startsrc + #hunkfind - 1 then | 671 | if lineno == hunk.startsrc + #hunkfind - 1 then |
641 | debug(format("file %s hunk no.%d -- is ready to be patched", | 672 | debug(string.format("file %s hunk no.%d -- is ready to be patched", |
642 | source, hunkno)) | 673 | source, hunkno)) |
643 | hunkno = hunkno + 1 | 674 | hunkno = hunkno + 1 |
644 | validhunks = validhunks + 1 | 675 | validhunks = validhunks + 1 |
@@ -664,16 +695,16 @@ local function patch_file(source, target, epoch, hunks, strip, create_delete) | |||
664 | end | 695 | end |
665 | if not done then | 696 | if not done then |
666 | if hunkno <= #hunks and not create_file then | 697 | if hunkno <= #hunks and not create_file then |
667 | warning(format("premature end of source file %s at hunk %d", | 698 | warning(string.format("premature end of source file %s at hunk %d", |
668 | source, hunkno)) | 699 | source, hunkno)) |
669 | return false | 700 | return false |
670 | end | 701 | end |
671 | end | 702 | end |
672 | if validhunks < #hunks then | 703 | if validhunks < #hunks then |
673 | if check_patched(file, hunks) then | 704 | if check_patched(file, hunks) then |
674 | warning(format("already patched %s", source)) | 705 | warning(string.format("already patched %s", source)) |
675 | elseif not create_file then | 706 | elseif not create_file then |
676 | warning(format("source file is different - %s", source)) | 707 | warning(string.format("source file is different - %s", source)) |
677 | return false | 708 | return false |
678 | end | 709 | end |
679 | end | 710 | end |
@@ -682,29 +713,29 @@ local function patch_file(source, target, epoch, hunks, strip, create_delete) | |||
682 | end | 713 | end |
683 | local backupname = source .. ".orig" | 714 | local backupname = source .. ".orig" |
684 | if exists(backupname) then | 715 | if exists(backupname) then |
685 | warning(format("can't backup original file to %s - aborting", | 716 | warning(string.format("can't backup original file to %s - aborting", |
686 | backupname)) | 717 | backupname)) |
687 | return false | 718 | return false |
688 | end | 719 | end |
689 | local ok = os.rename(source, backupname) | 720 | local ok = os.rename(source, backupname) |
690 | if not ok then | 721 | if not ok then |
691 | warning(format("failed backing up %s when patching", source)) | 722 | warning(string.format("failed backing up %s when patching", source)) |
692 | return false | 723 | return false |
693 | end | 724 | end |
694 | patch_hunks(backupname, source, hunks) | 725 | patch_hunks(backupname, source, hunks) |
695 | info(format("successfully patched %s", source)) | 726 | info(string.format("successfully patched %s", source)) |
696 | os.remove(backupname) | 727 | os.remove(backupname) |
697 | return true | 728 | return true |
698 | end | 729 | end |
699 | 730 | ||
700 | function patch.apply_patch(the_patch, strip, create_delete) | 731 | function patch.apply_patch(the_patch: Files, strip: integer, create_delete: boolean): boolean |
701 | local all_ok = true | 732 | local all_ok = true |
702 | local total = #the_patch.source | 733 | local total = #the_patch.source |
703 | for fileno, source in ipairs(the_patch.source) do | 734 | for fileno, source in ipairs(the_patch.source) do |
704 | local target = the_patch.target[fileno] | 735 | local target = the_patch.target[fileno] |
705 | local hunks = the_patch.hunks[fileno] | 736 | local hunks = the_patch.hunks[fileno] |
706 | local epoch = the_patch.epoch[fileno] | 737 | local epoch = the_patch.epoch[fileno] |
707 | info(format("processing %d/%d:\t %s", fileno, total, source)) | 738 | info(string.format("processing %d/%d:\t %s", fileno, total, source)) |
708 | local ok = patch_file(source, target, epoch, hunks, strip, create_delete) | 739 | local ok = patch_file(source, target, epoch, hunks, strip, create_delete) |
709 | all_ok = all_ok and ok | 740 | all_ok = all_ok and ok |
710 | end | 741 | end |