-
-
Notifications
You must be signed in to change notification settings - Fork 135
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Convert scripts to the format used by console_scripts
Split from #474
- Loading branch information
1 parent
521082e
commit a7127b0
Showing
6 changed files
with
321 additions
and
270 deletions.
There are no files selected for viewing
165 changes: 165 additions & 0 deletions
165
argcomplete/scripts/activate_global_python_argcomplete.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
#!/usr/bin/env python3 | ||
# PYTHON_ARGCOMPLETE_OK | ||
|
||
# Copyright 2012-2023, Andrey Kislyuk and argcomplete contributors. | ||
# Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info. | ||
|
||
""" | ||
Activate the generic bash-completion script or zsh completion autoload function for the argcomplete module. | ||
""" | ||
|
||
import argparse | ||
import os | ||
import shutil | ||
import site | ||
import subprocess | ||
import sys | ||
|
||
import argcomplete | ||
|
||
__package__ = "argcomplete" | ||
|
||
zsh_shellcode = """ | ||
# Begin added by argcomplete | ||
fpath=( {zsh_fpath} "${{fpath[@]}}" ) | ||
# End added by argcomplete | ||
""" | ||
|
||
bash_shellcode = """ | ||
# Begin added by argcomplete | ||
source "{activator}" | ||
# End added by argcomplete | ||
""" | ||
|
||
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) | ||
parser.add_argument("-y", "--yes", help="automatically answer yes for all questions", action="store_true") | ||
parser.add_argument("--dest", help='Specify the shell completion modules directory to install into, or "-" for stdout') | ||
parser.add_argument("--user", help="Install into user directory", action="store_true") | ||
argcomplete.autocomplete(parser) | ||
args = None | ||
|
||
|
||
def get_local_dir(): | ||
try: | ||
return subprocess.check_output(["brew", "--prefix"]).decode().strip() | ||
except (FileNotFoundError, subprocess.CalledProcessError): | ||
return "/usr/local" | ||
|
||
|
||
def get_zsh_system_dir(): | ||
return f"{get_local_dir()}/share/zsh/site-functions" | ||
|
||
|
||
def get_bash_system_dir(): | ||
if "BASH_COMPLETION_COMPAT_DIR" in os.environ: | ||
return os.environ["BASH_COMPLETION_COMPAT_DIR"] | ||
elif sys.platform == "darwin": | ||
return f"{get_local_dir()}/etc/bash_completion.d" # created by homebrew | ||
else: | ||
return "/etc/bash_completion.d" # created by bash-completion | ||
|
||
|
||
def get_activator_dir(): | ||
return os.path.join(os.path.abspath(os.path.dirname(argcomplete.__file__)), "bash_completion.d") | ||
|
||
|
||
def get_activator_path(): | ||
return os.path.join(get_activator_dir(), "_python-argcomplete") | ||
|
||
|
||
def install_to_destination(dest): | ||
activator = get_activator_path() | ||
if dest == "-": | ||
with open(activator) as fh: | ||
sys.stdout.write(fh.read()) | ||
return | ||
destdir = os.path.dirname(dest) | ||
if not os.path.exists(destdir): | ||
try: | ||
os.makedirs(destdir, exist_ok=True) | ||
except Exception as e: | ||
parser.error(f"path {destdir} does not exist and could not be created: {e}") | ||
try: | ||
print(f"Installing {activator} to {dest}...", file=sys.stderr) | ||
shutil.copy(activator, dest) | ||
print("Installed.", file=sys.stderr) | ||
except Exception as e: | ||
parser.error( | ||
f"while installing to {dest}: {e}. Please run this command using sudo, or see --help for more options." | ||
) | ||
|
||
|
||
def get_consent(): | ||
if args.yes is True: | ||
return True | ||
while True: | ||
res = input("OK to proceed? [y/n] ") | ||
if res.lower() not in {"y", "n", "yes", "no"}: | ||
print('Please answer "yes" or "no".', file=sys.stderr) | ||
elif res.lower() in {"y", "yes"}: | ||
return True | ||
else: | ||
return False | ||
|
||
|
||
def append_to_config_file(path, shellcode): | ||
if os.path.exists(path): | ||
with open(path, 'r') as fh: | ||
if shellcode in fh.read(): | ||
print(f"The code already exists in the file {path}.", file=sys.stderr) | ||
return | ||
print(f"argcomplete needs to append to the file {path}. The following code will be appended:", file=sys.stderr) | ||
for line in shellcode.splitlines(): | ||
print(">", line, file=sys.stderr) | ||
if not get_consent(): | ||
print("Not added.", file=sys.stderr) | ||
return | ||
print(f"Adding shellcode to {path}...", file=sys.stderr) | ||
with open(path, "a") as fh: | ||
fh.write(shellcode) | ||
print("Added.", file=sys.stderr) | ||
|
||
|
||
def link_user_rcfiles(): | ||
# TODO: warn if running as superuser | ||
zsh_rcfile = os.path.join(os.path.expanduser(os.environ.get("ZDOTDIR", "~")), ".zshenv") | ||
append_to_config_file(zsh_rcfile, zsh_shellcode.format(zsh_fpath=get_activator_dir())) | ||
|
||
bash_completion_user_file = os.path.expanduser("~/.bash_completion") | ||
append_to_config_file(bash_completion_user_file, bash_shellcode.format(activator=get_activator_path())) | ||
|
||
|
||
def main(): | ||
global args | ||
args = parser.parse_args() | ||
|
||
destinations = [] | ||
|
||
if args.dest: | ||
if args.dest != "-" and not os.path.exists(args.dest): | ||
parser.error(f"directory {args.dest} was specified via --dest, but it does not exist") | ||
destinations.append(args.dest) | ||
elif site.ENABLE_USER_SITE and site.USER_SITE in argcomplete.__file__: | ||
print( | ||
"Argcomplete was installed in the user site local directory. Defaulting to user installation.", file=sys.stderr | ||
) | ||
link_user_rcfiles() | ||
elif sys.prefix != sys.base_prefix: | ||
print("Argcomplete was installed in a virtual environment. Defaulting to user installation.", file=sys.stderr) | ||
link_user_rcfiles() | ||
elif args.user: | ||
link_user_rcfiles() | ||
else: | ||
print("Defaulting to system-wide installation.", file=sys.stderr) | ||
destinations.append(f"{get_zsh_system_dir()}/_python-argcomplete") | ||
destinations.append(f"{get_bash_system_dir()}/python-argcomplete") | ||
|
||
for destination in destinations: | ||
install_to_destination(destination) | ||
|
||
if args.dest is None: | ||
print("Please restart your shell or source the installed file to activate it.", file=sys.stderr) | ||
|
||
|
||
if __name__ == "__main__": | ||
sys.exit(main()) |
70 changes: 70 additions & 0 deletions
70
argcomplete/scripts/python_argcomplete_check_easy_install_script.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#!/usr/bin/env python3 | ||
|
||
# Copyright 2012-2023, Andrey Kislyuk and argcomplete contributors. | ||
# Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info. | ||
|
||
""" | ||
This script is part of the Python argcomplete package (https://github.com/kislyuk/argcomplete). | ||
It is used to check if an EASY-INSTALL-SCRIPT wrapper redirects to a script that contains the string | ||
"PYTHON_ARGCOMPLETE_OK". If you have enabled global completion in argcomplete, the completion hook will run it every | ||
time you press <TAB> in your shell. | ||
Usage: | ||
python-argcomplete-check-easy-install-script <input executable file> | ||
""" | ||
|
||
import sys | ||
|
||
__package__ = "argcomplete" | ||
|
||
def main(): | ||
if len(sys.argv) != 2: | ||
sys.exit(__doc__) | ||
|
||
sys.tracebacklimit = 0 | ||
|
||
with open(sys.argv[1]) as fh: | ||
line1, head = fh.read(1024).split("\n", 1)[:2] | ||
if line1.startswith("#") and ("py" in line1 or "Py" in line1): | ||
import re | ||
|
||
lines = head.split("\n", 12) | ||
for line in lines: | ||
if line.startswith("# EASY-INSTALL-SCRIPT"): | ||
import pkg_resources | ||
|
||
dist, script = re.match("# EASY-INSTALL-SCRIPT: '(.+)','(.+)'", line).groups() | ||
if "PYTHON_ARGCOMPLETE_OK" in pkg_resources.get_distribution(dist).get_metadata("scripts/" + script): | ||
return 0 | ||
elif line.startswith("# EASY-INSTALL-ENTRY-SCRIPT"): | ||
dist, group, name = re.match("# EASY-INSTALL-ENTRY-SCRIPT: '(.+)','(.+)','(.+)'", line).groups() | ||
import pkgutil | ||
|
||
import pkg_resources | ||
|
||
module_name = pkg_resources.get_distribution(dist).get_entry_info(group, name).module_name | ||
with open(pkgutil.get_loader(module_name).get_filename()) as mod_fh: | ||
if "PYTHON_ARGCOMPLETE_OK" in mod_fh.read(1024): | ||
return 0 | ||
elif line.startswith("# EASY-INSTALL-DEV-SCRIPT"): | ||
for line2 in lines: | ||
if line2.startswith("__file__"): | ||
filename = re.match("__file__ = '(.+)'", line2).group(1) | ||
with open(filename) as mod_fh: | ||
if "PYTHON_ARGCOMPLETE_OK" in mod_fh.read(1024): | ||
return 0 | ||
elif line.startswith("# PBR Generated"): | ||
module = re.search("from (.*) import", head).groups()[0] | ||
import pkgutil | ||
|
||
import pkg_resources | ||
|
||
with open(pkgutil.get_loader(module).get_filename()) as mod_fh: | ||
if "PYTHON_ARGCOMPLETE_OK" in mod_fh.read(1024): | ||
return 0 | ||
|
||
return 1 | ||
|
||
|
||
if __name__ == "__main__": | ||
sys.exit(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
#!/usr/bin/env python3 | ||
# PYTHON_ARGCOMPLETE_OK | ||
|
||
# Copyright 2012-2023, Andrey Kislyuk and argcomplete contributors. | ||
# Licensed under the Apache License. See https://github.com/kislyuk/argcomplete for more info. | ||
|
||
""" | ||
Register a Python executable for use with the argcomplete module. | ||
To perform the registration, source the output of this script in your bash shell | ||
(quote the output to avoid interpolation). | ||
Example: | ||
$ eval "$(register-python-argcomplete my-favorite-script.py)" | ||
For Tcsh | ||
$ eval `register-python-argcomplete --shell tcsh my-favorite-script.py` | ||
For Fish | ||
$ register-python-argcomplete --shell fish my-favourite-script.py > ~/.config/fish/my-favourite-script.py.fish | ||
""" | ||
|
||
import argparse | ||
import sys | ||
|
||
import argcomplete | ||
|
||
__package__ = "argcomplete" | ||
|
||
def main(): | ||
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) | ||
|
||
parser.add_argument( | ||
"--no-defaults", | ||
dest="use_defaults", | ||
action="store_false", | ||
default=True, | ||
help="when no matches are generated, do not fallback to readline's default completion (affects bash only)", | ||
) | ||
parser.add_argument( | ||
"--complete-arguments", | ||
nargs=argparse.REMAINDER, | ||
help="arguments to call complete with; use of this option discards default options (affects bash only)", | ||
) | ||
parser.add_argument( | ||
"-s", | ||
"--shell", | ||
choices=("bash", "zsh", "tcsh", "fish", "powershell"), | ||
default="bash", | ||
help="output code for the specified shell", | ||
) | ||
parser.add_argument( | ||
"-e", "--external-argcomplete-script", help="external argcomplete script for auto completion of the executable" | ||
) | ||
|
||
parser.add_argument("executable", nargs="+", help="executable to completed (when invoked by exactly this name)") | ||
|
||
argcomplete.autocomplete(parser) | ||
|
||
if len(sys.argv) == 1: | ||
parser.print_help() | ||
sys.exit(1) | ||
|
||
args = parser.parse_args() | ||
|
||
|
||
sys.stdout.write( | ||
argcomplete.shellcode( | ||
args.executable, args.use_defaults, args.shell, args.complete_arguments, args.external_argcomplete_script | ||
) | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
sys.exit(main()) |
Oops, something went wrong.