##// END OF EJS Templates
patch: set desired mode when patching, not in updatedir()...
Patrick Mezard -
r14367:468d7d17 default
parent child Browse files
Show More
@@ -595,11 +595,11 def reposetup(ui, repo):
595 wlock.release()
595 wlock.release()
596
596
597 # monkeypatches
597 # monkeypatches
598 def kwpatchfile_init(orig, self, ui, fname, backend,
598 def kwpatchfile_init(orig, self, ui, fname, backend, mode,
599 missing=False, eolmode=None):
599 missing=False, eolmode=None):
600 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
600 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
601 rejects or conflicts due to expanded keywords in working dir.'''
601 rejects or conflicts due to expanded keywords in working dir.'''
602 orig(self, ui, fname, backend, missing, eolmode)
602 orig(self, ui, fname, backend, mode, missing, eolmode)
603 # shrink keywords read from working dir
603 # shrink keywords read from working dir
604 self.lines = kwt.shrinklines(self.fname, self.lines)
604 self.lines = kwt.shrinklines(self.fname, self.lines)
605
605
@@ -372,8 +372,10 class abstractbackend(object):
372 """
372 """
373 raise NotImplementedError
373 raise NotImplementedError
374
374
375 def writelines(self, fname, lines):
375 def writelines(self, fname, lines, mode):
376 """Write lines to target file."""
376 """Write lines to target file. mode is a (islink, isexec)
377 tuple, or None if there is no mode information.
378 """
377 raise NotImplementedError
379 raise NotImplementedError
378
380
379 def unlink(self, fname):
381 def unlink(self, fname):
@@ -397,6 +399,10 class abstractbackend(object):
397 def exists(self, fname):
399 def exists(self, fname):
398 raise NotImplementedError
400 raise NotImplementedError
399
401
402 def setmode(self, fname, islink, isexec):
403 """Change target file mode."""
404 raise NotImplementedError
405
400 class fsbackend(abstractbackend):
406 class fsbackend(abstractbackend):
401 def __init__(self, ui, basedir):
407 def __init__(self, ui, basedir):
402 super(fsbackend, self).__init__(ui)
408 super(fsbackend, self).__init__(ui)
@@ -414,29 +420,24 class fsbackend(abstractbackend):
414 finally:
420 finally:
415 fp.close()
421 fp.close()
416
422
417 def writelines(self, fname, lines):
423 def writelines(self, fname, lines, mode):
418 # Ensure supplied data ends in fname, being a regular file or
424 if not mode:
419 # a symlink. _updatedir will -too magically- take care
425 # Preserve mode information
420 # of setting it to the proper type afterwards.
426 isexec, islink = False, False
421 st_mode = None
427 try:
428 isexec = os.lstat(self._join(fname)).st_mode & 0100 != 0
422 islink = os.path.islink(self._join(fname))
429 islink = os.path.islink(self._join(fname))
423 if islink:
424 fp = cStringIO.StringIO()
425 else:
426 try:
427 st_mode = os.lstat(self._join(fname)).st_mode & 0777
428 except OSError, e:
430 except OSError, e:
429 if e.errno != errno.ENOENT:
431 if e.errno != errno.ENOENT:
430 raise
432 raise
431 fp = self.opener(fname, 'w')
433 else:
432 try:
434 islink, isexec = mode
433 fp.writelines(lines)
434 if islink:
435 if islink:
435 self.opener.symlink(fp.getvalue(), fname)
436 self.opener.symlink(''.join(lines), fname)
436 if st_mode is not None:
437 else:
437 os.chmod(self._join(fname), st_mode)
438 self.opener(fname, 'w').writelines(lines)
438 finally:
439 if isexec:
439 fp.close()
440 util.setflags(self._join(fname), False, True)
440
441
441 def unlink(self, fname):
442 def unlink(self, fname):
442 os.unlink(self._join(fname))
443 os.unlink(self._join(fname))
@@ -470,13 +471,17 class fsbackend(abstractbackend):
470 def exists(self, fname):
471 def exists(self, fname):
471 return os.path.lexists(self._join(fname))
472 return os.path.lexists(self._join(fname))
472
473
474 def setmode(self, fname, islink, isexec):
475 util.setflags(self._join(fname), islink, isexec)
476
473 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
477 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
474 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
478 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
475 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
479 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
476 eolmodes = ['strict', 'crlf', 'lf', 'auto']
480 eolmodes = ['strict', 'crlf', 'lf', 'auto']
477
481
478 class patchfile(object):
482 class patchfile(object):
479 def __init__(self, ui, fname, backend, missing=False, eolmode='strict'):
483 def __init__(self, ui, fname, backend, mode, missing=False,
484 eolmode='strict'):
480 self.fname = fname
485 self.fname = fname
481 self.eolmode = eolmode
486 self.eolmode = eolmode
482 self.eol = None
487 self.eol = None
@@ -485,6 +490,7 class patchfile(object):
485 self.lines = []
490 self.lines = []
486 self.exists = False
491 self.exists = False
487 self.missing = missing
492 self.missing = missing
493 self.mode = mode
488 if not missing:
494 if not missing:
489 try:
495 try:
490 self.lines = self.backend.readlines(fname)
496 self.lines = self.backend.readlines(fname)
@@ -516,7 +522,7 class patchfile(object):
516 self.printfile(False)
522 self.printfile(False)
517 self.hunks = 0
523 self.hunks = 0
518
524
519 def writelines(self, fname, lines):
525 def writelines(self, fname, lines, mode):
520 if self.eolmode == 'auto':
526 if self.eolmode == 'auto':
521 eol = self.eol
527 eol = self.eol
522 elif self.eolmode == 'crlf':
528 elif self.eolmode == 'crlf':
@@ -532,7 +538,7 class patchfile(object):
532 rawlines.append(l)
538 rawlines.append(l)
533 lines = rawlines
539 lines = rawlines
534
540
535 self.backend.writelines(fname, lines)
541 self.backend.writelines(fname, lines, mode)
536
542
537 def printfile(self, warn):
543 def printfile(self, warn):
538 if self.fileprinted:
544 if self.fileprinted:
@@ -670,7 +676,7 class patchfile(object):
670
676
671 def close(self):
677 def close(self):
672 if self.dirty:
678 if self.dirty:
673 self.writelines(self.fname, self.lines)
679 self.writelines(self.fname, self.lines, self.mode)
674 self.write_rej()
680 self.write_rej()
675 return len(self.rej)
681 return len(self.rej)
676
682
@@ -1087,14 +1093,16 def iterhunks(fp):
1087 hunknum += 1
1093 hunknum += 1
1088 if emitfile:
1094 if emitfile:
1089 emitfile = False
1095 emitfile = False
1090 yield 'file', (afile, bfile, h)
1096 yield 'file', (afile, bfile, h, gpatch and gpatch.mode or None)
1091 yield 'hunk', h
1097 yield 'hunk', h
1092 elif state == BFILE and x.startswith('GIT binary patch'):
1098 elif state == BFILE and x.startswith('GIT binary patch'):
1093 h = binhunk(changed[bfile])
1099 gpatch = changed[bfile]
1100 h = binhunk(gpatch)
1094 hunknum += 1
1101 hunknum += 1
1095 if emitfile:
1102 if emitfile:
1096 emitfile = False
1103 emitfile = False
1097 yield 'file', ('a/' + afile, 'b/' + bfile, h)
1104 yield 'file', ('a/' + afile, 'b/' + bfile, h,
1105 gpatch and gpatch.mode or None)
1098 h.extract(lr)
1106 h.extract(lr)
1099 yield 'hunk', h
1107 yield 'hunk', h
1100 elif x.startswith('diff --git'):
1108 elif x.startswith('diff --git'):
@@ -1181,11 +1189,11 def _applydiff(ui, fp, patcher, backend,
1181 elif state == 'file':
1189 elif state == 'file':
1182 if current_file:
1190 if current_file:
1183 rejects += current_file.close()
1191 rejects += current_file.close()
1184 afile, bfile, first_hunk = values
1192 afile, bfile, first_hunk, mode = values
1185 try:
1193 try:
1186 current_file, missing = selectfile(backend, afile, bfile,
1194 current_file, missing = selectfile(backend, afile, bfile,
1187 first_hunk, strip)
1195 first_hunk, strip)
1188 current_file = patcher(ui, current_file, backend,
1196 current_file = patcher(ui, current_file, backend, mode,
1189 missing=missing, eolmode=eolmode)
1197 missing=missing, eolmode=eolmode)
1190 except PatchError, inst:
1198 except PatchError, inst:
1191 ui.warn(str(inst) + '\n')
1199 ui.warn(str(inst) + '\n')
@@ -1208,6 +1216,16 def _applydiff(ui, fp, patcher, backend,
1208 if current_file:
1216 if current_file:
1209 rejects += current_file.close()
1217 rejects += current_file.close()
1210
1218
1219 # Handle mode changes without hunk
1220 for gp in changed.itervalues():
1221 if not gp or not gp.mode:
1222 continue
1223 if gp.op == 'ADD' and not backend.exists(gp.path):
1224 # Added files without content have no hunk and must be created
1225 backend.writelines(gp.path, [], gp.mode)
1226 else:
1227 backend.setmode(gp.path, gp.mode[0], gp.mode[1])
1228
1211 if rejects:
1229 if rejects:
1212 return -1
1230 return -1
1213 return err
1231 return err
@@ -1240,16 +1258,6 def _updatedir(ui, repo, patches, simila
1240 if (not similarity) and removes:
1258 if (not similarity) and removes:
1241 wctx.remove(sorted(removes), True)
1259 wctx.remove(sorted(removes), True)
1242
1260
1243 for f in patches:
1244 gp = patches[f]
1245 if gp and gp.mode:
1246 islink, isexec = gp.mode
1247 dst = repo.wjoin(gp.path)
1248 # patch won't create empty files
1249 if gp.op == 'ADD' and not os.path.lexists(dst):
1250 flags = (isexec and 'x' or '') + (islink and 'l' or '')
1251 repo.wwrite(gp.path, '', flags)
1252 util.setflags(dst, islink, isexec)
1253 scmutil.addremove(repo, cfiles, similarity=similarity)
1261 scmutil.addremove(repo, cfiles, similarity=similarity)
1254 files = patches.keys()
1262 files = patches.keys()
1255 files.extend([r for r in removes if r not in files])
1263 files.extend([r for r in removes if r not in files])
@@ -1359,7 +1367,7 def changedfiles(ui, repo, patchpath, st
1359 if state == 'hunk':
1367 if state == 'hunk':
1360 continue
1368 continue
1361 elif state == 'file':
1369 elif state == 'file':
1362 afile, bfile, first_hunk = values
1370 afile, bfile, first_hunk, mode = values
1363 current_file, missing = selectfile(backend, afile, bfile,
1371 current_file, missing = selectfile(backend, afile, bfile,
1364 first_hunk, strip)
1372 first_hunk, strip)
1365 changed.add(current_file)
1373 changed.add(current_file)
General Comments 0
You need to be logged in to leave comments. Login now