Show More
@@ -595,11 +595,11 b' 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 b' 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 b' 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 b' 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 |
|
|||
422 | islink = os.path.islink(self._join(fname)) |
|
|||
423 | if islink: |
|
|||
424 | fp = cStringIO.StringIO() |
|
|||
425 | else: |
|
|||
426 | try: |
|
427 | try: | |
427 |
|
|
428 | isexec = os.lstat(self._join(fname)).st_mode & 0100 != 0 | |
|
429 | islink = os.path.islink(self._join(fname)) | |||
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) |
|
435 | if islink: | |
434 | if islink: |
|
436 | self.opener.symlink(''.join(lines), fname) | |
435 | self.opener.symlink(fp.getvalue(), fname) |
|
437 | else: | |
436 | if st_mode is not None: |
|
438 | self.opener(fname, 'w').writelines(lines) | |
437 | os.chmod(self._join(fname), st_mode) |
|
439 | if isexec: | |
438 | finally: |
|
440 | util.setflags(self._join(fname), False, True) | |
439 | fp.close() |
|
|||
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 b' 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, |
|
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 b' 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 b' 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 b' 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 b' 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 b' 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 = |
|
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 b' 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 b' 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 b' 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 b' 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