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: |