# Copyright (c) 2014-present PlatformIO # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import json from os.path import dirname, isdir import click from platformio import app, exception, util from platformio.commands.boards import print_boards from platformio.managers.platform import PlatformFactory, PlatformManager @click.group(short_help="Platform Manager") def cli(): pass def _print_platforms(platforms): for platform in platforms: click.echo("{name} ~ {title}".format( name=click.style(platform['name'], fg="cyan"), title=platform['title'])) click.echo("=" * (3 + len(platform['name'] + platform['title']))) click.echo(platform['description']) click.echo() if "homepage" in platform: click.echo("Home: %s" % platform['homepage']) if "frameworks" in platform and platform['frameworks']: click.echo("Frameworks: %s" % ", ".join(platform['frameworks'])) if "packages" in platform: click.echo("Packages: %s" % ", ".join(platform['packages'])) if "version" in platform: click.echo("Version: " + platform['version']) click.echo() def _get_registry_platforms(): platforms = util.get_api_result("/platforms", cache_valid="7d") pm = PlatformManager() for platform in platforms or []: platform['versions'] = pm.get_all_repo_versions(platform['name']) return platforms def _original_version(version): if version.count(".") != 2: return None _, y = version.split(".")[:2] if int(y) < 100: return None if len(y) % 2 != 0: y = "0" + y parts = [str(int(y[i * 2:i * 2 + 2])) for i in range(int(len(y) / 2))] return ".".join(parts) def _get_platform_data(*args, **kwargs): try: return _get_installed_platform_data(*args, **kwargs) except exception.UnknownPlatform: return _get_registry_platform_data(*args, **kwargs) def _get_installed_platform_data(platform, with_boards=True, expose_packages=True): p = PlatformFactory.newPlatform(platform) data = dict( name=p.name, title=p.title, description=p.description, version=p.version, homepage=p.homepage, repository=p.repository_url, url=p.vendor_url, docs=p.docs_url, license=p.license, forDesktop=not p.is_embedded(), frameworks=sorted(list(p.frameworks) if p.frameworks else []), packages=list(p.packages) if p.packages else []) # if dump to API # del data['version'] # return data # overwrite VCS version and add extra fields manifest = PlatformManager().load_manifest(dirname(p.manifest_path)) assert manifest for key in manifest: if key == "version" or key.startswith("__"): data[key] = manifest[key] if with_boards: data['boards'] = [c.get_brief_data() for c in p.get_boards().values()] if not data['packages'] or not expose_packages: return data data['packages'] = [] installed_pkgs = p.get_installed_packages() for name, opts in p.packages.items(): item = dict( name=name, type=p.get_package_type(name), requirements=opts.get("version"), optional=opts.get("optional") is True) if name in installed_pkgs: for key, value in installed_pkgs[name].items(): if key not in ("url", "version", "description"): continue item[key] = value if key == "version": item["originalVersion"] = _original_version(value) data['packages'].append(item) return data def _get_registry_platform_data( # pylint: disable=unused-argument platform, with_boards=True, expose_packages=True): _data = None for p in _get_registry_platforms(): if p['name'] == platform: _data = p break if not _data: return None data = dict( name=_data['name'], title=_data['title'], description=_data['description'], homepage=_data['homepage'], repository=_data['repository'], url=_data['url'], license=_data['license'], forDesktop=_data['forDesktop'], frameworks=_data['frameworks'], packages=_data['packages'], versions=_data['versions']) if with_boards: data['boards'] = [ board for board in PlatformManager().get_registered_boards() if board['platform'] == _data['name'] ] return data @cli.command("search", short_help="Search for development platform") @click.argument("query", required=False) @click.option("--json-output", is_flag=True) def platform_search(query, json_output): platforms = [] for platform in _get_registry_platforms(): if query == "all": query = "" search_data = json.dumps(platform) if query and query.lower() not in search_data.lower(): continue platforms.append( _get_registry_platform_data( platform['name'], with_boards=False, expose_packages=False)) if json_output: click.echo(json.dumps(platforms)) else: _print_platforms(platforms) @cli.command("frameworks", short_help="List supported frameworks, SDKs") @click.argument("query", required=False) @click.option("--json-output", is_flag=True) def platform_frameworks(query, json_output): frameworks = [] for framework in util.get_api_result("/frameworks", cache_valid="7d"): if query == "all": query = "" search_data = json.dumps(framework) if query and query.lower() not in search_data.lower(): continue framework['homepage'] = ( "https://platformio.org/frameworks/" + framework['name']) framework['platforms'] = [ platform['name'] for platform in _get_registry_platforms() if framework['name'] in platform['frameworks'] ] frameworks.append(framework) frameworks = sorted(frameworks, key=lambda manifest: manifest['name']) if json_output: click.echo(json.dumps(frameworks)) else: _print_platforms(frameworks) @cli.command("list", short_help="List installed development platforms") @click.option("--json-output", is_flag=True) def platform_list(json_output): platforms = [] pm = PlatformManager() for manifest in pm.get_installed(): platforms.append( _get_installed_platform_data( manifest['__pkg_dir'], with_boards=False, expose_packages=False)) platforms = sorted(platforms, key=lambda manifest: manifest['name']) if json_output: click.echo(json.dumps(platforms)) else: _print_platforms(platforms) @cli.command("show", short_help="Show details about development platform") @click.argument("platform") @click.option("--json-output", is_flag=True) def platform_show(platform, json_output): # pylint: disable=too-many-branches data = _get_platform_data(platform) if not data: raise exception.UnknownPlatform(platform) if json_output: return click.echo(json.dumps(data)) click.echo("{name} ~ {title}".format( name=click.style(data['name'], fg="cyan"), title=data['title'])) click.echo("=" * (3 + len(data['name'] + data['title']))) click.echo(data['description']) click.echo() if "version" in data: click.echo("Version: %s" % data['version']) if data['homepage']: click.echo("Home: %s" % data['homepage']) if data['repository']: click.echo("Repository: %s" % data['repository']) if data['url']: click.echo("Vendor: %s" % data['url']) if data['license']: click.echo("License: %s" % data['license']) if data['frameworks']: click.echo("Frameworks: %s" % ", ".join(data['frameworks'])) if not data['packages']: return None if not isinstance(data['packages'][0], dict): click.echo("Packages: %s" % ", ".join(data['packages'])) else: click.echo() click.secho("Packages", bold=True) click.echo("--------") for item in data['packages']: click.echo() click.echo("Package %s" % click.style(item['name'], fg="yellow")) click.echo("-" * (8 + len(item['name']))) if item['type']: click.echo("Type: %s" % item['type']) click.echo("Requirements: %s" % item['requirements']) click.echo("Installed: %s" % ("Yes" if item.get("version") else "No (optional)")) if "version" in item: click.echo("Version: %s" % item['version']) if "originalVersion" in item: click.echo("Original version: %s" % item['originalVersion']) if "description" in item: click.echo("Description: %s" % item['description']) if data['boards']: click.echo() click.secho("Boards", bold=True) click.echo("------") print_boards(data['boards']) return True @cli.command("install", short_help="Install new development platform") @click.argument("platforms", nargs=-1, required=True, metavar="[PLATFORM...]") @click.option("--with-package", multiple=True) @click.option("--without-package", multiple=True) @click.option("--skip-default-package", is_flag=True) @click.option( "-f", "--force", is_flag=True, help="Reinstall/redownload dev/platform and its packages if exist") def platform_install(platforms, with_package, without_package, skip_default_package, force): pm = PlatformManager() for platform in platforms: if pm.install( name=platform, with_packages=with_package, without_packages=without_package, skip_default_package=skip_default_package, force=force): click.secho( "The platform '%s' has been successfully installed!\n" "The rest of packages will be installed automatically " "depending on your build environment." % platform, fg="green") @cli.command("uninstall", short_help="Uninstall development platform") @click.argument("platforms", nargs=-1, required=True, metavar="[PLATFORM...]") def platform_uninstall(platforms): pm = PlatformManager() for platform in platforms: if pm.uninstall(platform): click.secho( "The platform '%s' has been successfully " "uninstalled!" % platform, fg="green") @cli.command("update", short_help="Update installed development platforms") @click.argument("platforms", nargs=-1, required=False, metavar="[PLATFORM...]") @click.option( "-p", "--only-packages", is_flag=True, help="Update only the platform packages") @click.option( "-c", "--only-check", is_flag=True, help="Do not update, only check for a new version") @click.option("--json-output", is_flag=True) def platform_update(platforms, only_packages, only_check, json_output): pm = PlatformManager() pkg_dir_to_name = {} if not platforms: platforms = [] for manifest in pm.get_installed(): platforms.append(manifest['__pkg_dir']) pkg_dir_to_name[manifest['__pkg_dir']] = manifest.get( "title", manifest['name']) if only_check and json_output: result = [] for platform in platforms: pkg_dir = platform if isdir(platform) else None requirements = None url = None if not pkg_dir: name, requirements, url = pm.parse_pkg_uri(platform) pkg_dir = pm.get_package_dir(name, requirements, url) if not pkg_dir: continue latest = pm.outdated(pkg_dir, requirements) if (not latest and not PlatformFactory.newPlatform(pkg_dir). are_outdated_packages()): continue data = _get_installed_platform_data( pkg_dir, with_boards=False, expose_packages=False) if latest: data['versionLatest'] = latest result.append(data) return click.echo(json.dumps(result)) # cleanup cached board and platform lists app.clean_cache() for platform in platforms: click.echo("Platform %s" % click.style( pkg_dir_to_name.get(platform, platform), fg="cyan")) click.echo("--------") pm.update(platform, only_packages=only_packages, only_check=only_check) click.echo() return True