AcademySoftwareFoundation / rez

An integrated package configuration, build and deployment system for software
https://rez.readthedocs.io
Apache License 2.0
916 stars 328 forks source link

Add argcomplete vendored version to vendor README.md #1742

Closed BryceGattis closed 2 months ago

BryceGattis commented 2 months ago

Did some digging to find out which version of argcomplete we are using. Going to put the diff in a comment as well.

BryceGattis commented 2 months ago

Comparing argcomplete/__init__.py in Rez to v0.8.2.

diff --git a/argcomplete/__init__.py b/argcomplete/__init__.py
index 210e08f..50cefcd 100644
--- a/argcomplete/__init__.py
+++ b/argcomplete/__init__.py
@@ -3,7 +3,8 @@

 from __future__ import print_function, unicode_literals

-import os, sys, argparse, contextlib, subprocess, locale, re
+import os, sys, contextlib, locale, re
+import argparse

 from . import my_shlex as shlex

@@ -56,7 +57,7 @@ class ArgcompleteException(Exception):

 def split_line(line, point=None):
     if point is None:
-        point = len(line)
+        point = len(line)-1
     lexer = shlex.shlex(line, posix=True, punctuation_chars=True)
     words = []

@@ -109,13 +110,11 @@ class CompletionFinder(object):
     directly (it's a convenience instance of this class). It has the same signature as
     :meth:`CompletionFinder.__call__()`.
     '''
-    def __init__(self, argument_parser=None, always_complete_options=True, exclude=None, validator=None):
+    def __init__(self, argument_parser=None, always_complete_options=True, exclude=None):
         self._parser = argument_parser
         self.always_complete_options = always_complete_options
         self.exclude = exclude
-        if validator is None:
-            validator = default_validator
-        self.validator = validator
+        self.wordbreaks = " \t\"'@><=;|&(:."

     def __call__(self, argument_parser, always_complete_options=True, exit_method=os._exit, output_stream=None,
                  exclude=None, validator=None):
@@ -139,7 +138,7 @@ class CompletionFinder(object):
         added to argcomplete.safe_actions, if their values are wanted in the ``parsed_args`` completer argument, or their
         execution is otherwise desirable.
         '''
-        self.__init__(argument_parser, always_complete_options, exclude, validator)
+        self.__init__(argument_parser, always_complete_options, exclude)

         if '_ARGCOMPLETE' not in os.environ:
             # not an argument completion invocation
@@ -158,6 +157,10 @@ class CompletionFinder(object):
                 debug("Unable to open fd 8 for writing, quitting")
                 exit_method(1)

+        if validator is None:
+            validator = default_validator
+        self.validator = validator
+
         # print("", stream=debug_stream)
         # for v in 'COMP_CWORD', 'COMP_LINE', 'COMP_POINT', 'COMP_TYPE', 'COMP_KEY', '_ARGCOMPLETE_COMP_WORDBREAKS', 'COMP_WORDS':
         #     print(v, os.environ[v], stream=debug_stream)
@@ -323,6 +326,8 @@ class CompletionFinder(object):
                                     completions.append(next_completion)
                         debug("Completions:", completions)
                     elif not isinstance(active_action, argparse._SubParsersAction):
+                        pass
+                        """
                         debug("Completer not available, falling back")
                         try:
                             # TODO: what happens if completions contain newlines? How do I make compgen use IFS?
@@ -330,6 +335,7 @@ class CompletionFinder(object):
                             completions += subprocess.check_output(bashcomp_cmd).decode(sys_encoding).splitlines()
                         except subprocess.CalledProcessError:
                             pass
+                        """
         return completions

     def filter_completions(self, completions):
@@ -358,14 +364,14 @@ class CompletionFinder(object):
         If the word under the cursor started with a quote (as indicated by a nonempty ``cword_prequote``), escapes
         occurrences of that quote character in the completions, and adds the quote to the beginning of each completion.
         Otherwise, escapes all characters that bash splits words on (``COMP_WORDBREAKS``), and removes portions of
-        completions before the first colon if (``COMP_WORDBREAKS``) contains a colon.
+        completions before the first colon.

         If there is only one completion, and it doesn't end with a **continuation character** (``/``, ``:``, or ``=``),
         adds a space after the completion.

         This method is exposed for overriding in subclasses; there is no need to use it directly.
         '''
-        comp_wordbreaks = os.environ.get('_ARGCOMPLETE_COMP_WORDBREAKS', os.environ.get('COMP_WORDBREAKS', " \t\"'@><=;|&(:."))
+        comp_wordbreaks = os.environ.get('_ARGCOMPLETE_COMP_WORDBREAKS', os.environ.get('COMP_WORDBREAKS', self.wordbreaks))
         if USING_PYTHON2:
             comp_wordbreaks = comp_wordbreaks.decode(sys_encoding)

@@ -377,9 +383,9 @@ class CompletionFinder(object):
         # If the word under the cursor was quoted, escape the quote char and add the leading quote back in.
         # Otherwise, escape all COMP_WORDBREAKS chars.
         if cword_prequote == '':
-            # Bash mangles completions which contain colons if COMP_WORDBREAKS contains a colon.
+            # Bash mangles completions which contain colons.
             # This workaround has the same effect as __ltrim_colon_completions in bash_completion.
-            if ':' in comp_wordbreaks and first_colon_pos:
+            if first_colon_pos:
                 completions = [c[first_colon_pos+1:] for c in completions]

             for wordbreak_char in comp_wordbreaks:
@@ -420,11 +426,14 @@ class CompletionFinder(object):
         (Use ``raw_input`` instead of ``input`` on Python 2, or use `eight <https://github.com/kislyuk/eight>`_).
         '''
         if state == 0:
+            print("Retrieving matches for", text)
             cword_prequote, cword_prefix, cword_suffix, comp_words, first_colon_pos = split_line(text)
-            comp_words.insert(0, sys.argv[0])
+            print("Split line into prequote={}, prefix={}, suffix={}, words={}, fcp={}".format(cword_prequote, cword_prefix, cword_suffix, comp_words, first_colon_pos))
+            comp_words.insert(0, "prog")
             self.matches = self._get_completions(comp_words, cword_prefix, cword_prequote, first_colon_pos)
-
+            print("Set matches to", self.matches)
         if state < len(self.matches):
+            print("Returning", self.matches[state])
             return self.matches[state]
         else:
             return None
BryceGattis commented 2 months ago

Comparing argcomplete/my_argparse.py in Rez to v0.8.2.

diff --git a/argcomplete/my_argparse.py b/argcomplete/my_argparse.py
index fa58018..6c3150f 100644
--- a/argcomplete/my_argparse.py
+++ b/argcomplete/my_argparse.py
@@ -1,9 +1,8 @@
 # Copyright 2012-2013, Andrey Kislyuk and argcomplete contributors.
 # Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info.

-from argparse import ArgumentParser, ArgumentError, SUPPRESS
-from argparse import OPTIONAL, ZERO_OR_MORE, ONE_OR_MORE, REMAINDER, PARSER
-from argparse import _get_action_name, _
+from argparse import ArgumentParser, ArgumentError, SUPPRESS, \
+    OPTIONAL, ZERO_OR_MORE, ONE_OR_MORE, REMAINDER, PARSER, _get_action_name, _

 def action_is_satisfied(action):
     ''' Returns False if the parse would raise an error if no more arguments are given to this action, True otherwise.
JeanChristopheMorinPerso commented 2 months ago

I wrote this script:

#!/bin/bash

# Set the range of commits or tags to compare
range="v0.6.7..v0.8.5"

# Get the list of commits between the specified range
commits=$(git rev-list $range)

# Initialize variables to store the best commit and the minimum difference
best_commit=""
best_commit_diff=""

min_diff=999999999

# Loop through each commit
for commit in $commits; do
    closestTag=$(git describe --contains $commit | cut -d'~' -f1)

    echo "${commit}  (${closestTag})"
    # Checkout the commit
    git checkout $commit -q

    diff_stats=$(git diff --short /tmp/asdasd/rez/src/rez/vendor/argcomplete ./argcomplete)
    echo "${diff_stats}"

    diff_count=$(echo "$diff_stats" | awk '{print $4 + $6}')

    # Update the best commit and minimum difference if needed
    if [ $diff_count -lt $min_diff ]; then
        min_diff=$diff_count
        best_commit="${commit}  (${closestTag})"
    fi
done

# Output the best commit and minimum difference
echo "Best commit: $best_commit"
echo "Minimum difference: $min_diff"

It takes every commit between v0.6.7 and v0.8.5 and gets the diff stats between that commit and our code. For each diff, it sums the insertions and deletions. And it prints the best match at the end.

The result is that https://github.com/kislyuk/argcomplete/commit/6f943d76400d6755c2152deff4f2c5c5fa4d9e7c is what is the closest to what we have. It's almost v0.8.2 but not quite. I think it's slightly before v0.8.2... Though, we would have to look at the diff to see if it's really 6f943d76400d6755c2152deff4f2c5c5fa4d9e7c or if v0.8.2 is good enough.

BryceGattis commented 2 months ago

@JeanChristopheMorinPerso Yep looks like you're right! Thanks for writing up that script that's great! It's only a 8 line diff across the files comparing to 6f943d76400d6755c2152deff4f2c5c5fa4d9e7c instead of the 23 line diff from v0.8.2. I'll update the README.md to reference that commit.