mirror of
https://github.com/espressif/esptool.git
synced 2025-10-21 15:10:33 +08:00
feat(errors): Print errors to STDERR, catch KeyboardInterrupt
BREAKING CHANGE Closes https://github.com/espressif/esptool/issues/981 Closes https://github.com/espressif/esptool/issues/888 Closes https://github.com/espressif/esptool/issues/934
This commit is contained in:
@@ -56,3 +56,20 @@ The ``--verify`` option for the :ref:`write_flash <write-flash>` command has bee
|
||||
|
||||
1. Remove all ``--verify`` arguments from existing ``write_flash`` commands.
|
||||
2. Update scripts/CI pipelines to remove ``--verify`` flags.
|
||||
|
||||
Error Output Handling
|
||||
*********************
|
||||
|
||||
In ``v5``, error handling and output behavior have been improved to provide better user experience and script compatibility.
|
||||
|
||||
**Key Changes:**
|
||||
|
||||
- All error messages, including fatal errors, are now printed to **STDERR** instead of STDOUT.
|
||||
- User keyboard interrupts (e.g., Ctrl+C) are caught and raise an exit code of 2 to indicate an operation interruption.
|
||||
- Error messages are displayed in **red text** for better visibility.
|
||||
- This change ensures that errors are not lost when STDOUT is filtered or redirected.
|
||||
|
||||
**Migration Steps:**
|
||||
|
||||
1. Update scripts that rely on parsing STDOUT for error messages to check STDERR instead.
|
||||
2. Ensure scripts handle non-zero exit codes correctly in the case of operations interrupted by the user.
|
||||
|
@@ -25,6 +25,7 @@ import espefuse.efuse.esp32s3 as esp32s3_efuse
|
||||
import espefuse.efuse.esp32s3beta2 as esp32s3beta2_efuse
|
||||
|
||||
import esptool
|
||||
from esptool.logger import log
|
||||
|
||||
DefChip = namedtuple("DefChip", ["chip_name", "efuse_lib", "chip_class"])
|
||||
|
||||
@@ -361,7 +362,10 @@ def _main():
|
||||
try:
|
||||
main()
|
||||
except esptool.FatalError as e:
|
||||
print("\nA fatal error occurred: %s" % e)
|
||||
log.error(f"\nA fatal error occurred: {e}")
|
||||
sys.exit(2)
|
||||
except KeyboardInterrupt:
|
||||
log.error("KeyboardInterrupt: Run cancelled by user.")
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
|
@@ -21,6 +21,8 @@ from cryptography.hazmat.primitives.asymmetric import ec, padding, rsa, utils
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from cryptography.utils import int_to_bytes
|
||||
|
||||
from esptool.logger import log
|
||||
|
||||
import ecdsa
|
||||
|
||||
import esptool
|
||||
@@ -1921,18 +1923,21 @@ def _main():
|
||||
try:
|
||||
main()
|
||||
except esptool.FatalError as e:
|
||||
print("\nA fatal error occurred: %s" % e)
|
||||
log.error(f"\nA fatal error occurred: {e}")
|
||||
sys.exit(2)
|
||||
except ValueError as e:
|
||||
try:
|
||||
if [arg for arg in e.args if "Could not deserialize key data." in arg]:
|
||||
print(
|
||||
log.error(
|
||||
"Note: This error originates from the cryptography module. "
|
||||
"It is likely not a problem with espsecure, "
|
||||
"please make sure you are using a compatible OpenSSL backend."
|
||||
)
|
||||
finally:
|
||||
raise
|
||||
except KeyboardInterrupt:
|
||||
log.error("KeyboardInterrupt: Run cancelled by user.")
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@@ -814,7 +814,7 @@ def main(argv=None, esp=None):
|
||||
if esp is None:
|
||||
raise FatalError(
|
||||
"Could not connect to an Espressif device "
|
||||
"on any of the %d available serial ports." % len(ser_list)
|
||||
f"on any of the {len(ser_list)} available serial ports."
|
||||
)
|
||||
|
||||
if esp.secure_download_mode:
|
||||
@@ -1226,7 +1226,7 @@ def get_default_connected_device(
|
||||
except (FatalError, OSError) as err:
|
||||
if port is not None:
|
||||
raise
|
||||
log.print(f"{each_port} failed to connect: {err}")
|
||||
log.error(f"{each_port} failed to connect: {err}")
|
||||
if _esp and _esp._port:
|
||||
_esp._port.close()
|
||||
_esp = None
|
||||
@@ -1338,23 +1338,26 @@ def _main():
|
||||
try:
|
||||
main()
|
||||
except FatalError as e:
|
||||
log.print(f"\nA fatal error occurred: {e}")
|
||||
log.error(f"\nA fatal error occurred: {e}")
|
||||
sys.exit(2)
|
||||
except serial.serialutil.SerialException as e:
|
||||
log.print(f"\nA serial exception error occurred: {e}")
|
||||
log.print(
|
||||
log.error(f"\nA serial exception error occurred: {e}")
|
||||
log.error(
|
||||
"Note: This error originates from pySerial. "
|
||||
"It is likely not a problem with esptool, "
|
||||
"but with the hardware connection or drivers."
|
||||
)
|
||||
log.print(
|
||||
log.error(
|
||||
"For troubleshooting steps visit: "
|
||||
"https://docs.espressif.com/projects/esptool/en/latest/troubleshooting.html"
|
||||
)
|
||||
sys.exit(1)
|
||||
except StopIteration:
|
||||
log.print(traceback.format_exc())
|
||||
log.print("A fatal error occurred: The chip stopped responding.")
|
||||
log.error(traceback.format_exc())
|
||||
log.error("A fatal error occurred: The chip stopped responding.")
|
||||
sys.exit(2)
|
||||
except KeyboardInterrupt:
|
||||
log.error("KeyboardInterrupt: Run cancelled by user.")
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
|
@@ -32,9 +32,9 @@ from .util import byte, hexify, mask_to_shift, pad_to, strip_chip_name
|
||||
try:
|
||||
import serial
|
||||
except ImportError:
|
||||
log.print(
|
||||
f"Pyserial is not installed for {sys.executable}. "
|
||||
"Check the README for installation instructions."
|
||||
log.error(
|
||||
f"PySerial is not installed for {sys.executable}. "
|
||||
"Check the documentation for installation instructions."
|
||||
)
|
||||
raise
|
||||
|
||||
@@ -59,7 +59,7 @@ except TypeError:
|
||||
try:
|
||||
import serial.tools.list_ports as list_ports
|
||||
except ImportError:
|
||||
log.print(
|
||||
log.error(
|
||||
f"The installed version ({serial.VERSION}) of pySerial appears to be too old "
|
||||
f"for esptool.py (Python interpreter {sys.executable}). "
|
||||
"Check the documentation for installation instructions."
|
||||
|
@@ -161,6 +161,7 @@ class EfuseTestCase:
|
||||
shell=False,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
universal_newlines=True,
|
||||
)
|
||||
output, _ = p.communicate()
|
||||
|
@@ -45,7 +45,7 @@ class TestImageInfo:
|
||||
print("\nExecuting {}".format(" ".join(cmd)))
|
||||
|
||||
try:
|
||||
output = subprocess.check_output(cmd)
|
||||
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
|
||||
output = output.decode("utf-8")
|
||||
print(output) # for more complete stdout logs on failure
|
||||
assert (
|
||||
|
@@ -146,7 +146,7 @@ class BaseTestCase:
|
||||
cmd += [elf_path] + extra_args
|
||||
print("\nExecuting {}".format(" ".join(cmd)))
|
||||
try:
|
||||
output = subprocess.check_output(cmd)
|
||||
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
|
||||
output = output.decode("utf-8")
|
||||
print(output)
|
||||
assert (
|
||||
|
Reference in New Issue
Block a user