def pioplus_call(args, **kwargs): if "windows" in util.get_systype() and sys.version_info < (2, 7, 6): raise exception.PlatformioException( "PlatformIO Core Plus v%s does not run under Python version %s.\n" "Minimum supported version is 2.7.6, please upgrade Python.\n" "Python 3 is not yet supported.\n" % (__version__, sys.version.split()[0])) pioplus_path = join(get_core_package_dir("tool-pioplus"), "pioplus") os.environ['PYTHONEXEPATH'] = util.get_pythonexe_path() os.environ['PYTHONPYSITEDIR'] = get_core_package_dir("pysite-pioplus") util.copy_pythonpath_to_osenv() code = subprocess.call([pioplus_path] + args, **kwargs) # handle remote update request if code == 13: count_attr = "_update_count" try: count_value = getattr(pioplus_call, count_attr) except AttributeError: count_value = 0 setattr(pioplus_call, count_attr, 1) count_value += 1 setattr(pioplus_call, count_attr, count_value) if count_value < PIOPLUS_AUTO_UPDATES_MAX: update_core_packages() return pioplus_call(args, **kwargs) # handle reload request elif code == 14: return pioplus_call(args, **kwargs) if code != 0: raise exception.ReturnErrorCode(1)
def get_project_build_data(self): data = { "defines": [], "includes": [], "cxx_path": None, "prog_path": None } envdata = self.get_project_env() if not envdata: return data result = CliRunner().invoke(cmd_run, [ "--project-dir", self.project_dir, "--environment", envdata['env_name'], "--target", "idedata" ]) if result.exit_code != 0 and not isinstance(result.exception, exception.ReturnErrorCode): raise result.exception if '"includes":' not in result.output: raise exception.PlatformioException(result.output) for line in result.output.split("\n"): line = line.strip() if line.startswith('{"') and line.endswith("}"): data = json.loads(line) return data
def load_json(file_path): try: with open(file_path, "r") as f: return json.load(f) except ValueError: raise exception.PlatformioException("Could not load broken JSON: %s" % file_path)
def load_project_ide_data(project_dir, envs): from platformio.commands.run import cli as cmd_run assert envs if not isinstance(envs, (list, tuple, set)): envs = [envs] args = ["--project-dir", project_dir, "--target", "idedata"] for env in envs: args.extend(["-e", env]) result = CliRunner().invoke(cmd_run, args) if result.exit_code != 0 and not isinstance(result.exception, exception.ReturnErrorCode): raise result.exception if '"includes":' not in result.output: raise exception.PlatformioException(result.output) data = {} for line in result.output.split("\n"): line = line.strip() if (line.startswith('{"') and line.endswith("}") and "env_name" in line): _data = json.loads(line) if "env_name" in _data: data[_data['env_name']] = _data if len(envs) == 1 and envs[0] in data: return data[envs[0]] return data or None
def connect(self): self.log.info("Name: {name}", name=self.name) self.log.info("Connecting to PlatformIO Remote Development Cloud") # pylint: disable=protected-access proto, options = endpoints._parse(__pioremote_endpoint__) proto = proto[0] factory = RemoteClientFactory() factory.remote_client = self factory.sslContextFactory = None if proto == "ssl": factory.sslContextFactory = SSLContextFactory(options["host"]) reactor.connectSSL( options["host"], int(options["port"]), factory, factory.sslContextFactory, ) elif proto == "tcp": reactor.connectTCP(options["host"], int(options["port"]), factory) else: raise exception.PlatformioException( "Unknown PIO Remote Cloud protocol") reactor.run() if self._exit_code != 0: raise exception.ReturnErrorCode(self._exit_code)
def get_project_build_data(self): data = {"defines": [], "includes": [], "cxx_path": None} envdata = self.get_project_env() if "env_name" not in envdata: return data cmd = [ normpath(sys.executable), "-m", "platformio" + (".__main__" if sys.version_info < (2, 7, 0) else ""), "-f" ] if app.get_session_var("caller_id"): cmd.extend(["-c", app.get_session_var("caller_id")]) cmd.extend(["run", "-t", "idedata", "-e", envdata['env_name']]) cmd.extend(["-d", self.project_dir]) result = util.exec_command(cmd) if result['returncode'] != 0 or '"includes":' not in result['out']: raise exception.PlatformioException("\n".join( [result['out'], result['err']])) output = result['out'] start_index = output.index('{"') stop_index = output.rindex('}') data = json.loads(output[start_index:stop_index + 1]) return data
def main(): try: if "cygwin" in system().lower(): raise exception.CygwinEnvDetected() # https://urllib3.readthedocs.org # /en/latest/security.html#insecureplatformwarning try: requests.packages.urllib3.disable_warnings() except AttributeError: raise exception.PlatformioException( "Invalid installation of Python `requests` package`. See " "< https://github.com/platformio/platformio/issues/252 >") cli(None, None, None) except Exception as e: # pylint: disable=W0703 if not isinstance(e, exception.ReturnErrorCode): maintenance.on_platformio_exception(e) error_str = "Error: " if isinstance(e, exception.PlatformioException): error_str += str(e) else: error_str += format_exc() click.secho(error_str, fg="red", err=True) return 1 return 0
def get_core_package_dir(name): if name not in CORE_PACKAGES: raise exception.PlatformioException("Please upgrade PIO Core") requirements = CORE_PACKAGES[name] pm = CorePackageManager() pkg_dir = pm.get_package_dir(name, requirements) if pkg_dir: return pkg_dir return pm.install(name, requirements)
def configure_default_packages(self, envoptions, targets): if (envoptions.get("framework") == "wiringpi" and "linux_arm" not in util.get_systype()): raise exception.PlatformioException( "PlatformIO does not support temporary cross-compilation " "for WiringPi framework. Please run PlatformIO directly on " "Raspberry Pi") return BasePlatform.configure_default_packages(self, envoptions, targets)
def configure_default_packages(self, variables, targets): if ("wiringpi" in variables.get("pioframework") and "linux_arm" not in util.get_systype()): raise exception.PlatformioException( "PlatformIO temporary does not support cross-compilation " "for WiringPi framework. Please run PlatformIO directly on " "Raspberry Pi") return PlatformBase.configure_default_packages(self, variables, targets)
def configure_default_packages(self, variables, targets): if not self._is_native() and "wiringpi" in variables.get( "pioframework"): raise exception.PlatformioException( "PlatformIO temporary does not support cross-compilation " "for WiringPi framework. Please use PIO Core directly on " "Raspberry Pi") return PlatformBase.configure_default_packages(self, variables, targets)
def new(tool, project_dir, config, envname, options): cls = None if tool == "cppcheck": cls = CppcheckCheckTool elif tool == "clangtidy": cls = ClangtidyCheckTool else: raise exception.PlatformioException("Unknown check tool `%s`" % tool) return cls(project_dir, config, envname, options)
def get_transport(self): if self.env_options.get("platform") == "native": transport = "native" elif "framework" in self.env_options: transport = self.env_options.get("framework")[0] if "test_transport" in self.env_options: transport = self.env_options["test_transport"] if transport not in TRANSPORT_OPTIONS: raise exception.PlatformioException( "Unknown Unit Test transport `%s`" % transport) return transport.lower()
def __init__(self, manifest_path): self._id = basename(manifest_path)[:-5] assert isfile(manifest_path) self.manifest_path = manifest_path try: self._manifest = util.load_json(manifest_path) except ValueError: raise exception.InvalidBoardManifest(manifest_path) if not set(["name", "url", "vendor"]) <= set(self._manifest.keys()): raise exception.PlatformioException( "Please specify name, url and vendor fields for " + manifest_path)
def get_core_package_dir(name): if name not in __core_packages__: raise exception.PlatformioException("Please upgrade PlatformIO Core") pm = ToolPackageManager() spec = PackageSpec(owner="platformio", name=name, requirements=__core_packages__[name]) pkg = pm.get_package(spec) if pkg: return pkg.path assert pm.install(spec) _remove_unnecessary_packages() return pm.get_package(spec).path
def main(): try: if "cygwin" in system().lower(): raise exception.CygwinEnvDetected() # https://urllib3.readthedocs.org # /en/latest/security.html#insecureplatformwarning try: requests.packages.urllib3.disable_warnings() except AttributeError: raise exception.PlatformioException( "Invalid installation of Python `requests` package`. See " "< https://github.com/platformio/platformio/issues/252 >") # handle PLATFORMIO_FORCE_COLOR if str(getenv("PLATFORMIO_FORCE_COLOR", "")).lower() == "true": try: # pylint: disable=protected-access click._compat.isatty = lambda stream: True except: # pylint: disable=bare-except pass cli(None, None, None) except Exception as e: # pylint: disable=W0703 if not isinstance(e, exception.ReturnErrorCode): maintenance.on_platformio_exception(e) error_str = "Error: " if isinstance(e, exception.PlatformioException): error_str += str(e) else: error_str += format_exc() error_str += """ ============================================================ An unexpected error occurred. Further steps: * Verify that you have the latest version of PlatformIO using `pip install -U platformio` command * Try to find answer in FAQ Troubleshooting section http://docs.platformio.org/en/stable/faq.html * Report this problem to the developers https://github.com/platformio/platformio/issues ============================================================ """ click.secho(error_str, fg="red", err=True) return 1 return 0
def get_transport(self): transport = None if self.env_options.get("platform") == "native": transport = "native" elif "framework" in self.env_options: transport = self.env_options.get("framework")[0] if "test_transport" in self.env_options: transport = self.env_options["test_transport"] if transport not in TRANSPORT_OPTIONS: raise exception.PlatformioException( "Unknown Unit Test transport `%s`. Please check a documentation how " "to create an own 'Test Transport':\n" "- https://docs.platformio.org/page/plus/unit-testing.html" % transport ) return transport.lower()
def load_project_ide_data(project_dir, env_name): from platformio.commands.run import cli as cmd_run result = CliRunner().invoke(cmd_run, [ "--project-dir", project_dir, "--environment", env_name, "--target", "idedata" ]) if result.exit_code != 0 and not isinstance(result.exception, exception.ReturnErrorCode): raise result.exception if '"includes":' not in result.output: raise exception.PlatformioException(result.output) for line in result.output.split("\n"): line = line.strip() if line.startswith('{"') and line.endswith("}"): return json.loads(line) return None
def _lock_state_file(self): if not self.lock: return self._lockfile = LockFile(self.path) if self._lockfile.is_locked() and \ (time() - getmtime(self._lockfile.lock_file)) > 10: self._lockfile.break_lock() try: self._lockfile.acquire() except LockFailed: raise exception.PlatformioException( "The directory `{0}` or its parent directory is not owned by " "the current user and PlatformIO can not store configuration " "data. \nPlease check the permissions and owner of that " "directory. Otherwise, please remove manually `{0}` " "directory and PlatformIO will create new from the current " "user.".format(dirname(self.path)))
def get_project_build_data(self): data = {"defines": [], "includes": [], "cxx_path": None} envdata = self.get_project_env() if "env_name" not in envdata: return data result = util.exec_command([ "platformio", "-f", "run", "-t", "idedata", "-e", envdata['env_name'], "-d", self.project_dir ]) if result['returncode'] != 0 or '"includes":' not in result['out']: raise exception.PlatformioException("\n".join( [result['out'], result['err']])) output = result['out'] start_index = output.index('{"') stop_index = output.rindex('}') data = json.loads(output[start_index:stop_index + 1]) return data
def get_project_build_data(self): data = {"defines": [], "includes": [], "cxx_path": None} envdata = self.get_project_env() if "env_name" not in envdata: return data cmd = [util.get_pythonexe_path(), "-m", "platformio", "-f"] if app.get_session_var("caller_id"): cmd.extend(["-c", app.get_session_var("caller_id")]) cmd.extend(["run", "-t", "idedata", "-e", envdata['env_name']]) cmd.extend(["-d", self.project_dir]) result = util.exec_command(cmd) if result['returncode'] != 0 or '"includes":' not in result['out']: raise exception.PlatformioException("\n".join( [result['out'], result['err']])) for line in result['out'].split("\n"): line = line.strip() if line.startswith('{"') and line.endswith("}"): data = json.loads(line) return data
def pioplus_call(args, **kwargs): if WINDOWS and sys.version_info < (2, 7, 6): raise exception.PlatformioException( "PlatformIO Core Plus v%s does not run under Python version %s.\n" "Minimum supported version is 2.7.6, please upgrade Python.\n" "Python 3 is not yet supported.\n" % (__version__, sys.version)) pioplus_path = join(get_core_package_dir("tool-pioplus"), "pioplus") pythonexe_path = get_pythonexe_path() os.environ["PYTHONEXEPATH"] = pythonexe_path os.environ["PYTHONPYSITEDIR"] = get_core_package_dir("contrib-pysite") os.environ["PIOCOREPYSITEDIR"] = dirname(fs.get_source_dir() or "") if dirname(pythonexe_path) not in os.environ["PATH"].split(os.pathsep): os.environ["PATH"] = (os.pathsep).join( [dirname(pythonexe_path), os.environ["PATH"]]) copy_pythonpath_to_osenv() code = subprocess.call([pioplus_path] + args, **kwargs) # handle remote update request if code == 13: count_attr = "_update_count" try: count_value = getattr(pioplus_call, count_attr) except AttributeError: count_value = 0 setattr(pioplus_call, count_attr, 1) count_value += 1 setattr(pioplus_call, count_attr, count_value) if count_value < PIOPLUS_AUTO_UPDATES_MAX: update_core_packages() return pioplus_call(args, **kwargs) # handle reload request elif code == 14: return pioplus_call(args, **kwargs) if code != 0: raise exception.ReturnErrorCode(1) return True
def get_project_build_data(self): data = {"defines": [], "includes": [], "cxx_path": None} envdata = self.get_project_env() if not envdata: return data out = StringIO() with util.capture_stdout(out): click.get_current_context().invoke( cmd_run, project_dir=self.project_dir, environment=[envdata['env_name']], target=["idedata"]) result = out.getvalue() if '"includes":' not in result: raise exception.PlatformioException(result) for line in result.split("\n"): line = line.strip() if line.startswith('{"') and line.endswith("}"): data = json.loads(line) return data
def get_test_port(self): # if test port is specified manually or in config if self.options.get("test_port"): return self.options.get("test_port") if self.env_options.get("test_port"): return self.env_options.get("test_port") assert set(["platform", "board"]) & set(self.env_options.keys()) p = PlatformFactory.newPlatform(self.env_options['platform']) board_hwids = p.board_config(self.env_options['board']).get( "build.hwids", []) port = None elapsed = 0 while elapsed < 5 and not port: for item in util.get_serialports(): port = item['port'] for hwid in board_hwids: hwid_str = ("%s:%s" % (hwid[0], hwid[1])).replace("0x", "") if hwid_str in item['hwid']: return port # check if port is already configured try: serial.Serial(port, timeout=self.SERIAL_TIMEOUT).close() except serial.SerialException: port = None if not port: sleep(0.25) elapsed += 0.25 if not port: raise exception.PlatformioException( "Please specify `test_port` for environment or use " "global `--test-port` option.") return port
def cli(port, host, no_open, shutdown_timeout): # pylint: disable=import-error, import-outside-toplevel # import contrib modules inject_contrib_pysite() from autobahn.twisted.resource import WebSocketResource from twisted.internet import reactor from twisted.web import server from platformio.commands.home.rpc.handlers.app import AppRPC from platformio.commands.home.rpc.handlers.ide import IDERPC from platformio.commands.home.rpc.handlers.misc import MiscRPC from platformio.commands.home.rpc.handlers.os import OSRPC from platformio.commands.home.rpc.handlers.piocore import PIOCoreRPC from platformio.commands.home.rpc.handlers.project import ProjectRPC from platformio.commands.home.rpc.server import JSONRPCServerFactory from platformio.commands.home.web import WebRoot factory = JSONRPCServerFactory(shutdown_timeout) factory.addHandler(AppRPC(), namespace="app") factory.addHandler(IDERPC(), namespace="ide") factory.addHandler(MiscRPC(), namespace="misc") factory.addHandler(OSRPC(), namespace="os") factory.addHandler(PIOCoreRPC(), namespace="core") factory.addHandler(ProjectRPC(), namespace="project") contrib_dir = get_core_package_dir("contrib-piohome") if not isdir(contrib_dir): raise exception.PlatformioException("Invalid path to PIO Home Contrib") # Ensure PIO Home mimetypes are known mimetypes.add_type("text/html", ".html") mimetypes.add_type("text/css", ".css") mimetypes.add_type("application/javascript", ".js") root = WebRoot(contrib_dir) root.putChild(b"wsrpc", WebSocketResource(factory)) site = server.Site(root) # hook for `platformio-node-helpers` if host == "__do_not_start__": return # if already started already_started = False socket.setdefaulttimeout(1) try: socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port)) already_started = True except: # pylint: disable=bare-except pass home_url = "http://%s:%d" % (host, port) if not no_open: if already_started: click.launch(home_url) else: reactor.callLater(1, lambda: click.launch(home_url)) click.echo("\n".join([ "", " ___I_", " /\\-_--\\ PlatformIO Home", "/ \\_-__\\", "|[]| [] | %s" % home_url, "|__|____|______________%s" % ("_" * len(host)), ])) click.echo("") click.echo("Open PIO Home in your browser by this URL => %s" % home_url) if already_started: return click.echo("PIO Home has been started. Press Ctrl+C to shutdown.") reactor.listenTCP(port, site, interface=host) reactor.run()
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