changeset 2878:ffa2be02c4e5

merge.
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Sat, 12 Aug 2006 15:43:38 -0700
parents 8eaaf1321bfe (current diff) 9a2a481ec3ea (diff)
children 5dd6631c8238
files mercurial/commands.py
diffstat 43 files changed, 582 insertions(+), 219 deletions(-) [+]
line wrap: on
line diff
--- a/doc/hg.1.txt	Sat Aug 12 15:01:46 2006 -0700
+++ b/doc/hg.1.txt	Sat Aug 12 15:43:38 2006 -0700
@@ -216,6 +216,6 @@
 
 COPYING
 -------
-Copyright \(C) 2005 Matt Mackall.
+Copyright \(C) 2005, 2006 Matt Mackall.
 Free use of this software is granted under the terms of the GNU General
 Public License (GPL).
--- a/doc/hgmerge.1.txt	Sat Aug 12 15:01:46 2006 -0700
+++ b/doc/hgmerge.1.txt	Sat Aug 12 15:43:38 2006 -0700
@@ -30,6 +30,6 @@
 
 COPYING
 -------
-Copyright \(C) 2005 Matt Mackall.
+Copyright \(C) 2005, 2006 Matt Mackall.
 Free use of this software is granted under the terms of the GNU General
 Public License (GPL).
--- a/doc/ja/hg.1.ja.txt	Sat Aug 12 15:01:46 2006 -0700
+++ b/doc/ja/hg.1.ja.txt	Sat Aug 12 15:43:38 2006 -0700
@@ -862,6 +862,6 @@
 
 著作権情報
 -----
-Copyright (C) 2005 Matt Mackall.
+Copyright (C) 2005, 2006 Matt Mackall.
 このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
 認められます。
--- a/doc/ja/hgmerge.1.ja.txt	Sat Aug 12 15:01:46 2006 -0700
+++ b/doc/ja/hgmerge.1.ja.txt	Sat Aug 12 15:43:38 2006 -0700
@@ -32,6 +32,6 @@
 
 著作権情報
 ----
-Copyright (C) 2005 Matt Mackall.
+Copyright (C) 2005, 2006 Matt Mackall.
 このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
 認められます。
--- a/hgext/hgk.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/hgext/hgk.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,6 @@
 # Minimal support for git commands on an hg repository
 #
-# Copyright 2005 Chris Mason <mason@suse.com>
+# Copyright 2005, 2006 Chris Mason <mason@suse.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/hgext/mq.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/hgext/mq.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,7 +1,6 @@
-
 # queue.py - patch queues for mercurial
 #
-# Copyright 2005 Chris Mason <mason@suse.com>
+# Copyright 2005, 2006 Chris Mason <mason@suse.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -31,9 +30,9 @@
 '''
 
 from mercurial.demandload import *
+from mercurial.i18n import gettext as _
 demandload(globals(), "os sys re struct traceback errno bz2")
-from mercurial.i18n import gettext as _
-from mercurial import ui, hg, revlog, commands, util
+demandload(globals(), "mercurial:commands,hg,revlog,ui,util")
 
 commands.norepo += " qclone qversion"
 
@@ -561,7 +560,7 @@
         r = self.qrepo()
         if r: r.add([patch])
         if commitfiles:
-            self.refresh(repo, msg=None, short=True)
+            self.refresh(repo, short=True)
 
     def strip(self, repo, rev, update=True, backup="all", wlock=None):
         def limitheads(chlog, stop):
@@ -888,7 +887,6 @@
             top = self.check_toppatch(repo)
             qp = self.qparents(repo, rev)
             changes = repo.changelog.read(qp)
-            mf1 = repo.manifest.readflags(changes[0])
             mmap = repo.manifest.read(changes[0])
             (c, a, r, d, u) = repo.changes(qp, top)
             if d:
@@ -897,7 +895,7 @@
                 getfile(f, mmap[f])
             for f in r:
                 getfile(f, mmap[f])
-                util.set_exec(repo.wjoin(f), mf1[f])
+                util.set_exec(repo.wjoin(f), mmap.execf[f])
             repo.dirstate.update(c + r, 'n')
             for f in a:
                 try: os.unlink(repo.wjoin(f))
@@ -922,7 +920,7 @@
         qp = self.qparents(repo, top)
         commands.dodiff(sys.stdout, self.ui, repo, qp, None, files)
 
-    def refresh(self, repo, msg=None, short=False):
+    def refresh(self, repo, msg='', short=False):
         if len(self.applied) == 0:
             self.ui.write("No patches applied\n")
             return
@@ -1988,4 +1986,3 @@
     "qtop": (top, [], 'hg qtop'),
     "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
 }
-
--- a/mercurial/archival.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/archival.py	Sat Aug 12 15:43:38 2006 -0700
@@ -163,12 +163,12 @@
     change = repo.changelog.read(node)
     mn = change[0]
     archiver = archivers[kind](dest, prefix, mtime or change[2][0])
-    mf = repo.manifest.read(mn).items()
-    mff = repo.manifest.readflags(mn)
-    mf.sort()
+    m = repo.manifest.read(mn)
+    items = m.items()
+    items.sort()
     write('.hg_archival.txt', 0644,
           'repo: %s\nnode: %s\n' % (hex(repo.changelog.node(0)), hex(node)))
-    for filename, filenode in mf:
-        write(filename, mff[filename] and 0755 or 0644,
+    for filename, filenode in items:
+        write(filename, m.execf(filename) and 0755 or 0644,
               repo.file(filename).read(filenode))
     archiver.done()
--- a/mercurial/bdiff.c	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/bdiff.c	Sat Aug 12 15:43:38 2006 -0700
@@ -1,7 +1,7 @@
 /*
  bdiff.c - efficient binary diff extension for Mercurial
 
- Copyright 2005 Matt Mackall <mpm@selenic.com>
+ Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 
  This software may be used and distributed according to the terms of
  the GNU General Public License, incorporated herein by reference.
--- a/mercurial/changelog.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/changelog.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,6 @@
 # changelog.py - changelog class for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/commands.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/commands.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,6 @@
 # commands.py - command processing for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -10,9 +10,9 @@
 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 difflib random signal tempfile time")
+demandload(globals(), "fnmatch mdiff difflib patch random signal tempfile time")
 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
-demandload(globals(), "archival cStringIO changegroup email.Parser")
+demandload(globals(), "archival cStringIO changegroup")
 demandload(globals(), "hgweb.server sshserver")
 
 class UnknownCommand(Exception):
@@ -633,7 +633,7 @@
     ui.write(_("Mercurial Distributed SCM (version %s)\n")
              % version.get_version())
     ui.status(_(
-        "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
+        "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
         "This is free software; see the source for copying conditions. "
         "There is NO\nwarranty; "
         "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
@@ -1333,9 +1333,9 @@
         rev = repo.lookup(rev)
     change = repo.changelog.read(rev)
     n = change[0]
-    files = repo.manifest.readflags(n)
+    files = repo.manifest.read(n)
     wlock = repo.wlock()
-    repo.dirstate.rebuild(rev, files.iteritems())
+    repo.dirstate.rebuild(rev, files)
 
 def debugcheckstate(ui, repo):
     """validate the correctness of the current dirstate"""
@@ -1843,84 +1843,23 @@
     d = opts["base"]
     strip = opts["strip"]
 
-    mailre = re.compile(r'(?:From |[\w-]+:)')
-
-    # attempt to detect the start of a patch
-    # (this heuristic is borrowed from quilt)
-    diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
-                        'retrieving revision [0-9]+(\.[0-9]+)*$|' +
-                        '(---|\*\*\*)[ \t])', re.MULTILINE)
-
     wlock = repo.wlock()
     lock = repo.lock()
 
-    for patch in patches:
-        pf = os.path.join(d, patch)
-
-        message = None
-        user = None
-        date = None
-        hgpatch = False
-
-        p = email.Parser.Parser()
+    for p in patches:
+        pf = os.path.join(d, p)
+
         if pf == '-':
-            msg = p.parse(sys.stdin)
             ui.status(_("applying patch from stdin\n"))
+            tmpname, message, user, date = patch.extract(ui, sys.stdin)
         else:
-            msg = p.parse(file(pf))
-            ui.status(_("applying %s\n") % patch)
-
-        fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
-        tmpfp = os.fdopen(fd, 'w')
+            ui.status(_("applying %s\n") % p)
+            tmpname, message, user, date = patch.extract(ui, file(pf))
+
+        if tmpname is None:
+            raise util.Abort(_('no diffs found'))
+
         try:
-            message = msg['Subject']
-            if message:
-                message = message.replace('\n\t', ' ')
-                ui.debug('Subject: %s\n' % message)
-            user = msg['From']
-            if user:
-                ui.debug('From: %s\n' % user)
-            diffs_seen = 0
-            ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
-            for part in msg.walk():
-                content_type = part.get_content_type()
-                ui.debug('Content-Type: %s\n' % content_type)
-                if content_type not in ok_types:
-                    continue
-                payload = part.get_payload(decode=True)
-                m = diffre.search(payload)
-                if m:
-                    ui.debug(_('found patch at byte %d\n') % m.start(0))
-                    diffs_seen += 1
-                    hgpatch = False
-                    fp = cStringIO.StringIO()
-                    if message:
-                        fp.write(message)
-                        fp.write('\n')
-                    for line in payload[:m.start(0)].splitlines():
-                        if line.startswith('# HG changeset patch'):
-                            ui.debug(_('patch generated by hg export\n'))
-                            hgpatch = True
-                            # drop earlier commit message content
-                            fp.seek(0)
-                            fp.truncate()
-                        elif hgpatch:
-                            if line.startswith('# User '):
-                                user = line[7:]
-                                ui.debug('From: %s\n' % user)
-                            elif line.startswith("# Date "):
-                                date = line[7:]
-                        if not line.startswith('# '):
-                            fp.write(line)
-                            fp.write('\n')
-                    message = fp.getvalue()
-                    if tmpfp:
-                        tmpfp.write(payload)
-                        if not payload.endswith('\n'):
-                            tmpfp.write('\n')
-                elif not diffs_seen and message and content_type == 'text/plain':
-                    message += '\n' + payload
-
             if opts['message']:
                 # pickup the cmdline msg
                 message = opts['message']
@@ -1932,17 +1871,45 @@
                 message = None
             ui.debug(_('message:\n%s\n') % message)
 
-            tmpfp.close()
-            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
+                cfiles = files.keys()
+                copies = []
+                copts = {'after': False, 'force': False}
                 cwd = repo.getcwd()
                 if cwd:
-                    cfiles = [util.pathto(cwd, f) for f in files]
+                    cfiles = [util.pathto(cwd, f) for f in files.keys()]
+                for f in files:
+                    ctype, gp = files[f]
+                    if ctype == 'RENAME':
+                        copies.append((gp.oldpath, gp.path, gp.copymod))
+                        removes.append(gp.oldpath)
+                    elif ctype == 'COPY':
+                        copies.append((gp.oldpath, gp.path, gp.copymod))
+                    elif ctype == 'DELETE':
+                        removes.append(gp.path)
+                for src, dst, after in copies:
+                    absdst = os.path.join(repo.root, dst)
+                    if not after and os.path.exists(absdst):
+                        raise util.Abort(_('patch creates existing file %s') % dst)
+                    if cwd:
+                        src, dst = [util.pathto(cwd, f) for f in (src, dst)]
+                    copts['after'] = after
+                    errs, copied = docopy(ui, repo, (src, dst), copts, wlock=wlock)
+                    if errs:
+                        raise util.Abort(errs)
+                if removes:
+                    repo.remove(removes, True, wlock=wlock)
+                for f in files:
+                    ctype, gp = files[f]
+                    if gp and gp.mode:
+                        x = gp.mode & 0100 != 0
+                        dst = os.path.join(repo.root, gp.path)
+                        util.set_exec(dst, x)
                 addremove_lock(ui, repo, cfiles, {}, wlock=wlock)
+            files = files.keys()
+            files.extend([r for r in removes if r not in files])
             repo.commit(files, message, user, date, wlock=wlock, lock=lock)
         finally:
             os.unlink(tmpname)
@@ -2178,12 +2145,12 @@
     else:
         n = repo.manifest.tip()
     m = repo.manifest.read(n)
-    mf = repo.manifest.readflags(n)
     files = m.keys()
     files.sort()
 
     for f in files:
-        ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
+        ui.write("%40s %3s %s\n" % (hex(m[f]),
+                                    m.execf(f) and "755" or "644", f))
 
 def merge(ui, repo, node=None, force=None, branch=None):
     """Merge working directory with another revision
--- a/mercurial/context.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/context.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,6 @@
 # context.py - changeset and file context objects for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/dirstate.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/dirstate.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,7 +1,7 @@
 """
 dirstate.py - working directory tracking for mercurial
 
-Copyright 2005 Matt Mackall <mpm@selenic.com>
+Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 
 This software may be used and distributed according to the terms
 of the GNU General Public License, incorporated herein by reference.
@@ -238,8 +238,8 @@
         self.clear()
         umask = os.umask(0)
         os.umask(umask)
-        for f, mode in files:
-            if mode:
+        for f in files:
+            if files.execf(f):
                 self.map[f] = ('n', ~umask, -1, 0)
             else:
                 self.map[f] = ('n', ~umask & 0666, -1, 0)
--- a/mercurial/filelog.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/filelog.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,6 @@
 # filelog.py - file history class for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/hg.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/hg.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,7 @@
 # hg.py - repository classes for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/hgweb/common.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/hgweb/common.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,7 +1,7 @@
 # hgweb/common.py - Utility functions needed by hgweb_mod and hgwebdir_mod
 #
 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/hgweb/hgweb_mod.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/hgweb/hgweb_mod.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,7 +1,7 @@
 # hgweb/hgweb_mod.py - Web interface for a repository.
 #
 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -398,7 +398,7 @@
                      parent=self.siblings(fl.parents(n), fl.rev, file=f),
                      child=self.siblings(fl.children(n), fl.rev, file=f),
                      rename=self.renamelink(fl, n),
-                     permissions=self.repo.manifest.readflags(mfn)[f])
+                     permissions=self.repo.manifest.read(mfn).execf(f))
 
     def fileannotate(self, f, node):
         bcache = {}
@@ -452,7 +452,7 @@
                      rename=self.renamelink(fl, n),
                      parent=self.siblings(fl.parents(n), fl.rev, file=f),
                      child=self.siblings(fl.children(n), fl.rev, file=f),
-                     permissions=self.repo.manifest.readflags(mfn)[f])
+                     permissions=self.repo.manifest.read(mfn).execf(f))
 
     def manifest(self, mnode, path):
         man = self.repo.manifest
@@ -462,7 +462,6 @@
         rev = man.rev(mn)
         changerev = man.linkrev(mn)
         node = self.repo.changelog.node(changerev)
-        mff = man.readflags(mn)
 
         files = {}
 
@@ -496,7 +495,7 @@
                        "filenode": hex(fnode),
                        "parity": self.stripes(parity),
                        "basename": f,
-                       "permissions": mff[full]}
+                       "permissions": mf.execf(full)}
                 parity += 1
 
         def dirlist(**map):
--- a/mercurial/hgweb/hgwebdir_mod.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/hgweb/hgwebdir_mod.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,7 +1,7 @@
 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
 #
 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/hgweb/request.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/hgweb/request.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,7 +1,7 @@
 # hgweb/request.py - An http request from either CGI or the standalone server.
 #
 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/hgweb/server.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/hgweb/server.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,7 +1,7 @@
 # hgweb/server.py - The standalone hg web server.
 #
 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/httprangereader.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/httprangereader.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,6 @@
 # httprangereader.py - just what it says
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/httprepo.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/httprepo.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,7 @@
 # httprepo.py - HTTP repository proxy classes for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/i18n.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/i18n.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,7 +1,7 @@
 """
 i18n.py - internationalization support for mercurial
 
-Copyright 2005 Matt Mackall <mpm@selenic.com>
+Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 
 This software may be used and distributed according to the terms
 of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/localrepo.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/localrepo.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,6 @@
 # localrepo.py - read/write repository class for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -470,8 +470,7 @@
         p2 = p2 or self.dirstate.parents()[1] or nullid
         c1 = self.changelog.read(p1)
         c2 = self.changelog.read(p2)
-        m1 = self.manifest.read(c1[0])
-        mf1 = self.manifest.readflags(c1[0])
+        m1 = self.manifest.read(c1[0]).copy()
         m2 = self.manifest.read(c2[0])
         changed = []
 
@@ -484,36 +483,32 @@
             wlock = self.wlock()
         l = self.lock()
         tr = self.transaction()
-        mm = m1.copy()
-        mfm = mf1.copy()
         linkrev = self.changelog.count()
         for f in files:
             try:
                 t = self.wread(f)
-                tm = util.is_exec(self.wjoin(f), mfm.get(f, False))
+                m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
                 r = self.file(f)
-                mfm[f] = tm
 
                 (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2)
                 if entry:
-                    mm[f] = entry
+                    m1[f] = entry
                     continue
 
-                mm[f] = r.add(t, {}, tr, linkrev, fp1, fp2)
+                m1[f] = r.add(t, {}, tr, linkrev, fp1, fp2)
                 changed.append(f)
                 if update_dirstate:
                     self.dirstate.update([f], "n")
             except IOError:
                 try:
-                    del mm[f]
-                    del mfm[f]
+                    del m1[f]
                     if update_dirstate:
                         self.dirstate.forget([f])
                 except:
                     # deleted from p2?
                     pass
 
-        mnode = self.manifest.add(mm, mfm, tr, linkrev, c1[0], c2[0])
+        mnode = self.manifest.add(m1, tr, linkrev, c1[0], c2[0])
         user = user or self.ui.username()
         n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date)
         tr.close()
@@ -544,8 +539,7 @@
         p1, p2 = self.dirstate.parents()
         c1 = self.changelog.read(p1)
         c2 = self.changelog.read(p2)
-        m1 = self.manifest.read(c1[0])
-        mf1 = self.manifest.readflags(c1[0])
+        m1 = self.manifest.read(c1[0]).copy()
         m2 = self.manifest.read(c2[0])
 
         if not commit and not remove and not force and p2 == nullid:
@@ -571,7 +565,7 @@
         for f in commit:
             self.ui.note(f + "\n")
             try:
-                mf1[f] = util.is_exec(self.wjoin(f), mf1.get(f, False))
+                m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
                 t = self.wread(f)
             except IOError:
                 self.ui.warn(_("trouble committing %s!\n") % f)
@@ -598,12 +592,11 @@
             changed.append(f)
 
         # update manifest
-        m1 = m1.copy()
         m1.update(new)
         for f in remove:
             if f in m1:
                 del m1[f]
-        mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0],
+        mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0],
                                (new, remove))
 
         # add changeset
@@ -816,7 +809,6 @@
     def undelete(self, list, wlock=None):
         p = self.dirstate.parents()[0]
         mn = self.changelog.read(p)[0]
-        mf = self.manifest.readflags(mn)
         m = self.manifest.read(mn)
         if not wlock:
             wlock = self.wlock()
@@ -826,7 +818,7 @@
             else:
                 t = self.file(f).read(m[f])
                 self.wwrite(f, t)
-                util.set_exec(self.wjoin(f), mf[f])
+                util.set_exec(self.wjoin(f), m.execf(f))
                 self.dirstate.update([f], "n")
 
     def copy(self, source, dest, wlock=None):
--- a/mercurial/lock.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/lock.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,6 @@
 # lock.py - simple locking scheme for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/manifest.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/manifest.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,6 @@
 # manifest.py - manifest revision class for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -10,6 +10,31 @@
 from demandload import *
 demandload(globals(), "array bisect struct")
 
+class manifestdict(dict):
+    def __init__(self, mapping=None, flags=None):
+        if mapping is None: mapping = {}
+        if flags is None: flags = {}
+        dict.__init__(self, mapping)
+        self._flags = flags
+    def flags(self, f):
+        return self._flags.get(f, "")
+    def execf(self, f):
+        "test for executable in manifest flags"
+        return "x" in self.flags(f)
+    def linkf(self, f):
+        "test for symlink in manifest flags"
+        return "l" in self.flags(f)
+    def rawset(self, f, entry):
+        self[f] = bin(entry[:40])
+        fl = entry[40:-1]
+        if fl: self._flags[f] = fl
+    def set(self, f, execf=False, linkf=False):
+        if linkf: self._flags[f] = "l"
+        elif execf: self._flags[f] = "x"
+        else: self._flags[f] = ""
+    def copy(self):
+        return manifestdict(dict.copy(self), dict.copy(self._flags))
+
 class manifest(revlog):
     def __init__(self, opener, defversion=REVLOGV0):
         self.mapcache = None
@@ -18,26 +43,18 @@
                         defversion)
 
     def read(self, node):
-        if node == nullid: return {} # don't upset local cache
+        if node == nullid: return manifestdict() # don't upset local cache
         if self.mapcache and self.mapcache[0] == node:
             return self.mapcache[1]
         text = self.revision(node)
-        map = {}
-        flag = {}
         self.listcache = array.array('c', text)
         lines = text.splitlines(1)
+        mapping = manifestdict()
         for l in lines:
             (f, n) = l.split('\0')
-            map[f] = bin(n[:40])
-            flag[f] = (n[40:-1] == "x")
-        self.mapcache = (node, map, flag)
-        return map
-
-    def readflags(self, node):
-        if node == nullid: return {} # don't upset local cache
-        if not self.mapcache or self.mapcache[0] != node:
-            self.read(node)
-        return self.mapcache[2]
+            mapping.rawset(f, n)
+        self.mapcache = (node, mapping)
+        return mapping
 
     def diff(self, a, b):
         return mdiff.textdiff(str(a), str(b))
@@ -86,7 +103,7 @@
         '''look up entry for a single file efficiently.
         return (node, flag) pair if found, (None, None) if not.'''
         if self.mapcache and node == self.mapcache[0]:
-            return self.mapcache[1].get(f), self.mapcache[2].get(f)
+            return self.mapcache[1].get(f), self.mapcache[1].flags(f)
         text = self.revision(node)
         start, end = self._search(text, f)
         if start == end:
@@ -95,7 +112,7 @@
         f, n = l.split('\0')
         return bin(n[:40]), n[40:-1] == 'x'
 
-    def add(self, map, flags, transaction, link, p1=None, p2=None,
+    def add(self, map, transaction, link, p1=None, p2=None,
             changed=None):
         # apply the changes collected during the bisect loop to our addlist
         # return a delta suitable for addrevision
@@ -123,9 +140,7 @@
 
             # if this is changed to support newlines in filenames,
             # be sure to check the templates/ dir again (especially *-raw.tmpl)
-            text = ["%s\000%s%s\n" %
-                            (f, hex(map[f]), flags[f] and "x" or '')
-                            for f in files]
+            text = ["%s\000%s%s\n" % (f, hex(map[f]), map.flags(f)) for f in files]
             self.listcache = array.array('c', "".join(text))
             cachedelta = None
         else:
@@ -151,8 +166,7 @@
                 # bs will either be the index of the item or the insert point
                 start, end = self._search(addbuf, f, start)
                 if w[1] == 0:
-                    l = "%s\000%s%s\n" % (f, hex(map[f]),
-                                          flags[f] and "x" or '')
+                    l = "%s\000%s%s\n" % (f, hex(map[f]), map.flags(f))
                 else:
                     l = ""
                 if start == end and w[1] == 1:
@@ -183,6 +197,6 @@
 
         n = self.addrevision(buffer(self.listcache), transaction, link, p1,  \
                              p2, cachedelta)
-        self.mapcache = (n, map, flags)
+        self.mapcache = (n, map)
 
         return n
--- a/mercurial/mdiff.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/mdiff.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,6 @@
 # mdiff.py - diff and patch routines for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/merge.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/merge.py	Sat Aug 12 15:43:38 2006 -0700
@@ -84,11 +84,8 @@
     m2n = repo.changelog.read(p2)[0]
     man = repo.manifest.ancestor(m1n, m2n)
     m1 = repo.manifest.read(m1n)
-    mf1 = repo.manifest.readflags(m1n)
     m2 = repo.manifest.read(m2n).copy()
-    mf2 = repo.manifest.readflags(m2n)
     ma = repo.manifest.read(man)
-    mfa = repo.manifest.readflags(man)
 
     if not forcemerge and not overwrite:
         for f in unknown:
@@ -113,12 +110,11 @@
 
     # construct a working dir manifest
     mw = m1.copy()
-    mfw = mf1.copy()
     umap = dict.fromkeys(unknown)
 
     for f in added + modified + unknown:
         mw[f] = ""
-        mfw[f] = util.is_exec(repo.wjoin(f), mfw.get(f, False))
+        mw.set(f, util.is_exec(repo.wjoin(f), mw.execf(f)))
 
     for f in deleted + removed:
         if f in mw:
@@ -155,28 +151,28 @@
                     repo.ui.debug(_(" %s versions differ, resolve\n") % f)
                     # merge executable bits
                     # "if we changed or they changed, change in merge"
-                    a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
+                    a, b, c = ma.execf(f), mw.execf(f), m2.execf(f)
                     mode = ((a^b) | (a^c)) ^ a
-                    merge[f] = (m1.get(f, nullid), m2[f], mode)
+                    merge[f] = (mode, m1.get(f, nullid), m2[f])
                     s = 1
                 # are we clobbering?
                 # is remote's version newer?
                 # or are we going back in time?
                 elif overwrite or m2[f] != a or (p2 == pa and mw[f] == m1[f]):
                     repo.ui.debug(_(" remote %s is newer, get\n") % f)
-                    get[f] = m2[f]
+                    get[f] = (m2.execf(f), m2[f])
                     s = 1
             elif f in umap or f in added:
                 # this unknown file is the same as the checkout
                 # we need to reset the dirstate if the file was added
-                get[f] = m2[f]
+                get[f] = (m2.execf(f), m2[f])
 
-            if not s and mfw[f] != mf2[f]:
+            if not s and mw.execf(f) != m2.execf(f):
                 if overwrite:
                     repo.ui.debug(_(" updating permissions for %s\n") % f)
-                    util.set_exec(repo.wjoin(f), mf2[f])
+                    util.set_exec(repo.wjoin(f), m2.execf(f))
                 else:
-                    a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
+                    a, b, c = ma.execf(f), mw.execf(f), m2.execf(f)
                     mode = ((a^b) | (a^c)) ^ a
                     if mode != b:
                         repo.ui.debug(_(" updating permissions for %s\n")
@@ -221,14 +217,14 @@
                     (_("remote changed %s which local deleted\n") % f) +
                      _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
             if r == _("k"):
-                get[f] = n
+                get[f] = (m2.execf(f), n)
         elif f not in ma:
             repo.ui.debug(_("remote created %s\n") % f)
-            get[f] = n
+            get[f] = (m2.execf(f), n)
         else:
             if overwrite or p2 == pa: # going backwards?
                 repo.ui.debug(_("local deleted %s, recreating\n") % f)
-                get[f] = n
+                get[f] = (m2.execf(f), n)
             else:
                 repo.ui.debug(_("local deleted %s\n") % f)
 
@@ -236,7 +232,7 @@
 
     if overwrite:
         for f in merge:
-            get[f] = merge[f][1]
+            get[f] = merge[f][:2]
         merge = {}
 
     if linear_path or overwrite:
@@ -254,12 +250,13 @@
     files = get.keys()
     files.sort()
     for f in files:
+        flag, node = get[f]
         if f[0] == "/":
             continue
         repo.ui.note(_("getting %s\n") % f)
-        t = repo.file(f).read(get[f])
+        t = repo.file(f).read(node)
         repo.wwrite(f, t)
-        util.set_exec(repo.wjoin(f), mf2[f])
+        util.set_exec(repo.wjoin(f), flag)
         if not partial:
             if branchmerge:
                 repo.dirstate.update([f], 'n', st_mtime=-1)
@@ -272,7 +269,7 @@
     files.sort()
     for f in files:
         repo.ui.status(_("merging %s\n") % f)
-        my, other, flag = merge[f]
+        flag, my, other = merge[f]
         ret = merge3(repo, f, my, other, xp1, xp2)
         if ret:
             unresolved.append(f)
--- a/mercurial/mpatch.c	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/mpatch.c	Sat Aug 12 15:43:38 2006 -0700
@@ -14,7 +14,7 @@
  allocation of intermediate Python objects. Working memory is about 2x
  the total number of hunks.
 
- Copyright 2005 Matt Mackall <mpm@selenic.com>
+ Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 
  This software may be used and distributed according to the terms
  of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/node.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/node.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,7 +1,7 @@
 """
 node.py - basic nodeid manipulation for mercurial
 
-Copyright 2005 Matt Mackall <mpm@selenic.com>
+Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 
 This software may be used and distributed according to the terms
 of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/packagescan.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/packagescan.py	Sat Aug 12 15:43:38 2006 -0700
@@ -2,7 +2,7 @@
 # Used for the py2exe distutil.
 # This module must be the first mercurial module imported in setup.py
 #
-# Copyright 2005 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
+# Copyright 2005, 2006 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/patch.py	Sat Aug 12 15:43:38 2006 -0700
@@ -0,0 +1,251 @@
+# patch.py - patch file parsing routines
+#
+# Copyright 2006 Brendan Cully <brendan@kublai.com>
+#
+# 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
+from i18n import gettext as _
+demandload(globals(), "util")
+demandload(globals(), "cStringIO email.Parser os re shutil tempfile")
+
+def extract(ui, fileobj):
+    '''extract patch from data read from fileobj.
+
+    patch can be normal patch or contained in email message.
+
+    return tuple (filename, message, user, date). any item in returned
+    tuple can be None.  if filename is None, fileobj did not contain
+    patch. caller must unlink filename when done.'''
+
+    # attempt to detect the start of a patch
+    # (this heuristic is borrowed from quilt)
+    diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
+                        'retrieving revision [0-9]+(\.[0-9]+)*$|' +
+                        '(---|\*\*\*)[ \t])', re.MULTILINE)
+
+    fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
+    tmpfp = os.fdopen(fd, 'w')
+    try:
+        hgpatch = False
+
+        msg = email.Parser.Parser().parse(fileobj)
+
+        message = msg['Subject']
+        user = msg['From']
+        # should try to parse msg['Date']
+        date = None
+
+        if message:
+            message = message.replace('\n\t', ' ')
+            ui.debug('Subject: %s\n' % message)
+        if user:
+            ui.debug('From: %s\n' % user)
+        diffs_seen = 0
+        ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
+
+        for part in msg.walk():
+            content_type = part.get_content_type()
+            ui.debug('Content-Type: %s\n' % content_type)
+            if content_type not in ok_types:
+                continue
+            payload = part.get_payload(decode=True)
+            m = diffre.search(payload)
+            if m:
+                ui.debug(_('found patch at byte %d\n') % m.start(0))
+                diffs_seen += 1
+                cfp = cStringIO.StringIO()
+                if message:
+                    cfp.write(message)
+                    cfp.write('\n')
+                for line in payload[:m.start(0)].splitlines():
+                    if line.startswith('# HG changeset patch'):
+                        ui.debug(_('patch generated by hg export\n'))
+                        hgpatch = True
+                        # drop earlier commit message content
+                        cfp.seek(0)
+                        cfp.truncate()
+                    elif hgpatch:
+                        if line.startswith('# User '):
+                            user = line[7:]
+                            ui.debug('From: %s\n' % user)
+                        elif line.startswith("# Date "):
+                            date = line[7:]
+                    if not line.startswith('# '):
+                        cfp.write(line)
+                        cfp.write('\n')
+                message = cfp.getvalue()
+                if tmpfp:
+                    tmpfp.write(payload)
+                    if not payload.endswith('\n'):
+                        tmpfp.write('\n')
+            elif not diffs_seen and message and content_type == 'text/plain':
+                message += '\n' + payload
+    except:
+        tmpfp.close()
+        os.unlink(tmpname)
+        raise
+
+    tmpfp.close()
+    if not diffs_seen:
+        os.unlink(tmpname)
+        return None, message, user, date
+    return tmpname, message, user, date
+
+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)]
+
+            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") %
+                             util.explain_exit(code)[0])
+
+    for gp in gitpatches:
+        files[gp.path] = (gp.op, gp)
+
+    return files
--- a/mercurial/remoterepo.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/remoterepo.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,6 @@
-# remoterepo - remote repositort proxy classes for mercurial
+# remoterepo - remote repository proxy classes for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/repo.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/repo.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,7 @@
 # repo.py - repository base classes for mercurial
 #
 # Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/revlog.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/revlog.py	Sat Aug 12 15:43:38 2006 -0700
@@ -4,7 +4,7 @@
 This provides efficient delta storage with O(1) retrieve and append
 and O(changes) merge between branches
 
-Copyright 2005 Matt Mackall <mpm@selenic.com>
+Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 
 This software may be used and distributed according to the terms
 of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/sshrepo.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/sshrepo.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,6 @@
 # sshrepo.py - ssh repository proxy class for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/sshserver.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/sshserver.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,7 @@
 # sshserver.py - ssh protocol server support for mercurial
 #
 # Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/statichttprepo.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/statichttprepo.py	Sat Aug 12 15:43:38 2006 -0700
@@ -2,7 +2,7 @@
 #
 # This provides read-only repo access to repositories exported via static http
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/transaction.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/transaction.py	Sat Aug 12 15:43:38 2006 -0700
@@ -6,7 +6,7 @@
 # effectively log-structured, this should amount to simply truncating
 # anything that isn't referenced in the changelog.
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/ui.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/ui.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,6 +1,6 @@
 # ui.py - user interface bits for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/util.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/util.py	Sat Aug 12 15:43:38 2006 -0700
@@ -2,6 +2,8 @@
 util.py - Mercurial utility functions and platform specfic implementations
 
  Copyright 2005 K. Thananchayan <thananck@yahoo.com>
+ Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
+ Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
 
 This software may be used and distributed according to the terms
 of the GNU General Public License, incorporated herein by reference.
@@ -93,27 +95,6 @@
             return p_name
     return default
 
-def patch(strip, patchname, ui, cwd=None):
-    """apply the patch <patchname> to the working directory.
-    a list of patched files is returned"""
-    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)))
-    files = {}
-    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, 1)
-    code = fp.close()
-    if code:
-        raise Abort(_("patch command failed: %s") % explain_exit(code)[0])
-    return files.keys()
-
 def binary(s):
     """return true if a string is binary data using diff's heuristic"""
     if s and '\0' in s[:4096]:
--- a/mercurial/version.py	Sat Aug 12 15:01:46 2006 -0700
+++ b/mercurial/version.py	Sat Aug 12 15:43:38 2006 -0700
@@ -1,4 +1,4 @@
-# Copyright (C) 2005 by Intevation GmbH
+# Copyright (C) 2005, 2006 by Intevation GmbH
 # Author(s):
 # Thomas Arendsen Hein <thomas@intevation.de>
 #
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-git-import	Sat Aug 12 15:43:38 2006 -0700
@@ -0,0 +1,122 @@
+#!/bin/sh
+
+hg init a
+cd a
+
+echo % new file
+hg import -mnew - <<EOF
+diff --git a/new b/new
+new file mode 100644
+index 0000000..7898192
+--- /dev/null
++++ b/new
+@@ -0,0 +1 @@
++a
+EOF
+
+echo % chmod +x
+hg import -msetx - <<EOF
+diff --git a/new b/new
+old mode 100644
+new mode 100755
+EOF
+
+test -x new || echo failed
+
+echo % copy
+hg import -mcopy - <<EOF
+diff --git a/new b/copy
+old mode 100755
+new mode 100644
+similarity index 100%
+copy from new
+copy to copy
+diff --git a/new b/copyx
+similarity index 100%
+copy from new
+copy to copyx
+EOF
+
+test -f copy -a ! -x copy || echo failed
+test -x copyx || echo failed
+cat copy
+hg cat copy
+
+echo % rename
+hg import -mrename - <<EOF
+diff --git a/copy b/rename
+similarity index 100%
+rename from copy
+rename to rename
+EOF
+
+hg locate
+
+echo % delete
+hg import -mdelete - <<EOF
+diff --git a/copyx b/copyx
+deleted file mode 100755
+index 7898192..0000000
+--- a/copyx
++++ /dev/null
+@@ -1 +0,0 @@
+-a
+EOF
+
+hg locate
+test -f copyx && echo failed || true
+
+echo % regular diff
+hg import -mregular - <<EOF
+diff --git a/rename b/rename
+index 7898192..72e1fe3 100644
+--- a/rename
++++ b/rename
+@@ -1 +1,5 @@
+ a
++a
++a
++a
++a
+EOF
+
+echo % copy and modify
+hg import -mcopymod - <<EOF
+diff --git a/rename b/copy2
+similarity index 80%
+copy from rename
+copy to copy2
+index 72e1fe3..b53c148 100644
+--- a/rename
++++ b/copy2
+@@ -1,5 +1,5 @@
+ a
+ a
+-a
++b
+ a
+ a
+EOF
+
+hg cat copy2
+
+echo % rename and modify
+hg import -mrenamemod - <<EOF
+diff --git a/copy2 b/rename2
+similarity index 80%
+rename from copy2
+rename to rename2
+index b53c148..8f81e29 100644
+--- a/copy2
++++ b/rename2
+@@ -1,5 +1,5 @@
+ a
+ a
+ b
+-a
++c
+ a
+EOF
+
+hg locate copy2
+hg cat rename2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-git-import.out	Sat Aug 12 15:43:38 2006 -0700
@@ -0,0 +1,39 @@
+% new file
+applying patch from stdin
+patching file new
+% chmod +x
+applying patch from stdin
+% copy
+applying patch from stdin
+a
+a
+% rename
+applying patch from stdin
+copyx
+new
+rename
+% delete
+applying patch from stdin
+patching file copyx
+new
+rename
+% regular diff
+applying patch from stdin
+patching file rename
+% copy and modify
+applying patch from stdin
+patching file copy2
+a
+a
+b
+a
+a
+% rename and modify
+applying patch from stdin
+patching file rename2
+copy2: No such file or directory
+a
+a
+b
+c
+a