def fullclean(action: str, ctx: Context, args: PropertyDict) -> None: build_dir = args.build_dir if not os.path.isdir(build_dir): print("Build directory '%s' not found. Nothing to clean." % build_dir) return if len(os.listdir(build_dir)) == 0: print("Build directory '%s' is empty. Nothing to clean." % build_dir) return if not os.path.exists(os.path.join(build_dir, 'CMakeCache.txt')): raise FatalError( "Directory '%s' doesn't seem to be a CMake build directory. Refusing to automatically " "delete files in this directory. Delete the directory manually to 'clean' it." % build_dir) red_flags = ['CMakeLists.txt', '.git', '.svn'] for red in red_flags: red = os.path.join(build_dir, red) if os.path.exists(red): raise FatalError( "Refusing to automatically delete files in directory containing '%s'. Delete files manually if you're sure." % red) if args.verbose and len(build_dir) > 1: print('The following symlinks were identified and removed:\n%s' % '\n'.join(build_dir)) for f in os.listdir(build_dir): # TODO: once we are Python 3 only, this can be os.scandir() f = os.path.join(build_dir, f) if args.verbose: print('Removing: %s' % f) if os.path.isdir(f): shutil.rmtree(f) else: os.remove(f)
def openocd(action, ctx, args, openocd_scripts, openocd_commands): """ Execute openocd as external tool """ if os.getenv("OPENOCD_SCRIPTS") is None: raise FatalError("OPENOCD_SCRIPTS not found in the environment: Please run export.sh/export.bin", ctx) openocd_arguments = os.getenv("OPENOCD_COMMANDS") if openocd_commands is None else openocd_commands project_desc = get_project_desc(args, ctx) if openocd_arguments is None: # use default value if commands not defined in the environment nor command line if project_desc["target"] == "esp32": openocd_arguments = "-f board/esp32-wrover-kit-3.3v.cfg" else: openocd_arguments = "-f interface/ftdi/esp32_devkitj_v1.cfg -f target/{}.cfg".format(project_desc["target"]) print('Note: OpenOCD cfg not found (via env variable OPENOCD_COMMANDS nor as a --openocd-commands argument)\n' 'OpenOCD arguments default to: "{}"'.format(openocd_arguments)) # script directory is taken from the environment by OpenOCD, update only if command line arguments to override if openocd_scripts is not None: openocd_arguments += " -s {}".format(openocd_scripts) local_dir = project_desc["build_dir"] args = ["openocd"] + shlex.split(openocd_arguments) openocd_out_name = os.path.join(local_dir, OPENOCD_OUT_FILE) openocd_out = open(openocd_out_name, "a+") try: process = subprocess.Popen(args, stdout=openocd_out, stderr=subprocess.STDOUT, bufsize=1) except Exception as e: print(e) raise FatalError("Error starting openocd. Please make sure it is installed and is present in executable paths", ctx) processes["openocd"] = process processes["openocd_outfile"] = openocd_out processes["openocd_outfile_name"] = openocd_out_name print("OpenOCD started as a background task {}".format(process.pid))
def fullclean(action, ctx, args): build_dir = args.build_dir if not os.path.isdir(build_dir): print("Build directory '%s' not found. Nothing to clean." % build_dir) return if len(os.listdir(build_dir)) == 0: print("Build directory '%s' is empty. Nothing to clean." % build_dir) return if not os.path.exists(os.path.join(build_dir, "CMakeCache.txt")): raise FatalError( "Directory '%s' doesn't seem to be a CMake build directory. Refusing to automatically " "delete files in this directory. Delete the directory manually to 'clean' it." % build_dir) red_flags = ["CMakeLists.txt", ".git", ".svn"] for red in red_flags: red = os.path.join(build_dir, red) if os.path.exists(red): raise FatalError( "Refusing to automatically delete files in directory containing '%s'. Delete files manually if you're sure." % red) # OK, delete everything in the build directory... # Note: Python 2.7 doesn't detect symlinks on Windows (it is supported form 3.2). Tools promising to not # follow symlinks will actually follow them. Deleting the build directory with symlinks deletes also items # outside of this directory. deleted_symlinks = _delete_windows_symlinks(build_dir) if args.verbose and len(deleted_symlinks) > 1: print("The following symlinks were identified and removed:\n%s" % "\n".join(deleted_symlinks)) for f in os.listdir(build_dir): # TODO: once we are Python 3 only, this can be os.scandir() f = os.path.join(build_dir, f) if args.verbose: print("Removing: %s" % f) if os.path.isdir(f): shutil.rmtree(f) else: os.remove(f)
def check_environment(): """ Verify the environment contains the top-level tools we need to operate (cmake will check a lot of other things) """ checks_output = [] if not executable_exists(['cmake', '--version']): debug_print_idf_version() raise FatalError("'cmake' must be available on the PATH to use %s" % PROG) # verify that IDF_PATH env variable is set # find the directory idf.py is in, then the parent directory of this, and assume this is IDF_PATH detected_idf_path = realpath(os.path.join(os.path.dirname(__file__), '..')) if 'IDF_PATH' in os.environ: set_idf_path = realpath(os.environ['IDF_PATH']) if set_idf_path != detected_idf_path: print_warning( 'WARNING: IDF_PATH environment variable is set to %s but %s path indicates IDF directory %s. ' 'Using the environment variable directory, but results may be unexpected...' % (set_idf_path, PROG, detected_idf_path)) else: print_warning('Setting IDF_PATH environment variable: %s' % detected_idf_path) os.environ['IDF_PATH'] = detected_idf_path try: # The Python compatibility check could have been done earlier (tools/detect_python.{sh,fish}) but PATH is # not set for import at that time. Even if the check would be done before, the same check needs to be done # here as well (for example one can call idf.py from a not properly set-up environment). python_version_checker.check() except RuntimeError as e: raise FatalError(e) # check Python dependencies checks_output.append('Checking Python dependencies...') try: out = subprocess.check_output( [ os.environ['PYTHON'], os.path.join(os.environ['IDF_PATH'], 'tools', 'check_python_dependencies.py'), ], env=os.environ, ) checks_output.append(out.decode('utf-8', 'ignore').strip()) except subprocess.CalledProcessError as e: print_warning(e.output.decode('utf-8', 'ignore'), stream=sys.stderr) debug_print_idf_version() raise SystemExit(1) return checks_output
def openocd(action: str, ctx: Context, args: PropertyDict, openocd_scripts: Optional[str], openocd_commands: str) -> None: """ Execute openocd as external tool """ OPENOCD_TAGET_CONFIG = { 'esp32': '-f board/esp32-wrover-kit-3.3v.cfg', 'esp32s2': '-f board/esp32s2-kaluga-1.cfg', } if os.getenv('OPENOCD_SCRIPTS') is None: raise FatalError( 'OPENOCD_SCRIPTS not found in the environment: Please run export.sh/export.bat', ctx) openocd_arguments = os.getenv( 'OPENOCD_COMMANDS' ) if openocd_commands is None else openocd_commands project_desc = get_project_desc(args, ctx) if openocd_arguments is None: # use default value if commands not defined in the environment nor command line target = project_desc['target'] default_args = '-f interface/ftdi/esp32_devkitj_v1.cfg -f target/{}.cfg'.format( target) openocd_arguments = OPENOCD_TAGET_CONFIG.get(target, default_args) print( 'Note: OpenOCD cfg not found (via env variable OPENOCD_COMMANDS nor as a --openocd-commands argument)\n' 'OpenOCD arguments default to: "{}"'.format(openocd_arguments)) # script directory is taken from the environment by OpenOCD, update only if command line arguments to override if openocd_scripts is not None: openocd_arguments += ' -s {}'.format(openocd_scripts) local_dir = project_desc['build_dir'] args = ['openocd'] + shlex.split(openocd_arguments) openocd_out_name = os.path.join(local_dir, OPENOCD_OUT_FILE) openocd_out = open(openocd_out_name, 'a+') try: process = subprocess.Popen(args, stdout=openocd_out, stderr=subprocess.STDOUT, bufsize=1) except Exception as e: print(e) raise FatalError( 'Error starting openocd. Please make sure it is installed and is present in executable paths', ctx) processes['openocd'] = process processes['openocd_outfile'] = openocd_out processes['openocd_outfile_name'] = openocd_out_name print('OpenOCD started as a background task {}'.format(process.pid))
def _check_openocd_errors(fail_if_openocd_failed, target, ctx): if fail_if_openocd_failed: if "openocd" in processes and processes["openocd"] is not None: p = processes["openocd"] name = processes["openocd_outfile_name"] # watch OpenOCD (for 5x500ms) to check if it hasn't terminated or outputs an error for _ in range(5): if p.poll() is not None: print("OpenOCD exited with {}".format(p.poll())) break with open(name, "r") as f: content = f.read() if re.search(r"no device found", content): break if re.search( r"Listening on port \d+ for gdb connections", content): # expect OpenOCD has started successfully - stop watching return time.sleep(0.5) else: return # OpenOCD exited or error message detected -> print possible output and terminate with open(name, "r") as f: print(f.read()) raise FatalError( 'Action "{}" failed due to errors in OpenOCD: Please check jtag connection!' .format(target), ctx)
def _find_usable_locale(): try: locales = subprocess.Popen(['locale', '-a'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] except OSError: locales = '' if isinstance(locales, bytes): locales = locales.decode('ascii', 'replace') usable_locales = [] for line in locales.splitlines(): locale = line.strip() locale_name = locale.lower().replace('-', '') # C.UTF-8 is the best option, if supported if locale_name == 'c.utf8': return locale if locale_name.endswith('.utf8'): # Make a preference of english locales if locale.startswith('en_'): usable_locales.insert(0, locale) else: usable_locales.append(locale) if not usable_locales: raise FatalError( 'Support for Unicode filenames is required, but no suitable UTF-8 locale was found on your system.' ' Please refer to the manual for your operating system for details on locale reconfiguration.') return usable_locales[0]
def _check_openocd_errors(fail_if_openocd_failed, target, ctx): if fail_if_openocd_failed: if 'openocd' in processes and processes['openocd'] is not None: p = processes['openocd'] name = processes['openocd_outfile_name'] # watch OpenOCD (for 5x500ms) to check if it hasn't terminated or outputs an error for _ in range(5): if p.poll() is not None: print('OpenOCD exited with {}'.format(p.poll())) break with open(name, 'r') as f: content = f.read() if re.search(r'no device found', content): break if re.search( r'Listening on port \d+ for gdb connections', content): # expect OpenOCD has started successfully - stop watching return time.sleep(0.5) else: return # OpenOCD exited or error message detected -> print possible output and terminate raise FatalError( 'Action "{}" failed due to errors in OpenOCD:\n{}'.format( target, _check_for_common_openocd_issues(name)), ctx)
def gdbui(action, ctx, args, gdbgui_port, gdbinit, require_openocd): """ Asynchronous GDB-UI target """ project_desc = get_project_desc(args, ctx) local_dir = project_desc['build_dir'] gdb = project_desc['monitor_toolprefix'] + 'gdb' if gdbinit is None: gdbinit = os.path.join(local_dir, 'gdbinit') create_local_gdbinit(gdbinit, os.path.join(args.build_dir, project_desc['app_elf'])) args = ['gdbgui', '-g', gdb, '--gdb-args="-x={}"'.format(gdbinit)] if gdbgui_port is not None: args += ['--port', gdbgui_port] gdbgui_out_name = os.path.join(local_dir, GDBGUI_OUT_FILE) gdbgui_out = open(gdbgui_out_name, 'a+') env = os.environ.copy() # The only known solution for https://github.com/cs01/gdbgui/issues/359 is to set the following environment # variable. The greenlet package cannot be downgraded for compatibility with other requirements (gdbgui, # pygdbmi). env['PURE_PYTHON'] = '1' try: process = subprocess.Popen(args, stdout=gdbgui_out, stderr=subprocess.STDOUT, bufsize=1, env=env) except Exception as e: print(e) raise FatalError('Error starting gdbgui. Please make sure gdbgui can be started', ctx) processes['gdbgui'] = process processes['gdbgui_outfile'] = gdbgui_out processes['gdbgui_outfile_name'] = gdbgui_out_name print('gdbgui started as a background task {}'.format(process.pid)) _check_openocd_errors(fail_if_openocd_failed, action, ctx)
def monitor(action, ctx, args, print_filter, monitor_baud, encrypted, timestamps, timestamp_format): """ Run idf_monitor.py to watch build output """ desc_path = os.path.join(args.build_dir, 'project_description.json') if not os.path.exists(desc_path): ensure_build_directory(args, ctx.info_name) with open(desc_path, 'r') as f: project_desc = json.load(f) elf_file = os.path.join(args.build_dir, project_desc['app_elf']) if not os.path.exists(elf_file): raise FatalError("ELF file '%s' not found. You need to build & flash the project before running 'monitor', " 'and the binary on the device must match the one in the build directory exactly. ' "Try '%s flash monitor'." % (elf_file, ctx.info_name), ctx) idf_monitor = os.path.join(os.environ['IDF_PATH'], 'tools/idf_monitor.py') monitor_args = [PYTHON, idf_monitor] esp_port = args.port or _get_default_serial_port(args) monitor_args += ['-p', esp_port] if not monitor_baud: monitor_baud = os.getenv('IDF_MONITOR_BAUD') or os.getenv('MONITORBAUD') or project_desc['monitor_baud'] monitor_args += ['-b', monitor_baud] monitor_args += ['--toolchain-prefix', project_desc['monitor_toolprefix']] coredump_decode = get_sdkconfig_value(project_desc['config_file'], 'CONFIG_ESP_COREDUMP_DECODE') if coredump_decode is not None: monitor_args += ['--decode-coredumps', coredump_decode] target_arch_riscv = get_sdkconfig_value(project_desc['config_file'], 'CONFIG_IDF_TARGET_ARCH_RISCV') monitor_args += ['--target', project_desc['target']] revision = project_desc.get('rev') if revision: monitor_args += ['--revision', revision] if target_arch_riscv: monitor_args += ['--decode-panic', 'backtrace'] if print_filter is not None: monitor_args += ['--print_filter', print_filter] monitor_args += [elf_file] if encrypted: monitor_args += ['--encrypted'] if timestamps: monitor_args += ['--timestamps'] if timestamp_format: monitor_args += ['--timestamp-format', timestamp_format] idf_py = [PYTHON] + _get_commandline_options(ctx) # commands to re-run idf.py monitor_args += ['-m', ' '.join("'%s'" % a for a in idf_py)] if 'MSYSTEM' in os.environ: monitor_args = ['winpty'] + monitor_args run_tool('idf_monitor', monitor_args, args.project_dir)
def gdbui(action, ctx, args, gdbgui_port, gdbinit, require_openocd): """ Asynchronous GDB-UI target """ project_desc = get_project_desc(args, ctx) local_dir = project_desc["build_dir"] gdb = project_desc["monitor_toolprefix"] + "gdb" if gdbinit is None: gdbinit = os.path.join(local_dir, 'gdbinit') create_local_gdbinit(gdbinit, os.path.join(args.build_dir, project_desc["app_elf"])) args = ["gdbgui", "-g", gdb, '--gdb-args="-x={}"'.format(gdbinit)] if gdbgui_port is not None: args += ["--port", gdbgui_port] gdbgui_out_name = os.path.join(local_dir, GDBGUI_OUT_FILE) gdbgui_out = open(gdbgui_out_name, "a+") try: process = subprocess.Popen(args, stdout=gdbgui_out, stderr=subprocess.STDOUT, bufsize=1) except Exception as e: print(e) raise FatalError("Error starting gdbgui. Please make sure gdbgui can be started", ctx) processes["gdbgui"] = process processes["gdbgui_outfile"] = gdbgui_out processes["gdbgui_outfile_name"] = gdbgui_out_name print("gdbgui started as a background task {}".format(process.pid)) _check_openocd_errors(fail_if_openocd_failed, action, ctx)
def _find_usable_locale(): try: locales = subprocess.Popen(["locale", "-a"], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] except OSError: locales = "" if isinstance(locales, bytes): locales = locales.decode("ascii", "replace") usable_locales = [] for line in locales.splitlines(): locale = line.strip() locale_name = locale.lower().replace("-", "") # C.UTF-8 is the best option, if supported if locale_name == "c.utf8": return locale if locale_name.endswith(".utf8"): # Make a preference of english locales if locale.startswith("en_"): usable_locales.insert(0, locale) else: usable_locales.append(locale) if not usable_locales: raise FatalError( "Support for Unicode filenames is required, but no suitable UTF-8 locale was found on your system." " Please refer to the manual for your operating system for details on locale reconfiguration." ) return usable_locales[0]
def _get_default_serial_port(args): # Import is done here in order to move it after the check_environment() ensured that pyserial has been installed try: import serial.tools.list_ports esptool_path = os.path.join(os.environ['IDF_PATH'], 'components/esptool_py/esptool/') sys.path.insert(0, esptool_path) import esptool ports = list( sorted(p.device for p in serial.tools.list_ports.comports())) # high baud rate could cause the failure of creation of the connection esp = esptool.get_default_connected_device(serial_list=ports, port=None, connect_attempts=4, initial_baud=115200) if esp is None: raise NoSerialPortFoundError( "No serial ports found. Connect a device, or use '-p PORT' option to set a specific port." ) serial_port = esp.serial_port esp._port.close() return serial_port except NoSerialPortFoundError: raise except Exception as e: raise FatalError( 'An exception occurred during detection of the serial port: {}' .format(e))
def monitor(action, ctx, args, print_filter): """ Run idf_monitor.py to watch build output """ if args.port is None: args.port = _get_default_serial_port() desc_path = os.path.join(args.build_dir, "project_description.json") if not os.path.exists(desc_path): ensure_build_directory(args, ctx.info_name) with open(desc_path, "r") as f: project_desc = json.load(f) elf_file = os.path.join(args.build_dir, project_desc["app_elf"]) if not os.path.exists(elf_file): raise FatalError("ELF file '%s' not found. You need to build & flash the project before running 'monitor', " "and the binary on the device must match the one in the build directory exactly. " "Try '%s flash monitor'." % (elf_file, ctx.info_name)) idf_monitor = os.path.join(os.environ["IDF_PATH"], "tools/idf_monitor.py") monitor_args = [PYTHON, idf_monitor] if args.port is not None: monitor_args += ["-p", args.port] monitor_args += ["-b", project_desc["monitor_baud"]] monitor_args += ["--toolchain-prefix", project_desc["monitor_toolprefix"]] if print_filter is not None: monitor_args += ["--print_filter", print_filter] monitor_args += [elf_file] idf_py = [PYTHON] + _get_commandline_options(ctx) # commands to re-run idf.py monitor_args += ["-m", " ".join("'%s'" % a for a in idf_py)] if "MSYSTEM" in os.environ: monitor_args = ["winpty"] + monitor_args run_tool("idf_monitor", monitor_args, args.project_dir)
def fallback_target(target_name: str, ctx: Context, args: PropertyDict) -> None: """ Execute targets that are not explicitly known to idf.py """ ensure_build_directory(args, ctx.info_name) try: subprocess.check_output(GENERATORS[args.generator]['dry_run'] + [target_name], cwd=args.build_dir) except Exception: if target_name in ['clang-check', 'clang-html-report']: raise FatalError('command "{}" requires an additional plugin "pyclang". ' 'Please install it via "pip install --upgrade pyclang"'.format(target_name)) raise FatalError( 'command "%s" is not known to idf.py and is not a %s target' % (target_name, args.generator)) run_target(target_name, args)
def validate_root_options(ctx: Context, args: PropertyDict, tasks: List) -> None: args.project_dir = realpath(args.project_dir) if args.build_dir is not None and args.project_dir == realpath(args.build_dir): raise FatalError( 'Setting the build directory to the project directory is not supported. Suggest dropping ' "--build-dir option, the default is a 'build' subdirectory inside the project directory.") if args.build_dir is None: args.build_dir = os.path.join(args.project_dir, 'build') args.build_dir = realpath(args.build_dir)
def __init__(self, scope=None): if scope is None: self._scope = 'default' elif isinstance(scope, str) and scope in self.SCOPES: self._scope = scope elif isinstance(scope, Scope): self._scope = str(scope) else: raise FatalError('Unknown scope for option: %s' % scope)
def validate_root_options(ctx, args, tasks): args.project_dir = realpath(args.project_dir) if args.build_dir is not None and args.project_dir == realpath(args.build_dir): raise FatalError( "Setting the build directory to the project directory is not supported. Suggest dropping " "--build-dir option, the default is a 'build' subdirectory inside the project directory.") if args.build_dir is None: args.build_dir = os.path.join(args.project_dir, "build") args.build_dir = realpath(args.build_dir)
def monitor(action, ctx, args, print_filter, monitor_baud, encrypted): """ Run idf_monitor.py to watch build output """ if args.port is None: args.port = _get_default_serial_port() desc_path = os.path.join(args.build_dir, "project_description.json") if not os.path.exists(desc_path): ensure_build_directory(args, ctx.info_name) with open(desc_path, "r") as f: project_desc = json.load(f) elf_file = os.path.join(args.build_dir, project_desc["app_elf"]) if not os.path.exists(elf_file): raise FatalError( "ELF file '%s' not found. You need to build & flash the project before running 'monitor', " "and the binary on the device must match the one in the build directory exactly. " "Try '%s flash monitor'." % (elf_file, ctx.info_name), ctx) idf_monitor = os.path.join(os.environ["IDF_PATH"], "tools/idf_monitor.py") monitor_args = [PYTHON, idf_monitor] if args.port is not None: monitor_args += ["-p", args.port] if not monitor_baud: if os.getenv("IDF_MONITOR_BAUD"): monitor_baud = os.getenv("IDF_MONITOR_BAUD", None) elif os.getenv("MONITORBAUD"): monitor_baud = os.getenv("MONITORBAUD", None) else: monitor_baud = project_desc["monitor_baud"] monitor_args += ["-b", monitor_baud] monitor_args += [ "--toolchain-prefix", project_desc["monitor_toolprefix"] ] coredump_decode = get_sdkconfig_value(project_desc["config_file"], "CONFIG_ESP32_CORE_DUMP_DECODE") if coredump_decode is not None: monitor_args += ["--decode-coredumps", coredump_decode] if print_filter is not None: monitor_args += ["--print_filter", print_filter] monitor_args += [elf_file] if encrypted: monitor_args += ['--encrypted'] idf_py = [PYTHON] + _get_commandline_options( ctx) # commands to re-run idf.py monitor_args += ["-m", " ".join("'%s'" % a for a in idf_py)] if "MSYSTEM" in os.environ: monitor_args = ["winpty"] + monitor_args run_tool("idf_monitor", monitor_args, args.project_dir)
def check_environment(): """ Verify the environment contains the top-level tools we need to operate (cmake will check a lot of other things) """ checks_output = [] if not executable_exists(['cmake', '--version']): debug_print_idf_version() raise FatalError("'cmake' must be available on the PATH to use %s" % PROG) # verify that IDF_PATH env variable is set # find the directory idf.py is in, then the parent directory of this, and assume this is IDF_PATH detected_idf_path = realpath(os.path.join(os.path.dirname(__file__), '..')) if 'IDF_PATH' in os.environ: set_idf_path = realpath(os.environ['IDF_PATH']) if set_idf_path != detected_idf_path: print_warning( 'WARNING: IDF_PATH environment variable is set to %s but %s path indicates IDF directory %s. ' 'Using the environment variable directory, but results may be unexpected...' % (set_idf_path, PROG, detected_idf_path)) else: print_warning('Setting IDF_PATH environment variable: %s' % detected_idf_path) os.environ['IDF_PATH'] = detected_idf_path # check Python version if sys.version_info[0] < 3: print_warning( 'WARNING: Support for Python 2 is deprecated and will be removed in future versions.' ) elif sys.version_info[0] == 3 and sys.version_info[1] < 6: print_warning( 'WARNING: Python 3 versions older than 3.6 are not supported.') # check Python dependencies checks_output.append('Checking Python dependencies...') try: out = subprocess.check_output( [ os.environ['PYTHON'], os.path.join(os.environ['IDF_PATH'], 'tools', 'check_python_dependencies.py'), ], env=os.environ, ) checks_output.append(out.decode('utf-8', 'ignore').strip()) except subprocess.CalledProcessError as e: print_warning(e.output.decode('utf-8', 'ignore'), stream=sys.stderr) debug_print_idf_version() raise SystemExit(1) return checks_output
def check_deprecation(ctx): """Prints deprecation warnings for arguments in given context""" for option in ctx.command.params: default = () if option.multiple else option.default if isinstance(option, Option) and option.deprecated and ctx.params[option.name] != default: deprecation = Deprecation(option.deprecated) if deprecation.exit_with_error: raise FatalError('Error: %s' % deprecation.full_message('Option "%s"' % option.name)) else: print_warning('Warning: %s' % deprecation.full_message('Option "%s"' % option.name))
def idf_version_callback(ctx, param, value): if not value or ctx.resilient_parsing: return version = idf_version() if not version: raise FatalError("ESP-IDF version cannot be determined") print("ESP-IDF %s" % version) sys.exit(0)
def idf_version_callback(ctx: Context, param: str, value: str) -> None: if not value or ctx.resilient_parsing: return version = idf_version() if not version: raise FatalError('ESP-IDF version cannot be determined') print('ESP-IDF %s' % version) sys.exit(0)
def gdbui(action: str, ctx: Context, args: PropertyDict, gdbgui_port: Optional[str], gdbinit: Optional[str], require_openocd: bool) -> None: """ Asynchronous GDB-UI target """ project_desc = get_project_desc(args, ctx) local_dir = project_desc['build_dir'] gdb = project_desc['monitor_toolprefix'] + 'gdb' if gdbinit is None: gdbinit = os.path.join(local_dir, 'gdbinit') create_local_gdbinit( gdb, gdbinit, os.path.join(args.build_dir, project_desc['app_elf'])) # this is a workaround for gdbgui # gdbgui is using shlex.split for the --gdb-args option. When the input is: # - '"-x=foo -x=bar"', would return ['foo bar'] # - '-x=foo', would return ['-x', 'foo'] and mess up the former option '--gdb-args' # so for one item, use extra double quotes. for more items, use no extra double quotes. gdb_args_list = get_gdb_args(gdbinit, project_desc) gdb_args = '"{}"'.format(' '.join(gdb_args_list)) if len( gdb_args_list) == 1 else ' '.join(gdb_args_list) args = ['gdbgui', '-g', gdb, '--gdb-args', gdb_args] print(args) if gdbgui_port is not None: args += ['--port', gdbgui_port] gdbgui_out_name = os.path.join(local_dir, GDBGUI_OUT_FILE) gdbgui_out = open(gdbgui_out_name, 'a+') env = os.environ.copy() # The only known solution for https://github.com/cs01/gdbgui/issues/359 is to set the following environment # variable. The greenlet package cannot be downgraded for compatibility with other requirements (gdbgui, # pygdbmi). env['PURE_PYTHON'] = '1' try: process = subprocess.Popen(args, stdout=gdbgui_out, stderr=subprocess.STDOUT, bufsize=1, env=env) except Exception as e: print(e) raise FatalError( 'Error starting gdbgui. Please make sure gdbgui has been installed with ' '"install.{sh,bat,ps1,fish} --enable-gdbgui" and can be started.', ctx) processes['gdbgui'] = process processes['gdbgui_outfile'] = gdbgui_out processes['gdbgui_outfile_name'] = gdbgui_out_name print('gdbgui started as a background task {}'.format(process.pid)) _check_openocd_errors(fail_if_openocd_failed, action, ctx)
def fallback_target(target_name, ctx, args): """ Execute targets that are not explicitly known to idf.py """ ensure_build_directory(args, ctx.info_name) try: subprocess.check_output(GENERATORS[args.generator]["dry_run"] + [target_name], cwd=args.build_dir) except Exception: raise FatalError( 'command "%s" is not known to idf.py and is not a %s target' % (target_name, args.generator)) run_target(target_name, args)
def set_target(action: str, ctx: Context, args: PropertyDict, idf_target: str) -> None: if (not args['preview'] and idf_target in PREVIEW_TARGETS): raise FatalError( "%s is still in preview. You have to append '--preview' option after idf.py to use any preview feature." % idf_target) args.define_cache_entry.append('IDF_TARGET=' + idf_target) sdkconfig_path = os.path.join(args.project_dir, 'sdkconfig') sdkconfig_old = sdkconfig_path + '.old' if os.path.exists(sdkconfig_old): os.remove(sdkconfig_old) if os.path.exists(sdkconfig_path): os.rename(sdkconfig_path, sdkconfig_old) print('Set Target to: %s, new sdkconfig created. Existing sdkconfig renamed to sdkconfig.old.' % idf_target) ensure_build_directory(args, ctx.info_name, True)
def set_target(action, ctx, args, idf_target): if (not args["preview"] and idf_target in PREVIEW_TARGETS): raise FatalError( "%s is still in preview. You have to append '--preview' option after idf.py to use any preview feature." % idf_target) args.define_cache_entry.append("IDF_TARGET=" + idf_target) sdkconfig_path = os.path.join(args.project_dir, 'sdkconfig') sdkconfig_old = sdkconfig_path + ".old" if os.path.exists(sdkconfig_old): os.remove(sdkconfig_old) if os.path.exists(sdkconfig_path): os.rename(sdkconfig_path, sdkconfig_old) print("Set Target to: %s, new sdkconfig created. Existing sdkconfig renamed to sdkconfig.old." % idf_target) ensure_build_directory(args, ctx.info_name, True)
def _get_default_serial_port(args): # Import is done here in order to move it after the check_environment() ensured that pyserial has been installed try: import serial.tools.list_ports esptool_path = os.path.join(os.environ["IDF_PATH"], "components/esptool_py/esptool/") sys.path.insert(0, esptool_path) import esptool ports = list(sorted(p.device for p in serial.tools.list_ports.comports())) esp = esptool.get_default_connected_device(serial_list=ports, port=None, connect_attempts=3, initial_baud=args.baud) return esp.serial_port except Exception: raise FatalError("No serial ports found. Connect a device, or use '-p PORT' option to set a specific port.")
def invoke(self, ctx): if self.deprecated: deprecation = Deprecation(self.deprecated) message = deprecation.full_message('Command "%s"' % self.name) if deprecation.exit_with_error: raise FatalError('Error: %s' % message) else: print_warning('Warning: %s' % message) self.deprecated = False # disable Click's built-in deprecation handling # Print warnings for options check_deprecation(ctx) return super(Action, self).invoke(ctx)
def gdb(action, ctx, args, gdb_tui, gdbinit, require_openocd): """ Synchronous GDB target """ watch_openocd = Thread(target=_check_openocd_errors, args=( fail_if_openocd_failed, action, ctx, )) watch_openocd.start() processes['threads_to_join'].append(watch_openocd) desc_path = os.path.join(args.build_dir, 'project_description.json') if not os.path.exists(desc_path): ensure_build_directory(args, ctx.info_name) with open(desc_path, 'r') as f: project_desc = json.load(f) elf_file = os.path.join(args.build_dir, project_desc['app_elf']) if not os.path.exists(elf_file): raise FatalError( 'ELF file not found. You need to build & flash the project before running debug targets', ctx) gdb = project_desc['monitor_toolprefix'] + 'gdb' local_dir = project_desc['build_dir'] if gdbinit is None: gdbinit = os.path.join(local_dir, 'gdbinit') create_local_gdbinit(gdbinit, elf_file) args = [gdb, '-x={}'.format(gdbinit)] if gdb_tui is not None: args += ['-tui'] t = Thread(target=run_gdb, args=(args, )) t.start() while True: try: t.join() break except KeyboardInterrupt: # Catching Keyboard interrupt, as this is used for breaking running program in gdb continue finally: watch_openocd.join() try: processes['threads_to_join'].remove(watch_openocd) except ValueError: # Valid scenario: watch_openocd task won't be in the list if openocd not started from idf.py pass