Move patch-related code into its own module.
authorBrendan Cully <brendan@kublai.com>
Fri, 11 Aug 2006 15:50:16 -0700
changeset 2861 0f08f2c042ec
parent 2860 b3d1145ed06c
child 2862 1f813d4fbcc8
Move patch-related code into its own module.
mercurial/commands.py
mercurial/patch.py
mercurial/util.py
--- a/mercurial/commands.py	Fri Aug 11 15:50:07 2006 -0700
+++ b/mercurial/commands.py	Fri Aug 11 15:50:16 2006 -0700
@@ -10,7 +10,7 @@
 from i18n import gettext as _
 demandload(globals(), "os re sys signal shutil imp urllib pdb")
 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
-demandload(globals(), "fnmatch mdiff random signal tempfile time")
+demandload(globals(), "fnmatch mdiff patch random signal tempfile time")
 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
 demandload(globals(), "archival cStringIO changegroup email.Parser")
 demandload(globals(), "hgweb.server sshserver")
@@ -1826,21 +1826,21 @@
     lock = repo.lock()
 
     wlock = repo.wlock()
-    for patch in patches:
-        pf = os.path.join(d, patch)
+    for p in patches:
+        pf = os.path.join(d, p)
 
         message = None
         user = None
         date = None
         hgpatch = False
 
-        p = email.Parser.Parser()
+        parser = email.Parser.Parser()
         if pf == '-':
-            msg = p.parse(sys.stdin)
+            msg = parser.parse(sys.stdin)
             ui.status(_("applying patch from stdin\n"))
         else:
-            msg = p.parse(file(pf))
-            ui.status(_("applying %s\n") % patch)
+            msg = parser.parse(file(pf))
+            ui.status(_("applying %s\n") % p)
 
         fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
         tmpfp = os.fdopen(fd, 'w')
@@ -1908,7 +1908,7 @@
             if not diffs_seen:
                 raise util.Abort(_('no diffs found'))
 
-            files = util.patch(strip, tmpname, ui, cwd=repo.root)
+            files = patch.patch(strip, tmpname, ui, cwd=repo.root)
             removes = []
             if len(files) > 0:
                 cfiles = files.keys()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/patch.py	Fri Aug 11 15:50:16 2006 -0700
@@ -0,0 +1,165 @@
+# patch.py - patch file parsing routines
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+from demandload import demandload
+demandload(globals(), "util")
+demandload(globals(), "os re shutil tempfile")
+
+def readgitpatch(patchname):
+    """extract git-style metadata about patches from <patchname>"""
+    class gitpatch:
+        "op is one of ADD, DELETE, RENAME, MODIFY or COPY"
+        def __init__(self, path):
+            self.path = path
+            self.oldpath = None
+            self.mode = None
+            self.op = 'MODIFY'
+            self.copymod = False
+            self.lineno = 0
+    
+    # Filter patch for git information
+    gitre = re.compile('diff --git a/(.*) b/(.*)')
+    pf = file(patchname)
+    gp = None
+    gitpatches = []
+    # Can have a git patch with only metadata, causing patch to complain
+    dopatch = False
+
+    lineno = 0
+    for line in pf:
+        lineno += 1
+        if line.startswith('diff --git'):
+            m = gitre.match(line)
+            if m:
+                if gp:
+                    gitpatches.append(gp)
+                src, dst = m.group(1,2)
+                gp = gitpatch(dst)
+                gp.lineno = lineno
+        elif gp:
+            if line.startswith('--- '):
+                if gp.op in ('COPY', 'RENAME'):
+                    gp.copymod = True
+                    dopatch = 'filter'
+                gitpatches.append(gp)
+                gp = None
+                if not dopatch:
+                    dopatch = True
+                continue
+            if line.startswith('rename from '):
+                gp.op = 'RENAME'
+                gp.oldpath = line[12:].rstrip()
+            elif line.startswith('rename to '):
+                gp.path = line[10:].rstrip()
+            elif line.startswith('copy from '):
+                gp.op = 'COPY'
+                gp.oldpath = line[10:].rstrip()
+            elif line.startswith('copy to '):
+                gp.path = line[8:].rstrip()
+            elif line.startswith('deleted file'):
+                gp.op = 'DELETE'
+            elif line.startswith('new file mode '):
+                gp.op = 'ADD'
+                gp.mode = int(line.rstrip()[-3:], 8)
+            elif line.startswith('new mode '):
+                gp.mode = int(line.rstrip()[-3:], 8)
+    if gp:
+        gitpatches.append(gp)
+
+    if not gitpatches:
+        dopatch = True
+
+    return (dopatch, gitpatches)
+
+def dogitpatch(patchname, gitpatches):
+    """Preprocess git patch so that vanilla patch can handle it"""
+    pf = file(patchname)
+    pfline = 1
+
+    fd, patchname = tempfile.mkstemp(prefix='hg-patch-')
+    tmpfp = os.fdopen(fd, 'w')
+
+    try:
+        for i in range(len(gitpatches)):
+            p = gitpatches[i]
+            if not p.copymod:
+                continue
+
+            if os.path.exists(p.path):
+                raise util.Abort(_("cannot create %s: destination already exists") %
+                            p.path)
+
+            (src, dst) = [os.path.join(os.getcwd(), n)
+                          for n in (p.oldpath, p.path)]
+
+            print "copying %s to %s" % (src, dst)
+            targetdir = os.path.dirname(dst)
+            if not os.path.isdir(targetdir):
+                os.makedirs(targetdir)
+            try:
+                shutil.copyfile(src, dst)
+                shutil.copymode(src, dst)
+            except shutil.Error, inst:
+                raise util.Abort(str(inst))
+
+            # rewrite patch hunk
+            while pfline < p.lineno:
+                tmpfp.write(pf.readline())
+                pfline += 1
+            tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path))
+            line = pf.readline()
+            pfline += 1
+            while not line.startswith('--- a/'):
+                tmpfp.write(line)
+                line = pf.readline()
+                pfline += 1
+            tmpfp.write('--- a/%s\n' % p.path)
+
+        line = pf.readline()
+        while line:
+            tmpfp.write(line)
+            line = pf.readline()
+    except:
+        tmpfp.close()
+        os.unlink(patchname)
+        raise
+
+    tmpfp.close()
+    return patchname
+
+def patch(strip, patchname, ui, cwd=None):
+    """apply the patch <patchname> to the working directory.
+    a list of patched files is returned"""
+
+    (dopatch, gitpatches) = readgitpatch(patchname)
+
+    files = {}
+    if dopatch:
+        if dopatch == 'filter':
+            patchname = dogitpatch(patchname, gitpatches)
+        patcher = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
+        args = []
+        if cwd:
+            args.append('-d %s' % util.shellquote(cwd))
+        fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
+                                           util.shellquote(patchname)))
+
+        if dopatch == 'filter':
+            False and os.unlink(patchname)
+
+        for line in fp:
+            line = line.rstrip()
+            ui.status("%s\n" % line)
+            if line.startswith('patching file '):
+                pf = util.parse_patch_output(line)
+                files.setdefault(pf, (None, None))
+        code = fp.close()
+        if code:
+            raise util.Abort(_("patch command failed: %s") % explain_exit(code)[0])
+
+    for gp in gitpatches:
+        files[gp.path] = (gp.op, gp)
+
+    return files
--- a/mercurial/util.py	Fri Aug 11 15:50:07 2006 -0700
+++ b/mercurial/util.py	Fri Aug 11 15:50:16 2006 -0700
@@ -93,163 +93,6 @@
             return p_name
     return default
 
-def readgitpatch(patchname):
-    """extract git-style metadata about patches from <patchname>"""
-    class gitpatch:
-        "op is one of ADD, DELETE, RENAME, MODIFY or COPY"
-        def __init__(self, path):
-            self.path = path
-            self.oldpath = None
-            self.mode = None
-            self.op = 'MODIFY'
-            self.copymod = False
-            self.lineno = 0
-    
-    # Filter patch for git information
-    gitre = re.compile('diff --git a/(.*) b/(.*)')
-    pf = file(patchname)
-    gp = None
-    gitpatches = []
-    # Can have a git patch with only metadata, causing patch to complain
-    dopatch = False
-
-    lineno = 0
-    for line in pf:
-        lineno += 1
-        if line.startswith('diff --git'):
-            m = gitre.match(line)
-            if m:
-                if gp:
-                    gitpatches.append(gp)
-                src, dst = m.group(1,2)
-                gp = gitpatch(dst)
-                gp.lineno = lineno
-        elif gp:
-            if line.startswith('--- '):
-                if gp.op in ('COPY', 'RENAME'):
-                    gp.copymod = True
-                    dopatch = 'filter'
-                gitpatches.append(gp)
-                gp = None
-                if not dopatch:
-                    dopatch = True
-                continue
-            if line.startswith('rename from '):
-                gp.op = 'RENAME'
-                gp.oldpath = line[12:].rstrip()
-            elif line.startswith('rename to '):
-                gp.path = line[10:].rstrip()
-            elif line.startswith('copy from '):
-                gp.op = 'COPY'
-                gp.oldpath = line[10:].rstrip()
-            elif line.startswith('copy to '):
-                gp.path = line[8:].rstrip()
-            elif line.startswith('deleted file'):
-                gp.op = 'DELETE'
-            elif line.startswith('new file mode '):
-                gp.op = 'ADD'
-                gp.mode = int(line.rstrip()[-3:], 8)
-            elif line.startswith('new mode '):
-                gp.mode = int(line.rstrip()[-3:], 8)
-    if gp:
-        gitpatches.append(gp)
-
-    if not gitpatches:
-        dopatch = True
-
-    return (dopatch, gitpatches)
-
-def dogitpatch(patchname, gitpatches):
-    """Preprocess git patch so that vanilla patch can handle it"""
-    pf = file(patchname)
-    pfline = 1
-
-    fd, patchname = tempfile.mkstemp(prefix='hg-patch-')
-    tmpfp = os.fdopen(fd, 'w')
-
-    try:
-        for i in range(len(gitpatches)):
-            p = gitpatches[i]
-            if not p.copymod:
-                continue
-
-            if os.path.exists(p.path):
-                raise Abort(_("cannot create %s: destination already exists") %
-                            p.path)
-
-            (src, dst) = [os.path.join(os.getcwd(), n)
-                          for n in (p.oldpath, p.path)]
-
-            print "copying %s to %s" % (src, dst)
-            targetdir = os.path.dirname(dst)
-            if not os.path.isdir(targetdir):
-                os.makedirs(targetdir)
-            try:
-                shutil.copyfile(src, dst)
-                shutil.copymode(src, dst)
-            except shutil.Error, inst:
-                raise Abort(str(inst))
-
-            # rewrite patch hunk
-            while pfline < p.lineno:
-                tmpfp.write(pf.readline())
-                pfline += 1
-            tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path))
-            line = pf.readline()
-            pfline += 1
-            while not line.startswith('--- a/'):
-                tmpfp.write(line)
-                line = pf.readline()
-                pfline += 1
-            tmpfp.write('--- a/%s\n' % p.path)
-
-        line = pf.readline()
-        while line:
-            tmpfp.write(line)
-            line = pf.readline()
-    except:
-        tmpfp.close()
-        os.unlink(patchname)
-        raise
-
-    tmpfp.close()
-    return patchname
-
-def patch(strip, patchname, ui, cwd=None):
-    """apply the patch <patchname> to the working directory.
-    a list of patched files is returned"""
-
-    (dopatch, gitpatches) = readgitpatch(patchname)
-
-    files = {}
-    if dopatch:
-        if dopatch == 'filter':
-            patchname = dogitpatch(patchname, gitpatches)
-        patcher = find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
-        args = []
-        if cwd:
-            args.append('-d %s' % shellquote(cwd))
-        fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
-                                           shellquote(patchname)))
-
-        if dopatch == 'filter':
-            False and os.unlink(patchname)
-
-        for line in fp:
-            line = line.rstrip()
-            ui.status("%s\n" % line)
-            if line.startswith('patching file '):
-                pf = parse_patch_output(line)
-                files.setdefault(pf, (None, None))
-        code = fp.close()
-        if code:
-            raise Abort(_("patch command failed: %s") % explain_exit(code)[0])
-
-    for gp in gitpatches:
-        files[gp.path] = (gp.op, gp)
-
-    return files
-
 def binary(s):
     """return true if a string is binary data using diff's heuristic"""
     if s and '\0' in s[:4096]: