Patchwork D3639: remotenames: add paths argument to remotenames revset

login
register
mail settings
Submitter phabricator
Date May 20, 2018, 9:22 p.m.
Message ID <differential-rev-PHID-DREV-ypb3ru7muz2k64qi37dk-req@phab.mercurial-scm.org>
Download mbox | patch
Permalink /patch/31766/
State New
Headers show

Comments

phabricator - May 20, 2018, 9:22 p.m.
pulkit created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  This patch adds paths argument to the revsets provided by the remotenames
  extension. The revsets are remotenames(), remotebranches() and
  remotebookmarks(). paths can be a single path, list of paths or can be empty too
  which means it's an optional argument.
  
  If paths is/are passed, changesets which have remotenames from those remote
  paths are shown only.
  If paths is/are not passed, changesets from all the remote paths are shown.
  
  Passing an invalid path name does not throw error.
  
  Tests are added for the argument in tests/test-logexchange.t

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3639

AFFECTED FILES
  hgext/remotenames.py
  tests/test-logexchange.t

CHANGE DETAILS




To: pulkit, #hg-reviewers
Cc: mercurial-devel
Yuya Nishihara - May 24, 2018, 1:13 p.m.
> +def _parsepaths(x):
> +    """parses the argument passed in revsets as paths and return
> +    them as a set or returns None if no path is specified"""
> +
> +    if not x:
> +        return None
> +
> +    paths = set()
> +    if x[0] in ('symbol', 'string'):
> +        paths.add(x[1])
> +    elif x[0] == 'list':
> +        for t, p in x[1:]:
> +            paths.add(p)
> +    return paths

Use `revsetlang.getlist()` and apply `.getstring()` to each element, which
is more robust.

That said, the common idiom is to accept a literal/re pattern. See
`revset.bookmark()` for example.
phabricator - May 24, 2018, 1:13 p.m.
yuja added a comment.


  > +def _parsepaths(x):
  >  +    """parses the argument passed in revsets as paths and return
  >  +    them as a set or returns None if no path is specified"""
  >  +
  >  +    if not x:
  >  +        return None
  >  +
  >  +    paths = set()
  >  +    if x[0] in ('symbol', 'string'):
  >  +        paths.add(x[1])
  >  +    elif x[0] == 'list':
  >  +        for t, p in x[1:]:
  >  +            paths.add(p)
  >  +    return paths
  
  Use `revsetlang.getlist()` and apply `.getstring()` to each element, which
  is more robust.
  
  That said, the common idiom is to accept a literal/re pattern. See
  `revset.bookmark()` for example.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3639

To: pulkit, #hg-reviewers
Cc: yuja, mercurial-devel
phabricator - May 31, 2018, 7:21 p.m.
durin42 added a comment.


  I like the literal/re pattern idea. I think if this lands I can stop maintaining remotebranches, so I'd very much like to see it land.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3639

To: pulkit, #hg-reviewers
Cc: durin42, yuja, mercurial-devel

Patch

diff --git a/tests/test-logexchange.t b/tests/test-logexchange.t
--- a/tests/test-logexchange.t
+++ b/tests/test-logexchange.t
@@ -291,6 +291,7 @@ 
   ~
 
 Updating to revision using hoisted name
+---------------------------------------
 
 Deleting local bookmark to make sure we update to hoisted name only
 
@@ -395,3 +396,173 @@ 
      default/bar               6:87d6d6676308
      default/foo               8:3e1487808078
    * foo                       8:3e1487808078
+
+Testing the paths argument to remotenames, remotebranches and remotebookmarks revsets
+--------------------------------------------------------------------------------------
+
+  $ cd ..
+  $ hg clone ssh://user@dummy/server client2
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 9 changesets with 9 changes to 9 files (+1 heads)
+  new changesets 18d04c59bb5d:3e1487808078
+  updating to branch default
+  8 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd server2
+  $ hg up wat
+  6 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo foo > watwat
+  $ hg ci -Aqm "added watwat"
+  $ hg bookmark bar
+  abort: bookmark 'bar' already exists (use -f to force)
+  [255]
+  $ hg up ec24
+  3 files updated, 0 files merged, 2 files removed, 0 files unresolved
+  $ echo i > i
+  $ hg ci -Aqm "added i"
+
+  $ cd ../client2
+  $ echo "[paths]" >> .hg/hgrc
+  $ echo "server2 = $TESTTMP/server2" >> .hg/hgrc
+  $ hg pull server2
+  pulling from $TESTTMP/server2
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  new changesets f34adec73c21:bf433e48adea
+  (run 'hg update' to get a working copy)
+
+  $ hg log -Gr 'remotenames()' -T '{rev}:{node|short} {desc}\n({remotebranches})  [{remotebookmarks}]\n\n'
+  o  10:bf433e48adea added i
+  |  (server2/default)  []
+  |
+  | o  9:f34adec73c21 added watwat
+  | |  (server2/wat)  []
+  | |
+  | o  8:3e1487808078 added bar
+  | :  (default/wat)  [default/foo]
+  | :
+  @ :  7:ec2426147f0e Added h
+  | :  (default/default)  []
+  | :
+  o :  6:87d6d6676308 Added g
+  :/   ()  [default/bar server2/bar]
+  :
+  o  3:62615734edd5 Added d
+  |  ()  [server2/foo]
+  ~
+
+Testing for a single path name which exists
+
+  $ hg log -r 'remotebranches(default)' -GT "{rev}:{node|short} {remotebranches}\n"
+  o  8:3e1487808078 default/wat
+  |
+  ~
+  @  7:ec2426147f0e default/default
+  |
+  ~
+
+  $ hg log -r 'remotebookmarks("server2")' -GT "{rev}:{node|short} {remotebookmarks}\n"
+  o  6:87d6d6676308 default/bar server2/bar
+  :
+  o  3:62615734edd5 server2/foo
+  |
+  ~
+
+  $ hg log -r 'remotenames(default)' -GT "{rev}:{node|short} {remotenames}\n"
+  o  8:3e1487808078 default/foo default/wat
+  |
+  ~
+  @  7:ec2426147f0e default/default
+  |
+  o  6:87d6d6676308 default/bar server2/bar
+  |
+  ~
+
+Testing for a single path name which does not exists
+
+  $ hg log -r 'remotebranches(def)' -GT "{rev}:{node|short} {remotenames}\n"
+
+  $ hg log -r 'remotebookmarks("server3")' -GT "{rev}:{node|short} {remotenames}\n"
+
+  $ hg log -r 'remotenames("server3")' -GT "{rev}:{node|short} {remotenames}\n"
+
+Testing for multiple paths where all of them exists
+
+  $ hg log -r 'remotenames(default, server2)' -GT "{rev}:{node|short} {remotenames}\n"
+  o  10:bf433e48adea server2/default
+  |
+  | o  9:f34adec73c21 server2/wat
+  | |
+  | o  8:3e1487808078 default/foo default/wat
+  | :
+  @ :  7:ec2426147f0e default/default
+  | :
+  o :  6:87d6d6676308 default/bar server2/bar
+  :/
+  o  3:62615734edd5 server2/foo
+  |
+  ~
+
+  $ hg log -r 'remotebranches(default, server2)' -GT "{rev}:{node|short} {remotebranches}\n"
+  o  10:bf433e48adea server2/default
+  |
+  | o  9:f34adec73c21 server2/wat
+  | |
+  | o  8:3e1487808078 default/wat
+  | |
+  | ~
+  @  7:ec2426147f0e default/default
+  |
+  ~
+
+  $ hg log -r 'remotebookmarks(default, server2)' -GT "{rev}:{node|short} {remotebookmarks}\n"
+  o  8:3e1487808078 default/foo
+  :
+  : o  6:87d6d6676308 default/bar server2/bar
+  :/
+  o  3:62615734edd5 server2/foo
+  |
+  ~
+
+Testing for multipe paths where some exists and some not
+
+  $ hg log -r 'remotenames(def, server2)' -GT "{rev}:{node|short} {remotenames}\n"
+  o  10:bf433e48adea server2/default
+  :
+  : o  9:f34adec73c21 server2/wat
+  : :
+  o :  6:87d6d6676308 default/bar server2/bar
+  :/
+  o  3:62615734edd5 server2/foo
+  |
+  ~
+
+  $ hg log -r 'remotebranches(default, server)' -GT "{rev}:{node|short} {remotebranches}\n"
+  o  8:3e1487808078 default/wat
+  |
+  ~
+  @  7:ec2426147f0e default/default
+  |
+  ~
+
+  $ hg log -r 'remotebookmarks(default, serv)' -GT "{rev}:{node|short} {remotebookmarks}\n"
+  o  8:3e1487808078 default/foo
+  |
+  ~
+  o  6:87d6d6676308 default/bar server2/bar
+  |
+  ~
+
+Where multiple paths specified and None of them exists
+
+  $ hg log -r 'remotenames(def, serv2)' -GT "{rev}:{node|short} {remotenames}\n"
+
+  $ hg log -r 'remotebranches(defu, server)' -GT "{rev}:{node|short} {remotebranches}\n"
+
+  $ hg log -r 'remotebookmarks(delt, serv)' -GT "{rev}:{node|short} {remotebookmarks}\n"
+
diff --git a/hgext/remotenames.py b/hgext/remotenames.py
--- a/hgext/remotenames.py
+++ b/hgext/remotenames.py
@@ -26,8 +26,6 @@ 
 
 from __future__ import absolute_import
 
-from mercurial.i18n import _
-
 from mercurial.node import (
     bin,
 )
@@ -38,7 +36,6 @@ 
     namespaces,
     pycompat,
     registrar,
-    revsetlang,
     smartset,
     templateutil,
 )
@@ -343,34 +340,60 @@ 
     return templateutil.compatlist(context, mapping, 'remotebranch',
                                    remotebranches, plural='remotebranches')
 
-def _revsetutil(repo, subset, x, rtypes):
+def _revsetutil(repo, subset, x, rtypes, paths):
     """utility function to return a set of revs based on the rtypes"""
 
     revs = set()
     cl = repo.changelog
     for rtype in rtypes:
         if rtype in repo.names:
             ns = repo.names[rtype]
             for name in ns.listnames(repo):
-                revs.update(ns.nodes(repo, name))
+                if paths:
+                    if name.split('/')[0] in paths:
+                        revs.update(ns.nodes(repo, name))
+                else:
+                    revs.update(ns.nodes(repo, name))
 
     results = (cl.rev(n) for n in revs if cl.hasnode(n))
     return subset & smartset.baseset(sorted(results))
 
-@revsetpredicate('remotenames()')
+def _parsepaths(x):
+    """parses the argument passed in revsets as paths and return
+    them as a set or returns None if no path is specified"""
+
+    if not x:
+        return None
+
+    paths = set()
+    if x[0] in ('symbol', 'string'):
+        paths.add(x[1])
+    elif x[0] == 'list':
+        for t, p in x[1:]:
+            paths.add(p)
+    return paths
+
+@revsetpredicate('remotenames([path, ...])')
 def remotenamesrevset(repo, subset, x):
-    """All changesets which have a remotename on them."""
-    revsetlang.getargs(x, 0, 0, _("remotenames takes no arguments"))
-    return _revsetutil(repo, subset, x, ('remotebookmarks', 'remotebranches'))
+    """All changesets which have a remotename on them. If paths are specified,
+    remotenames of those remote paths are only considered."""
 
-@revsetpredicate('remotebranches()')
+    paths = _parsepaths(x)
+    return _revsetutil(repo, subset, x, ('remotebookmarks', 'remotebranches'),
+                       paths)
+
+@revsetpredicate('remotebranches([path, ...])')
 def remotebranchesrevset(repo, subset, x):
-    """All changesets which are branch heads on remotes."""
-    revsetlang.getargs(x, 0, 0, _("remotebranches takes no arguments"))
-    return _revsetutil(repo, subset, x, ('remotebranches',))
+    """All changesets which are branch heads on remotes. If paths are specified,
+    only those remotes paths are considered"""
+
+    paths = _parsepaths(x)
+    return _revsetutil(repo, subset, x, ('remotebranches',), paths)
 
-@revsetpredicate('remotebookmarks()')
+@revsetpredicate('remotebookmarks([path, ...])')
 def remotebmarksrevset(repo, subset, x):
-    """All changesets which have bookmarks on remotes."""
-    revsetlang.getargs(x, 0, 0, _("remotebookmarks takes no arguments"))
-    return _revsetutil(repo, subset, x, ('remotebookmarks',))
+    """All changesets which have bookmarks on remotes. If paths are specified,
+    only those remote paths are considered"""
+
+    paths = _parsepaths(x)
+    return _revsetutil(repo, subset, x, ('remotebookmarks',), paths)