esp-idf/tools/export_utils/activate_venv.py

178 lines
6.4 KiB
Python
Raw Normal View History

# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import argparse
import os
import sys
from typing import Any
from typing import Dict
from console_output import CONSOLE_STDERR
from console_output import CONSOLE_STDOUT
from console_output import debug
from console_output import die
from console_output import eprint
from console_output import oprint
from console_output import status_message
from shell_types import SHELL_CLASSES
from shell_types import SUPPORTED_SHELLS
from utils import conf
from utils import run_cmd
def parse_arguments() -> argparse.Namespace:
parser = argparse.ArgumentParser(prog='activate',
description='Activate ESP-IDF environment',
epilog='On Windows, run `python activate.py` to execute this script in the current terminal window.')
parser.add_argument('-s', '--shell',
metavar='SHELL',
default=os.environ.get('ESP_IDF_SHELL', None),
help='Explicitly specify shell to start. For example bash, zsh, powershell.exe, cmd.exe')
parser.add_argument('-l', '--list',
action='store_true',
help=('List supported shells.'))
parser.add_argument('-e', '--export',
action='store_true',
help=('Generate commands to run in the terminal.'))
parser.add_argument('-n', '--no-color',
action='store_true',
help=('Disable ANSI color escape sequences.'))
parser.add_argument('-d', '--debug',
action='store_true',
help=('Enable debug information.'))
parser.add_argument('-q', '--quiet',
action='store_true',
help=('Suppress all output.'))
return parser.parse_args()
@status_message('Checking python version', rv_on_ok=True)
def check_python_version() -> str:
# Check the Python version within a virtual environment
python_version_checker = os.path.join(conf.IDF_PATH, 'tools', 'python_version_checker.py')
run_cmd([sys.executable, python_version_checker])
ver = sys.version_info
return f'{ver[0]}.{ver[1]}.{ver[2]}'
@status_message('Checking python dependencies')
def check_python_dependencies() -> None:
# Check Python dependencies within the virtual environment
run_cmd([sys.executable, conf.IDF_TOOLS_PY, 'check-python-dependencies'])
@status_message('Deactivating the current ESP-IDF environment (if any)')
def get_deactivate_cmd() -> str:
# Get previous ESP-IDF system environment variables
cmd = [sys.executable, conf.IDF_TOOLS_PY, 'export', '--deactivate']
stdout: str = run_cmd(cmd)
return stdout
@status_message('Establishing a new ESP-IDF environment')
def get_idf_env() -> Dict[str,str]:
# Get ESP-IDF system environment variables
extra_paths_list = [os.path.join('components', 'espcoredump'),
os.path.join('components', 'partition_table'),
os.path.join('components', 'app_update')]
extra_paths = os.pathsep.join([os.path.join(conf.IDF_PATH, path) for path in extra_paths_list])
cmd = [sys.executable, conf.IDF_TOOLS_PY, 'export', '--format', 'key-value', '--add_paths_extras', extra_paths]
stdout = run_cmd(cmd)
# idf_tools.py might not export certain environment variables if they are already set
idf_env: Dict[str, Any] = {
'IDF_PATH': os.environ['IDF_PATH'],
'ESP_IDF_VERSION': os.environ['ESP_IDF_VERSION'],
'IDF_PYTHON_ENV_PATH': os.environ['IDF_PYTHON_ENV_PATH'],
}
for line in stdout.splitlines():
var, val = line.split('=')
idf_env[var] = val
if 'PATH' in idf_env:
idf_env['PATH'] = os.pathsep.join([extra_paths, idf_env['PATH']])
return idf_env
@status_message('Identifying shell', rv_on_ok=True)
def detect_shell(args: Any) -> str:
import psutil
if args.shell is not None:
return str(args.shell)
current_pid = os.getpid()
detected_shell_name = ''
while True:
parent_pid = psutil.Process(current_pid).ppid()
parent_name = os.path.basename(psutil.Process(parent_pid).exe())
if not parent_name.lower().startswith('python'):
detected_shell_name = parent_name
conf.DETECTED_SHELL_PATH = psutil.Process(parent_pid).exe()
break
current_pid = parent_pid
return detected_shell_name
@status_message('Detecting outdated tools in system', rv_on_ok=True)
def print_uninstall_msg() -> Any:
stdout = run_cmd([sys.executable, conf.IDF_TOOLS_PY, 'uninstall', '--dry-run'])
if stdout:
python_cmd = 'python.exe' if sys.platform == 'win32' else 'python'
msg = (f'Found tools that are not used by active ESP-IDF version.\n'
f'[bright_cyan]{stdout}\n'
f'To free up even more space, remove installation packages of those tools.\n'
f'Use option {python_cmd} {conf.IDF_TOOLS_PY} uninstall --remove-archives.')
else:
msg = 'OK - no outdated tools found'
return msg
def main() -> None:
args = parse_arguments()
# Setup parsed arguments
CONSOLE_STDERR.no_color = args.no_color
CONSOLE_STDOUT.no_color = args.no_color
CONSOLE_STDERR.quiet = args.quiet
CONSOLE_STDOUT.quiet = args.quiet
# Fill config global holder
conf.ARGS = args
if conf.ARGS.list:
oprint(SUPPORTED_SHELLS)
sys.exit()
eprint(f'[dark_orange]Activating ESP-IDF {conf.IDF_VERSION}')
debug(f'IDF_PATH {conf.IDF_PATH}')
debug(f'IDF_PYTHON_ENV_PATH {conf.IDF_PYTHON_ENV_PATH}')
check_python_version()
check_python_dependencies()
deactivate_cmd = get_deactivate_cmd()
new_esp_idf_env = get_idf_env()
detected_shell = detect_shell(conf.ARGS)
print_uninstall_msg()
if detected_shell not in SHELL_CLASSES:
die(f'"{detected_shell}" shell is not among the supported options: "{SUPPORTED_SHELLS}"')
shell = SHELL_CLASSES[detected_shell](detected_shell, deactivate_cmd, new_esp_idf_env)
if conf.ARGS.export:
shell.export()
sys.exit()
eprint(f'[dark_orange]Starting new \'{shell.shell}\' shell with ESP-IDF environment... (use "exit" command to quit)')
shell.spawn()
eprint(f'[dark_orange]ESP-IDF environment exited.')
if __name__ == '__main__':
main()