Merge branch 'fix/username_special_characters_v5.5' into 'release/v5.5'

feat(tools): Added encoding when special characters used with username (v5.5)

See merge request espressif/esp-idf!40568
This commit is contained in:
Roland Dobai
2025-07-22 09:14:16 +02:00
+62 -37
View File
@@ -1,5 +1,6 @@
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import base64
import getpass
import os
import re
@@ -10,9 +11,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,14 +27,22 @@ 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
try:
self.tmp_dir_path = Path(gettempdir()) / ('esp_idf_activate_' + getpass.getuser())
username = getpass.getuser()
username_safe = (
# If username contains special characters, base64-encode it
base64.urlsafe_b64encode(username.encode('utf-8')).decode('ascii').rstrip('=')
# Find characters that are not ASCII alphanumeric, dot, or dash
if re.search(r'[^\w.-]', username, flags=re.ASCII)
else username
)
self.tmp_dir_path = Path(gettempdir()) / f'esp_idf_activate_{username_safe}'
except Exception as e:
self.tmp_dir_path = Path(gettempdir()) / 'esp_idf_activate'
warn(f'Failed to get username with error: {e}. Using default temporary directory {self.tmp_dir_path}.')
@@ -79,7 +88,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 +109,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 +208,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 +232,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 +243,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 +269,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 +285,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 +298,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 +321,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()
@@ -331,7 +356,7 @@ SHELL_CLASSES = {
'powershell.exe': PowerShell,
'powershell': PowerShell,
'cmd.exe': WinCmd,
'cmd': WinCmd
'cmd': WinCmd,
}
SUPPORTED_SHELLS = ' '.join(SHELL_CLASSES.keys())