Merge with mainline
authorBenoit Boissinot <benoit.boissinot@ens-lyon.org>
Mon, 18 Sep 2006 11:55:38 +0200
changeset 3128 70e62df12704
parent 3127 8e8deb8035a4 (current diff)
parent 3121 2ef0b3aae186 (diff)
child 3129 f145d04899d2
Merge with mainline
mercurial/util.py
tests/test-trusted.py
tests/test-trusted.py.out
--- a/doc/hgrc.5.txt	Fri Sep 15 22:55:17 2006 +0200
+++ b/doc/hgrc.5.txt	Mon Sep 18 11:55:38 2006 +0200
@@ -50,8 +50,6 @@
     particular repository.  This file is not version-controlled, and
     will not get transferred during a "clone" operation.  Options in
     this file override options in all other configuration files.
-    On Unix, this file is only read if it belongs to a trusted user
-    or to a trusted group.
 
 SYNTAX
 ------
@@ -366,16 +364,6 @@
     6Mbps), uncompressed streaming is slower, because of the extra
     data transfer overhead.  Default is False.
 
-trusted::
-  Mercurial will only read the .hg/hgrc file from a repository if
-  it belongs to a trusted user or to a trusted group. This section
-  specifies what users and groups are trusted. To trust everybody,
-  list a user or a group with name "*".
-  users;;
-    Comma-separated list of trusted users.
-  groups;;
-    Comma-separated list of trusted groups.
-
 ui::
   User interface controls.
   debug;;
--- a/mercurial/merge.py	Fri Sep 15 22:55:17 2006 +0200
+++ b/mercurial/merge.py	Mon Sep 18 11:55:38 2006 +0200
@@ -10,11 +10,6 @@
 from demandload import *
 demandload(globals(), "errno util os tempfile")
 
-def fmerge(f, local, other, ancestor):
-    """merge executable flags"""
-    a, b, c = ancestor.execf(f), local.execf(f), other.execf(f)
-    return ((a^b) | (a^c)) ^ a
-
 def merge3(repo, fn, my, other, p1, p2):
     """perform a 3-way merge in the working directory"""
 
@@ -52,6 +47,193 @@
     os.unlink(c)
     return r
 
+def checkunknown(repo, m2, status):
+    """
+    check for collisions between unknown files and files in m2
+    """
+    modified, added, removed, deleted, unknown = status[:5]
+    for f in unknown:
+        if f in m2:
+            if repo.file(f).cmp(m2[f], repo.wread(f)):
+                raise util.Abort(_("'%s' already exists in the working"
+                                   " dir and differs from remote") % f)
+
+def workingmanifest(repo, man, status):
+    """
+    Update manifest to correspond to the working directory
+    """
+
+    modified, added, removed, deleted, unknown = status[:5]
+    for i,l in (("a", added), ("m", modified), ("u", unknown)):
+        for f in l:
+            man[f] = man.get(f, nullid) + i
+            man.set(f, util.is_exec(repo.wjoin(f), man.execf(f)))
+
+    for f in deleted + removed:
+        del man[f]
+
+    return man
+
+def forgetremoved(m2, status):
+    """
+    Forget removed files
+
+    If we're jumping between revisions (as opposed to merging), and if
+    neither the working directory nor the target rev has the file,
+    then we need to remove it from the dirstate, to prevent the
+    dirstate from listing the file when it is no longer in the
+    manifest.
+    """
+
+    modified, added, removed, deleted, unknown = status[:5]
+    action = []
+
+    for f in deleted + removed:
+        if f not in m2:
+            action.append((f, "f"))
+
+    return action
+
+def manifestmerge(ui, m1, m2, ma, overwrite, backwards, partial):
+    """
+    Merge manifest m1 with m2 using ancestor ma and generate merge action list
+    """
+
+    def fmerge(f):
+        """merge executable flags"""
+        a, b, c = ma.execf(f), m1.execf(f), m2.execf(f)
+        return ((a^b) | (a^c)) ^ a
+
+    action = []
+
+    def act(msg, f, m, *args):
+        ui.debug(" %s: %s -> %s\n" % (f, msg, m))
+        action.append((f, m) + args)
+
+    # Filter manifests
+    if partial:
+        for f in m1.keys():
+            if not partial(f): del m1[f]
+        for f in m2.keys():
+            if not partial(f): del m2[f]
+
+    # Compare manifests
+    for f, n in m1.iteritems():
+        if f in m2:
+            # are files different?
+            if n != m2[f]:
+                a = ma.get(f, nullid)
+                # are both different from the ancestor?
+                if not overwrite and n != a and m2[f] != a:
+                    act("versions differ", f, "m", fmerge(f), n[:20], m2[f])
+                # are we clobbering?
+                # is remote's version newer?
+                # or are we going back in time and clean?
+                elif overwrite or m2[f] != a or (backwards and not n[20:]):
+                    act("remote is newer", f, "g", m2.execf(f), m2[f])
+                # local is newer, not overwrite, check mode bits
+                elif fmerge(f) != m1.execf(f):
+                    act("update permissions", f, "e", m2.execf(f))
+            # contents same, check mode bits
+            elif m1.execf(f) != m2.execf(f):
+                if overwrite or fmerge(f) != m1.execf(f):
+                    act("update permissions", f, "e", m2.execf(f))
+            del m2[f]
+        elif f in ma:
+            if n != ma[f] and not overwrite:
+                if ui.prompt(
+                    (_(" local changed %s which remote deleted\n") % f) +
+                    _("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("d"):
+                    act("prompt delete", f, "r")
+            else:
+                act("other deleted", f, "r")
+        else:
+            # file is created on branch or in working directory
+            if (overwrite and n[20:] != "u") or (backwards and not n[20:]):
+                act("remote deleted", f, "r")
+
+    for f, n in m2.iteritems():
+        if f in ma:
+            if overwrite or backwards:
+                act("recreating", f, "g", m2.execf(f), n)
+            elif n != ma[f]:
+                if ui.prompt(
+                    (_("remote changed %s which local deleted\n") % f) +
+                    _("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("k"):
+                    act("prompt recreating", f, "g", m2.execf(f), n)
+        else:
+            act("remote created", f, "g", m2.execf(f), n)
+
+    return action
+
+def applyupdates(repo, action, xp1, xp2):
+    updated, merged, removed, unresolved = 0, 0, 0, 0
+    action.sort()
+    for a in action:
+        f, m = a[:2]
+        if f[0] == "/":
+            continue
+        if m == "r": # remove
+            repo.ui.note(_("removing %s\n") % f)
+            util.audit_path(f)
+            try:
+                util.unlink(repo.wjoin(f))
+            except OSError, inst:
+                if inst.errno != errno.ENOENT:
+                    repo.ui.warn(_("update failed to remove %s: %s!\n") %
+                                 (f, inst.strerror))
+            removed +=1
+        elif m == "m": # merge
+            flag, my, other = a[2:]
+            repo.ui.status(_("merging %s\n") % f)
+            if merge3(repo, f, my, other, xp1, xp2):
+                unresolved += 1
+            util.set_exec(repo.wjoin(f), flag)
+            merged += 1
+        elif m == "g": # get
+            flag, node = a[2:]
+            repo.ui.note(_("getting %s\n") % f)
+            t = repo.file(f).read(node)
+            repo.wwrite(f, t)
+            util.set_exec(repo.wjoin(f), flag)
+            updated += 1
+        elif m == "e": # exec
+            flag = a[2:]
+            util.set_exec(repo.wjoin(f), flag)
+
+    return updated, merged, removed, unresolved
+
+def recordupdates(repo, action, branchmerge):
+    for a in action:
+        f, m = a[:2]
+        if m == "r": # remove
+            if branchmerge:
+                repo.dirstate.update([f], 'r')
+            else:
+                repo.dirstate.forget([f])
+        elif m == "f": # forget
+            repo.dirstate.forget([f])
+        elif m == "g": # get
+            if branchmerge:
+                repo.dirstate.update([f], 'n', st_mtime=-1)
+            else:
+                repo.dirstate.update([f], 'n')
+        elif m == "m": # merge
+            flag, my, other = a[2:]
+            if branchmerge:
+                # We've done a branch merge, mark this file as merged
+                # so that we properly record the merger later
+                repo.dirstate.update([f], 'm')
+            else:
+                # We've update-merged a locally modified file, so
+                # we set the dirstate to emulate a normal checkout
+                # of that file some time in the past. Thus our
+                # merge will appear as a normal local file
+                # modification.
+                fl = repo.file(f)
+                f_len = fl.size(fl.rev(other))
+                repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
+
 def update(repo, node, branchmerge=False, force=False, partial=None,
            wlock=None, show_stats=True, remind=True):
 
@@ -74,238 +256,65 @@
     backwards = (pa == p2)
 
     # is there a linear path from p1 to p2?
-    linear_path = (pa == p1 or pa == p2)
-    if branchmerge and linear_path:
-        raise util.Abort(_("there is nothing to merge, just use "
-                           "'hg update' or look at 'hg heads'"))
-
-    if not linear_path and not (overwrite or branchmerge):
+    if pa == p1 or pa == p2:
+        if branchmerge:
+            raise util.Abort(_("there is nothing to merge, just use "
+                               "'hg update' or look at 'hg heads'"))
+    elif not (overwrite or branchmerge):
         raise util.Abort(_("update spans branches, use 'hg merge' "
                            "or 'hg update -C' to lose changes"))
 
-    modified, added, removed, deleted, unknown = repo.status()[:5]
+    status = repo.status()
+    modified, added, removed, deleted, unknown = status[:5]
     if branchmerge and not forcemerge:
         if modified or added or removed:
             raise util.Abort(_("outstanding uncommitted changes"))
 
-    m1n = repo.changelog.read(p1)[0]
-    m2n = repo.changelog.read(p2)[0]
-    man = repo.manifest.ancestor(m1n, m2n)
-    m1 = repo.manifest.read(m1n).copy()
-    m2 = repo.manifest.read(m2n).copy()
-    ma = repo.manifest.read(man)
-
-    if not force:
-        for f in unknown:
-            if f in m2:
-                if repo.file(f).cmp(m2[f], repo.wread(f)):
-                    raise util.Abort(_("'%s' already exists in the working"
-                                       " dir and differs from remote") % f)
+    m1 = repo.changectx(p1).manifest().copy()
+    m2 = repo.changectx(p2).manifest().copy()
+    ma = repo.changectx(pa).manifest()
 
     # resolve the manifest to determine which files
     # we care about merging
     repo.ui.note(_("resolving manifests\n"))
-    repo.ui.debug(_(" overwrite %s branchmerge %s partial %s linear %s\n") %
-                  (overwrite, branchmerge, bool(partial), linear_path))
+    repo.ui.debug(_(" overwrite %s branchmerge %s partial %s\n") %
+                  (overwrite, branchmerge, bool(partial)))
     repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
-                  (short(man), short(m1n), short(m2n)))
-
-    action = {}
-    forget = []
-
-    # update m1 from working dir
-    umap = dict.fromkeys(unknown)
-
-    for f in added + modified + unknown:
-        m1[f] = m1.get(f, nullid) + "+"
-        m1.set(f, util.is_exec(repo.wjoin(f), m1.execf(f)))
-
-    for f in deleted + removed:
-        del m1[f]
-
-        # If we're jumping between revisions (as opposed to merging),
-        # and if neither the working directory nor the target rev has
-        # the file, then we need to remove it from the dirstate, to
-        # prevent the dirstate from listing the file when it is no
-        # longer in the manifest.
-        if linear_path and f not in m2:
-            forget.append(f)
-
-    if partial:
-        for f in m1.keys():
-            if not partial(f): del m1[f]
-        for f in m2.keys():
-            if not partial(f): del m2[f]
-
-    # Compare manifests
-    for f, n in m1.iteritems():
-        if f in m2:
-            queued = 0
-
-            # are files different?
-            if n != m2[f]:
-                a = ma.get(f, nullid)
-                # are both different from the ancestor?
-                if not overwrite and n != a and m2[f] != a:
-                    repo.ui.debug(_(" %s versions differ, resolve\n") % f)
-                    action[f] = (fmerge(f, m1, m2, ma), n[:20], m2[f])
-                    queued = 1
-                # are we clobbering?
-                # is remote's version newer?
-                # or are we going back in time and clean?
-                elif overwrite or m2[f] != a or (backwards and not n[20:]):
-                    repo.ui.debug(_(" remote %s is newer, get\n") % f)
-                    action[f] = (m2.execf(f), m2[f], None)
-                    queued = 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
-                action[f] = (m2.execf(f), m2[f], None)
+                  (short(p1), short(p2), short(pa)))
 
-            # do we still need to look at mode bits?
-            if not queued and m1.execf(f) != m2.execf(f):
-                if overwrite:
-                    repo.ui.debug(_(" updating permissions for %s\n") % f)
-                    util.set_exec(repo.wjoin(f), m2.execf(f))
-                else:
-                    mode = fmerge(f, m1, m2, ma)
-                    if mode != m1.execf(f):
-                        repo.ui.debug(_(" updating permissions for %s\n")
-                                      % f)
-                        util.set_exec(repo.wjoin(f), mode)
-            del m2[f]
-        elif f in ma:
-            if n != ma[f]:
-                r = _("d")
-                if not overwrite:
-                    r = repo.ui.prompt(
-                        (_(" local changed %s which remote deleted\n") % f) +
-                         _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
-                if r == _("d"):
-                    action[f] = (None, None, None)
-            else:
-                repo.ui.debug(_("other deleted %s\n") % f)
-                action[f] = (None, None, None)
-        else:
-            # file is created on branch or in working directory
-            if overwrite and f not in umap:
-                repo.ui.debug(_("remote deleted %s, clobbering\n") % f)
-                action[f] = (None, None, None)
-            elif not n[20:]: # same as parent
-                if backwards:
-                    repo.ui.debug(_("remote deleted %s\n") % f)
-                    action[f] = (None, None, None)
-                else:
-                    repo.ui.debug(_("local modified %s, keeping\n") % f)
-            else:
-                repo.ui.debug(_("working dir created %s, keeping\n") % f)
+    action = []
+    m1 = workingmanifest(repo, m1, status)
 
-    for f, n in m2.iteritems():
-        if f[0] == "/":
-            continue
-        if f in ma and n != ma[f]:
-            r = _("k")
-            if not overwrite:
-                r = repo.ui.prompt(
-                    (_("remote changed %s which local deleted\n") % f) +
-                     _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
-            if r == _("k"):
-                action[f] = (m2.execf(f), n, None)
-        elif f not in ma:
-            repo.ui.debug(_("remote created %s\n") % f)
-            action[f] = (m2.execf(f), n, None)
-        else:
-            if overwrite or backwards:
-                repo.ui.debug(_("local deleted %s, recreating\n") % f)
-                action[f] = (m2.execf(f), n, None)
-            else:
-                repo.ui.debug(_("local deleted %s\n") % f)
-
+    if not force:
+        checkunknown(repo, m2, status)
+    if not branchmerge:
+        action += forgetremoved(m2, status)
+    action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards, partial)
     del m1, m2, ma
 
     ### apply phase
 
-    if linear_path or overwrite:
+    if not branchmerge:
         # we don't need to do any magic, just jump to the new rev
         p1, p2 = p2, nullid
 
-    xp1 = hex(p1)
-    xp2 = hex(p2)
-    if p2 == nullid: xxp2 = ''
-    else: xxp2 = xp2
-
-    repo.hook('preupdate', throw=True, parent1=xp1, parent2=xxp2)
+    xp1, xp2 = hex(p1), hex(p2)
+    if p2 == nullid: xp2 = ''
 
-    # update files
-    unresolved = []
-    updated, merged, removed = 0, 0, 0
-    files = action.keys()
-    files.sort()
-    for f in files:
-        flag, my, other = action[f]
-        if f[0] == "/":
-            continue
-        if not my:
-            repo.ui.note(_("removing %s\n") % f)
-            util.audit_path(f)
-            try:
-                util.unlink(repo.wjoin(f))
-            except OSError, inst:
-                if inst.errno != errno.ENOENT:
-                    repo.ui.warn(_("update failed to remove %s: %s!\n") %
-                                 (f, inst.strerror))
-            removed +=1
-        elif other:
-            repo.ui.status(_("merging %s\n") % f)
-            if merge3(repo, f, my, other, xp1, xp2):
-                unresolved.append(f)
-            util.set_exec(repo.wjoin(f), flag)
-            merged += 1
-        else:
-            repo.ui.note(_("getting %s\n") % f)
-            t = repo.file(f).read(my)
-            repo.wwrite(f, t)
-            util.set_exec(repo.wjoin(f), flag)
-            updated += 1
+    repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
+
+    updated, merged, removed, unresolved = applyupdates(repo, action, xp1, xp2)
 
     # update dirstate
     if not partial:
         repo.dirstate.setparents(p1, p2)
-        repo.dirstate.forget(forget)
-        files = action.keys()
-        files.sort()
-        for f in files:
-            flag, my, other = action[f]
-            if not my:
-                if branchmerge:
-                    repo.dirstate.update([f], 'r')
-                else:
-                    repo.dirstate.forget([f])
-            elif not other:
-                if branchmerge:
-                    repo.dirstate.update([f], 'n', st_mtime=-1)
-                else:
-                    repo.dirstate.update([f], 'n')
-            else:
-                if branchmerge:
-                    # We've done a branch merge, mark this file as merged
-                    # so that we properly record the merger later
-                    repo.dirstate.update([f], 'm')
-                else:
-                    # We've update-merged a locally modified file, so
-                    # we set the dirstate to emulate a normal checkout
-                    # of that file some time in the past. Thus our
-                    # merge will appear as a normal local file
-                    # modification.
-                    fl = repo.file(f)
-                    f_len = fl.size(fl.rev(other))
-                    repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
+        recordupdates(repo, action, branchmerge)
 
     if show_stats:
         stats = ((updated, _("updated")),
-                 (merged - len(unresolved), _("merged")),
+                 (merged - unresolved, _("merged")),
                  (removed, _("removed")),
-                 (len(unresolved), _("unresolved")))
+                 (unresolved, _("unresolved")))
         note = ", ".join([_("%d files %s") % s for s in stats])
         repo.ui.status("%s\n" % note)
     if not partial:
@@ -323,6 +332,6 @@
             repo.ui.status(_("There are unresolved merges with"
                              " locally modified files.\n"))
 
-    repo.hook('update', parent1=xp1, parent2=xxp2, error=len(unresolved))
-    return len(unresolved)
+    repo.hook('update', parent1=xp1, parent2=xp2, error=unresolved)
+    return unresolved
 
--- a/mercurial/ui.py	Fri Sep 15 22:55:17 2006 +0200
+++ b/mercurial/ui.py	Mon Sep 18 11:55:38 2006 +0200
@@ -18,8 +18,6 @@
             # this is the parent of all ui children
             self.parentui = None
             self.readhooks = []
-            self.trusted_users = {}
-            self.trusted_groups = {}
             self.cdata = ConfigParser.SafeConfigParser()
             self.readconfig(util.rcpath())
 
@@ -38,8 +36,6 @@
             # parentui may point to an ui object which is already a child
             self.parentui = parentui.parentui or parentui
             self.readhooks = parentui.readhooks[:]
-            self.trusted_users = parentui.trusted_users.copy()
-            self.trusted_groups = parentui.trusted_groups.copy()
             parent_cdata = self.parentui.cdata
             self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults())
             # make interpolation work
@@ -75,22 +71,7 @@
             fn = [fn]
         for f in fn:
             try:
-                fp = open(f)
-            except IOError:
-                continue
-            if ((self.trusted_users or self.trusted_groups) and
-                '*' not in self.trusted_users and
-                '*' not in self.trusted_groups):
-                st = util.fstat(fp)
-                user = util.username(st.st_uid)
-                group = util.groupname(st.st_gid)
-                if (user not in self.trusted_users and
-                    group not in self.trusted_groups):
-                    self.warn(_('not reading file %s from untrusted '
-                                'user %s, group %s\n') % (f, user, group))
-                    continue
-            try:
-                self.cdata.readfp(fp, f)
+                self.cdata.read(f)
             except ConfigParser.ParsingError, inst:
                 raise util.Abort(_("Failed to parse %s\n%s") % (f, inst))
         # translate paths relative to root (or home) into absolute paths
@@ -99,13 +80,6 @@
         for name, path in self.configitems("paths"):
             if path and "://" not in path and not os.path.isabs(path):
                 self.cdata.set("paths", name, os.path.join(root, path))
-        user = util.username()
-        if user is not None:
-            self.trusted_users[user] = 1
-            for user in self.configlist('trusted', 'users'):
-                self.trusted_users[user] = 1
-            for group in self.configlist('trusted', 'groups'):
-                self.trusted_groups[group] = 1
         for hook in self.readhooks:
             hook(self)
 
--- a/mercurial/util.py	Fri Sep 15 22:55:17 2006 +0200
+++ b/mercurial/util.py	Mon Sep 18 11:55:38 2006 +0200
@@ -15,7 +15,7 @@
 from i18n import gettext as _
 from demandload import *
 demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile")
-demandload(globals(), "os threading time pwd grp")
+demandload(globals(), "os threading time")
 
 # used by parsedate
 defaultdateformats = ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M',
@@ -509,38 +509,6 @@
     raise Abort(_('user name not available - set USERNAME '
                   'environment variable'))
 
-def username(uid=None):
-    """Return the name of the user with the given uid.
-
-    If uid is None, return the name of the current user."""
-    try:
-        # force an ImportError if there's no module pwd
-        getpwuid = pwd.getpwuid
-        if uid is None:
-            uid = os.getuid()
-        try:
-            return getpwuid(uid)[0]
-        except KeyError:
-            return str(uid)
-    except ImportError:
-        return None
-
-def groupname(gid=None):
-    """Return the name of the group with the given gid.
-
-    If gid is None, return the name of the current group."""
-    try:
-        # force an ImportError if there's no module grp
-        getgrgid = grp.getgrgid
-        if gid is None:
-            gid = os.getgid()
-        try:
-            return getgrgid(gid)[0]
-        except KeyError:
-            return str(gid)
-    except ImportError:
-        return None
-
 # Platform specific variants
 if os.name == 'nt':
     demandload(globals(), "msvcrt")
--- a/tests/test-merge7.out	Fri Sep 15 22:55:17 2006 +0200
+++ b/tests/test-merge7.out	Mon Sep 18 11:55:38 2006 +0200
@@ -22,9 +22,9 @@
 (run 'hg heads' to see heads, 'hg merge' to merge)
 merge: warning: conflicts during merge
 resolving manifests
- overwrite None branchmerge True partial False linear False
- ancestor 055d847dd401 local 2eded9ab0a5c remote 84cf5750dd20
- test.txt versions differ, resolve
+ overwrite None branchmerge True partial False
+ ancestor 451c744aabcc local a070d41e8360 remote faaea63e63a9
+ test.txt: versions differ -> m
 merging test.txt
 resolving test.txt
 file test.txt: my fc3148072371 other d40249267ae3 ancestor 8fe46a3eb557
--- a/tests/test-trusted.py	Fri Sep 15 22:55:17 2006 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-#!/usr/bin/env python
-# Since it's not easy to write a test that portably deals
-# with files from different users/groups, we cheat a bit by
-# monkey-patching some functions in the util module
-
-import os
-from mercurial import ui, util
-
-hgrc = os.environ['HGRCPATH']
-
-def testui(user='foo', group='bar', tusers=(), tgroups=(),
-           cuser='foo', cgroup='bar'):
-    # user, group => owners of the file
-    # tusers, tgroups => trusted users/groups
-    # cuser, cgroup => user/group of the current process
-
-    # write a global hgrc with the list of trusted users/groups and
-    # some setting so that we can be sure it was read
-    f = open(hgrc, 'w')
-    f.write('[paths]\n')
-    f.write('global = /some/path\n\n')
-
-    if tusers or tgroups:
-        f.write('[trusted]\n')
-        if tusers:
-            f.write('users = %s\n' % ', '.join(tusers))
-        if tgroups:
-            f.write('groups = %s\n' % ', '.join(tgroups))
-    f.close()
-
-    # override the functions that give names to uids and gids
-    def username(uid=None):
-        if uid is None:
-            return cuser
-        return user
-    util.username = username
-
-    def groupname(gid=None):
-        if gid is None:
-            return 'bar'
-        return group
-    util.groupname = groupname
-
-    # try to read everything
-    #print '# File belongs to user %s, group %s' % (user, group)
-    #print '# trusted users = %s; trusted groups = %s' % (tusers, tgroups)
-    kind = ('different', 'same')
-    who = ('', 'user', 'group', 'user and the group')
-    trusted = who[(user in tusers) + 2*(group in tgroups)]
-    if trusted:
-        trusted = ', but we trust the ' + trusted
-    print '# %s user, %s group%s' % (kind[user == cuser], kind[group == cgroup],
-                                     trusted)
-
-    parentui = ui.ui()
-    u = ui.ui(parentui=parentui)
-    u.readconfig('.hg/hgrc')
-    for name, path in u.configitems('paths'):
-        print name, '=', path
-    print
-
-    return u
-
-os.mkdir('repo')
-os.chdir('repo')
-os.mkdir('.hg')
-f = open('.hg/hgrc', 'w')
-f.write('[paths]\n')
-f.write('local = /another/path\n\n')
-f.close()
-
-#print '# Everything is run by user foo, group bar\n'
-
-# same user, same group
-testui()
-# same user, different group
-testui(group='def')
-# different user, same group
-testui(user='abc')
-# ... but we trust the group
-testui(user='abc', tgroups=['bar'])
-# different user, different group
-testui(user='abc', group='def')
-# ... but we trust the user
-testui(user='abc', group='def', tusers=['abc'])
-# ... but we trust the group
-testui(user='abc', group='def', tgroups=['def'])
-# ... but we trust the user and the group
-testui(user='abc', group='def', tusers=['abc'], tgroups=['def'])
-# ... but we trust all users
-print '# we trust all users'
-testui(user='abc', group='def', tusers=['*'])
-# ... but we trust all groups
-print '# we trust all groups'
-testui(user='abc', group='def', tgroups=['*'])
-# ... but we trust the whole universe
-print '# we trust all users and groups'
-testui(user='abc', group='def', tusers=['*'], tgroups=['*'])
-# ... check that users and groups are in different namespaces
-print "# we don't get confused by users and groups with the same name"
-testui(user='abc', group='def', tusers=['def'], tgroups=['abc'])
-# ... lists of user names work
-print "# list of user names"
-testui(user='abc', group='def', tusers=['foo', 'xyz', 'abc', 'bleh'],
-       tgroups=['bar', 'baz', 'qux'])
-# ... lists of group names work
-print "# list of group names"
-testui(user='abc', group='def', tusers=['foo', 'xyz', 'bleh'],
-       tgroups=['bar', 'def', 'baz', 'qux'])
-
-print "# Can't figure out the name of the user running this process"
-testui(user='abc', group='def', cuser=None)
--- a/tests/test-trusted.py.out	Fri Sep 15 22:55:17 2006 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-# same user, same group
-global = /some/path
-local = /another/path
-
-# same user, different group
-global = /some/path
-local = /another/path
-
-# different user, same group
-not reading file .hg/hgrc from untrusted user abc, group bar
-global = /some/path
-
-# different user, same group, but we trust the group
-global = /some/path
-local = /another/path
-
-# different user, different group
-not reading file .hg/hgrc from untrusted user abc, group def
-global = /some/path
-
-# different user, different group, but we trust the user
-global = /some/path
-local = /another/path
-
-# different user, different group, but we trust the group
-global = /some/path
-local = /another/path
-
-# different user, different group, but we trust the user and the group
-global = /some/path
-local = /another/path
-
-# we trust all users
-# different user, different group
-global = /some/path
-local = /another/path
-
-# we trust all groups
-# different user, different group
-global = /some/path
-local = /another/path
-
-# we trust all users and groups
-# different user, different group
-global = /some/path
-local = /another/path
-
-# we don't get confused by users and groups with the same name
-# different user, different group
-not reading file .hg/hgrc from untrusted user abc, group def
-global = /some/path
-
-# list of user names
-# different user, different group, but we trust the user
-global = /some/path
-local = /another/path
-
-# list of group names
-# different user, different group, but we trust the group
-global = /some/path
-local = /another/path
-
-# Can't figure out the name of the user running this process
-# different user, different group
-global = /some/path
-local = /another/path
-
--- a/tests/test-up-local-change.out	Fri Sep 15 22:55:17 2006 +0200
+++ b/tests/test-up-local-change.out	Mon Sep 18 11:55:38 2006 +0200
@@ -15,10 +15,10 @@
 summary:     1
 
 resolving manifests
- overwrite False branchmerge False partial False linear True
- ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
- a versions differ, resolve
-remote created b
+ overwrite False branchmerge False partial False
+ ancestor 33aaa84a386b local 802f095af299 remote 33aaa84a386b
+ a: versions differ -> m
+ b: remote created -> g
 merging a
 resolving a
 file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2
@@ -31,9 +31,9 @@
 summary:     2
 
 resolving manifests
- overwrite False branchmerge False partial False linear True
- ancestor a0c8bcbbb45c local 1165e8bd193e remote a0c8bcbbb45c
-remote deleted b
+ overwrite False branchmerge False partial False
+ ancestor 802f095af299 local 33aaa84a386b remote 33aaa84a386b
+ b: remote deleted -> r
 removing b
 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
 changeset:   0:33aaa84a386b
@@ -49,10 +49,10 @@
 summary:     1
 
 resolving manifests
- overwrite False branchmerge False partial False linear True
- ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
- a versions differ, resolve
-remote created b
+ overwrite False branchmerge False partial False
+ ancestor 33aaa84a386b local 802f095af299 remote 33aaa84a386b
+ a: versions differ -> m
+ b: remote created -> g
 merging a
 resolving a
 file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2
@@ -100,10 +100,10 @@
 abort: outstanding uncommitted changes
 failed
 resolving manifests
- overwrite False branchmerge True partial False linear False
- ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392
- a versions differ, resolve
- b versions differ, resolve
+ overwrite False branchmerge True partial False
+ ancestor 802f095af299 local 030602aee63d remote 33aaa84a386b
+ a: versions differ -> m
+ b: versions differ -> m
 merging a
 resolving a
 file a: my d730145abbf9 other 13e0d5f949fa ancestor b789fdd96dc2
--- a/tests/test-update-reverse.out	Fri Sep 15 22:55:17 2006 +0200
+++ b/tests/test-update-reverse.out	Mon Sep 18 11:55:38 2006 +0200
@@ -40,11 +40,11 @@
 side1
 side2
 resolving manifests
- overwrite True branchmerge False partial False linear False
- ancestor 8515d4bfda76 local 1c0f48f8ece6 remote 0594b9004bae
-remote deleted side2, clobbering
-remote deleted side1, clobbering
-remote created main
+ overwrite True branchmerge False partial False
+ ancestor ded32b0db104 local 221226fb2bd8 remote 537353581d3d
+ side2: remote deleted -> r
+ side1: remote deleted -> r
+ main: remote created -> g
 getting main
 removing side1
 removing side2