scmutil: add utility fn to return repo object with user passed revs unhidden
There has been a need for accessing hidden changesets by default without passing
--hidden. This is currently done using the directaccess extension but is bit
hacky.
This patch adds a utility function to return a repo object having user passed
revisions unhidden. This functionality will live behind a
config option and won't be the default behaviour. There is also a config option
added by this patch which tells whether we want to unhide only those revisions
whose hashes are passed or should we consider revisions numbers also.
Differential Revision: https://phab.mercurial-scm.org/D1733
--- a/mercurial/configitems.py Mon Dec 18 17:50:02 2017 +0530
+++ b/mercurial/configitems.py Fri Dec 15 04:31:29 2017 +0530
@@ -452,6 +452,12 @@
coreconfigitem('experimental', 'crecordtest',
default=None,
)
+coreconfigitem('experimental', 'directaccess',
+ default=False,
+)
+coreconfigitem('experimental', 'directaccess.revnums',
+ default=False,
+)
coreconfigitem('experimental', 'editortmpinhg',
default=False,
)
--- a/mercurial/scmutil.py Mon Dec 18 17:50:02 2017 +0530
+++ b/mercurial/scmutil.py Fri Dec 15 04:31:29 2017 +0530
@@ -1305,3 +1305,79 @@
before it is used, whether or not the convert extension was formally loaded.
"""
return sink
+
+def unhidehashlikerevs(repo, specs, hiddentype):
+ """parse the user specs and unhide changesets whose hash or revision number
+ is passed.
+
+ hiddentype can be: 1) 'warn': warn while unhiding changesets
+ 2) 'nowarn': don't warn while unhiding changesets
+
+ returns a repo object with the required changesets unhidden
+ """
+ if not repo.filtername or not repo.ui.configbool('experimental',
+ 'directaccess'):
+ return repo
+
+ if not repo.filtername.startswith('visible'):
+ return repo
+
+ symbols = set()
+ for spec in specs:
+ try:
+ tree = revsetlang.parse(spec)
+ except error.ParseError: # will be reported by scmutil.revrange()
+ continue
+
+ symbols.update(revsetlang.gethashlikesymbols(tree))
+
+ if not symbols:
+ return repo
+
+ revs = _getrevsfromsymbols(repo, symbols)
+
+ if not revs:
+ return repo
+
+ if hiddentype == 'warn':
+ unfi = repo.unfiltered()
+ revstr = ", ".join([pycompat.bytestr(unfi[l]) for l in revs])
+ repo.ui.warn(_("warning: accessing hidden changesets for write "
+ "operation: %s\n") % revstr)
+
+ return repo.filtered('visible-hidden', revs)
+
+def _getrevsfromsymbols(repo, symbols):
+ """parse the list of symbols and returns a set of revision numbers of hidden
+ changesets present in symbols"""
+ revs = set()
+ unfi = repo.unfiltered()
+ unficl = unfi.changelog
+ cl = repo.changelog
+ tiprev = len(unficl)
+ pmatch = unficl._partialmatch
+ allowrevnums = repo.ui.configbool('experimental', 'directaccess.revnums')
+ for s in symbols:
+ try:
+ n = int(s)
+ if n <= tiprev:
+ if not allowrevnums:
+ continue
+ else:
+ if n not in cl:
+ revs.add(n)
+ continue
+ except ValueError:
+ pass
+
+ try:
+ s = pmatch(s)
+ except error.LookupError:
+ s = None
+
+ if s is not None:
+ rev = unficl.rev(s)
+ if rev not in cl:
+ revs.add(rev)
+
+ return revs