merge with i18n stable 3.3
authorMatt Mackall <mpm@selenic.com>
Sun, 01 Feb 2015 18:47:04 -0600
branchstable
changeset 23987 fbdd5195528f
parent 23984 2896f53509a7 (diff)
parent 23986 baa0652000b5 (current diff)
child 23988 a44e06cf0d9d
merge with i18n
--- a/hgext/convert/hg.py	Sun Feb 01 08:24:08 2015 +0900
+++ b/hgext/convert/hg.py	Sun Feb 01 18:47:04 2015 -0600
@@ -26,7 +26,7 @@
 from common import NoRepo, commit, converter_source, converter_sink
 
 import re
-sha1re = re.compile(r'\b[0-9a-f]{6,40}\b')
+sha1re = re.compile(r'\b[0-9a-f]{12,40}\b')
 
 class mercurial_sink(converter_sink):
     def __init__(self, ui, path):
--- a/hgext/largefiles/overrides.py	Sun Feb 01 08:24:08 2015 +0900
+++ b/hgext/largefiles/overrides.py	Sun Feb 01 18:47:04 2015 -0600
@@ -316,9 +316,14 @@
 
         for i in range(0, len(m._files)):
             standin = lfutil.standin(m._files[i])
+            # If the "standin" is a directory, append instead of replace to
+            # support naming a directory on the command line with only
+            # largefiles.  The original directory is kept to support normal
+            # files.
             if standin in repo[ctx.node()]:
                 m._files[i] = standin
-            elif m._files[i] not in repo[ctx.node()]:
+            elif m._files[i] not in repo[ctx.node()] \
+                    and repo.wvfs.isdir(standin):
                 m._files.append(standin)
             pats.add(standin)
 
--- a/mercurial/context.py	Sun Feb 01 08:24:08 2015 +0900
+++ b/mercurial/context.py	Sun Feb 01 18:47:04 2015 -0600
@@ -22,41 +22,6 @@
 # dirty in the working copy.
 _newnode = '!' * 21
 
-def _adjustlinkrev(repo, path, filelog, fnode, srcrev, inclusive=False):
-    """return the first ancestor of <srcrev> introducting <fnode>
-
-    If the linkrev of the file revision does not point to an ancestor of
-    srcrev, we'll walk down the ancestors until we find one introducing this
-    file revision.
-
-    :repo: a localrepository object (used to access changelog and manifest)
-    :path: the file path
-    :fnode: the nodeid of the file revision
-    :filelog: the filelog of this path
-    :srcrev: the changeset revision we search ancestors from
-    :inclusive: if true, the src revision will also be checked
-    """
-    cl = repo.unfiltered().changelog
-    ma = repo.manifest
-    # fetch the linkrev
-    fr = filelog.rev(fnode)
-    lkr = filelog.linkrev(fr)
-    # check if this linkrev is an ancestor of srcrev
-    anc = cl.ancestors([srcrev], lkr, inclusive=inclusive)
-    if lkr not in anc:
-        for a in anc:
-            ac = cl.read(a) # get changeset data (we avoid object creation).
-            if path in ac[3]: # checking the 'files' field.
-                # The file has been touched, check if the content is similar
-                # to the one we search for.
-                if fnode == ma.readfast(ac[0]).get(path):
-                    return a
-        # In theory, we should never get out of that loop without a result. But
-        # if manifest uses a buggy file revision (not children of the one it
-        # replaces) we could. Such a buggy situation will likely result is crash
-        # somewhere else at to some point.
-    return lkr
-
 class basectx(object):
     """A basectx object represents the common logic for its children:
     changectx: read-only context that is already present in the repo,
@@ -668,6 +633,11 @@
             return self._changeid
         elif '_changectx' in self.__dict__:
             return self._changectx.rev()
+        elif '_descendantrev' in self.__dict__:
+            # this file context was created from a revision with a known
+            # descendant, we can (lazily) correct for linkrev aliases
+            return self._adjustlinkrev(self._path, self._filelog,
+                                       self._filenode, self._descendantrev)
         else:
             return self._filelog.linkrev(self._filerev)
 
@@ -781,6 +751,49 @@
 
         return True
 
+    def _adjustlinkrev(self, path, filelog, fnode, srcrev, inclusive=False):
+        """return the first ancestor of <srcrev> introducting <fnode>
+
+        If the linkrev of the file revision does not point to an ancestor of
+        srcrev, we'll walk down the ancestors until we find one introducing
+        this file revision.
+
+        :repo: a localrepository object (used to access changelog and manifest)
+        :path: the file path
+        :fnode: the nodeid of the file revision
+        :filelog: the filelog of this path
+        :srcrev: the changeset revision we search ancestors from
+        :inclusive: if true, the src revision will also be checked
+        """
+        repo = self._repo
+        cl = repo.unfiltered().changelog
+        ma = repo.manifest
+        # fetch the linkrev
+        fr = filelog.rev(fnode)
+        lkr = filelog.linkrev(fr)
+        # hack to reuse ancestor computation when searching for renames
+        memberanc = getattr(self, '_ancestrycontext', None)
+        iteranc = None
+        if memberanc is None:
+            memberanc = iteranc = cl.ancestors([srcrev], lkr,
+                                               inclusive=inclusive)
+        # check if this linkrev is an ancestor of srcrev
+        if lkr not in memberanc:
+            if iteranc is None:
+                iteranc = cl.ancestors([srcrev], lkr, inclusive=inclusive)
+            for a in iteranc:
+                ac = cl.read(a) # get changeset data (we avoid object creation)
+                if path in ac[3]: # checking the 'files' field.
+                    # The file has been touched, check if the content is
+                    # similar to the one we search for.
+                    if fnode == ma.readfast(ac[0]).get(path):
+                        return a
+            # In theory, we should never get out of that loop without a result.
+            # But if manifest uses a buggy file revision (not children of the
+            # one it replaces) we could. Such a buggy situation will likely
+            # result is crash somewhere else at to some point.
+        return lkr
+
     def introrev(self):
         """return the rev of the changeset which introduced this file revision
 
@@ -795,8 +808,8 @@
         noctx = not ('_changeid' in attrs or '_changectx' in attrs)
         if noctx or self.rev() == lkr:
             return self.linkrev()
-        return _adjustlinkrev(self._repo, self._path, self._filelog,
-                              self._filenode, self.rev(), inclusive=True)
+        return self._adjustlinkrev(self._path, self._filelog, self._filenode,
+                                   self.rev(), inclusive=True)
 
     def parents(self):
         _path = self._path
@@ -822,9 +835,15 @@
                 # If self is associated with a changeset (probably explicitly
                 # fed), ensure the created filectx is associated with a
                 # changeset that is an ancestor of self.changectx.
-                rev = _adjustlinkrev(self._repo, path, l, fnode, self.rev())
-                fctx = filectx(self._repo, path, fileid=fnode, filelog=l,
-                               changeid=rev)
+                # This lets us later use _adjustlinkrev to get a correct link.
+                fctx = filectx(self._repo, path, fileid=fnode, filelog=l)
+                fctx._descendantrev = self.rev()
+                fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
+            elif '_descendantrev' in vars(self):
+                # Otherwise propagate _descendantrev if we have one associated.
+                fctx = filectx(self._repo, path, fileid=fnode, filelog=l)
+                fctx._descendantrev = self._descendantrev
+                fctx._ancestrycontext = getattr(self, '_ancestrycontext', None)
             else:
                 fctx = filectx(self._repo, path, fileid=fnode, filelog=l)
             ret.append(fctx)
@@ -944,7 +963,7 @@
         cut = followfirst and 1 or None
         while True:
             for parent in c.parents()[:cut]:
-                visit[(parent.rev(), parent.node())] = parent
+                visit[(parent.linkrev(), parent.filenode())] = parent
             if not visit:
                 break
             c = visit.pop(max(visit))
--- a/mercurial/copies.py	Sun Feb 01 08:24:08 2015 +0900
+++ b/mercurial/copies.py	Sun Feb 01 18:47:04 2015 -0600
@@ -133,7 +133,7 @@
     for f in fctx.ancestors():
         if am.get(f.path(), None) == f.filenode():
             return f
-        if f.rev() < limit:
+        if limit >= 0 and f.linkrev() < limit and f.rev() < limit:
             return None
 
 def _dirstatecopies(d):
@@ -170,8 +170,11 @@
     missing = set(b.manifest().iterkeys())
     missing.difference_update(a.manifest().iterkeys())
 
+    ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True)
     for f in missing:
-        ofctx = _tracefile(b[f], am, limit)
+        fctx = b[f]
+        fctx._ancestrycontext = ancestrycontext
+        ofctx = _tracefile(fctx, am, limit)
         if ofctx:
             cm[f] = ofctx.path()
 
--- a/mercurial/exchange.py	Sun Feb 01 08:24:08 2015 +0900
+++ b/mercurial/exchange.py	Sun Feb 01 18:47:04 2015 -0600
@@ -946,8 +946,9 @@
         scommon = set(common)
         filteredrheads = []
         for n in rheads:
-            if n in nm and n not in scommon:
-                common.append(n)
+            if n in nm:
+                if n not in scommon:
+                    common.append(n)
             else:
                 filteredrheads.append(n)
         if not filteredrheads:
--- a/mercurial/merge.py	Sun Feb 01 08:24:08 2015 +0900
+++ b/mercurial/merge.py	Sun Feb 01 18:47:04 2015 -0600
@@ -741,7 +741,15 @@
 
     numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
 
+    def dirtysubstate():
+        # mark '.hgsubstate' as possibly dirty forcibly, because
+        # modified '.hgsubstate' is misunderstood as clean,
+        # when both st_size/st_mtime of '.hgsubstate' aren't changed,
+        # even if "submerge" fails and '.hgsubstate' is inconsistent
+        repo.dirstate.normallookup('.hgsubstate')
+
     if [a for a in actions['r'] if a[0] == '.hgsubstate']:
+        dirtysubstate()
         subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
 
     # remove in parallel (must come first)
@@ -760,6 +768,7 @@
     updated = len(actions['g'])
 
     if [a for a in actions['g'] if a[0] == '.hgsubstate']:
+        dirtysubstate()
         subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
 
     # forget (manifest only, just log it) (must come first)
@@ -785,6 +794,7 @@
         z += 1
         progress(_updating, z, item=f, total=numupdates, unit=_files)
         if f == '.hgsubstate': # subrepo states need updating
+            dirtysubstate()
             subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
                              overwrite)
             continue
--- a/mercurial/obsolete.py	Sun Feb 01 08:24:08 2015 +0900
+++ b/mercurial/obsolete.py	Sun Feb 01 18:47:04 2015 -0600
@@ -462,6 +462,16 @@
         """The flags field of the marker"""
         return self._data[2]
 
+def _checkinvalidmarkers(obsstore):
+    """search for marker with invalid data and raise error if needed
+
+    Exist as a separated function to allow the evolve extension for a more
+    subtle handling.
+    """
+    if node.nullid in obsstore.precursors:
+        raise util.Abort(_('bad obsolescence marker detected: '
+                           'invalid successors nullid'))
+
 class obsstore(object):
     """Store obsolete markers
 
@@ -598,9 +608,8 @@
             if parents is not None:
                 for p in parents:
                     self.children.setdefault(p, set()).add(mark)
-        if node.nullid in self.precursors:
-            raise util.Abort(_('bad obsolescence marker detected: '
-                               'invalid successors nullid'))
+        _checkinvalidmarkers(self)
+
     def relevantmarkers(self, nodes):
         """return a set of all obsolescence markers relevant to a set of nodes.
 
--- a/mercurial/revset.py	Sun Feb 01 08:24:08 2015 +0900
+++ b/mercurial/revset.py	Sun Feb 01 18:47:04 2015 -0600
@@ -496,7 +496,8 @@
         if kind == 'literal':
             bmrev = repo._bookmarks.get(pattern, None)
             if not bmrev:
-                raise util.Abort(_("bookmark '%s' does not exist") % bm)
+                raise error.RepoLookupError(_("bookmark '%s' does not exist")
+                                            % bm)
             bms.add(repo[bmrev].rev())
         else:
             matchrevs = set()
@@ -504,8 +505,8 @@
                 if matcher(name):
                     matchrevs.add(bmrev)
             if not matchrevs:
-                raise util.Abort(_("no bookmarks exist that match '%s'")
-                                 % pattern)
+                raise error.RepoLookupError(_("no bookmarks exist"
+                                              " that match '%s'") % pattern)
             for bmrev in matchrevs:
                 bms.add(repo[bmrev].rev())
     else:
@@ -1262,15 +1263,16 @@
     namespaces = set()
     if kind == 'literal':
         if pattern not in repo.names:
-            raise util.Abort(_("namespace '%s' does not exist") % ns)
+            raise error.RepoLookupError(_("namespace '%s' does not exist")
+                                        % ns)
         namespaces.add(repo.names[pattern])
     else:
         for name, ns in repo.names.iteritems():
             if matcher(name):
                 namespaces.add(ns)
         if not namespaces:
-            raise util.Abort(_("no namespace exists that match '%s'")
-                             % pattern)
+            raise error.RepoLookupError(_("no namespace exists"
+                                          " that match '%s'") % pattern)
 
     names = set()
     for ns in namespaces:
@@ -1816,7 +1818,8 @@
             # avoid resolving all tags
             tn = repo._tagscache.tags.get(pattern, None)
             if tn is None:
-                raise util.Abort(_("tag '%s' does not exist") % pattern)
+                raise error.RepoLookupError(_("tag '%s' does not exist")
+                                            % pattern)
             s = set([repo[tn].rev()])
         else:
             s = set([cl.rev(n) for t, n in repo.tagslist() if matcher(t)])
--- a/mercurial/templatekw.py	Sun Feb 01 08:24:08 2015 +0900
+++ b/mercurial/templatekw.py	Sun Feb 01 18:47:04 2015 -0600
@@ -382,6 +382,13 @@
     names = ns.names(repo, ctx.node())
     return showlist(ns.templatename, names, plural=namespace, **args)
 
+# don't remove "showtags" definition, even though namespaces will put
+# a helper function for "tags" keyword into "keywords" map automatically,
+# because online help text is built without namespaces initialization
+def showtags(**args):
+    """:tags: List of strings. Any tags associated with the changeset."""
+    return shownames('tags', **args)
+
 # keywords are callables like:
 # fn(repo, ctx, templ, cache, revcache, **args)
 # with:
@@ -420,6 +427,7 @@
     'phaseidx': showphaseidx,
     'rev': showrev,
     'subrepos': showsubrepos,
+    'tags': showtags,
 }
 
 def _showparents(**args):
--- a/tests/test-bookmarks.t	Sun Feb 01 08:24:08 2015 +0900
+++ b/tests/test-bookmarks.t	Sun Feb 01 18:47:04 2015 -0600
@@ -133,8 +133,13 @@
   
 
   $ hg log -r 'bookmark(unknown)'
-  abort: bookmark 'unknown' does not exist
+  abort: bookmark 'unknown' does not exist!
   [255]
+  $ hg log -r 'bookmark("re:unknown")'
+  abort: no bookmarks exist that match 'unknown'!
+  [255]
+  $ hg log -r 'present(bookmark("literal:unknown"))'
+  $ hg log -r 'present(bookmark("re:unknown"))'
 
   $ hg help revsets | grep 'bookmark('
       "bookmark([name])"
--- a/tests/test-extdiff.t	Sun Feb 01 08:24:08 2015 +0900
+++ b/tests/test-extdiff.t	Sun Feb 01 18:47:04 2015 -0600
@@ -179,7 +179,7 @@
 TODO
 #else
   $ hg --debug odd | grep '^running'
-  running "/bin/echo --foo='sp ace' 'sp ace' --bar='sp ace' 'sp ace'" in * (glob)
+  running "*/bin/echo --foo='sp ace' 'sp ace' --bar='sp ace' 'sp ace'" in * (glob)
 #endif
 
 #if execbit
--- a/tests/test-log.t	Sun Feb 01 08:24:08 2015 +0900
+++ b/tests/test-log.t	Sun Feb 01 18:47:04 2015 -0600
@@ -45,6 +45,13 @@
   $ hg mv dir/b e
   $ hg ci -me -d '5 0'
 
+Make sure largefiles doesn't interfere with logging a regular file
+  $ hg log a --config extensions.largefiles=
+  changeset:   0:9161b9aeaf16
+  user:        test
+  date:        Thu Jan 01 00:00:01 1970 +0000
+  summary:     a
+  
   $ hg log a
   changeset:   0:9161b9aeaf16
   user:        test
@@ -1629,6 +1636,12 @@
   |
   o  a
   
+Ensure that largefiles doesn't intefere with following a normal file
+  $ hg  --config extensions.largefiles= log -f d -T '{desc}' -G
+  @  c
+  |
+  o  a
+  
   $ hg log -f d/a -T '{desc}' -G
   @  c
   |
--- a/tests/test-revset.t	Sun Feb 01 08:24:08 2015 +0900
+++ b/tests/test-revset.t	Sun Feb 01 18:47:04 2015 -0600
@@ -709,7 +709,7 @@
 we can use patterns when searching for tags
 
   $ log 'tag("1..*")'
-  abort: tag '1..*' does not exist
+  abort: tag '1..*' does not exist!
   [255]
   $ log 'tag("re:1..*")'
   6
@@ -720,11 +720,17 @@
   $ log 'tag("re:0..*")'
 
   $ log 'tag(unknown)'
-  abort: tag 'unknown' does not exist
+  abort: tag 'unknown' does not exist!
   [255]
+  $ log 'tag("re:unknown")'
+  $ log 'present(tag("unknown"))'
+  $ log 'present(tag("re:unknown"))'
   $ log 'branch(unknown)'
   abort: unknown revision 'unknown'!
   [255]
+  $ log 'branch("re:unknown")'
+  $ log 'present(branch("unknown"))'
+  $ log 'present(branch("re:unknown"))'
   $ log 'user(bob)'
   2
 
@@ -772,6 +778,15 @@
   3
   1
 
+  $ log 'named("unknown")'
+  abort: namespace 'unknown' does not exist!
+  [255]
+  $ log 'named("re:unknown")'
+  abort: no namespace exists that match 'unknown'!
+  [255]
+  $ log 'present(named("unknown"))'
+  $ log 'present(named("re:unknown"))'
+
 issue2437
 
   $ log '3 and p1(5)'
--- a/tests/test-subrepo.t	Sun Feb 01 08:24:08 2015 +0900
+++ b/tests/test-subrepo.t	Sun Feb 01 18:47:04 2015 -0600
@@ -758,6 +758,8 @@
 
   $ echo issue3276_ok > repo/s/b
   $ hg -R repo2 push -f -q
+  $ touch -t 200001010000 repo/.hgsubstate
+  $ hg -R repo status --config debug.dirstate.delaywrite=2 repo/.hgsubstate
   $ hg -R repo update
   b: untracked file differs
   abort: untracked files in working directory differ from files in requested revision (in subrepo s)
@@ -766,6 +768,7 @@
   $ cat repo/s/b
   issue3276_ok
   $ rm repo/s/b
+  $ touch -t 200001010000 repo/.hgsubstate
   $ hg -R repo revert --all
   reverting repo/.hgsubstate (glob)
   reverting subrepo s
--- a/tests/test-treediscovery.t	Sun Feb 01 08:24:08 2015 +0900
+++ b/tests/test-treediscovery.t	Sun Feb 01 18:47:04 2015 -0600
@@ -520,7 +520,7 @@
   "GET /?cmd=heads HTTP/1.1" 200 -
   "GET /?cmd=branches HTTP/1.1" 200 - x-hgarg-1:nodes=d8f638ac69e9ae8dea4f09f11d696546a912d961
   "GET /?cmd=between HTTP/1.1" 200 - x-hgarg-1:pairs=d8f638ac69e9ae8dea4f09f11d696546a912d961-d57206cc072a18317c1e381fb60aa31bd3401785
-  "GET /?cmd=changegroupsubset HTTP/1.1" 200 - x-hgarg-1:bases=d8f638ac69e9ae8dea4f09f11d696546a912d961&heads=d8f638ac69e9ae8dea4f09f11d696546a912d961+2c8d5d5ec612be65cdfdeac78b7662ab1696324a
+  "GET /?cmd=changegroupsubset HTTP/1.1" 200 - x-hgarg-1:bases=d8f638ac69e9ae8dea4f09f11d696546a912d961&heads=d8f638ac69e9ae8dea4f09f11d696546a912d961
   "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
   "GET /?cmd=capabilities HTTP/1.1" 200 -
   "GET /?cmd=heads HTTP/1.1" 200 -