379 l = self.readline() |
379 l = self.readline() |
380 if not l: |
380 if not l: |
381 break |
381 break |
382 yield l |
382 yield l |
383 |
383 |
384 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1 |
384 class abstractbackend(object): |
385 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@') |
385 def __init__(self, ui): |
386 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)') |
386 self.ui = ui |
387 eolmodes = ['strict', 'crlf', 'lf', 'auto'] |
387 |
388 |
388 def readlines(self, fname): |
389 class patchfile(object): |
389 """Return target file lines, or its content as a single line |
390 def __init__(self, ui, fname, opener, missing=False, eolmode='strict'): |
390 for symlinks. |
391 self.fname = fname |
391 """ |
392 self.eolmode = eolmode |
392 raise NotImplementedError |
393 self.eol = None |
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 """ |
|
407 pass |
|
408 |
|
409 class fsbackend(abstractbackend): |
|
410 def __init__(self, ui, opener): |
|
411 super(fsbackend, self).__init__(ui) |
394 self.opener = opener |
412 self.opener = opener |
395 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: |
|
404 pass |
|
405 else: |
|
406 self.ui.warn(_("unable to find '%s' for patching\n") % self.fname) |
|
407 |
|
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 |
|
416 |
413 |
417 def readlines(self, fname): |
414 def readlines(self, fname): |
418 if os.path.islink(fname): |
415 if os.path.islink(fname): |
419 return [os.readlink(fname)] |
416 return [os.readlink(fname)] |
420 fp = self.opener(fname, 'r') |
417 fp = self.opener(fname, 'r') |
421 try: |
418 try: |
422 lr = linereader(fp, self.eolmode != 'strict') |
419 return list(fp) |
423 lines = list(lr) |
|
424 self.eol = lr.eol |
|
425 return lines |
|
426 finally: |
420 finally: |
427 fp.close() |
421 fp.close() |
428 |
422 |
429 def writelines(self, fname, lines): |
423 def writelines(self, fname, lines): |
430 # Ensure supplied data ends in fname, being a regular file or |
424 # Ensure supplied data ends in fname, being a regular file or |
440 except OSError, e: |
434 except OSError, e: |
441 if e.errno != errno.ENOENT: |
435 if e.errno != errno.ENOENT: |
442 raise |
436 raise |
443 fp = self.opener(fname, 'w') |
437 fp = self.opener(fname, 'w') |
444 try: |
438 try: |
445 if self.eolmode == 'auto': |
439 fp.writelines(lines) |
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 fp.writelines(lines) |
|
459 if islink: |
440 if islink: |
460 self.opener.symlink(fp.getvalue(), fname) |
441 self.opener.symlink(fp.getvalue(), fname) |
461 if st_mode is not None: |
442 if st_mode is not None: |
462 os.chmod(fname, st_mode) |
443 os.chmod(fname, st_mode) |
463 finally: |
444 finally: |
464 fp.close() |
445 fp.close() |
465 |
446 |
466 def unlink(self, fname): |
447 def unlink(self, fname): |
467 os.unlink(fname) |
448 os.unlink(fname) |
|
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) |
468 |
522 |
469 def printfile(self, warn): |
523 def printfile(self, warn): |
470 if self.fileprinted: |
524 if self.fileprinted: |
471 return |
525 return |
472 if warn or self.ui.verbose: |
526 if warn or self.ui.verbose: |
501 def write_rej(self): |
555 def write_rej(self): |
502 # our rejects are a little different from patch(1). This always |
556 # our rejects are a little different from patch(1). This always |
503 # creates rejects in the same form as the original patch. A file |
557 # creates rejects in the same form as the original patch. A file |
504 # header is inserted so that you can run the reject through patch again |
558 # header is inserted so that you can run the reject through patch again |
505 # without having to type the filename. |
559 # without having to type the filename. |
506 |
|
507 if not self.rej: |
560 if not self.rej: |
508 return |
561 return |
509 |
562 self.backend.writerej(self.fname, len(self.rej), self.hunks, |
510 fname = self.fname + ".rej" |
563 self.makerejlines(self.fname)) |
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() |
|
518 |
564 |
519 def apply(self, h): |
565 def apply(self, h): |
520 if not h.complete(): |
566 if not h.complete(): |
521 raise PatchError(_("bad hunk #%d %s (%d %d %d %d)") % |
567 raise PatchError(_("bad hunk #%d %s (%d %d %d %d)") % |
522 (h.number, h.desc, len(h.a), h.lena, len(h.b), |
568 (h.number, h.desc, len(h.a), h.lena, len(h.b), |
561 # if there's skew we want to emit the "(offset %d lines)" even |
607 # if there's skew we want to emit the "(offset %d lines)" even |
562 # when the hunk cleanly applies at start + skew, so skip the |
608 # when the hunk cleanly applies at start + skew, so skip the |
563 # fast case code |
609 # fast case code |
564 if self.skew == 0 and diffhelpers.testhunk(old, self.lines, start) == 0: |
610 if self.skew == 0 and diffhelpers.testhunk(old, self.lines, start) == 0: |
565 if h.rmfile(): |
611 if h.rmfile(): |
566 self.unlink(self.fname) |
612 self.backend.unlink(self.fname) |
567 else: |
613 else: |
568 self.lines[start : start + h.lena] = h.new() |
614 self.lines[start : start + h.lena] = h.new() |
569 self.offset += h.lenb - h.lena |
615 self.offset += h.lenb - h.lena |
570 self.dirty = True |
616 self.dirty = True |
571 return 0 |
617 return 0 |
1110 def _applydiff(ui, fp, patcher, copyfn, changed, strip=1, eolmode='strict'): |
1156 def _applydiff(ui, fp, patcher, copyfn, changed, strip=1, eolmode='strict'): |
1111 rejects = 0 |
1157 rejects = 0 |
1112 err = 0 |
1158 err = 0 |
1113 current_file = None |
1159 current_file = None |
1114 cwd = os.getcwd() |
1160 cwd = os.getcwd() |
1115 opener = scmutil.opener(cwd) |
1161 backend = fsbackend(ui, scmutil.opener(cwd)) |
1116 |
1162 |
1117 for state, values in iterhunks(fp): |
1163 for state, values in iterhunks(fp): |
1118 if state == 'hunk': |
1164 if state == 'hunk': |
1119 if not current_file: |
1165 if not current_file: |
1120 continue |
1166 continue |
1128 rejects += current_file.close() |
1174 rejects += current_file.close() |
1129 afile, bfile, first_hunk = values |
1175 afile, bfile, first_hunk = values |
1130 try: |
1176 try: |
1131 current_file, missing = selectfile(afile, bfile, |
1177 current_file, missing = selectfile(afile, bfile, |
1132 first_hunk, strip) |
1178 first_hunk, strip) |
1133 current_file = patcher(ui, current_file, opener, |
1179 current_file = patcher(ui, current_file, backend, |
1134 missing=missing, eolmode=eolmode) |
1180 missing=missing, eolmode=eolmode) |
1135 except PatchError, inst: |
1181 except PatchError, inst: |
1136 ui.warn(str(inst) + '\n') |
1182 ui.warn(str(inst) + '\n') |
1137 current_file = None |
1183 current_file = None |
1138 rejects += 1 |
1184 rejects += 1 |