indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers.
REVISION SUMMARY It is common for projects or companies to define/recommend common customizations for Mercurial. However, distributing these customizations can be difficult because there's no distribution channel built into Mercurial itself. The "configexpress" extension is making some inroads here. But it is geared towards hgrc files. I think there's room to make certain customizations outside of the config system via specially named files checked into the repository. In this commit, we introduce a new experimental feature for reading revset aliases from a .hgrevsets file in the working directory. A repository can then add this file to define custom revset aliases which will automagically be made available to anyone who clones the repo and has a modern enough Mercurial client [with the feature enabled]. Essentially, the .hgrevsets file is parsed as a [revsetalias] config section but with lower priority than all config files. This is because a user may want to overwrite an alias defined in the repo and since not all users can commit to the repo, config files or --config must take precedence. One can imagine applying this pattern of "define customizations in .hg<thing> files" to other features. For example, repositories could also define templates - either keywords or full template maps. Another potential area is filesets. You could create named collections of files and do things like `hg files mycollection` or even reference those named collections as part of building a narrow clone or sparse checkout profile. While I'm reasonably confident in the implementation, the feature is marked as experimental because it is close to freeze and this feature feels a bit dangerous to enable by default with minimal time to bake. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D98 AFFECTED FILES mercurial/configitems.py mercurial/revset.py tests/test-revset.t CHANGE DETAILS Index: tests/test-revset.t =================================================================== --- tests/test-revset.t +++ tests/test-revset.t @@ -4114,6 +4114,102 @@ 5:904fa392b941 6:e0cc66ef77e8 +.hgrevsets file from working directory can define aliases + + $ cat > .hgrevsets << EOF + > filealiasall = all() + > filealiasthroughfour = 0:4 + > EOF + + $ hg log -q -r 'filealiasall' + abort: unknown revision 'filealiasall'! + [255] + + $ hg log -q -r 'filealiasall' --config experimental.hgrevsetsfile=true + 0:2785f51eece5 + 1:d75937da8da0 + 2:5ed5505e9f1c + 3:8528aa5637f2 + 4:2326846efdab + 5:904fa392b941 + 6:e0cc66ef77e8 + 7:013af1973af4 + 8:d5d0dcbdc4d9 + 9:24286f4ae135 + +.hgrevsets is combined with revsetalias + + $ hg log -q -r 'filealiasall & m' --config experimental.hgrevsetsfile=true + 6:e0cc66ef77e8 + +Value from config overwrites .hgrevsets + + $ cat > .hgrevsets << EOF + > m = all() + > EOF + + $ hg log -q -r m --config experimental.hgrevsetsfile=true + 6:e0cc66ef77e8 + +Minimum version filtering in .hgrevset entries works + + $ cat > fakeversion.py << EOF + > from mercurial import util + > util.version = lambda: '4.1' + > EOF + + $ cat > .hgrevsets << EOF + > requiresnew = 0:1 + > requiresnew:minversion = 4.2 + > requiresold = 2:3 + > requiresold:minversion = 4.1 + > EOF + + $ hg log -q -r requiresnew --config experimental.hgrevsetsfile=true --config extensions.fakeversion=`pwd`/fakeversion.py + abort: unknown revision 'requiresnew'! + [255] + + $ hg log -q -r requiresold --config experimental.hgrevsetsfile=true --config extensions.fakeversion=`pwd`/fakeversion.py + 2:5ed5505e9f1c + 3:8528aa5637f2 + +Missing .hgrevsetsfile is OK + + $ rm .hgrevsets + $ hg log -q -r 1 --config experimental.hgrevsetsfile=true + 1:d75937da8da0 + +Invalid syntax in .hgrevsets file + + $ cat > .hgrevsets << EOF + > fileall = all() + > bar + > EOF + + $ hg log -q -r fileall --config experimental.hgrevsetsfile=true + invalid syntax in .hgrevsets: bar + 0:2785f51eece5 + 1:d75937da8da0 + 2:5ed5505e9f1c + 3:8528aa5637f2 + 4:2326846efdab + 5:904fa392b941 + 6:e0cc66ef77e8 + 7:013af1973af4 + 8:d5d0dcbdc4d9 + 9:24286f4ae135 + +Unable to parse :minversion in .hgrevsets file + + $ cat > .hgrevsets << EOF + > fileall = all() + > fileall:minversion = invalid + > EOF + + $ hg log -q -r foo --config experimental.hgrevsetsfile=true + abort: unknown revision 'foo'! + [255] + issue2549 - correct optimizations $ try 'limit(1 or 2 or 3, 2) and not 2' Index: mercurial/revset.py =================================================================== --- mercurial/revset.py +++ mercurial/revset.py @@ -2061,6 +2061,9 @@ If localalias is not None, it is a dict {name: definitionstring}. It takes precedence over [revsetalias] config section. + + Aliases from the config file and a ``.hgrevsets`` file in the working + directory are only expanded if ``ui`` is defined. """ if not specs: def mfunc(repo, subset=None): @@ -2079,6 +2082,12 @@ aliases = [] warn = None + + # Aliases from the .hgrevsets file in the repo have the lowest priority + # because the user is in the least control of them. An hgrc or config + # option can be set easily. A file in the repo cannot be changed as easily. + if ui and repo and repo.ui.configbool('experimental', 'hgrevsetsfile'): + aliases.extend(_parsehgrevsetsfile(repo)) if ui: aliases.extend(ui.configitems('revsetalias')) warn = ui.warn @@ -2108,6 +2117,47 @@ if func._safe: safesymbols.add(name) +def _parsehgrevsetsfile(repo): + options = {} + + data = repo.wvfs.tryread('.hgrevsets') + for line in data.splitlines(): + line = line.strip() + if not line or line.startswith('#'): + continue + + if '=' not in line: + repo.ui.warn(_('invalid syntax in .hgrevsets: %s\n') % line) + continue + + name, value = line.split('=', 1) + options[name.strip()] = value.strip() + + aliases = [] + ourversion = util.versiontuple(n=2) + + for key, value in options.iteritems(): + if ':' in key: + continue + + # Revsets in repo may require features not available to old clients. + # Allow revsets to self-advertise minimum version requirements. + minversion = options.get('%s:minversion' % key) + if minversion: + try: + wantversion = util.versiontuple(minversion, n=2) + except IndexError: + repo.ui.warn(_('illegal value for %s in .hgrevsetsfile: %s\n') % + ('%s:minversion' % key, minversion)) + continue + + if wantversion > ourversion: + continue + + aliases.append((key, value)) + + return aliases + # load built-in predicates explicitly to setup safesymbols loadpredicate(None, None, predicate) Index: mercurial/configitems.py =================================================================== --- mercurial/configitems.py +++ mercurial/configitems.py @@ -199,6 +199,9 @@ coreconfigitem('experimental', 'graphshorten', default=False, ) +coreconfigitem('experimental', 'hgrevsetsfile', + default=False, +) coreconfigitem('experimental', 'hook-track-tags', default=False, ) EMAIL PREFERENCES https://phab.mercurial-scm.org/settings/panel/emailpreferences/ To: indygreg, #hg-reviewers Cc: mercurial-devel _______________________________________________ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel