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