mercurial/patch.py
changeset 14350 00da6624e167
parent 14349 776ae95b8835
child 14351 d54f9bbcc640
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: