Merge branch 'feat/ksh_compatible_shells' into 'master'

fix(tools): add support for shells compatible with ksh

Closes IDFGH-15389

See merge request espressif/esp-idf!39602
This commit is contained in:
Roland Dobai
2025-06-03 12:11:23 +02:00

View File

@ -10,9 +10,9 @@ from datetime import datetime
from datetime import timedelta
from pathlib import Path
from subprocess import run
from tempfile import gettempdir
from tempfile import NamedTemporaryFile
from tempfile import TemporaryDirectory
from tempfile import gettempdir
from typing import Dict
from typing import List
from typing import TextIO
@ -26,8 +26,8 @@ from utils import conf
from utils import run_cmd
class Shell():
def __init__(self, shell: str, deactivate_cmd: str, new_esp_idf_env: Dict[str,str]):
class Shell:
def __init__(self, shell: str, deactivate_cmd: str, new_esp_idf_env: Dict[str, str]):
self.shell = shell
self.deactivate_cmd = deactivate_cmd
self.new_esp_idf_env = new_esp_idf_env
@ -79,7 +79,7 @@ class Shell():
class UnixShell(Shell):
def __init__(self, shell: str, deactivate_cmd: str, new_esp_idf_env: Dict[str,str]):
def __init__(self, shell: str, deactivate_cmd: str, new_esp_idf_env: Dict[str, str]):
super().__init__(shell, deactivate_cmd, new_esp_idf_env)
with NamedTemporaryFile(dir=self.tmp_dir_path, delete=False, prefix='activate_') as fd:
@ -100,8 +100,12 @@ class UnixShell(Shell):
stdout = self.autocompletion() # type: ignore
if stdout is not None:
fd.write(f'{stdout}\n')
fd.write((f'echo "\nDone! You can now compile ESP-IDF projects.\n'
'Go to the project directory and run:\n\n idf.py build"\n'))
fd.write(
(
'echo "\nDone! You can now compile ESP-IDF projects.\n'
'Go to the project directory and run:\n\n idf.py build"\n'
)
)
def export(self) -> None:
with open(self.script_file_path, 'w', encoding='utf-8') as fd:
@ -195,7 +199,7 @@ class ZshShell(UnixShell):
class FishShell(UnixShell):
def __init__(self, shell: str, deactivate_cmd: str, new_esp_idf_env: Dict[str,str]):
def __init__(self, shell: str, deactivate_cmd: str, new_esp_idf_env: Dict[str, str]):
super().__init__(shell, deactivate_cmd, new_esp_idf_env)
self.new_esp_idf_env['IDF_TOOLS_INSTALL_CMD'] = os.path.join(conf.IDF_PATH, 'install.fish')
self.new_esp_idf_env['IDF_TOOLS_EXPORT_CMD'] = os.path.join(conf.IDF_PATH, 'export.fish')
@ -219,7 +223,7 @@ class FishShell(UnixShell):
class PowerShell(Shell):
def __init__(self, shell: str, deactivate_cmd: str, new_esp_idf_env: Dict[str,str]):
def __init__(self, shell: str, deactivate_cmd: str, new_esp_idf_env: Dict[str, str]):
super().__init__(shell, deactivate_cmd, new_esp_idf_env)
with NamedTemporaryFile(dir=self.tmp_dir_path, delete=False, prefix='activate_', suffix='.ps1') as fd:
@ -230,14 +234,16 @@ class PowerShell(Shell):
self.new_esp_idf_env['IDF_TOOLS_EXPORT_CMD'] = os.path.join(conf.IDF_PATH, 'export.ps1')
def get_functions(self) -> str:
return '\n'.join([
r'function idf.py { &python "$Env:IDF_PATH\tools\idf.py" $args }',
r'function global:esptool.py { &python -m esptool $args }',
r'function global:espefuse.py { &python -m espefuse $args }',
r'function global:espsecure.py { &python -m espsecure $args }',
r'function global:otatool.py { &python "$Env:IDF_PATH\components\app_update\otatool.py" $args }',
r'function global:parttool.py { &python "$Env:IDF_PATH\components\partition_table\parttool.py" $args }',
])
return '\n'.join(
[
r'function idf.py { &python "$Env:IDF_PATH\tools\idf.py" $args }',
r'function global:esptool.py { &python -m esptool $args }',
r'function global:espefuse.py { &python -m espefuse $args }',
r'function global:espsecure.py { &python -m espsecure $args }',
r'function global:otatool.py { &python "$Env:IDF_PATH\components\app_update\otatool.py" $args }',
r'function global:parttool.py { &python "$Env:IDF_PATH\components\partition_table\parttool.py" $args }',
]
)
def export(self) -> None:
self.init_file()
@ -254,8 +260,12 @@ class PowerShell(Shell):
fd.write(f'$Env:{var}="{value}"\n')
functions = self.get_functions()
fd.write(f'{functions}\n')
fd.write((f'echo "\nDone! You can now compile ESP-IDF projects.\n'
'Go to the project directory and run:\n\n idf.py build\n"'))
fd.write(
(
'echo "\nDone! You can now compile ESP-IDF projects.\n'
'Go to the project directory and run:\n\n idf.py build\n"'
)
)
def spawn(self) -> None:
self.init_file()
@ -266,7 +276,7 @@ class PowerShell(Shell):
class WinCmd(Shell):
def __init__(self, shell: str, deactivate_cmd: str, new_esp_idf_env: Dict[str,str]):
def __init__(self, shell: str, deactivate_cmd: str, new_esp_idf_env: Dict[str, str]):
super().__init__(shell, deactivate_cmd, new_esp_idf_env)
with NamedTemporaryFile(dir=self.tmp_dir_path, delete=False, prefix='activate_', suffix='.bat') as fd:
@ -279,14 +289,16 @@ class WinCmd(Shell):
self.new_esp_idf_env['IDF_TOOLS_PY_PATH'] = conf.IDF_TOOLS_PY
def get_functions(self) -> str:
return '\n'.join([
r'DOSKEY idf.py=python.exe "%IDF_PATH%\tools\idf.py" $*',
r'DOSKEY esptool.py=python.exe -m esptool $*',
r'DOSKEY espefuse.py=python.exe -m espefuse $*',
r'DOSKEY espsecure.py=python.exe -m espsecure $*',
r'DOSKEY otatool.py=python.exe "%IDF_PATH%\components\app_update\otatool.py" $*',
r'DOSKEY parttool.py=python.exe "%IDF_PATH%\components\partition_table\parttool.py" $*',
])
return '\n'.join(
[
r'DOSKEY idf.py=python.exe "%IDF_PATH%\tools\idf.py" $*',
r'DOSKEY esptool.py=python.exe -m esptool $*',
r'DOSKEY espefuse.py=python.exe -m espefuse $*',
r'DOSKEY espsecure.py=python.exe -m espsecure $*',
r'DOSKEY otatool.py=python.exe "%IDF_PATH%\components\app_update\otatool.py" $*',
r'DOSKEY parttool.py=python.exe "%IDF_PATH%\components\partition_table\parttool.py" $*',
]
)
def export(self) -> None:
self.init_file()
@ -300,14 +312,18 @@ class WinCmd(Shell):
fd.write(f'set {var}={value}\n')
functions = self.get_functions()
fd.write(f'{functions}\n')
fd.write('\n'.join([
'echo.',
'echo Done! You can now compile ESP-IDF projects.',
'echo Go to the project directory and run:',
'echo.',
'echo idf.py build',
'echo.',
]))
fd.write(
'\n'.join(
[
'echo.',
'echo Done! You can now compile ESP-IDF projects.',
'echo Go to the project directory and run:',
'echo.',
'echo idf.py build',
'echo.',
]
)
)
def spawn(self) -> None:
self.init_file()
@ -323,7 +339,14 @@ SHELL_CLASSES = {
'zsh': ZshShell,
'fish': FishShell,
'sh': UnixShell,
# KornShell variants
'ksh': UnixShell,
'ksh93': UnixShell,
'mksh': UnixShell,
'lksh': UnixShell,
'pdksh': UnixShell,
'oksh': UnixShell,
'loksh': UnixShell,
'dash': UnixShell,
'nu': UnixShell,
'pwsh.exe': PowerShell,
@ -331,7 +354,7 @@ SHELL_CLASSES = {
'powershell.exe': PowerShell,
'powershell': PowerShell,
'cmd.exe': WinCmd,
'cmd': WinCmd
'cmd': WinCmd,
}
SUPPORTED_SHELLS = ' '.join(SHELL_CLASSES.keys())