def cli(ctx, **options): storage_cmds = ("install", "uninstall", "update", "list") # skip commands that don't need storage folder if ctx.invoked_subcommand not in storage_cmds or ( len(ctx.args) == 2 and ctx.args[1] in ("-h", "--help") ): return storage_dirs = list(options["storage_dir"]) if options["global"]: storage_dirs.append(get_project_global_lib_dir()) if not storage_dirs: if is_platformio_project(): storage_dirs = [get_project_dir()] elif is_ci(): storage_dirs = [get_project_global_lib_dir()] click.secho( "Warning! Global library storage is used automatically. " "Please use `platformio lib --global %s` command to remove " "this warning." % ctx.invoked_subcommand, fg="yellow", ) if not storage_dirs: raise NotGlobalLibDir( get_project_dir(), get_project_global_lib_dir(), ctx.invoked_subcommand ) in_silence = PlatformioCLI.in_silence() ctx.meta[CTX_META_PROJECT_ENVIRONMENTS_KEY] = options["environment"] ctx.meta[CTX_META_INPUT_DIRS_KEY] = storage_dirs ctx.meta[CTX_META_STORAGE_DIRS_KEY] = [] ctx.meta[CTX_META_STORAGE_LIBDEPS_KEY] = {} for storage_dir in storage_dirs: if not is_platformio_project(storage_dir): ctx.meta[CTX_META_STORAGE_DIRS_KEY].append(storage_dir) continue with fs.cd(storage_dir): config = ProjectConfig.get_instance( os.path.join(storage_dir, "platformio.ini") ) config.validate(options["environment"], silent=in_silence) libdeps_dir = config.get_optional_dir("libdeps") for env in config.envs(): if options["environment"] and env not in options["environment"]: continue storage_dir = os.path.join(libdeps_dir, env) ctx.meta[CTX_META_STORAGE_DIRS_KEY].append(storage_dir) ctx.meta[CTX_META_STORAGE_LIBDEPS_KEY][storage_dir] = config.get( "env:" + env, "lib_deps", [] )
def load_state(): with app.State(AppRPC.APPSTATE_PATH, lock=True) as state: storage = state.get("storage", {}) # base data caller_id = app.get_session_var("caller_id") storage['cid'] = app.get_cid() storage['coreVersion'] = __version__ storage['coreSystype'] = util.get_systype() storage['coreCaller'] = (str(caller_id).lower() if caller_id else None) storage['coreSettings'] = { name: { "description": data['description'], "default_value": data['value'], "value": app.get_setting(name) } for name, data in app.DEFAULT_SETTINGS.items() } storage['homeDir'] = expanduser("~") storage['projectsDir'] = storage['coreSettings']['projects_dir'][ 'value'] # skip non-existing recent projects storage['recentProjects'] = [ p for p in storage.get("recentProjects", []) if is_platformio_project(p) ] state['storage'] = storage return state.as_dict()
def project_data(project_dir, environment, json_output): if not is_platformio_project(project_dir): raise NotPlatformIOProjectError(project_dir) with fs.cd(project_dir): config = ProjectConfig.get_instance() config.validate(environment) environment = list(environment or config.envs()) if json_output: return click.echo( json.dumps(load_project_ide_data(project_dir, environment))) for envname in environment: click.echo("Environment: " + click.style(envname, fg="cyan", bold=True)) click.echo("=" * (13 + len(envname))) click.echo( tabulate( [(click.style(name, bold=True), "=", json.dumps(value, indent=2)) for name, value in load_project_ide_data( project_dir, envname).items()], tablefmt="plain", )) click.echo() return None
def _save_deps(ctx, pkgs, action="add"): specs = [] for library, pkg in pkgs.items(): spec = PackageSpec(library) if spec.external: specs.append(spec) else: specs.append( PackageSpec( owner=pkg.metadata.spec.owner, name=pkg.metadata.spec.name, requirements=spec.requirements or ( ("^%s" % pkg.metadata.version) if not pkg.metadata.version.build else pkg.metadata.version ), ) ) input_dirs = ctx.meta.get(CTX_META_INPUT_DIRS_KEY, []) project_environments = ctx.meta[CTX_META_PROJECT_ENVIRONMENTS_KEY] for input_dir in input_dirs: if not is_platformio_project(input_dir): continue save_project_libdeps(input_dir, specs, project_environments, action=action)
def load_state(): with app.State(AppRPC.APPSTATE_PATH, lock=True) as state: storage = state.get("storage", {}) # base data caller_id = app.get_session_var("caller_id") storage["cid"] = app.get_cid() storage["coreVersion"] = __version__ storage["coreSystype"] = util.get_systype() storage["coreCaller"] = str( caller_id).lower() if caller_id else None storage["coreSettings"] = { name: { "description": data["description"], "default_value": data["value"], "value": app.get_setting(name), } for name, data in app.DEFAULT_SETTINGS.items() } storage["homeDir"] = fs.expanduser("~") storage["projectsDir"] = storage["coreSettings"]["projects_dir"][ "value"] # skip non-existing recent projects storage["recentProjects"] = [ p for p in storage.get("recentProjects", []) if is_platformio_project(p) ] state["storage"] = storage state.modified = False # skip saving extra fields return state.as_dict()
def __init__(self, clone: Clone, env): self.kind = Kind.BUILTIN self.build = BuildModel(kind=self.kind, env=env, version=clone.version, sha1=str(clone.sha1)) self.clone = clone self.path = self.clone.path self.package_manager = None self._old_dir = None self.project_config = None if not is_platformio_project(self.path): logger.error(f"Raising FileNotFoundError for path: {self.path}") raise FileNotFoundError(self.path)
async def import_arduino(self, board, use_arduino_libs, arduino_project_dir): board = str(board) # don't import PIO Project if is_platformio_project(arduino_project_dir): return arduino_project_dir is_arduino_project = any([ os.path.isfile( os.path.join( arduino_project_dir, "%s.%s" % (os.path.basename(arduino_project_dir), ext), )) for ext in ("ino", "pde") ]) if not is_arduino_project: raise jsonrpc.exceptions.JSONRPCDispatchException( code=4000, message="Not an Arduino project: %s" % arduino_project_dir) state = AppRPC.load_state() project_dir = os.path.join(state["storage"]["projectsDir"], time.strftime("%y%m%d-%H%M%S-") + board) if not os.path.isdir(project_dir): os.makedirs(project_dir) args = ["init", "--board", board] args.extend(["--project-option", "framework = arduino"]) if use_arduino_libs: args.extend([ "--project-option", "lib_extra_dirs = ~/Documents/Arduino/libraries" ]) if (state["storage"]["coreCaller"] and state["storage"]["coreCaller"] in ProjectGenerator.get_supported_ides()): args.extend(["--ide", state["storage"]["coreCaller"]]) await PIOCoreRPC.call(args, options={ "cwd": project_dir, "force_subprocess": True }) with fs.cd(project_dir): config = ProjectConfig() src_dir = config.get_optional_dir("src") if os.path.isdir(src_dir): fs.rmtree(src_dir) shutil.copytree(arduino_project_dir, src_dir, symlinks=True) return project_dir
def import_pio(project_dir): if not project_dir or not is_platformio_project(project_dir): raise jsonrpc.exceptions.JSONRPCDispatchException( code=4001, message="Not an PlatformIO project: %s" % project_dir) new_project_dir = join( AppRPC.load_state()['storage']['projectsDir'], time.strftime("%y%m%d-%H%M%S-") + basename(project_dir)) shutil.copytree(project_dir, new_project_dir) state = AppRPC.load_state() args = ["init"] if (state['storage']['coreCaller'] and state['storage']['coreCaller'] in ProjectGenerator.get_supported_ides()): args.extend(["--ide", state['storage']['coreCaller']]) d = PIOCoreRPC.call(args, options={"cwd": new_project_dir}) d.addCallback(lambda _: new_project_dir) return d
def import_arduino(self, board, use_arduino_libs, arduino_project_dir): board = str(board) if arduino_project_dir and PY2: arduino_project_dir = arduino_project_dir.encode( get_filesystem_encoding()) # don't import PIO Project if is_platformio_project(arduino_project_dir): return arduino_project_dir is_arduino_project = any([ os.path.isfile( os.path.join( arduino_project_dir, "%s.%s" % (os.path.basename(arduino_project_dir), ext), )) for ext in ("ino", "pde") ]) if not is_arduino_project: raise jsonrpc.exceptions.JSONRPCDispatchException( code=4000, message="Not an Arduino project: %s" % arduino_project_dir) state = AppRPC.load_state() project_dir = os.path.join(state["storage"]["projectsDir"], time.strftime("%y%m%d-%H%M%S-") + board) if not os.path.isdir(project_dir): os.makedirs(project_dir) args = ["init", "--board", board] args.extend(["--project-option", "framework = arduino"]) if use_arduino_libs: args.extend([ "--project-option", "lib_extra_dirs = ~/Documents/Arduino/libraries" ]) if (state["storage"]["coreCaller"] and state["storage"]["coreCaller"] in ProjectGenerator.get_supported_ides()): args.extend(["--ide", state["storage"]["coreCaller"]]) d = PIOCoreRPC.call(args, options={ "cwd": project_dir, "force_subprocess": True }) d.addCallback(self._finalize_arduino_import, project_dir, arduino_project_dir) return d
def dump_run_environment(options): non_sensitive_data = [ "platform", "platform_packages", "framework", "board", "upload_protocol", "check_tool", "debug_tool", "monitor_filters", ] safe_options = { k: v for k, v in options.items() if k in non_sensitive_data } if is_platformio_project(os.getcwd()): phash = hashlib.sha1(hashlib_encode_data(app.get_cid())) safe_options["pid"] = phash.hexdigest() return json.dumps(safe_options, sort_keys=True, ensure_ascii=False)
def project_config(project_dir, json_output): if not is_platformio_project(project_dir): raise NotPlatformIOProjectError(project_dir) with fs.cd(project_dir): config = ProjectConfig.get_instance() if json_output: return click.echo(config.to_json()) click.echo("Computed project configuration for %s" % click.style(project_dir, fg="cyan")) for section, options in config.as_tuple(): click.secho(section, fg="cyan") click.echo("-" * len(section)) click.echo( tabulate( [(name, "=", "\n".join(value) if isinstance(value, list) else value) for name, value in options], tablefmt="plain", )) click.echo() return None
async def import_pio(project_dir): if not project_dir or not is_platformio_project(project_dir): raise JSONRPC20DispatchException( code=4001, message="Not an PlatformIO project: %s" % project_dir) new_project_dir = os.path.join( AppRPC.load_state()["storage"]["projectsDir"], time.strftime("%y%m%d-%H%M%S-") + os.path.basename(project_dir), ) shutil.copytree(project_dir, new_project_dir, symlinks=True) state = AppRPC.load_state() args = ["init"] if (state["storage"]["coreCaller"] and state["storage"]["coreCaller"] in ProjectGenerator.get_supported_ides()): args.extend(["--ide", state["storage"]["coreCaller"]]) await PIOCoreRPC.call(args, options={ "cwd": new_project_dir, "force_subprocess": True }) return new_project_dir
def cli(ctx, project_dir, project_conf, environment, verbose, interface, __unprocessed): # use env variables from Eclipse or CLion for sysenv in ("CWD", "PWD", "PLATFORMIO_PROJECT_DIR"): if is_platformio_project(project_dir): break if os.getenv(sysenv): project_dir = os.getenv(sysenv) with util.cd(project_dir): config = ProjectConfig.get_instance( project_conf or join(project_dir, "platformio.ini")) config.validate(envs=[environment] if environment else None) env_name = environment or helpers.get_default_debug_env(config) env_options = config.items(env=env_name, as_dict=True) if not set(env_options.keys()) >= set(["platform", "board"]): raise exception.ProjectEnvsNotAvailable() debug_options = helpers.validate_debug_options(ctx, env_options) assert debug_options if not interface: return helpers.predebug_project(ctx, project_dir, env_name, False, verbose) configuration = load_project_ide_data(project_dir, env_name) if not configuration: raise exception.DebugInvalidOptions( "Could not load debug configuration") if "--version" in __unprocessed: result = util.exec_command([configuration['gdb_path'], "--version"]) if result['returncode'] == 0: return click.echo(result['out']) raise exception.PlatformioException("\n".join( [result['out'], result['err']])) try: util.ensure_udev_rules() except NameError: pass except exception.InvalidUdevRules as e: for line in str(e).split("\n") + [""]: click.echo( ('~"%s\\n"' if helpers.is_mi_mode(__unprocessed) else "%s") % line) debug_options['load_cmds'] = helpers.configure_esp32_load_cmds( debug_options, configuration) rebuild_prog = False preload = debug_options['load_cmds'] == ["preload"] load_mode = debug_options['load_mode'] if load_mode == "always": rebuild_prog = ( preload or not helpers.has_debug_symbols(configuration['prog_path'])) elif load_mode == "modified": rebuild_prog = ( helpers.is_prog_obsolete(configuration['prog_path']) or not helpers.has_debug_symbols(configuration['prog_path'])) else: rebuild_prog = not isfile(configuration['prog_path']) if preload or (not rebuild_prog and load_mode != "always"): # don't load firmware through debug server debug_options['load_cmds'] = [] if rebuild_prog: if helpers.is_mi_mode(__unprocessed): click.echo('~"Preparing firmware for debugging...\\n"') output = helpers.GDBBytesIO() with util.capture_std_streams(output): helpers.predebug_project(ctx, project_dir, env_name, preload, verbose) output.close() else: click.echo("Preparing firmware for debugging...") helpers.predebug_project(ctx, project_dir, env_name, preload, verbose) # save SHA sum of newly created prog if load_mode == "modified": helpers.is_prog_obsolete(configuration['prog_path']) if not isfile(configuration['prog_path']): raise exception.DebugInvalidOptions("Program/firmware is missed") # run debugging client inject_contrib_pysite() from platformio.commands.debug.client import GDBClient, reactor client = GDBClient(project_dir, __unprocessed, debug_options, env_options) client.spawn(configuration['gdb_path'], configuration['prog_path']) signal.signal(signal.SIGINT, lambda *args, **kwargs: None) reactor.run() return True
def cli(ctx, project_dir, project_conf, environment, verbose, interface, __unprocessed): app.set_session_var("custom_project_conf", project_conf) # use env variables from Eclipse or CLion for sysenv in ("CWD", "PWD", "PLATFORMIO_PROJECT_DIR"): if is_platformio_project(project_dir): break if os.getenv(sysenv): project_dir = os.getenv(sysenv) with fs.cd(project_dir): config = ProjectConfig.get_instance(project_conf) config.validate(envs=[environment] if environment else None) env_name = environment or helpers.get_default_debug_env(config) env_options = config.items(env=env_name, as_dict=True) if not set(env_options.keys()) >= set(["platform", "board"]): raise ProjectEnvsNotAvailableError() debug_options = helpers.validate_debug_options(ctx, env_options) assert debug_options if not interface: return helpers.predebug_project(ctx, project_dir, env_name, False, verbose) configuration = load_project_ide_data(project_dir, env_name) if not configuration: raise DebugInvalidOptionsError("Could not load debug configuration") if "--version" in __unprocessed: result = proc.exec_command([configuration["gdb_path"], "--version"]) if result["returncode"] == 0: return click.echo(result["out"]) raise exception.PlatformioException("\n".join( [result["out"], result["err"]])) try: fs.ensure_udev_rules() except exception.InvalidUdevRules as e: click.echo( helpers.escape_gdbmi_stream("~", str(e) + "\n") if helpers.is_gdbmi_mode() else str(e) + "\n", nl=False, ) debug_options["load_cmds"] = helpers.configure_esp32_load_cmds( debug_options, configuration) rebuild_prog = False preload = debug_options["load_cmds"] == ["preload"] load_mode = debug_options["load_mode"] if load_mode == "always": rebuild_prog = preload or not helpers.has_debug_symbols( configuration["prog_path"]) elif load_mode == "modified": rebuild_prog = helpers.is_prog_obsolete( configuration["prog_path"]) or not helpers.has_debug_symbols( configuration["prog_path"]) else: rebuild_prog = not isfile(configuration["prog_path"]) if preload or (not rebuild_prog and load_mode != "always"): # don't load firmware through debug server debug_options["load_cmds"] = [] if rebuild_prog: if helpers.is_gdbmi_mode(): click.echo( helpers.escape_gdbmi_stream( "~", "Preparing firmware for debugging...\n"), nl=False, ) stream = helpers.GDBMIConsoleStream() with util.capture_std_streams(stream): helpers.predebug_project(ctx, project_dir, env_name, preload, verbose) stream.close() else: click.echo("Preparing firmware for debugging...") helpers.predebug_project(ctx, project_dir, env_name, preload, verbose) # save SHA sum of newly created prog if load_mode == "modified": helpers.is_prog_obsolete(configuration["prog_path"]) if not isfile(configuration["prog_path"]): raise DebugInvalidOptionsError("Program/firmware is missed") # run debugging client inject_contrib_pysite() # pylint: disable=import-outside-toplevel from platformio.commands.debug.process.client import GDBClient, reactor client = GDBClient(project_dir, __unprocessed, debug_options, env_options) client.spawn(configuration["gdb_path"], configuration["prog_path"]) signal.signal(signal.SIGINT, lambda *args, **kwargs: None) reactor.run() return True
def cli( ctx, # pylint: disable=R0913 project_dir, board, ide, project_option, env_prefix, silent): if not silent: if project_dir == getcwd(): click.secho("\nThe current working directory", fg="yellow", nl=False) click.secho(" %s " % project_dir, fg="cyan", nl=False) click.secho("will be used for the project.", fg="yellow") click.echo("") click.echo("The next files/directories have been created in %s" % click.style(project_dir, fg="cyan")) click.echo("%s - Put project header files here" % click.style("include", fg="cyan")) click.echo("%s - Put here project specific (private) libraries" % click.style("lib", fg="cyan")) click.echo("%s - Put project source files here" % click.style("src", fg="cyan")) click.echo("%s - Project Configuration File" % click.style("platformio.ini", fg="cyan")) is_new_project = not is_platformio_project(project_dir) if is_new_project: init_base_project(project_dir) if board: fill_project_envs(ctx, project_dir, board, project_option, env_prefix, ide is not None) if ide: pg = ProjectGenerator(project_dir, ide, board) pg.generate() if is_new_project: init_ci_conf(project_dir) init_cvs_ignore(project_dir) if silent: return if ide: click.secho( "\nProject has been successfully %s including configuration files " "for `%s` IDE." % ("initialized" if is_new_project else "updated", ide), fg="green") else: click.secho( "\nProject has been successfully %s! Useful commands:\n" "`pio run` - process/build project from the current directory\n" "`pio run --target upload` or `pio run -t upload` " "- upload firmware to a target\n" "`pio run --target clean` - clean project (remove compiled files)" "\n`pio run --help` - additional information" % ("initialized" if is_new_project else "updated"), fg="green")
def parse_examples_from_dir(package_dir): assert os.path.isdir(package_dir) examples_dir = os.path.join(package_dir, "examples") if not os.path.isdir(examples_dir): examples_dir = os.path.join(package_dir, "Examples") if not os.path.isdir(examples_dir): return None allowed_exts = ( ".c", ".cc", ".cpp", ".h", ".hpp", ".asm", ".ASM", ".s", ".S", ".ino", ".pde", ) result = {} last_pio_project = None for root, _, files in os.walk(examples_dir): # skip hidden files, symlinks, and folders files = [ f for f in files if not f.startswith(".") and not os.path.islink(os.path.join(root, f)) ] if os.path.basename(root).startswith(".") or not files: continue if is_platformio_project(root): last_pio_project = root result[last_pio_project] = dict( name=os.path.relpath(root, examples_dir), base=os.path.relpath(root, package_dir), files=files, ) continue if last_pio_project: if root.startswith(last_pio_project): result[last_pio_project]["files"].extend([ os.path.relpath(os.path.join(root, f), last_pio_project) for f in files ]) continue last_pio_project = None matched_files = [f for f in files if f.endswith(allowed_exts)] if not matched_files: continue result[root] = dict( name="Examples" if root == examples_dir else os.path.relpath( root, examples_dir), base=os.path.relpath(root, package_dir), files=matched_files, ) result = list(result.values()) # normalize example names for item in result: item["name"] = item["name"].replace(os.path.sep, "/") item["name"] = re.sub(r"[^a-z\d\d\-\_/]+", "_", item["name"], flags=re.I) return result or None
def project_init( ctx, # pylint: disable=R0913 project_dir, board, ide, environment, project_option, env_prefix, silent, ): if not silent: if project_dir == os.getcwd(): click.secho("\nThe current working directory ", fg="yellow", nl=False) try: click.secho(project_dir, fg="cyan", nl=False) except UnicodeEncodeError: click.secho(json.dumps(project_dir), fg="cyan", nl=False) click.secho(" will be used for the project.", fg="yellow") click.echo("") click.echo("The next files/directories have been created in ", nl=False) try: click.secho(project_dir, fg="cyan") except UnicodeEncodeError: click.secho(json.dumps(project_dir), fg="cyan") click.echo("%s - Put project header files here" % click.style("include", fg="cyan")) click.echo("%s - Put here project specific (private) libraries" % click.style("lib", fg="cyan")) click.echo("%s - Put project source files here" % click.style("src", fg="cyan")) click.echo("%s - Project Configuration File" % click.style("platformio.ini", fg="cyan")) is_new_project = not is_platformio_project(project_dir) if is_new_project: init_base_project(project_dir) if environment: update_project_env(project_dir, environment, project_option) elif board: update_board_envs(ctx, project_dir, board, project_option, env_prefix, ide is not None) if ide: with fs.cd(project_dir): config = ProjectConfig.get_instance( os.path.join(project_dir, "platformio.ini")) config.validate() pg = ProjectGenerator(config, environment or get_best_envname(config, board), ide) pg.generate() if is_new_project: init_cvs_ignore(project_dir) if silent: return if ide: click.secho( "\nProject has been successfully %s including configuration files " "for `%s` IDE." % ("initialized" if is_new_project else "updated", ide), fg="green", ) else: click.secho( "\nProject has been successfully %s! Useful commands:\n" "`pio run` - process/build project from the current directory\n" "`pio run --target upload` or `pio run -t upload` " "- upload firmware to a target\n" "`pio run --target clean` - clean project (remove compiled files)" "\n`pio run --help` - additional information" % ("initialized" if is_new_project else "updated"), fg="green", )