##// END OF EJS Templates
patch: extract fs access from patchfile into fsbackend...
Patrick Mezard -
r14348:c1c71910 default
parent child Browse files
Show More
@@ -595,11 +595,11 b' def reposetup(ui, repo):'
595 595 wlock.release()
596 596
597 597 # monkeypatches
598 def kwpatchfile_init(orig, self, ui, fname, opener,
598 def kwpatchfile_init(orig, self, ui, fname, backend,
599 599 missing=False, eolmode=None):
600 600 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
601 601 rejects or conflicts due to expanded keywords in working dir.'''
602 orig(self, ui, fname, opener, missing, eolmode)
602 orig(self, ui, fname, backend, missing, eolmode)
603 603 # shrink keywords read from working dir
604 604 self.lines = kwt.shrinklines(self.fname, self.lines)
605 605
@@ -381,48 +381,42 b' class linereader(object):'
381 381 break
382 382 yield l
383 383
384 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
385 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
386 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
387 eolmodes = ['strict', 'crlf', 'lf', 'auto']
388
389 class patchfile(object):
390 def __init__(self, ui, fname, opener, missing=False, eolmode='strict'):
391 self.fname = fname
392 self.eolmode = eolmode
393 self.eol = None
394 self.opener = opener
384 class abstractbackend(object):
385 def __init__(self, ui):
395 386 self.ui = ui
396 self.lines = []
397 self.exists = False
398 self.missing = missing
399 if not missing:
400 try:
401 self.lines = self.readlines(fname)
402 self.exists = True
403 except IOError:
387
388 def readlines(self, fname):
389 """Return target file lines, or its content as a single line
390 for symlinks.
391 """
392 raise NotImplementedError
393
394 def writelines(self, fname, lines):
395 """Write lines to target file."""
396 raise NotImplementedError
397
398 def unlink(self, fname):
399 """Unlink target file."""
400 raise NotImplementedError
401
402 def writerej(self, fname, failed, total, lines):
403 """Write rejected lines for fname. total is the number of hunks
404 which failed to apply and total the total number of hunks for this
405 files.
406 """
404 407 pass
405 else:
406 self.ui.warn(_("unable to find '%s' for patching\n") % self.fname)
407 408
408 self.hash = {}
409 self.dirty = False
410 self.offset = 0
411 self.skew = 0
412 self.rej = []
413 self.fileprinted = False
414 self.printfile(False)
415 self.hunks = 0
409 class fsbackend(abstractbackend):
410 def __init__(self, ui, opener):
411 super(fsbackend, self).__init__(ui)
412 self.opener = opener
416 413
417 414 def readlines(self, fname):
418 415 if os.path.islink(fname):
419 416 return [os.readlink(fname)]
420 417 fp = self.opener(fname, 'r')
421 418 try:
422 lr = linereader(fp, self.eolmode != 'strict')
423 lines = list(lr)
424 self.eol = lr.eol
425 return lines
419 return list(fp)
426 420 finally:
427 421 fp.close()
428 422
@@ -442,19 +436,6 b' class patchfile(object):'
442 436 raise
443 437 fp = self.opener(fname, 'w')
444 438 try:
445 if self.eolmode == 'auto':
446 eol = self.eol
447 elif self.eolmode == 'crlf':
448 eol = '\r\n'
449 else:
450 eol = '\n'
451
452 if self.eolmode != 'strict' and eol and eol != '\n':
453 for l in lines:
454 if l and l[-1] == '\n':
455 l = l[:-1] + eol
456 fp.write(l)
457 else:
458 439 fp.writelines(lines)
459 440 if islink:
460 441 self.opener.symlink(fp.getvalue(), fname)
@@ -466,6 +447,79 b' class patchfile(object):'
466 447 def unlink(self, fname):
467 448 os.unlink(fname)
468 449
450 def writerej(self, fname, failed, total, lines):
451 fname = fname + ".rej"
452 self.ui.warn(
453 _("%d out of %d hunks FAILED -- saving rejects to file %s\n") %
454 (failed, total, fname))
455 fp = self.opener(fname, 'w')
456 fp.writelines(lines)
457 fp.close()
458
459 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
460 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
461 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
462 eolmodes = ['strict', 'crlf', 'lf', 'auto']
463
464 class patchfile(object):
465 def __init__(self, ui, fname, backend, missing=False, eolmode='strict'):
466 self.fname = fname
467 self.eolmode = eolmode
468 self.eol = None
469 self.backend = backend
470 self.ui = ui
471 self.lines = []
472 self.exists = False
473 self.missing = missing
474 if not missing:
475 try:
476 self.lines = self.backend.readlines(fname)
477 if self.lines:
478 # Normalize line endings
479 if self.lines[0].endswith('\r\n'):
480 self.eol = '\r\n'
481 elif self.lines[0].endswith('\n'):
482 self.eol = '\n'
483 if eolmode != 'strict':
484 nlines = []
485 for l in self.lines:
486 if l.endswith('\r\n'):
487 l = l[:-2] + '\n'
488 nlines.append(l)
489 self.lines = nlines
490 self.exists = True
491 except IOError:
492 pass
493 else:
494 self.ui.warn(_("unable to find '%s' for patching\n") % self.fname)
495
496 self.hash = {}
497 self.dirty = 0
498 self.offset = 0
499 self.skew = 0
500 self.rej = []
501 self.fileprinted = False
502 self.printfile(False)
503 self.hunks = 0
504
505 def writelines(self, fname, lines):
506 if self.eolmode == 'auto':
507 eol = self.eol
508 elif self.eolmode == 'crlf':
509 eol = '\r\n'
510 else:
511 eol = '\n'
512
513 if self.eolmode != 'strict' and eol and eol != '\n':
514 rawlines = []
515 for l in lines:
516 if l and l[-1] == '\n':
517 l = l[:-1] + eol
518 rawlines.append(l)
519 lines = rawlines
520
521 self.backend.writelines(fname, lines)
522
469 523 def printfile(self, warn):
470 524 if self.fileprinted:
471 525 return
@@ -503,18 +557,10 b' class patchfile(object):'
503 557 # creates rejects in the same form as the original patch. A file
504 558 # header is inserted so that you can run the reject through patch again
505 559 # without having to type the filename.
506
507 560 if not self.rej:
508 561 return
509
510 fname = self.fname + ".rej"
511 self.ui.warn(
512 _("%d out of %d hunks FAILED -- saving rejects to file %s\n") %
513 (len(self.rej), self.hunks, fname))
514
515 fp = self.opener(fname, 'w')
516 fp.writelines(self.makerejlines(self.fname))
517 fp.close()
562 self.backend.writerej(self.fname, len(self.rej), self.hunks,
563 self.makerejlines(self.fname))
518 564
519 565 def apply(self, h):
520 566 if not h.complete():
@@ -535,7 +581,7 b' class patchfile(object):'
535 581
536 582 if isinstance(h, binhunk):
537 583 if h.rmfile():
538 self.unlink(self.fname)
584 self.backend.unlink(self.fname)
539 585 else:
540 586 self.lines[:] = h.new()
541 587 self.offset += len(h.new())
@@ -563,7 +609,7 b' class patchfile(object):'
563 609 # fast case code
564 610 if self.skew == 0 and diffhelpers.testhunk(old, self.lines, start) == 0:
565 611 if h.rmfile():
566 self.unlink(self.fname)
612 self.backend.unlink(self.fname)
567 613 else:
568 614 self.lines[start : start + h.lena] = h.new()
569 615 self.offset += h.lenb - h.lena
@@ -1112,7 +1158,7 b' def _applydiff(ui, fp, patcher, copyfn, '
1112 1158 err = 0
1113 1159 current_file = None
1114 1160 cwd = os.getcwd()
1115 opener = scmutil.opener(cwd)
1161 backend = fsbackend(ui, scmutil.opener(cwd))
1116 1162
1117 1163 for state, values in iterhunks(fp):
1118 1164 if state == 'hunk':
@@ -1130,7 +1176,7 b' def _applydiff(ui, fp, patcher, copyfn, '
1130 1176 try:
1131 1177 current_file, missing = selectfile(afile, bfile,
1132 1178 first_hunk, strip)
1133 current_file = patcher(ui, current_file, opener,
1179 current_file = patcher(ui, current_file, backend,
1134 1180 missing=missing, eolmode=eolmode)
1135 1181 except PatchError, inst:
1136 1182 ui.warn(str(inst) + '\n')
General Comments 0
You need to be logged in to leave comments. Login now