modular_cli/modular_cli_autocomplete/complete_handler.py (144 lines of code) (raw):
import os
import subprocess
import sys
from modular_cli.modular_cli_autocomplete import BASH_COMPLETE_SCRIPT, ZSH_COMPLETE_SCRIPT, \
RELATIVE_PATH_TO_COMPLETE, PROFILE_D_PATH, PROFILE_ZSH_COMPLETE_SCRIPT, \
PROFILE_BASH_COMPLETE_SCRIPT, COMPLETE_PROCESS_FILE
from modular_cli.utils.logger import get_logger
_LOG = get_logger(__name__)
PYTHON_SYMLINK = 'PYTHON_SYMLINK'
SCRIPT_PATH = 'SCRIPT_PATH'
HELP_FILE = 'HELP_FILE'
BASH_INTERPRETER = 'bash'
ZSH_INTERPRETER = 'zsh'
COMMAND_TO_CHECK_INTERPRETER = "echo $SHELL"
SHRC_AUTOCOMPLETE_MARKER = 'admin_autocomplete_system_settings'
def _get_appropriate_script_name(stdout):
if BASH_INTERPRETER in stdout:
return BASH_INTERPRETER, BASH_COMPLETE_SCRIPT
if ZSH_INTERPRETER in stdout:
return ZSH_INTERPRETER, ZSH_COMPLETE_SCRIPT
return None, None
def _add_str_to_rc_file(interpreter, script, admin_home_path,
installed_python_link):
script_path = os.path.join(admin_home_path,
RELATIVE_PATH_TO_COMPLETE, script)
source_string = f'\nsource {script_path} "{installed_python_link}" ' \
f'"{admin_home_path}"'
rc_file_path = os.path.expanduser('~') + f'/.{interpreter}rc'
with open(rc_file_path, 'r+') as f:
if SHRC_AUTOCOMPLETE_MARKER not in f.read():
f.write(f'\n# {SHRC_AUTOCOMPLETE_MARKER}')
f.write(source_string)
_LOG.info(f'Modular-CLI autocomplete have been '
f'successfully injected to the RC file. '
f'Path to the RC file: {rc_file_path}')
return source_string
def _delete_str_from_rc_file(interpreter):
rc_file_path = os.path.expanduser('~') + f'/.{interpreter}rc'
with open(rc_file_path, 'r+') as f:
lines = f.readlines()
first_string_found = False
with open(rc_file_path, 'w') as f:
for line in lines:
if SHRC_AUTOCOMPLETE_MARKER in line.strip("\n"):
first_string_found = True
continue
if first_string_found:
first_string_found = False
continue
f.write(line)
_LOG.info(f'Modular-CLI autocomplete have been '
f'successfully removed from the RC file. ')
def _get_interpreter_and_appropriate_script():
if sys.platform not in ['darwin', 'linux']:
raise Exception(
f'The OS is not applicable for autocompletion '
f'setup. Current OS is {sys.platform}')
stdout = subprocess.check_output(COMMAND_TO_CHECK_INTERPRETER,
shell=True).decode('utf-8').strip()
_LOG.info(f'Current interpreter: {stdout}')
if not stdout:
raise Exception(
f'The interpreter can not be checked. Modular-CLI '
f'autocomplete installation will be skipped...')
interpreter, script = _get_appropriate_script_name(stdout)
if not interpreter:
raise Exception(
f'Unsupported interpreter {stdout}. Modular-CLI '
f'autocomplete installation will be skipped...')
return interpreter, script
def enable_autocomplete_handler():
interpreter, script = _get_interpreter_and_appropriate_script()
from platform import python_version
installed_python_link = 'python' + '.'.join(
python_version().lower().split('.')[0:-1])
try:
import pathlib
admin_home_path = pathlib.Path(__file__).parent.parent.resolve()
if not os.path.exists(PROFILE_D_PATH):
_LOG.info(f'Going to edit RC file')
source_string = _add_str_to_rc_file(interpreter, script,
admin_home_path,
installed_python_link)
return f'Autocomplete has been successfully installed and ' \
f'will start work after the current terminal session ' \
f'reload. If you want to manually activate ' \
f'autocomplete without reloading the terminal session, ' \
f'please run the following command \n {source_string}'
# if admin instance installation
_LOG.info(f'Going to copy autocomplete files to '
f'{PROFILE_D_PATH}')
init_profile_script_path = os.path.join(admin_home_path,
RELATIVE_PATH_TO_COMPLETE,
script)
python_script = os.path.join(admin_home_path,
RELATIVE_PATH_TO_COMPLETE,
COMPLETE_PROCESS_FILE)
script = 'profile_' + script
processed_profile_script_path = os.path.join(PROFILE_D_PATH, script)
with open(init_profile_script_path, 'r+') as f:
lines = f.readlines()
script_was_found = False
help_was_found = False
with open(processed_profile_script_path, 'w') as f:
for line in lines:
if SCRIPT_PATH in line.strip(
"\n") and not script_was_found:
line = f'SCRIPT_PATH={python_script}\n'
script_was_found = True
if HELP_FILE in line.strip(
"\n") and not help_was_found:
line = f'HELP_FILE=/home/$USER/modular_cli_help.txt'
help_was_found = True
f.write(line)
_LOG.info(f'Modular-CLI autocomplete has been '
f'successfully set up. Path to the "profile.d" file: '
f'{processed_profile_script_path}')
return f'Modular-CLI autocomplete has been ' \
f'successfully set up. Path to the "profile.d" file: ' \
f'{processed_profile_script_path}'
except AttributeError:
_LOG.error(f'Autocomplete installation is not available')
raise Exception(f'Autocomplete installation is not '
f'available')
except Exception as e:
_LOG.error(f'Something happen while setup autocomplete. Reason: {e}')
raise Exception(f'Something happen while setup '
f'autocomplete. Reason: {e}')
def disable_autocomplete_handler():
interpreter, script = _get_interpreter_and_appropriate_script()
try:
_delete_str_from_rc_file(interpreter)
if os.path.exists(PROFILE_D_PATH):
for each in os.listdir(PROFILE_D_PATH):
if each in [ZSH_COMPLETE_SCRIPT,
BASH_COMPLETE_SCRIPT,
PROFILE_ZSH_COMPLETE_SCRIPT,
PROFILE_BASH_COMPLETE_SCRIPT]:
os.remove(os.path.join(PROFILE_D_PATH, each))
return 'Modular-CLI autocomplete has been ' \
'successfully deleted'
except Exception as e:
_LOG.info(f'Something happen while removing autocomplete. Reason: {e}')
raise Exception(f'Something happen while removing '
f'autocomplete. Reason: {e}')