aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorV1K1NGbg <victor@ilchev.com>2024-08-03 14:49:25 +0300
committerV1K1NGbg <victor@ilchev.com>2024-08-05 20:51:31 +0300
commita22cc0d426e52254cca0ed623f1514b8391b48b3 (patch)
tree59c2894fe90b6f645c918d305693176e7c6288ee
parent3c2ab76e26c3cd4c863b7902cfd3f4424784d6b6 (diff)
downloadluarocks-a22cc0d426e52254cca0ed623f1514b8391b48b3.tar.gz
luarocks-a22cc0d426e52254cca0ed623f1514b8391b48b3.tar.bz2
luarocks-a22cc0d426e52254cca0ed623f1514b8391b48b3.zip
patch 2
-rw-r--r--src/luarocks/fs.d.tl2
-rw-r--r--src/luarocks/fun.tl2
-rw-r--r--src/luarocks/tools/patch.tl148
3 files changed, 79 insertions, 73 deletions
diff --git a/src/luarocks/fs.d.tl b/src/luarocks/fs.d.tl
index 17cf0517..a2218cd6 100644
--- a/src/luarocks/fs.d.tl
+++ b/src/luarocks/fs.d.tl
@@ -27,6 +27,8 @@ local record fs
27 Q: function(string): string 27 Q: function(string): string
28 download: function(string, string): boolean, string 28 download: function(string, string): boolean, string
29 set_permissions: function(string, string, string) 29 set_permissions: function(string, string, string)
30 -- patch
31 absolute_name: function(string, ?string): string
30end 32end
31 33
32return fs 34return fs
diff --git a/src/luarocks/fun.tl b/src/luarocks/fun.tl
index 16873dc2..e2d43d5d 100644
--- a/src/luarocks/fun.tl
+++ b/src/luarocks/fun.tl
@@ -16,7 +16,7 @@ function fun.concat<K>(xs: {K}, ys: {K}): {K}
16 return rs 16 return rs
17end 17end
18 18
19function fun.contains<K>(xs: {K}, v: K): boolean --? same logic as above fine? 19function fun.contains<K>(xs: {K}, v: any): boolean --? same logic as above fine?
20 for _, x in ipairs(xs) do 20 for _, x in ipairs(xs) do
21 if v == x then 21 if v == x then
22 return true 22 return true
diff --git a/src/luarocks/tools/patch.tl b/src/luarocks/tools/patch.tl
index 05b447da..bd6c3d63 100644
--- a/src/luarocks/tools/patch.tl
+++ b/src/luarocks/tools/patch.tl
@@ -14,7 +14,7 @@ local record patch
14 crlf: number 14 crlf: number
15 cr: number 15 cr: number
16 end 16 end
17 record Hunks 17 record Hunk
18 startsrc: number 18 startsrc: number
19 linessrc: number 19 linessrc: number
20 starttgt: number 20 starttgt: number
@@ -22,24 +22,27 @@ local record patch
22 invalid: boolean 22 invalid: boolean
23 text: {string} 23 text: {string}
24 end 24 end
25 record Files
26 source: {string | number} --!
27 target: {string | number}
28 epoch: {boolean}
29 hunks: {{Hunk}}
30 fileends: {Lineends}
31 hunkends: {Lineends}
32 end
25end 33end
26 34
27local fs = require("luarocks.fs") 35local fs = require("luarocks.fs")
28local fun = require("luarocks.fun") 36local fun = require("luarocks.fun")
29 37
30local type Lineends = patch.Lineends 38local type Lineends = patch.Lineends
31local type Hunks = patch.Hunks 39local type Hunk = patch.Hunk
32 40local type Files = patch.Files
33-- local io = io
34-- local os = os
35-- local string = string
36-- local table = table
37-- local format = string.format
38 41
39-- logging 42-- logging
40local debugmode = false 43local debugmode = false
41local function debug(_) end --! 44local function debug(_: string) end --!
42local function info(_) end 45local function info(_: string) end
43local function warning(s: string) io.stderr:write(s .. '\n') end 46local function warning(s: string) io.stderr:write(s .. '\n') end
44 47
45-- Returns boolean whether string s2 starts with string s. 48-- Returns boolean whether string s2 starts with string s.
@@ -148,7 +151,7 @@ local function match_epoch(str: string): string
148 return str:match("[^0-9]1969[^0-9]") or str:match("[^0-9]1970[^0-9]") 151 return str:match("[^0-9]1969[^0-9]") or str:match("[^0-9]1970[^0-9]")
149end 152end
150 153
151function patch.read_patch(filename: string, data: string) 154function patch.read_patch(filename: string, data: string): Files, boolean
152 -- define possible file regions that will direct the parser flow 155 -- define possible file regions that will direct the parser flow
153 local state = 'header' 156 local state = 'header'
154 -- 'header' - comments before the patch body 157 -- 'header' - comments before the patch body
@@ -159,17 +162,17 @@ function patch.read_patch(filename: string, data: string)
159 162
160 local all_ok = true 163 local all_ok = true
161 local lineends: Lineends = {lf=0, crlf=0, cr=0} 164 local lineends: Lineends = {lf=0, crlf=0, cr=0}
162 local files = {source={}, target={}, epoch={}, hunks: {{Hunks}}={}, fileends={}, hunkends: {Lineends}={}} 165 local files: Files = {source={}, target={}, epoch={}, hunks: {{Hunk}}={}, fileends={}, hunkends: {Lineends}={}}
163 local nextfileno = 0 166 local nextfileno = 0
164 local nexthunkno = 0 --: even if index starts with 0 user messages 167 local nexthunkno = 0 --: even if index starts with 0 user messages
165 -- number hunks from 1 168 -- number hunks from 1
166 169
167 -- hunkinfo holds parsed values, hunkactual - calculated 170 -- hunkinfo holds parsed values, hunkactual - calculated
168 local hunkinfo: Hunks = { 171 local hunkinfo: Hunk = {
169 startsrc=nil, linessrc=nil, starttgt=nil, linestgt=nil, 172 startsrc=nil, linessrc=nil, starttgt=nil, linestgt=nil,
170 invalid=false, text={} 173 invalid=false, text={}
171 } 174 }
172 local hunkactual: Hunks = {linessrc=nil, linestgt=nil} 175 local hunkactual: Hunk = {linessrc=nil, linestgt=nil}
173 176
174 info(string.format("reading patch %s", filename)) --! 177 info(string.format("reading patch %s", filename)) --!
175 178
@@ -224,7 +227,7 @@ function patch.read_patch(filename: string, data: string)
224 warning(string.format("invalid hunk no.%d at %d for target file %s", 227 warning(string.format("invalid hunk no.%d at %d for target file %s",
225 nexthunkno, lineno, files.target[nextfileno])) 228 nexthunkno, lineno, files.target[nextfileno]))
226 -- add hunk status node 229 -- add hunk status node
227 table.insert(files.hunks[nextfileno], table_copy(hunkinfo)) --! cast 230 table.insert(files.hunks[nextfileno], table_copy(hunkinfo as {any: any}) as Hunk)
228 files.hunks[nextfileno][nexthunkno].invalid = true 231 files.hunks[nextfileno][nexthunkno].invalid = true
229 all_ok = false 232 all_ok = false
230 state = 'hunkskip' 233 state = 'hunkskip'
@@ -237,13 +240,13 @@ function patch.read_patch(filename: string, data: string)
237 warning(string.format("extra hunk no.%d lines at %d for target %s", 240 warning(string.format("extra hunk no.%d lines at %d for target %s",
238 nexthunkno, lineno, files.target[nextfileno])) 241 nexthunkno, lineno, files.target[nextfileno]))
239 -- add hunk status node 242 -- add hunk status node
240 table.insert(files.hunks[nextfileno], table_copy(hunkinfo)) 243 table.insert(files.hunks[nextfileno], table_copy(hunkinfo as {any: any}) as Hunk)
241 files.hunks[nextfileno][nexthunkno].invalid = true 244 files.hunks[nextfileno][nexthunkno].invalid = true
242 state = 'hunkskip' 245 state = 'hunkskip'
243 elseif hunkinfo.linessrc == hunkactual.linessrc and 246 elseif hunkinfo.linessrc == hunkactual.linessrc and
244 hunkinfo.linestgt == hunkactual.linestgt 247 hunkinfo.linestgt == hunkactual.linestgt
245 then 248 then
246 table.insert(files.hunks[nextfileno], table_copy(hunkinfo)) 249 table.insert(files.hunks[nextfileno], table_copy(hunkinfo as {any: any}) as Hunk)
247 state = 'hunkskip' 250 state = 'hunkskip'
248 251
249 -- detect mixed window/unix line ends 252 -- detect mixed window/unix line ends
@@ -264,18 +267,18 @@ function patch.read_patch(filename: string, data: string)
264 elseif startswith(line, "--- ") then 267 elseif startswith(line, "--- ") then
265 state = 'filenames' 268 state = 'filenames'
266 if debugmode and #files.source > 0 then 269 if debugmode and #files.source > 0 then
267 debug(format("- %2d hunks for %s", #files.hunks[nextfileno], 270 debug(string.format("- %2d hunks for %s", #files.hunks[nextfileno],
268 files.source[nextfileno])) 271 files.source[nextfileno]))
269 end 272 end
270 end 273 end
271 -- state is 'hunkskip', 'hunkhead', or 'filenames' 274 -- state is 'hunkskip', 'hunkhead', or 'filenames'
272 end 275 end
273 local advance 276 local advance: boolean
274 if state == 'filenames' then 277 if state == 'filenames' then
275 if startswith(line, "--- ") then 278 if startswith(line, "--- ") then
276 if fun.contains(files.source, nextfileno) then 279 if fun.contains(files.source, nextfileno) then
277 all_ok = false 280 all_ok = false
278 warning(format("skipping invalid patch for %s", 281 warning(string.format("skipping invalid patch for %s",
279 files.source[nextfileno+1])) 282 files.source[nextfileno+1]))
280 table.remove(files.source, nextfileno+1) 283 table.remove(files.source, nextfileno+1)
281 -- double source filename line is encountered 284 -- double source filename line is encountered
@@ -287,7 +290,7 @@ function patch.read_patch(filename: string, data: string)
287 local match, rest = line:match("^%-%-%- ([^ \t\r\n]+)(.*)") 290 local match, rest = line:match("^%-%-%- ([^ \t\r\n]+)(.*)")
288 if not match then 291 if not match then
289 all_ok = false 292 all_ok = false
290 warning(format("skipping invalid filename at line %d", lineno+1)) 293 warning(string.format("skipping invalid filename at line %d", lineno+1))
291 state = 'header' 294 state = 'header'
292 else 295 else
293 if match_epoch(rest) then 296 if match_epoch(rest) then
@@ -298,7 +301,7 @@ function patch.read_patch(filename: string, data: string)
298 elseif not startswith(line, "+++ ") then 301 elseif not startswith(line, "+++ ") then
299 if fun.contains(files.source, nextfileno) then 302 if fun.contains(files.source, nextfileno) then
300 all_ok = false 303 all_ok = false
301 warning(format("skipping invalid patch with no target for %s", 304 warning(string.format("skipping invalid patch with no target for %s",
302 files.source[nextfileno+1])) 305 files.source[nextfileno+1]))
303 table.remove(files.source, nextfileno+1) 306 table.remove(files.source, nextfileno+1)
304 else 307 else
@@ -309,7 +312,7 @@ function patch.read_patch(filename: string, data: string)
309 else 312 else
310 if fun.contains(files.target, nextfileno) then 313 if fun.contains(files.target, nextfileno) then
311 all_ok = false 314 all_ok = false
312 warning(format("skipping invalid patch - double target at line %d", 315 warning(string.format("skipping invalid patch - double target at line %d",
313 lineno+1)) 316 lineno+1))
314 table.remove(files.source, nextfileno+1) 317 table.remove(files.source, nextfileno+1)
315 table.remove(files.target, nextfileno+1) 318 table.remove(files.target, nextfileno+1)
@@ -325,7 +328,7 @@ function patch.read_patch(filename: string, data: string)
325 local match, rest = line:match(re_filename) 328 local match, rest = line:match(re_filename)
326 if not match then 329 if not match then
327 all_ok = false 330 all_ok = false
328 warning(format( 331 warning(string.format(
329 "skipping invalid patch - no target filename at line %d", 332 "skipping invalid patch - no target filename at line %d",
330 lineno+1)) 333 lineno+1))
331 state = 'header' 334 state = 'header'
@@ -337,8 +340,8 @@ function patch.read_patch(filename: string, data: string)
337 end 340 end
338 nexthunkno = 0 341 nexthunkno = 0
339 table.insert(files.hunks, {}) 342 table.insert(files.hunks, {})
340 table.insert(files.hunkends, table_copy(lineends)) 343 table.insert(files.hunkends, table_copy(lineends as {any: any}) as Lineends)
341 table.insert(files.fileends, table_copy(lineends)) 344 table.insert(files.fileends, table_copy(lineends as {any: any}) as Lineends)
342 state = 'hunkhead' 345 state = 'hunkhead'
343 advance = true 346 advance = true
344 end 347 end
@@ -349,17 +352,17 @@ function patch.read_patch(filename: string, data: string)
349 if not advance and state == 'hunkhead' then 352 if not advance and state == 'hunkhead' then
350 local m1, m2, m3, m4 = match_linerange(line) 353 local m1, m2, m3, m4 = match_linerange(line)
351 if not m1 then 354 if not m1 then
352 if not fun.contains(files.hunks, nextfileno-1) then 355 if not fun.contains(files.hunks, nextfileno-1) then --!
353 all_ok = false 356 all_ok = false
354 warning(format("skipping invalid patch with no hunks for file %s", 357 warning(string.format("skipping invalid patch with no hunks for file %s",
355 files.target[nextfileno])) 358 files.target[nextfileno]))
356 end 359 end
357 state = 'header' 360 state = 'header'
358 else 361 else
359 hunkinfo.startsrc = tonumber(m1) 362 hunkinfo.startsrc = tonumber(m1)
360 hunkinfo.linessrc = tonumber(m2 or 1) 363 hunkinfo.linessrc = tonumber(tonumber(m2) or 1) --!
361 hunkinfo.starttgt = tonumber(m3) 364 hunkinfo.starttgt = tonumber(m3)
362 hunkinfo.linestgt = tonumber(m4 or 1) 365 hunkinfo.linestgt = tonumber(tonumber(m4) or 1)
363 hunkinfo.invalid = false 366 hunkinfo.invalid = false
364 hunkinfo.text = {} 367 hunkinfo.text = {}
365 368
@@ -373,24 +376,24 @@ function patch.read_patch(filename: string, data: string)
373 end 376 end
374 end 377 end
375 if state ~= 'hunkskip' then 378 if state ~= 'hunkskip' then
376 warning(format("patch file incomplete - %s", filename)) 379 warning(string.format("patch file incomplete - %s", filename))
377 all_ok = false 380 all_ok = false
378 -- os.exit(?) 381 -- os.exit(?)
379 else 382 else
380 -- duplicated message when an eof is reached 383 -- duplicated message when an eof is reached
381 if debugmode and #files.source > 0 then 384 if debugmode and #files.source > 0 then
382 debug(format("- %2d hunks for %s", #files.hunks[nextfileno], 385 debug(string.format("- %2d hunks for %s", #files.hunks[nextfileno],
383 files.source[nextfileno])) 386 files.source[nextfileno]))
384 end 387 end
385 end 388 end
386 389
387 local sum = 0; for _,hset in ipairs(files.hunks) do sum = sum + #hset end 390 local sum = 0; for _,hset in ipairs(files.hunks) do sum = sum + #hset end
388 info(format("total files: %d total hunks: %d", #files.source, sum)) 391 info(string.format("total files: %d total hunks: %d", #files.source, sum))
389 fp:close() 392 fp:close()
390 return files, all_ok 393 return files, all_ok
391end 394end
392 395
393local function find_hunk(file, h, hno) 396local function find_hunk(file: {string}, h: Hunk, hno: number): boolean
394 for fuzz=0,2 do 397 for fuzz=0,2 do
395 local lineno = h.startsrc 398 local lineno = h.startsrc
396 for i=0,#file do 399 for i=0,#file do
@@ -400,7 +403,7 @@ local function find_hunk(file, h, hno)
400 if l > fuzz then 403 if l > fuzz then
401 -- todo: \ No newline at the end of file 404 -- todo: \ No newline at the end of file
402 if startswith(hline, " ") or startswith(hline, "-") then 405 if startswith(hline, " ") or startswith(hline, "-") then
403 local line = file[lineno] 406 local line = file[lineno as integer] --! cast
404 lineno = lineno + 1 407 lineno = lineno + 1
405 if not line or #line == 0 then 408 if not line or #line == 0 then
406 found = false 409 found = false
@@ -416,7 +419,7 @@ local function find_hunk(file, h, hno)
416 if found then 419 if found then
417 local offset = location - h.startsrc - fuzz 420 local offset = location - h.startsrc - fuzz
418 if offset ~= 0 then 421 if offset ~= 0 then
419 warning(format("Hunk %d found at offset %d%s...", hno, offset, fuzz == 0 and "" or format(" (fuzz %d)", fuzz))) 422 warning(string.format("Hunk %d found at offset %d%s...", hno, offset, fuzz == 0 and "" or string.format(" (fuzz %d)", fuzz)))
420 end 423 end
421 h.startsrc = location 424 h.startsrc = location
422 h.starttgt = h.starttgt + offset 425 h.starttgt = h.starttgt + offset
@@ -432,8 +435,8 @@ local function find_hunk(file, h, hno)
432 return false 435 return false
433end 436end
434 437
435local function load_file(filename) 438local function load_file(filename: string): {string}
436 local fp = assert(io.open(filename)) 439 local fp = assert(io.open(filename) as (FILE, string)) --! cast
437 local file = {} 440 local file = {}
438 local readline = file_lines(fp) 441 local readline = file_lines(fp)
439 while true do 442 while true do
@@ -445,15 +448,15 @@ local function load_file(filename)
445 return file 448 return file
446end 449end
447 450
448local function find_hunks(file, hunks) 451local function find_hunks(file: {string}, hunks: {Hunk})
449 for hno, h in ipairs(hunks) do 452 for hno, h in ipairs(hunks) do
450 find_hunk(file, h, hno) 453 find_hunk(file, h, hno)
451 end 454 end
452end 455end
453 456
454local function check_patched(file, hunks) 457local function check_patched(file: {string}, hunks: {Hunk}): boolean
455 local lineno = 1 458 local lineno: integer = 1
456 local ok, err = pcall(function() 459 local ok, err: boolean, string = pcall(function()
457 if #file == 0 then 460 if #file == 0 then
458 error('nomatch', 0) 461 error('nomatch', 0)
459 end 462 end
@@ -462,7 +465,7 @@ local function check_patched(file, hunks)
462 if #file < h.starttgt then 465 if #file < h.starttgt then
463 error('nomatch', 0) 466 error('nomatch', 0)
464 end 467 end
465 lineno = h.starttgt 468 lineno = h.starttgt as integer --! cast
466 for _, hline in ipairs(h.text) do 469 for _, hline in ipairs(h.text) do
467 -- todo: \ No newline at the end of file 470 -- todo: \ No newline at the end of file
468 if not startswith(hline, "-") and not startswith(hline, "\\") then 471 if not startswith(hline, "-") and not startswith(hline, "\\") then
@@ -472,7 +475,7 @@ local function check_patched(file, hunks)
472 error('nomatch', 0) 475 error('nomatch', 0)
473 end 476 end
474 if endlstrip(line) ~= endlstrip(hline:sub(2)) then 477 if endlstrip(line) ~= endlstrip(hline:sub(2)) then
475 warning(format("file is not patched - failed hunk: %d", hno)) 478 warning(string.format("file is not patched - failed hunk: %d", hno))
476 error('nomatch', 0) 479 error('nomatch', 0)
477 end 480 end
478 end 481 end
@@ -483,9 +486,9 @@ local function check_patched(file, hunks)
483 return err ~= 'nomatch' 486 return err ~= 'nomatch'
484end 487end
485 488
486local function patch_hunks(srcname, tgtname, hunks) 489local function patch_hunks(srcname: string, tgtname: string, hunks: {Hunk}): boolean
487 local src = assert(io.open(srcname, "rb")) 490 local src = assert(io.open(srcname, "rb") as (FILE, string)) --! cast
488 local tgt = assert(io.open(tgtname, "wb")) 491 local tgt = assert(io.open(tgtname, "wb") as (FILE, string)) --! cast
489 492
490 local src_readline = file_lines(src) 493 local src_readline = file_lines(src)
491 494
@@ -498,7 +501,7 @@ local function patch_hunks(srcname, tgtname, hunks)
498 local srclineno = 1 501 local srclineno = 1
499 local lineends = {['\n']=0, ['\r\n']=0, ['\r']=0} 502 local lineends = {['\n']=0, ['\r\n']=0, ['\r']=0}
500 for hno, h in ipairs(hunks) do 503 for hno, h in ipairs(hunks) do
501 debug(format("processing hunk %d for file %s", hno, tgtname)) 504 debug(string.format("processing hunk %d for file %s", hno, tgtname))
502 -- skip to line just before hunk starts 505 -- skip to line just before hunk starts
503 while srclineno < h.startsrc do 506 while srclineno < h.startsrc do
504 local line = src_readline() 507 local line = src_readline()
@@ -527,10 +530,10 @@ local function patch_hunks(srcname, tgtname, hunks)
527 local line2write = hline:sub(2) 530 local line2write = hline:sub(2)
528 -- detect if line ends are consistent in source file 531 -- detect if line ends are consistent in source file
529 local sum = 0 532 local sum = 0
530 for _,v in pairs(lineends) do if v > 0 then sum=sum+1 end end 533 for _,v in pairs(lineends as {string:any}) do if v as integer > 0 then sum=sum+1 end end --! unchecked
531 if sum == 1 then 534 if sum == 1 then
532 local newline 535 local newline: string
533 for k,v in pairs(lineends) do if v ~= 0 then newline = k end end 536 for k,v in pairs(lineends as {string:any}) do if v ~= 0 then newline = k end end
534 tgt:write(endlstrip(line2write) .. newline) 537 tgt:write(endlstrip(line2write) .. newline)
535 else -- newlines are mixed or unknown 538 else -- newlines are mixed or unknown
536 tgt:write(line2write) 539 tgt:write(line2write)
@@ -546,7 +549,7 @@ local function patch_hunks(srcname, tgtname, hunks)
546 return true 549 return true
547end 550end
548 551
549local function strip_dirs(filename, strip) 552local function strip_dirs(filename: string, strip: integer): string
550 if strip == nil then return filename end 553 if strip == nil then return filename end
551 for _=1,strip do 554 for _=1,strip do
552 filename=filename:gsub("^[^/]*/", "") 555 filename=filename:gsub("^[^/]*/", "")
@@ -554,7 +557,7 @@ local function strip_dirs(filename, strip)
554 return filename 557 return filename
555end 558end
556 559
557local function write_new_file(filename, hunk) 560local function write_new_file(filename: string, hunk: Hunk): boolean, string
558 local fh = io.open(filename, "wb") 561 local fh = io.open(filename, "wb")
559 if not fh then return false end 562 if not fh then return false end
560 for _, hline in ipairs(hunk.text) do 563 for _, hline in ipairs(hunk.text) do
@@ -568,12 +571,12 @@ local function write_new_file(filename, hunk)
568 return true 571 return true
569end 572end
570 573
571local function patch_file(source, target, epoch, hunks, strip, create_delete) 574local function patch_file(source: string, target: string, epoch: boolean, hunks: {Hunk}, strip: integer, create_delete: boolean): boolean, string
572 local create_file = false 575 local create_file = false
573 if create_delete then 576 if create_delete then
574 local is_src_epoch = epoch and #hunks == 1 and hunks[1].startsrc == 0 and hunks[1].linessrc == 0 577 local is_src_epoch = epoch and #hunks == 1 and hunks[1].startsrc == 0 and hunks[1].linessrc == 0
575 if is_src_epoch or source == "/dev/null" then 578 if is_src_epoch or source == "/dev/null" then
576 info(format("will create %s", target)) 579 info(string.format("will create %s", target))
577 create_file = true 580 create_file = true
578 end 581 end
579 end 582 end
@@ -586,13 +589,14 @@ local function patch_file(source, target, epoch, hunks, strip, create_delete)
586 f2patch = strip_dirs(target, strip) 589 f2patch = strip_dirs(target, strip)
587 f2patch = fs.absolute_name(f2patch) 590 f2patch = fs.absolute_name(f2patch)
588 if not exists(f2patch) then --FIX:if f2patch nil 591 if not exists(f2patch) then --FIX:if f2patch nil
589 warning(format("source/target file does not exist\n--- %s\n+++ %s", 592 warning(string.format("source/target file does not exist\n--- %s\n+++ %s",
590 source, f2patch)) 593 source, f2patch))
591 return false 594 return false
592 end 595 end
593 end 596 end
594 if not isfile(f2patch) then 597 -- if not isfile(f2patch) then --!
595 warning(format("not a file - %s", f2patch)) 598 if not isfile() then --!
599 warning(string.format("not a file - %s", f2patch))
596 return false 600 return false
597 end 601 end
598 602
@@ -605,7 +609,7 @@ local function patch_file(source, target, epoch, hunks, strip, create_delete)
605 local hunkfind = {} 609 local hunkfind = {}
606 local validhunks = 0 610 local validhunks = 0
607 local canpatch = false 611 local canpatch = false
608 local hunklineno 612 local hunklineno: integer
609 if not file then 613 if not file then
610 return nil, "failed reading file " .. source 614 return nil, "failed reading file " .. source
611 end 615 end
@@ -616,14 +620,14 @@ local function patch_file(source, target, epoch, hunks, strip, create_delete)
616 if not ok then 620 if not ok then
617 return false 621 return false
618 end 622 end
619 info(format("successfully removed %s", source)) 623 info(string.format("successfully removed %s", source))
620 return true 624 return true
621 end 625 end
622 end 626 end
623 627
624 find_hunks(file, hunks) 628 find_hunks(file, hunks)
625 629
626 local function process_line(line, lineno) 630 local function process_line(line: string, lineno: number): boolean
627 if not hunk or lineno < hunk.startsrc then 631 if not hunk or lineno < hunk.startsrc then
628 return false 632 return false
629 end 633 end
@@ -643,7 +647,7 @@ local function patch_file(source, target, epoch, hunks, strip, create_delete)
643 if endlstrip(line) == hunkfind[hunklineno] then 647 if endlstrip(line) == hunkfind[hunklineno] then
644 hunklineno = hunklineno + 1 648 hunklineno = hunklineno + 1
645 else 649 else
646 debug(format("hunk no.%d doesn't match source file %s", 650 debug(string.format("hunk no.%d doesn't match source file %s",
647 hunkno, source)) 651 hunkno, source))
648 -- file may be already patched, but check other hunks anyway 652 -- file may be already patched, but check other hunks anyway
649 hunkno = hunkno + 1 653 hunkno = hunkno + 1
@@ -657,7 +661,7 @@ local function patch_file(source, target, epoch, hunks, strip, create_delete)
657 end 661 end
658 -- check if processed line is the last line 662 -- check if processed line is the last line
659 if lineno == hunk.startsrc + #hunkfind - 1 then 663 if lineno == hunk.startsrc + #hunkfind - 1 then
660 debug(format("file %s hunk no.%d -- is ready to be patched", 664 debug(string.format("file %s hunk no.%d -- is ready to be patched",
661 source, hunkno)) 665 source, hunkno))
662 hunkno = hunkno + 1 666 hunkno = hunkno + 1
663 validhunks = validhunks + 1 667 validhunks = validhunks + 1
@@ -683,16 +687,16 @@ local function patch_file(source, target, epoch, hunks, strip, create_delete)
683 end 687 end
684 if not done then 688 if not done then
685 if hunkno <= #hunks and not create_file then 689 if hunkno <= #hunks and not create_file then
686 warning(format("premature end of source file %s at hunk %d", 690 warning(string.format("premature end of source file %s at hunk %d",
687 source, hunkno)) 691 source, hunkno))
688 return false 692 return false
689 end 693 end
690 end 694 end
691 if validhunks < #hunks then 695 if validhunks < #hunks then
692 if check_patched(file, hunks) then 696 if check_patched(file, hunks) then
693 warning(format("already patched %s", source)) 697 warning(string.format("already patched %s", source))
694 elseif not create_file then 698 elseif not create_file then
695 warning(format("source file is different - %s", source)) 699 warning(string.format("source file is different - %s", source))
696 return false 700 return false
697 end 701 end
698 end 702 end
@@ -701,30 +705,30 @@ local function patch_file(source, target, epoch, hunks, strip, create_delete)
701 end 705 end
702 local backupname = source .. ".orig" 706 local backupname = source .. ".orig"
703 if exists(backupname) then 707 if exists(backupname) then
704 warning(format("can't backup original file to %s - aborting", 708 warning(string.format("can't backup original file to %s - aborting",
705 backupname)) 709 backupname))
706 return false 710 return false
707 end 711 end
708 local ok = os.rename(source, backupname) 712 local ok = os.rename(source, backupname)
709 if not ok then 713 if not ok then
710 warning(format("failed backing up %s when patching", source)) 714 warning(string.format("failed backing up %s when patching", source))
711 return false 715 return false
712 end 716 end
713 patch_hunks(backupname, source, hunks) 717 patch_hunks(backupname, source, hunks)
714 info(format("successfully patched %s", source)) 718 info(string.format("successfully patched %s", source))
715 os.remove(backupname) 719 os.remove(backupname)
716 return true 720 return true
717end 721end
718 722
719function patch.apply_patch(the_patch, strip, create_delete) 723function patch.apply_patch(the_patch: Files, strip: integer, create_delete: boolean): boolean
720 local all_ok = true 724 local all_ok = true
721 local total = #the_patch.source 725 local total = #the_patch.source
722 for fileno, source in ipairs(the_patch.source) do 726 for fileno, source in ipairs(the_patch.source) do
723 local target = the_patch.target[fileno] 727 local target = the_patch.target[fileno]
724 local hunks = the_patch.hunks[fileno] 728 local hunks = the_patch.hunks[fileno]
725 local epoch = the_patch.epoch[fileno] 729 local epoch = the_patch.epoch[fileno]
726 info(format("processing %d/%d:\t %s", fileno, total, source)) 730 info(string.format("processing %d/%d:\t %s", fileno, total, source))
727 local ok = patch_file(source, target, epoch, hunks, strip, create_delete) 731 local ok = patch_file(tostring(source), tostring(target), epoch, hunks, strip, create_delete)
728 all_ok = all_ok and ok 732 all_ok = all_ok and ok
729 end 733 end
730 -- todo: check for premature eof 734 -- todo: check for premature eof