Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/patch.py @ 14366:992a7e398ddd
patch: stop changing current directory before patching
_applydiff() patcher argument was added to help hgsubversion like extension
monkeypatching the patching process. While it could be removed at this point, I
prefer to leave it until patch.py is completely refactored and there is a valid
and tested alternative.
author | Patrick Mezard <pmezard@gmail.com> |
---|---|
date | Wed, 18 May 2011 23:48:13 +0200 |
parents | 077cdf172580 |
children | 468d7d1744b4 |
comparison
equal
deleted
inserted
replaced
14365:a8e3931e3fb5 | 14366:992a7e398ddd |
---|---|
400 class fsbackend(abstractbackend): | 400 class fsbackend(abstractbackend): |
401 def __init__(self, ui, basedir): | 401 def __init__(self, ui, basedir): |
402 super(fsbackend, self).__init__(ui) | 402 super(fsbackend, self).__init__(ui) |
403 self.opener = scmutil.opener(basedir) | 403 self.opener = scmutil.opener(basedir) |
404 | 404 |
405 def _join(self, f): | |
406 return os.path.join(self.opener.base, f) | |
407 | |
405 def readlines(self, fname): | 408 def readlines(self, fname): |
406 if os.path.islink(fname): | 409 if os.path.islink(self._join(fname)): |
407 return [os.readlink(fname)] | 410 return [os.readlink(self._join(fname))] |
408 fp = self.opener(fname, 'r') | 411 fp = self.opener(fname, 'r') |
409 try: | 412 try: |
410 return list(fp) | 413 return list(fp) |
411 finally: | 414 finally: |
412 fp.close() | 415 fp.close() |
414 def writelines(self, fname, lines): | 417 def writelines(self, fname, lines): |
415 # Ensure supplied data ends in fname, being a regular file or | 418 # Ensure supplied data ends in fname, being a regular file or |
416 # a symlink. _updatedir will -too magically- take care | 419 # a symlink. _updatedir will -too magically- take care |
417 # of setting it to the proper type afterwards. | 420 # of setting it to the proper type afterwards. |
418 st_mode = None | 421 st_mode = None |
419 islink = os.path.islink(fname) | 422 islink = os.path.islink(self._join(fname)) |
420 if islink: | 423 if islink: |
421 fp = cStringIO.StringIO() | 424 fp = cStringIO.StringIO() |
422 else: | 425 else: |
423 try: | 426 try: |
424 st_mode = os.lstat(fname).st_mode & 0777 | 427 st_mode = os.lstat(self._join(fname)).st_mode & 0777 |
425 except OSError, e: | 428 except OSError, e: |
426 if e.errno != errno.ENOENT: | 429 if e.errno != errno.ENOENT: |
427 raise | 430 raise |
428 fp = self.opener(fname, 'w') | 431 fp = self.opener(fname, 'w') |
429 try: | 432 try: |
430 fp.writelines(lines) | 433 fp.writelines(lines) |
431 if islink: | 434 if islink: |
432 self.opener.symlink(fp.getvalue(), fname) | 435 self.opener.symlink(fp.getvalue(), fname) |
433 if st_mode is not None: | 436 if st_mode is not None: |
434 os.chmod(fname, st_mode) | 437 os.chmod(self._join(fname), st_mode) |
435 finally: | 438 finally: |
436 fp.close() | 439 fp.close() |
437 | 440 |
438 def unlink(self, fname): | 441 def unlink(self, fname): |
439 os.unlink(fname) | 442 os.unlink(self._join(fname)) |
440 | 443 |
441 def writerej(self, fname, failed, total, lines): | 444 def writerej(self, fname, failed, total, lines): |
442 fname = fname + ".rej" | 445 fname = fname + ".rej" |
443 self.ui.warn( | 446 self.ui.warn( |
444 _("%d out of %d hunks FAILED -- saving rejects to file %s\n") % | 447 _("%d out of %d hunks FAILED -- saving rejects to file %s\n") % |
463 _("cannot create %s: unable to create destination directory") | 466 _("cannot create %s: unable to create destination directory") |
464 % dst) | 467 % dst) |
465 util.copyfile(abssrc, absdst) | 468 util.copyfile(abssrc, absdst) |
466 | 469 |
467 def exists(self, fname): | 470 def exists(self, fname): |
468 return os.path.lexists(fname) | 471 return os.path.lexists(self._join(fname)) |
469 | 472 |
470 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1 | 473 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1 |
471 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@') | 474 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@') |
472 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)') | 475 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)') |
473 eolmodes = ['strict', 'crlf', 'lf', 'auto'] | 476 eolmodes = ['strict', 'crlf', 'lf', 'auto'] |
1142 newfile = False | 1145 newfile = False |
1143 emitfile = True | 1146 emitfile = True |
1144 state = BFILE | 1147 state = BFILE |
1145 hunknum = 0 | 1148 hunknum = 0 |
1146 | 1149 |
1147 def applydiff(ui, fp, changed, strip=1, eolmode='strict'): | 1150 def applydiff(ui, fp, changed, backend, strip=1, eolmode='strict'): |
1148 """Reads a patch from fp and tries to apply it. | 1151 """Reads a patch from fp and tries to apply it. |
1149 | 1152 |
1150 The dict 'changed' is filled in with all of the filenames changed | 1153 The dict 'changed' is filled in with all of the filenames changed |
1151 by the patch. Returns 0 for a clean patch, -1 if any rejects were | 1154 by the patch. Returns 0 for a clean patch, -1 if any rejects were |
1152 found and 1 if there was any fuzz. | 1155 found and 1 if there was any fuzz. |
1156 patching then normalized according to 'eolmode'. | 1159 patching then normalized according to 'eolmode'. |
1157 | 1160 |
1158 Callers probably want to call '_updatedir' after this to | 1161 Callers probably want to call '_updatedir' after this to |
1159 apply certain categories of changes not done by this function. | 1162 apply certain categories of changes not done by this function. |
1160 """ | 1163 """ |
1161 return _applydiff(ui, fp, patchfile, changed, strip=strip, | 1164 return _applydiff(ui, fp, patchfile, backend, changed, strip=strip, |
1162 eolmode=eolmode) | 1165 eolmode=eolmode) |
1163 | 1166 |
1164 def _applydiff(ui, fp, patcher, changed, strip=1, eolmode='strict'): | 1167 def _applydiff(ui, fp, patcher, backend, changed, strip=1, eolmode='strict'): |
1165 rejects = 0 | 1168 rejects = 0 |
1166 err = 0 | 1169 err = 0 |
1167 current_file = None | 1170 current_file = None |
1168 backend = fsbackend(ui, os.getcwd()) | |
1169 | 1171 |
1170 for state, values in iterhunks(fp): | 1172 for state, values in iterhunks(fp): |
1171 if state == 'hunk': | 1173 if state == 'hunk': |
1172 if not current_file: | 1174 if not current_file: |
1173 continue | 1175 continue |
1301 eolmode = ui.config('patch', 'eol', 'strict') | 1303 eolmode = ui.config('patch', 'eol', 'strict') |
1302 if eolmode.lower() not in eolmodes: | 1304 if eolmode.lower() not in eolmodes: |
1303 raise util.Abort(_('unsupported line endings type: %s') % eolmode) | 1305 raise util.Abort(_('unsupported line endings type: %s') % eolmode) |
1304 eolmode = eolmode.lower() | 1306 eolmode = eolmode.lower() |
1305 | 1307 |
1308 backend = fsbackend(ui, cwd) | |
1306 try: | 1309 try: |
1307 fp = open(patchobj, 'rb') | 1310 fp = open(patchobj, 'rb') |
1308 except TypeError: | 1311 except TypeError: |
1309 fp = patchobj | 1312 fp = patchobj |
1310 if cwd: | |
1311 curdir = os.getcwd() | |
1312 os.chdir(cwd) | |
1313 try: | 1313 try: |
1314 ret = applydiff(ui, fp, files, strip=strip, eolmode=eolmode) | 1314 ret = applydiff(ui, fp, files, backend, strip=strip, eolmode=eolmode) |
1315 finally: | 1315 finally: |
1316 if cwd: | |
1317 os.chdir(curdir) | |
1318 if fp != patchobj: | 1316 if fp != patchobj: |
1319 fp.close() | 1317 fp.close() |
1320 touched = _updatedir(ui, repo, files, similarity) | 1318 touched = _updatedir(ui, repo, files, similarity) |
1321 files.update(dict.fromkeys(touched)) | 1319 files.update(dict.fromkeys(touched)) |
1322 if ret < 0: | 1320 if ret < 0: |