changeset 52997:1330278b9029

fix: add a `extra-bin-paths` option See inline document for details.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Wed, 19 Feb 2025 23:15:43 +0100
parents c54cc1d7076c
children 5480647c2964
files hgext/fix.py tests/test-fix-path.t tests/test-fix.t
diffstat 3 files changed, 96 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/fix.py	Tue Feb 18 23:30:50 2025 -0500
+++ b/hgext/fix.py	Wed Feb 19 23:15:43 2025 +0100
@@ -120,6 +120,9 @@
     mapping fixer tool names to lists of metadata values returned from
     executions that modified a file. This aggregates the same metadata
     previously passed to the "postfixfile" hook.
+
+You can specify a list of directories to search the tool command in using the
+`fix.extra-bin-paths` configuration.
 """
 
 from __future__ import annotations
@@ -129,6 +132,7 @@
 import os
 import re
 import subprocess
+import sys
 
 from mercurial.i18n import _
 from mercurial.node import (
@@ -143,6 +147,7 @@
     cmdutil,
     context,
     copies,
+    encoding,
     error,
     logcmdutil,
     match as matchmod,
@@ -193,6 +198,8 @@
 # problem.
 configitem(b'fix', b'failure', default=b'continue')
 
+configitem(b'fix', b'extra-bin-paths', default=list)
+
 
 def checktoolfailureaction(ui, message, hint=None):
     """Abort with 'message' if fix.failure=abort"""
@@ -678,6 +685,28 @@
         )
 
 
+def _augmented_env(wvfs, extra_paths):
+    if os.supports_bytes_environ:
+        env = encoding.environ.copy()
+        raw_path = env.get(b'PATH', b'')
+        extra_paths = [wvfs.join(i) for i in extra_paths]
+        path_items = extra_paths + raw_path.split(pycompat.ospathsep)
+        env[b'PATH'] = pycompat.ospathsep.join(path_items)
+    else:
+        path_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
+        extra_str = [p.decode(path_encoding, 'ignore') for p in extra_paths]
+        base = wvfs.base.decode(path_encoding, 'ignore')
+        extra_str = [os.path.join(base, i) for i in extra_str]
+
+        # use (os).xxx to bypass checkcode complains. We are doing this
+        # unicode access on purpose.
+        env = (os).environ.copy()
+        raw_path = env.get('PATH', '')
+        path_items = extra_str + raw_path.split((os).pathsep)
+        env['PATH'] = (os).pathsep.join(path_items)
+    return env
+
+
 def fixfile(ui, repo, opts, fixers, fixctx, path, basepaths, basectxs):
     """Run any configured fixers that should affect the file in this context
 
@@ -692,6 +721,11 @@
     """
     metadata = {}
     newdata = fixctx[path].data()
+
+    env = None
+    extra_paths = ui.configlist(b'fix', b'extra-bin-paths')
+    if extra_paths:
+        env = _augmented_env(repo.wvfs, extra_paths)
     for fixername, fixer in fixers.items():
         if fixer.affects(opts, fixctx, path):
             ranges = lineranges(
@@ -711,6 +745,7 @@
                 stdin=subprocess.PIPE,
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE,
+                env=env,
             )
             stdout, stderr = proc.communicate(newdata)
             if stderr:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-fix-path.t	Wed Feb 19 23:15:43 2025 +0100
@@ -0,0 +1,58 @@
+
+A script that implements uppercasing of specific lines in a file. This
+approximates the behavior of code formatters well enough for our tests.
+
+  $ hg init test-repo
+  $ cd test-repo
+
+  $ mkdir some
+  $ mkdir some/dir
+  $ cat > some/dir/uppercase.py <<EOF
+  > #!$PYTHON
+  > import re
+  > import sys
+  > from mercurial.utils import procutil
+  > procutil.setbinary(sys.stdin)
+  > procutil.setbinary(sys.stdout)
+  > stdin = getattr(sys.stdin, 'buffer', sys.stdin)
+  > stdout = getattr(sys.stdout, 'buffer', sys.stdout)
+  > def format(text):
+  >   return re.sub(b' +', b' ', text.upper())
+  > stdout.write(format(stdin.read()))
+  > EOF
+  $ chmod +x some/dir/uppercase.py
+
+
+  $ echo babar > babar.txt
+  $ hg add babar.txt
+
+Using absolute paths
+
+  $ cat >> $HGRCPATH <<EOF
+  > [extensions]
+  > fix =
+  > [experimental]
+  > evolution.createmarkers=True
+  > evolution.allowunstable=True
+  > [fix]
+  > extra-bin-paths=$TESTTMP/test-repo/some/dir/
+  > uppercase-whole-file:command=uppercase.py
+  > uppercase-whole-file:pattern=set:**.txt
+  > EOF
+
+  $ hg fix --working-dir
+  $ cat babar.txt
+  BABAR
+
+Using relative paths
+
+  $ cat >> $HGRCPATH <<EOF
+  > [fix]
+  > extra-bin-paths=./some/dir/
+  > EOF
+
+  $ echo celeste > celeste.txt
+  $ hg add celeste.txt
+  $ hg fix --working-dir
+  $ cat celeste.txt
+  CELESTE
--- a/tests/test-fix.t	Tue Feb 18 23:30:50 2025 -0500
+++ b/tests/test-fix.t	Wed Feb 19 23:15:43 2025 +0100
@@ -238,6 +238,9 @@
       executions that modified a file. This aggregates the same metadata
       previously passed to the "postfixfile" hook.
   
+  You can specify a list of directories to search the tool command in using the
+  'fix.extra-bin-paths' configuration.
+  
   list of commands:
   
    fix           rewrite file content in changesets or working directory