mercurial/patch.py
changeset 14611 adbf5e7df96d
parent 14609 f53dc0787424
child 14658 7ddf9a607b75
equal deleted inserted replaced
14610:5d6244930559 14611:adbf5e7df96d
     9 import cStringIO, email.Parser, os, errno, re
     9 import cStringIO, email.Parser, os, errno, re
    10 import tempfile, zlib, shutil
    10 import tempfile, zlib, shutil
    11 
    11 
    12 from i18n import _
    12 from i18n import _
    13 from node import hex, nullid, short
    13 from node import hex, nullid, short
    14 import base85, mdiff, scmutil, util, diffhelpers, copies, encoding
    14 import base85, mdiff, scmutil, util, diffhelpers, copies, encoding, error
       
    15 import context
    15 
    16 
    16 gitre = re.compile('diff --git a/(.*) b/(.*)')
    17 gitre = re.compile('diff --git a/(.*) b/(.*)')
    17 
    18 
    18 class PatchError(Exception):
    19 class PatchError(Exception):
    19     pass
    20     pass
   508         return self.opener.read(fn), mode, copied
   509         return self.opener.read(fn), mode, copied
   509 
   510 
   510     def close(self):
   511     def close(self):
   511         if self.opener:
   512         if self.opener:
   512             shutil.rmtree(self.opener.base)
   513             shutil.rmtree(self.opener.base)
       
   514 
       
   515 class repobackend(abstractbackend):
       
   516     def __init__(self, ui, repo, ctx, store):
       
   517         super(repobackend, self).__init__(ui)
       
   518         self.repo = repo
       
   519         self.ctx = ctx
       
   520         self.store = store
       
   521         self.changed = set()
       
   522         self.removed = set()
       
   523         self.copied = {}
       
   524 
       
   525     def _checkknown(self, fname):
       
   526         if fname not in self.ctx:
       
   527             raise PatchError(_('cannot patch %s: file is not tracked') % fname)
       
   528 
       
   529     def getfile(self, fname):
       
   530         try:
       
   531             fctx = self.ctx[fname]
       
   532         except error.LookupError:
       
   533             raise IOError()
       
   534         flags = fctx.flags()
       
   535         return fctx.data(), ('l' in flags, 'x' in flags)
       
   536 
       
   537     def setfile(self, fname, data, mode, copysource):
       
   538         if copysource:
       
   539             self._checkknown(copysource)
       
   540         if data is None:
       
   541             data = self.ctx[fname].data()
       
   542         self.store.setfile(fname, data, mode, copysource)
       
   543         self.changed.add(fname)
       
   544         if copysource:
       
   545             self.copied[fname] = copysource
       
   546 
       
   547     def unlink(self, fname):
       
   548         self._checkknown(fname)
       
   549         self.removed.add(fname)
       
   550 
       
   551     def exists(self, fname):
       
   552         return fname in self.ctx
       
   553 
       
   554     def close(self):
       
   555         return self.changed | self.removed
   513 
   556 
   514 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
   557 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
   515 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
   558 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
   516 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
   559 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
   517 eolmodes = ['strict', 'crlf', 'lf', 'auto']
   560 eolmodes = ['strict', 'crlf', 'lf', 'auto']
  1330     if code:
  1373     if code:
  1331         raise PatchError(_("patch command failed: %s") %
  1374         raise PatchError(_("patch command failed: %s") %
  1332                          util.explainexit(code)[0])
  1375                          util.explainexit(code)[0])
  1333     return fuzz
  1376     return fuzz
  1334 
  1377 
  1335 def internalpatch(ui, repo, patchobj, strip, files=None, eolmode='strict',
  1378 def patchbackend(ui, backend, patchobj, strip, files=None, eolmode='strict'):
  1336                   similarity=0):
       
  1337     """use builtin patch to apply <patchobj> to the working directory.
       
  1338     returns whether patch was applied with fuzz factor."""
       
  1339 
       
  1340     if files is None:
  1379     if files is None:
  1341         files = set()
  1380         files = set()
  1342     if eolmode is None:
  1381     if eolmode is None:
  1343         eolmode = ui.config('patch', 'eol', 'strict')
  1382         eolmode = ui.config('patch', 'eol', 'strict')
  1344     if eolmode.lower() not in eolmodes:
  1383     if eolmode.lower() not in eolmodes:
  1345         raise util.Abort(_('unsupported line endings type: %s') % eolmode)
  1384         raise util.Abort(_('unsupported line endings type: %s') % eolmode)
  1346     eolmode = eolmode.lower()
  1385     eolmode = eolmode.lower()
  1347 
  1386 
  1348     store = filestore()
  1387     store = filestore()
  1349     backend = workingbackend(ui, repo, similarity)
       
  1350     try:
  1388     try:
  1351         fp = open(patchobj, 'rb')
  1389         fp = open(patchobj, 'rb')
  1352     except TypeError:
  1390     except TypeError:
  1353         fp = patchobj
  1391         fp = patchobj
  1354     try:
  1392     try:
  1360         files.update(backend.close())
  1398         files.update(backend.close())
  1361         store.close()
  1399         store.close()
  1362     if ret < 0:
  1400     if ret < 0:
  1363         raise PatchError(_('patch failed to apply'))
  1401         raise PatchError(_('patch failed to apply'))
  1364     return ret > 0
  1402     return ret > 0
       
  1403 
       
  1404 def internalpatch(ui, repo, patchobj, strip, files=None, eolmode='strict',
       
  1405                   similarity=0):
       
  1406     """use builtin patch to apply <patchobj> to the working directory.
       
  1407     returns whether patch was applied with fuzz factor."""
       
  1408     backend = workingbackend(ui, repo, similarity)
       
  1409     return patchbackend(ui, backend, patchobj, strip, files, eolmode)
       
  1410 
       
  1411 def patchrepo(ui, repo, ctx, store, patchobj, strip, files=None,
       
  1412               eolmode='strict'):
       
  1413     backend = repobackend(ui, repo, ctx, store)
       
  1414     return patchbackend(ui, backend, patchobj, strip, files, eolmode)
       
  1415 
       
  1416 def makememctx(repo, parents, text, user, date, branch, files, store,
       
  1417                editor=None):
       
  1418     def getfilectx(repo, memctx, path):
       
  1419         data, (islink, isexec), copied = store.getfile(path)
       
  1420         return context.memfilectx(path, data, islink=islink, isexec=isexec,
       
  1421                                   copied=copied)
       
  1422     extra = {}
       
  1423     if branch:
       
  1424         extra['branch'] = encoding.fromlocal(branch)
       
  1425     ctx =  context.memctx(repo, parents, text, files, getfilectx, user,
       
  1426                           date, extra)
       
  1427     if editor:
       
  1428         ctx._text = editor(repo, ctx, [])
       
  1429     return ctx
  1365 
  1430 
  1366 def patch(ui, repo, patchname, strip=1, files=None, eolmode='strict',
  1431 def patch(ui, repo, patchname, strip=1, files=None, eolmode='strict',
  1367           similarity=0):
  1432           similarity=0):
  1368     """Apply <patchname> to the working directory.
  1433     """Apply <patchname> to the working directory.
  1369 
  1434