comparison mercurial/patch.py @ 14350:00da6624e167

patch: move copyfile() into backends, abstract basedir
author Patrick Mezard <pmezard@gmail.com>
date Tue, 17 May 2011 23:46:38 +0200
parents 776ae95b8835
children d54f9bbcc640
comparison
equal deleted inserted replaced
14349:776ae95b8835 14350:00da6624e167
16 gitre = re.compile('diff --git a/(.*) b/(.*)') 16 gitre = re.compile('diff --git a/(.*) b/(.*)')
17 17
18 class PatchError(Exception): 18 class PatchError(Exception):
19 pass 19 pass
20 20
21 # helper functions
22
23 def copyfile(src, dst, basedir):
24 abssrc, absdst = [scmutil.canonpath(basedir, basedir, x)
25 for x in [src, dst]]
26 if os.path.lexists(absdst):
27 raise util.Abort(_("cannot create %s: destination already exists") %
28 dst)
29
30 dstdir = os.path.dirname(absdst)
31 if dstdir and not os.path.isdir(dstdir):
32 try:
33 os.makedirs(dstdir)
34 except IOError:
35 raise util.Abort(
36 _("cannot create %s: unable to create destination directory")
37 % dst)
38
39 util.copyfile(abssrc, absdst)
40 21
41 # public functions 22 # public functions
42 23
43 def split(stream): 24 def split(stream):
44 '''return an iterator of individual patches from a stream''' 25 '''return an iterator of individual patches from a stream'''
404 which failed to apply and total the total number of hunks for this 385 which failed to apply and total the total number of hunks for this
405 files. 386 files.
406 """ 387 """
407 pass 388 pass
408 389
390 def copy(self, src, dst):
391 """Copy src file into dst file. Create intermediate directories if
392 necessary. Files are specified relatively to the patching base
393 directory.
394 """
395 raise NotImplementedError
396
409 class fsbackend(abstractbackend): 397 class fsbackend(abstractbackend):
410 def __init__(self, ui, opener): 398 def __init__(self, ui, basedir):
411 super(fsbackend, self).__init__(ui) 399 super(fsbackend, self).__init__(ui)
412 self.opener = opener 400 self.opener = scmutil.opener(basedir)
413 401
414 def readlines(self, fname): 402 def readlines(self, fname):
415 if os.path.islink(fname): 403 if os.path.islink(fname):
416 return [os.readlink(fname)] 404 return [os.readlink(fname)]
417 fp = self.opener(fname, 'r') 405 fp = self.opener(fname, 'r')
453 _("%d out of %d hunks FAILED -- saving rejects to file %s\n") % 441 _("%d out of %d hunks FAILED -- saving rejects to file %s\n") %
454 (failed, total, fname)) 442 (failed, total, fname))
455 fp = self.opener(fname, 'w') 443 fp = self.opener(fname, 'w')
456 fp.writelines(lines) 444 fp.writelines(lines)
457 fp.close() 445 fp.close()
446
447 def copy(self, src, dst):
448 basedir = self.opener.base
449 abssrc, absdst = [scmutil.canonpath(basedir, basedir, x)
450 for x in [src, dst]]
451 if os.path.lexists(absdst):
452 raise util.Abort(_("cannot create %s: destination already exists")
453 % dst)
454 dstdir = os.path.dirname(absdst)
455 if dstdir and not os.path.isdir(dstdir):
456 try:
457 os.makedirs(dstdir)
458 except IOError:
459 raise util.Abort(
460 _("cannot create %s: unable to create destination directory")
461 % dst)
462 util.copyfile(abssrc, absdst)
458 463
459 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1 464 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
460 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@') 465 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
461 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)') 466 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
462 eolmodes = ['strict', 'crlf', 'lf', 'auto'] 467 eolmodes = ['strict', 'crlf', 'lf', 'auto']
1145 patching then normalized according to 'eolmode'. 1150 patching then normalized according to 'eolmode'.
1146 1151
1147 Callers probably want to call '_updatedir' after this to 1152 Callers probably want to call '_updatedir' after this to
1148 apply certain categories of changes not done by this function. 1153 apply certain categories of changes not done by this function.
1149 """ 1154 """
1150 return _applydiff(ui, fp, patchfile, copyfile, changed, strip=strip, 1155 return _applydiff(ui, fp, patchfile, changed, strip=strip,
1151 eolmode=eolmode) 1156 eolmode=eolmode)
1152 1157
1153 def _applydiff(ui, fp, patcher, copyfn, changed, strip=1, eolmode='strict'): 1158 def _applydiff(ui, fp, patcher, changed, strip=1, eolmode='strict'):
1154 rejects = 0 1159 rejects = 0
1155 err = 0 1160 err = 0
1156 current_file = None 1161 current_file = None
1157 cwd = os.getcwd() 1162 cwd = os.getcwd()
1158 backend = fsbackend(ui, scmutil.opener(cwd)) 1163 backend = fsbackend(ui, os.getcwd())
1159 1164
1160 for state, values in iterhunks(fp): 1165 for state, values in iterhunks(fp):
1161 if state == 'hunk': 1166 if state == 'hunk':
1162 if not current_file: 1167 if not current_file:
1163 continue 1168 continue
1186 if gp.oldpath: 1191 if gp.oldpath:
1187 gp.oldpath = pathstrip(gp.oldpath, strip - 1)[1] 1192 gp.oldpath = pathstrip(gp.oldpath, strip - 1)[1]
1188 # Binary patches really overwrite target files, copying them 1193 # Binary patches really overwrite target files, copying them
1189 # will just make it fails with "target file exists" 1194 # will just make it fails with "target file exists"
1190 if gp.op in ('COPY', 'RENAME') and not gp.binary: 1195 if gp.op in ('COPY', 'RENAME') and not gp.binary:
1191 copyfn(gp.oldpath, gp.path, cwd) 1196 backend.copy(gp.oldpath, gp.path)
1192 changed[gp.path] = gp 1197 changed[gp.path] = gp
1193 else: 1198 else:
1194 raise util.Abort(_('unsupported parser state: %s') % state) 1199 raise util.Abort(_('unsupported parser state: %s') % state)
1195 1200
1196 if current_file: 1201 if current_file: