D5237: fix: add suboption for configuring execution order of tools
hooper (Danny Hooper)
phabricator at mercurial-scm.org
Wed Nov 7 22:05:13 UTC 2018
hooper updated this revision to Diff 12473.
REPOSITORY
rHG Mercurial
CHANGES SINCE LAST UPDATE
https://phab.mercurial-scm.org/D5237?vs=12461&id=12473
REVISION DETAIL
https://phab.mercurial-scm.org/D5237
AFFECTED FILES
hgext/fix.py
tests/test-fix.t
CHANGE DETAILS
diff --git a/tests/test-fix.t b/tests/test-fix.t
--- a/tests/test-fix.t
+++ b/tests/test-fix.t
@@ -165,6 +165,26 @@
[fix]
failure = abort
+ When multiple tools are configured to affect a file, they execute in an order
+ defined by the :priority suboption. The priority suboption has a default value
+ of zero for each tool. Tools are executed in order of descending priority. The
+ execution order of tools with equal priority is unspecified. For example, you
+ could use the 'sort' and 'head' utilities to keep only the 10 smallest numbers
+ in a text file by ensuring that 'sort' runs before 'head':
+
+ [fix]
+ sort:command = sort --numeric-sort
+ head:command = head --lines=10
+ sort:pattern = numbers.txt
+ head:pattern = numbers.txt
+ sort:priority = 2
+ head:priority = 1
+
+ To account for changes made by each tool, the line numbers used for
+ incremental formatting are recomputed before executing the next tool. So, each
+ tool may see different values for the arguments added by the :linerange
+ suboption.
+
list of commands:
fix rewrite file content in changesets or working directory
@@ -1127,3 +1147,51 @@
first
$ cd ..
+
+The execution order of tools can be controlled. This example doesn't work if
+you sort after truncating, but the config defines the correct order while the
+definitions are out of order (which might imply the incorrect order given the
+implementation of fix). The goal is to use multiple tools to select the lowest
+5 numbers in the file.
+
+ $ hg init priorityexample
+ $ cd priorityexample
+
+ $ cat >> .hg/hgrc <<EOF
+ > [fix]
+ > head:command = head --lines=5
+ > head:pattern = numbers.txt
+ > head:priority = 1
+ > sort:command = sort --numeric-sort
+ > sort:pattern = numbers.txt
+ > sort:priority = 2
+ > EOF
+
+ $ printf "8\n2\n3\n6\n7\n4\n9\n5\n1\n0\n" > numbers.txt
+ $ hg add -q
+ $ hg fix -w
+ $ cat numbers.txt
+ 0
+ 1
+ 2
+ 3
+ 4
+
+And of course we should be able to break this by reversing the execution order.
+Test negative priorities while we're at it.
+
+ $ cat >> .hg/hgrc <<EOF
+ > [fix]
+ > head:priority = -1
+ > sort:priority = -2
+ > EOF
+ $ printf "8\n2\n3\n6\n7\n4\n9\n5\n1\n0\n" > numbers.txt
+ $ hg fix -w
+ $ cat numbers.txt
+ 2
+ 3
+ 6
+ 7
+ 8
+
+ $ cd ..
diff --git a/hgext/fix.py b/hgext/fix.py
--- a/hgext/fix.py
+++ b/hgext/fix.py
@@ -54,6 +54,24 @@
[fix]
failure = abort
+When multiple tools are configured to affect a file, they execute in an order
+defined by the :priority suboption. The priority suboption has a default value
+of zero for each tool. Tools are executed in order of descending priority. The
+execution order of tools with equal priority is unspecified. For example, you
+could use the 'sort' and 'head' utilities to keep only the 10 smallest numbers
+in a text file by ensuring that 'sort' runs before 'head'::
+
+ [fix]
+ sort:command = sort --numeric-sort
+ head:command = head --lines=10
+ sort:pattern = numbers.txt
+ head:pattern = numbers.txt
+ sort:priority = 2
+ head:priority = 1
+
+To account for changes made by each tool, the line numbers used for incremental
+formatting are recomputed before executing the next tool. So, each tool may see
+different values for the arguments added by the :linerange suboption.
"""
from __future__ import absolute_import
@@ -100,10 +118,16 @@
configitem = registrar.configitem(configtable)
# Register the suboptions allowed for each configured fixer.
-FIXER_ATTRS = ('command', 'linerange', 'fileset', 'pattern')
+FIXER_ATTRS = {
+ 'command': None,
+ 'linerange': None,
+ 'fileset': None,
+ 'pattern': None,
+ 'priority': 0,
+}
-for key in FIXER_ATTRS:
- configitem('fix', '.*(:%s)?' % key, default=None, generic=True)
+for key, default in FIXER_ATTRS.items():
+ configitem('fix', '.*(:%s)?' % key, default=default, generic=True)
# A good default size allows most source code files to be fixed, but avoids
# letting fixer tools choke on huge inputs, which could be surprising to the
@@ -602,18 +626,21 @@
Each value is a Fixer object with methods that implement the behavior of the
fixer's config suboptions. Does not validate the config values.
"""
- result = {}
+ fixers = {}
for name in fixernames(ui):
- result[name] = Fixer()
+ fixers[name] = Fixer()
attrs = ui.configsuboptions('fix', name)[1]
if 'fileset' in attrs and 'pattern' not in attrs:
ui.warn(_('the fix.tool:fileset config name is deprecated; '
'please rename it to fix.tool:pattern\n'))
attrs['pattern'] = attrs['fileset']
- for key in FIXER_ATTRS:
- setattr(result[name], pycompat.sysstr('_' + key),
- attrs.get(key, ''))
- return result
+ for key, default in FIXER_ATTRS.items():
+ setattr(fixers[name], pycompat.sysstr('_' + key),
+ attrs.get(key, default))
+ fixers[name]._priority = int(fixers[name]._priority)
+ return collections.OrderedDict(
+ sorted(fixers.items(), key=lambda item: item[1]._priority,
+ reverse=True))
def fixernames(ui):
"""Returns the names of [fix] config options that have suboptions"""
To: hooper, #hg-reviewers
Cc: yuja, mercurial-devel
More information about the Mercurial-devel
mailing list