def fetch_portable_python(dst): url = get_portable_python_url() if not url: log.debug("Could not find portable Python for %s", util.get_systype()) return None try: log.debug("Downloading portable python...") archive_path = util.download_file( url, os.path.join(os.path.join(dst, ".cache", "tmp"), os.path.basename(url))) python_dir = os.path.join(dst, "python3") util.safe_remove_dir(python_dir) util.safe_create_dir(python_dir, raise_exception=True) log.debug("Unpacking portable python...") util.unpack_archive(archive_path, python_dir) if util.IS_WINDOWS: return os.path.join(python_dir, "python.exe") return os.path.join(python_dir, "bin", "python3") except: # pylint:disable=bare-except log.debug("Could not download portable python") return None
def create_core_penv(penv_dir=None, ignore_pythons=None): penv_dir = penv_dir or get_penv_dir() click.echo("Creating a virtual environment at %s" % penv_dir) result_dir = None for python_exe in python.find_compatible_pythons(ignore_pythons): result_dir = create_virtualenv(python_exe, penv_dir) if result_dir: break if (not result_dir and util.get_systype() in python.PORTABLE_PYTHONS and not python.is_portable()): python_exe = python.fetch_portable_python(os.path.dirname(penv_dir)) if python_exe: result_dir = create_virtualenv(python_exe, penv_dir) if not result_dir: raise exception.PIOInstallerException( "Could not create PIO Core Virtual Environment. Please report to " "https://github.com/platformio/platformio-core-installer/issues") python_exe = os.path.join(get_penv_bin_dir(penv_dir), "python.exe" if util.IS_WINDOWS else "python") add_state_info(python_exe, penv_dir) install_pip(python_exe, penv_dir) click.echo("Virtual environment has been successfully created!") return result_dir
def test_install_pio_core(pio_installer_script, tmpdir, monkeypatch): monkeypatch.setattr(util, "get_installer_script", lambda: pio_installer_script) core_dir = tmpdir.mkdir(".pio") penv_dir = str(core_dir.mkdir("penv")) os.environ["PLATFORMIO_CORE_DIR"] = str(core_dir) assert core.install_platformio_core(shutdown_piohome=False) python_exe = os.path.join( penv.get_penv_bin_dir(penv_dir), "python.exe" if util.IS_WINDOWS else "python" ) assert subprocess.check_call([python_exe, "-m", "platformio", "--version"]) == 0 core_state_path = os.path.join(str(core_dir), "core-state.json") assert ( subprocess.check_call( [ "python", pio_installer_script, "check", "core", "--dump-state=%s" % core_state_path, ], stderr=subprocess.STDOUT, ) == 0 ) with open(core_state_path) as fp: json_info = json.load(fp) assert json_info.get("core_dir") == str(core_dir) assert json_info.get("penv_dir") == penv_dir assert json_info.get("installer_version") == __version__ assert json_info.get("system") == util.get_systype() assert os.path.isfile( os.path.join( penv.get_penv_bin_dir(penv_dir), "platformio.exe" if util.IS_WINDOWS else "platformio", ) ) assert os.path.isfile( os.path.join(str(core_dir), "packages", "contrib-piohome", "package.json") ) assert os.path.isfile( os.path.join(str(core_dir), "packages", "contrib-pysite", "package.json") )
def get_portable_python_url(): systype = util.get_systype() result = requests.get("https://api.registry.platformio.org/v3/packages/" "platformio/tool/python-portable").json() versions = [ version for version in result["versions"] if is_version_system_compatible(version, systype) ] best_version = None for version in versions: if not best_version or semantic_version.Version( version.name) > semantic_version.Version(best_version.name): best_version = version for item in (best_version or {}).get("files", []): if systype in item["system"]: return item["download_url"] return None
def check(dev=False, auto_upgrade=False, version_spec=None): # pylint: disable=bad-option-value, import-outside-toplevel, unused-import, import-error, unused-variable, cyclic-import from pioinstaller import penv platformio_exe = os.path.join( penv.get_penv_bin_dir(), "platformio.exe" if util.IS_WINDOWS else "platformio", ) python_exe = os.path.join(penv.get_penv_bin_dir(), "python.exe" if util.IS_WINDOWS else "python") result = {} if not os.path.isfile(platformio_exe): raise exception.InvalidPlatformIOCore( "PlatformIO executable not found in `%s`" % penv.get_penv_bin_dir()) if not os.path.isfile(os.path.join(penv.get_penv_dir(), "state.json")): raise exception.InvalidPlatformIOCore( "Could not found state.json file in `%s`" % os.path.join(penv.get_penv_dir(), "state.json")) try: result.update(fetch_python_state(python_exe)) except subprocess.CalledProcessError as e: error = e.output.decode() raise exception.InvalidPlatformIOCore( "Could not import PlatformIO module. Error: %s" % error) piocore_version = convert_version(result.get("core_version")) dev = dev or bool(piocore_version.prerelease if piocore_version else False) result.update({ "core_dir": get_core_dir(), "cache_dir": get_cache_dir(), "penv_dir": penv.get_penv_dir(), "penv_bin_dir": penv.get_penv_bin_dir(), "platformio_exe": platformio_exe, "installer_version": __version__, "python_exe": python_exe, "system": util.get_systype(), "is_develop_core": dev, }) if version_spec: try: if piocore_version not in semantic_version.Spec(version_spec): raise exception.InvalidPlatformIOCore( "PlatformIO Core version %s does not match version requirements %s." % (str(piocore_version), version_spec)) except ValueError: click.secho("Invalid version requirements format: %s. " "More about Semantic Versioning: https://semver.org/" % version_spec) with open(os.path.join(penv.get_penv_dir(), "state.json")) as fp: penv_state = json.load(fp) if penv_state.get("platform") != platform.platform(terse=True): raise exception.InvalidPlatformIOCore( "PlatformIO Core was installed using another platform `%s`. " "Your current platform: %s" % (penv_state.get("platform"), platform.platform(terse=True))) try: subprocess.check_output([platformio_exe, "--version"], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: error = e.output.decode() raise exception.InvalidPlatformIOCore( "Could not run `%s --version`.\nError: %s" % (platformio_exe, str(error))) if not auto_upgrade: return result time_now = int(round(time.time())) last_piocore_version_check = penv_state.get("last_piocore_version_check") if (last_piocore_version_check and (time_now - int(last_piocore_version_check)) < UPDATE_INTERVAL): return result with open(os.path.join(penv.get_penv_dir(), "state.json"), "w") as fp: penv_state["last_piocore_version_check"] = time_now json.dump(penv_state, fp) if not last_piocore_version_check: return result upgrade_core(platformio_exe, dev) try: result.update(fetch_python_state(python_exe)) except: # pylint:disable=bare-except raise exception.InvalidPlatformIOCore( "Could not import PlatformIO module") return result