comparison mercurial/patch.py @ 10127:d8214e944b84

patch: fix eolmode=auto with new files If target file does not exist or has no eol, current code was normalizing eols to LF. Preserve patch file eols instead.
author Patrick Mezard <pmezard@gmail.com>
date Wed, 23 Dec 2009 19:31:47 +0100
parents 1720d70cd6d4
children ea7c392f2b08
comparison
equal deleted inserted replaced
10126:78b8acae2088 10127:d8214e944b84
319 if islink: 319 if islink:
320 fp = cStringIO.StringIO() 320 fp = cStringIO.StringIO()
321 else: 321 else:
322 fp = self.opener(fname, 'w') 322 fp = self.opener(fname, 'w')
323 try: 323 try:
324 if self.eolmode == 'auto' and self.eol: 324 if self.eolmode == 'auto':
325 eol = self.eol 325 eol = self.eol
326 elif self.eolmode == 'crlf': 326 elif self.eolmode == 'crlf':
327 eol = '\r\n' 327 eol = '\r\n'
328 else: 328 else:
329 eol = '\n' 329 eol = '\n'
330 330
331 if self.eolmode != 'strict' and eol != '\n': 331 if self.eolmode != 'strict' and eol and eol != '\n':
332 for l in lines: 332 for l in lines:
333 if l and l[-1] == '\n': 333 if l and l[-1] == '\n':
334 l = l[:-1] + eol 334 l = l[:-1] + eol
335 fp.write(l) 335 fp.write(l)
336 else: 336 else:
430 else: 430 else:
431 self.lines[:] = h.new() 431 self.lines[:] = h.new()
432 self.offset += len(h.new()) 432 self.offset += len(h.new())
433 self.dirty = 1 433 self.dirty = 1
434 return 0 434 return 0
435
436 horig = h
437 if self.eolmode == 'auto' and self.eol:
438 # If eolmode == 'auto' and target file exists and has line
439 # endings we have to normalize input data before patching.
440 # Otherwise, patchfile operates in 'strict' mode. If
441 # eolmode is set to 'crlf' or 'lf', input hunk is already
442 # normalized to avoid data copy.
443 h = h.getnormalized()
435 444
436 # fast case first, no offsets, no fuzz 445 # fast case first, no offsets, no fuzz
437 old = h.old() 446 old = h.old()
438 # patch starts counting at 1 unless we are adding the file 447 # patch starts counting at 1 unless we are adding the file
439 if h.starta == 0: 448 if h.starta == 0:
486 "(offset %d lines).\n") 495 "(offset %d lines).\n")
487 f(msg % (h.number, l+1, fuzzstr, offset)) 496 f(msg % (h.number, l+1, fuzzstr, offset))
488 return fuzzlen 497 return fuzzlen
489 self.printfile(True) 498 self.printfile(True)
490 self.ui.warn(_("Hunk #%d FAILED at %d\n") % (h.number, orig_start)) 499 self.ui.warn(_("Hunk #%d FAILED at %d\n") % (h.number, orig_start))
491 self.rej.append(h) 500 self.rej.append(horig)
492 return -1 501 return -1
493 502
494 class hunk(object): 503 class hunk(object):
495 def __init__(self, desc, num, lr, context, create=False, remove=False): 504 def __init__(self, desc, num, lr, context, create=False, remove=False):
496 self.number = num 505 self.number = num
498 self.hunk = [ desc ] 507 self.hunk = [ desc ]
499 self.a = [] 508 self.a = []
500 self.b = [] 509 self.b = []
501 self.starta = self.lena = None 510 self.starta = self.lena = None
502 self.startb = self.lenb = None 511 self.startb = self.lenb = None
503 if context: 512 if lr is not None:
504 self.read_context_hunk(lr) 513 if context:
505 else: 514 self.read_context_hunk(lr)
506 self.read_unified_hunk(lr) 515 else:
516 self.read_unified_hunk(lr)
507 self.create = create 517 self.create = create
508 self.remove = remove and not create 518 self.remove = remove and not create
519
520 def getnormalized(self):
521 """Return a copy with line endings normalized to LF."""
522
523 def normalize(lines):
524 nlines = []
525 for line in lines:
526 if line.endswith('\r\n'):
527 line = line[:-2] + '\n'
528 nlines.append(line)
529 return nlines
530
531 # Dummy object, it is rebuilt manually
532 nh = hunk(self.desc, self.number, None, None, False, False)
533 nh.number = self.number
534 nh.desc = self.desc
535 nh.a = normalize(self.a)
536 nh.b = normalize(self.b)
537 nh.starta = self.starta
538 nh.startb = self.startb
539 nh.lena = self.lena
540 nh.lenb = self.lenb
541 nh.create = self.create
542 nh.remove = self.remove
543 return nh
509 544
510 def read_unified_hunk(self, lr): 545 def read_unified_hunk(self, lr):
511 m = unidesc.match(self.desc) 546 m = unidesc.match(self.desc)
512 if not m: 547 if not m:
513 raise PatchError(_("bad hunk #%d") % self.number) 548 raise PatchError(_("bad hunk #%d") % self.number)
972 rejects = 0 1007 rejects = 0
973 err = 0 1008 err = 0
974 current_file = None 1009 current_file = None
975 gitpatches = None 1010 gitpatches = None
976 opener = util.opener(os.getcwd()) 1011 opener = util.opener(os.getcwd())
977 textmode = eolmode != 'strict' 1012 # In 'auto' mode, we must preserve original eols if target file
1013 # eols are undefined. Otherwise, hunk data will be normalized
1014 # later.
1015 textmode = eolmode not in ('strict', 'auto')
978 1016
979 def closefile(): 1017 def closefile():
980 if not current_file: 1018 if not current_file:
981 return 0 1019 return 0
982 current_file.close() 1020 current_file.close()