1# SPDX-FileCopyrightText: 2014-2023 Espressif Systems (Shanghai) CO LTD, 2# other contributors as noted. 3# 4# SPDX-License-Identifier: GPL-2.0-or-later 5 6import configparser 7import os 8 9CONFIG_OPTIONS = [ 10 "timeout", 11 "chip_erase_timeout", 12 "max_timeout", 13 "sync_timeout", 14 "md5_timeout_per_mb", 15 "erase_region_timeout_per_mb", 16 "erase_write_timeout_per_mb", 17 "mem_end_rom_timeout", 18 "serial_write_timeout", 19 "connect_attempts", 20 "write_block_attempts", 21 "reset_delay", 22 "open_port_attempts", 23 "custom_reset_sequence", 24] 25 26 27def _validate_config_file(file_path, verbose=False): 28 if not os.path.exists(file_path): 29 return False 30 31 cfg = configparser.RawConfigParser() 32 try: 33 cfg.read(file_path, encoding="UTF-8") 34 # Only consider it a valid config file if it contains [esptool] section 35 if cfg.has_section("esptool"): 36 if verbose: 37 unknown_opts = list(set(cfg.options("esptool")) - set(CONFIG_OPTIONS)) 38 unknown_opts.sort() 39 no_of_unknown_opts = len(unknown_opts) 40 if no_of_unknown_opts > 0: 41 suffix = "s" if no_of_unknown_opts > 1 else "" 42 print( 43 "Ignoring unknown config file option{}: {}".format( 44 suffix, ", ".join(unknown_opts) 45 ) 46 ) 47 return True 48 except (UnicodeDecodeError, configparser.Error) as e: 49 if verbose: 50 print(f"Ignoring invalid config file {file_path}: {e}") 51 return False 52 53 54def _find_config_file(dir_path, verbose=False): 55 for candidate in ("esptool.cfg", "setup.cfg", "tox.ini"): 56 cfg_path = os.path.join(dir_path, candidate) 57 if _validate_config_file(cfg_path, verbose): 58 return cfg_path 59 return None 60 61 62def load_config_file(verbose=False): 63 set_with_env_var = False 64 env_var_path = os.environ.get("ESPTOOL_CFGFILE") 65 if env_var_path is not None and _validate_config_file(env_var_path): 66 cfg_file_path = env_var_path 67 set_with_env_var = True 68 else: 69 home_dir = os.path.expanduser("~") 70 os_config_dir = ( 71 f"{home_dir}/.config/esptool" 72 if os.name == "posix" 73 else f"{home_dir}/AppData/Local/esptool/" 74 ) 75 # Search priority: 1) current dir, 2) OS specific config dir, 3) home dir 76 for dir_path in (os.getcwd(), os_config_dir, home_dir): 77 cfg_file_path = _find_config_file(dir_path, verbose) 78 if cfg_file_path: 79 break 80 81 cfg = configparser.ConfigParser() 82 cfg["esptool"] = {} # Create an empty esptool config for when no file is found 83 84 if cfg_file_path is not None: 85 # If config file is found and validated, read and parse it 86 cfg.read(cfg_file_path) 87 if verbose: 88 msg = " (set with ESPTOOL_CFGFILE)" if set_with_env_var else "" 89 print( 90 f"Loaded custom configuration from " 91 f"{os.path.abspath(cfg_file_path)}{msg}" 92 ) 93 return cfg, cfg_file_path 94