mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-30 10:07:14 +02:00
Use new unified package API for deprecated pio lib
command // Resolve #4198
This commit is contained in:
@ -17,16 +17,18 @@
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import time
|
|
||||||
from urllib.parse import quote
|
|
||||||
|
|
||||||
import click
|
import click
|
||||||
from tabulate import tabulate
|
|
||||||
|
|
||||||
from platformio import exception, fs, util
|
from platformio import exception, fs
|
||||||
from platformio.cli import PlatformioCLI
|
from platformio.cli import PlatformioCLI
|
||||||
from platformio.commands.lib.helpers import get_builtin_libs, save_project_libdeps
|
from platformio.package.commands.install import package_install_cmd
|
||||||
from platformio.package.exception import NotGlobalLibDir, UnknownPackageError
|
from platformio.package.commands.list import package_list_cmd
|
||||||
|
from platformio.package.commands.search import package_search_cmd
|
||||||
|
from platformio.package.commands.show import package_show_cmd
|
||||||
|
from platformio.package.commands.uninstall import package_uninstall_cmd
|
||||||
|
from platformio.package.commands.update import package_update_cmd
|
||||||
|
from platformio.package.exception import NotGlobalLibDir
|
||||||
from platformio.package.manager.library import LibraryPackageManager
|
from platformio.package.manager.library import LibraryPackageManager
|
||||||
from platformio.package.meta import PackageItem, PackageSpec
|
from platformio.package.meta import PackageItem, PackageSpec
|
||||||
from platformio.proc import is_ci
|
from platformio.proc import is_ci
|
||||||
@ -43,6 +45,20 @@ def get_project_global_lib_dir():
|
|||||||
return ProjectConfig.get_instance().get("platformio", "globallib_dir")
|
return ProjectConfig.get_instance().get("platformio", "globallib_dir")
|
||||||
|
|
||||||
|
|
||||||
|
def invoke_command(ctx, cmd, **kwargs):
|
||||||
|
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:
|
||||||
|
cmd_kwargs = kwargs.copy()
|
||||||
|
if is_platformio_project(input_dir):
|
||||||
|
cmd_kwargs["project_dir"] = input_dir
|
||||||
|
cmd_kwargs["environments"] = project_environments
|
||||||
|
else:
|
||||||
|
cmd_kwargs["global"] = True
|
||||||
|
cmd_kwargs["storage_dir"] = input_dir
|
||||||
|
ctx.invoke(cmd, **cmd_kwargs)
|
||||||
|
|
||||||
|
|
||||||
@click.group(short_help="Library manager", hidden=True)
|
@click.group(short_help="Library manager", hidden=True)
|
||||||
@click.option(
|
@click.option(
|
||||||
"-d",
|
"-d",
|
||||||
@ -146,55 +162,14 @@ def lib_install( # pylint: disable=too-many-arguments,unused-argument
|
|||||||
"the next releases. \nPlease use `pio pkg install` instead.\n",
|
"the next releases. \nPlease use `pio pkg install` instead.\n",
|
||||||
fg="yellow",
|
fg="yellow",
|
||||||
)
|
)
|
||||||
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
|
return invoke_command(
|
||||||
storage_libdeps = ctx.meta.get(CTX_META_STORAGE_LIBDEPS_KEY, [])
|
ctx,
|
||||||
|
package_install_cmd,
|
||||||
installed_pkgs = {}
|
libraries=libraries,
|
||||||
for storage_dir in storage_dirs:
|
no_save=not save,
|
||||||
if not silent and (libraries or storage_dir in storage_libdeps):
|
force=force,
|
||||||
print_storage_header(storage_dirs, storage_dir)
|
silent=silent,
|
||||||
lm = LibraryPackageManager(storage_dir)
|
)
|
||||||
lm.set_log_level(logging.WARN if silent else logging.DEBUG)
|
|
||||||
|
|
||||||
if libraries:
|
|
||||||
installed_pkgs = {
|
|
||||||
library: lm.install(library, force=force) for library in libraries
|
|
||||||
}
|
|
||||||
|
|
||||||
elif storage_dir in storage_libdeps:
|
|
||||||
for library in storage_libdeps[storage_dir]:
|
|
||||||
lm.install(library, force=force)
|
|
||||||
|
|
||||||
if save and installed_pkgs:
|
|
||||||
_save_deps(ctx, installed_pkgs)
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("uninstall", short_help="Remove libraries")
|
@cli.command("uninstall", short_help="Remove libraries")
|
||||||
@ -214,16 +189,13 @@ def lib_uninstall(ctx, libraries, save, silent):
|
|||||||
"the next releases. \nPlease use `pio pkg uninstall` instead.\n",
|
"the next releases. \nPlease use `pio pkg uninstall` instead.\n",
|
||||||
fg="yellow",
|
fg="yellow",
|
||||||
)
|
)
|
||||||
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
|
invoke_command(
|
||||||
uninstalled_pkgs = {}
|
ctx,
|
||||||
for storage_dir in storage_dirs:
|
package_uninstall_cmd,
|
||||||
print_storage_header(storage_dirs, storage_dir)
|
libraries=libraries,
|
||||||
lm = LibraryPackageManager(storage_dir)
|
no_save=not save,
|
||||||
lm.set_log_level(logging.WARN if silent else logging.DEBUG)
|
silent=silent,
|
||||||
uninstalled_pkgs = {library: lm.uninstall(library) for library in libraries}
|
)
|
||||||
|
|
||||||
if save and uninstalled_pkgs:
|
|
||||||
_save_deps(ctx, uninstalled_pkgs, action="remove")
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("update", short_help="Update installed libraries")
|
@cli.command("update", short_help="Update installed libraries")
|
||||||
@ -255,60 +227,51 @@ def lib_update( # pylint: disable=too-many-arguments
|
|||||||
"the next releases. \nPlease use `pio pkg update` instead.\n",
|
"the next releases. \nPlease use `pio pkg update` instead.\n",
|
||||||
fg="yellow",
|
fg="yellow",
|
||||||
)
|
)
|
||||||
|
return invoke_command(
|
||||||
|
ctx,
|
||||||
|
package_update_cmd,
|
||||||
|
libraries=libraries,
|
||||||
|
silent=silent,
|
||||||
|
)
|
||||||
|
|
||||||
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
|
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
|
||||||
json_result = {}
|
json_result = {}
|
||||||
for storage_dir in storage_dirs:
|
for storage_dir in storage_dirs:
|
||||||
if not json_output:
|
|
||||||
print_storage_header(storage_dirs, storage_dir)
|
|
||||||
lib_deps = ctx.meta.get(CTX_META_STORAGE_LIBDEPS_KEY, {}).get(storage_dir, [])
|
lib_deps = ctx.meta.get(CTX_META_STORAGE_LIBDEPS_KEY, {}).get(storage_dir, [])
|
||||||
lm = LibraryPackageManager(storage_dir)
|
lm = LibraryPackageManager(storage_dir)
|
||||||
lm.set_log_level(logging.WARN if silent else logging.DEBUG)
|
lm.set_log_level(logging.WARN if silent else logging.DEBUG)
|
||||||
_libraries = libraries or lib_deps or lm.get_installed()
|
_libraries = libraries or lib_deps or lm.get_installed()
|
||||||
|
|
||||||
if only_check and json_output:
|
result = []
|
||||||
result = []
|
for library in _libraries:
|
||||||
for library in _libraries:
|
spec = None
|
||||||
spec = None
|
pkg = None
|
||||||
pkg = None
|
if isinstance(library, PackageItem):
|
||||||
if isinstance(library, PackageItem):
|
pkg = library
|
||||||
pkg = library
|
else:
|
||||||
else:
|
spec = PackageSpec(library)
|
||||||
spec = PackageSpec(library)
|
pkg = lm.get_package(spec)
|
||||||
pkg = lm.get_package(spec)
|
if not pkg:
|
||||||
if not pkg:
|
continue
|
||||||
continue
|
outdated = lm.outdated(pkg, spec)
|
||||||
outdated = lm.outdated(pkg, spec)
|
if not outdated.is_outdated(allow_incompatible=True):
|
||||||
if not outdated.is_outdated(allow_incompatible=True):
|
continue
|
||||||
continue
|
manifest = lm.legacy_load_manifest(pkg)
|
||||||
manifest = lm.legacy_load_manifest(pkg)
|
manifest["versionWanted"] = (
|
||||||
manifest["versionWanted"] = (
|
str(outdated.wanted) if outdated.wanted else None
|
||||||
str(outdated.wanted) if outdated.wanted else None
|
|
||||||
)
|
|
||||||
manifest["versionLatest"] = (
|
|
||||||
str(outdated.latest) if outdated.latest else None
|
|
||||||
)
|
|
||||||
result.append(manifest)
|
|
||||||
json_result[storage_dir] = result
|
|
||||||
else:
|
|
||||||
for library in _libraries:
|
|
||||||
to_spec = (
|
|
||||||
None if isinstance(library, PackageItem) else PackageSpec(library)
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
lm.update(library, to_spec=to_spec)
|
|
||||||
except UnknownPackageError as e:
|
|
||||||
if library not in lib_deps:
|
|
||||||
raise e
|
|
||||||
|
|
||||||
if json_output:
|
|
||||||
return click.echo(
|
|
||||||
json.dumps(
|
|
||||||
json_result[storage_dirs[0]] if len(storage_dirs) == 1 else json_result
|
|
||||||
)
|
)
|
||||||
)
|
manifest["versionLatest"] = (
|
||||||
|
str(outdated.latest) if outdated.latest else None
|
||||||
|
)
|
||||||
|
result.append(manifest)
|
||||||
|
|
||||||
return True
|
json_result[storage_dir] = result
|
||||||
|
|
||||||
|
return click.echo(
|
||||||
|
json.dumps(
|
||||||
|
json_result[storage_dirs[0]] if len(storage_dirs) == 1 else json_result
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@cli.command("list", short_help="List installed libraries")
|
@cli.command("list", short_help="List installed libraries")
|
||||||
@ -321,29 +284,18 @@ def lib_list(ctx, json_output):
|
|||||||
"the next releases. \nPlease use `pio pkg list` instead.\n",
|
"the next releases. \nPlease use `pio pkg list` instead.\n",
|
||||||
fg="yellow",
|
fg="yellow",
|
||||||
)
|
)
|
||||||
|
return invoke_command(ctx, package_list_cmd, only_libraries=True)
|
||||||
|
|
||||||
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
|
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
|
||||||
json_result = {}
|
json_result = {}
|
||||||
for storage_dir in storage_dirs:
|
for storage_dir in storage_dirs:
|
||||||
if not json_output:
|
|
||||||
print_storage_header(storage_dirs, storage_dir)
|
|
||||||
lm = LibraryPackageManager(storage_dir)
|
lm = LibraryPackageManager(storage_dir)
|
||||||
items = lm.legacy_get_installed()
|
json_result[storage_dir] = lm.legacy_get_installed()
|
||||||
if json_output:
|
return click.echo(
|
||||||
json_result[storage_dir] = items
|
json.dumps(
|
||||||
elif items:
|
json_result[storage_dirs[0]] if len(storage_dirs) == 1 else json_result
|
||||||
for item in sorted(items, key=lambda i: i["name"]):
|
|
||||||
print_lib_item(item)
|
|
||||||
else:
|
|
||||||
click.echo("No items found")
|
|
||||||
|
|
||||||
if json_output:
|
|
||||||
return click.echo(
|
|
||||||
json.dumps(
|
|
||||||
json_result[storage_dirs[0]] if len(storage_dirs) == 1 else json_result
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("search", short_help="Search for a library")
|
@cli.command("search", short_help="Search for a library")
|
||||||
@ -363,14 +315,10 @@ def lib_list(ctx, json_output):
|
|||||||
is_flag=True,
|
is_flag=True,
|
||||||
help="Do not prompt, automatically paginate with delay",
|
help="Do not prompt, automatically paginate with delay",
|
||||||
)
|
)
|
||||||
def lib_search(query, json_output, page, noninteractive, **filters):
|
@click.pass_context
|
||||||
if not json_output:
|
def lib_search( # pylint: disable=unused-argument
|
||||||
click.secho(
|
ctx, query, json_output, page, noninteractive, **filters
|
||||||
"\nWARNING: This command is deprecated and will be removed in "
|
):
|
||||||
"the next releases. \nPlease use `pio pkg search` instead.\n",
|
|
||||||
fg="yellow",
|
|
||||||
)
|
|
||||||
regclient = LibraryPackageManager().get_registry_client_instance()
|
|
||||||
if not query:
|
if not query:
|
||||||
query = []
|
query = []
|
||||||
if not isinstance(query, list):
|
if not isinstance(query, list):
|
||||||
@ -380,72 +328,30 @@ def lib_search(query, json_output, page, noninteractive, **filters):
|
|||||||
for value in values:
|
for value in values:
|
||||||
query.append('%s:"%s"' % (key, value))
|
query.append('%s:"%s"' % (key, value))
|
||||||
|
|
||||||
|
if not json_output:
|
||||||
|
click.secho(
|
||||||
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
|
"the next releases. \nPlease use `pio pkg search` instead.\n",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
|
query.append("type:library")
|
||||||
|
return ctx.invoke(package_search_cmd, query=" ".join(query), page=page)
|
||||||
|
|
||||||
|
regclient = LibraryPackageManager().get_registry_client_instance()
|
||||||
result = regclient.fetch_json_data(
|
result = regclient.fetch_json_data(
|
||||||
"get",
|
"get",
|
||||||
"/v2/lib/search",
|
"/v2/lib/search",
|
||||||
params=dict(query=" ".join(query), page=page),
|
params=dict(query=" ".join(query), page=page),
|
||||||
x_cache_valid="1d",
|
x_cache_valid="1d",
|
||||||
)
|
)
|
||||||
|
return click.echo(json.dumps(result))
|
||||||
if json_output:
|
|
||||||
click.echo(json.dumps(result))
|
|
||||||
return
|
|
||||||
|
|
||||||
if result["total"] == 0:
|
|
||||||
click.secho(
|
|
||||||
"Nothing has been found by your request\n"
|
|
||||||
"Try a less-specific search or use truncation (or wildcard) "
|
|
||||||
"operator",
|
|
||||||
fg="yellow",
|
|
||||||
nl=False,
|
|
||||||
)
|
|
||||||
click.secho(" *", fg="green")
|
|
||||||
click.secho("For example: DS*, PCA*, DHT* and etc.\n", fg="yellow")
|
|
||||||
click.echo(
|
|
||||||
"For more examples and advanced search syntax, please use documentation:"
|
|
||||||
)
|
|
||||||
click.secho(
|
|
||||||
"https://docs.platformio.org/page/userguide/lib/cmd_search.html\n",
|
|
||||||
fg="cyan",
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
click.secho(
|
|
||||||
"Found %d libraries:\n" % result["total"],
|
|
||||||
fg="green" if result["total"] else "yellow",
|
|
||||||
)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
for item in result["items"]:
|
|
||||||
print_lib_item(item)
|
|
||||||
|
|
||||||
if int(result["page"]) * int(result["perpage"]) >= int(result["total"]):
|
|
||||||
break
|
|
||||||
|
|
||||||
if noninteractive:
|
|
||||||
click.echo()
|
|
||||||
click.secho(
|
|
||||||
"Loading next %d libraries... Press Ctrl+C to stop!"
|
|
||||||
% result["perpage"],
|
|
||||||
fg="yellow",
|
|
||||||
)
|
|
||||||
click.echo()
|
|
||||||
time.sleep(5)
|
|
||||||
elif not click.confirm("Show next libraries?"):
|
|
||||||
break
|
|
||||||
result = regclient.fetch_json_data(
|
|
||||||
"get",
|
|
||||||
"/v2/lib/search",
|
|
||||||
params=dict(query=" ".join(query), page=int(result["page"]) + 1),
|
|
||||||
x_cache_valid="1d",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("builtin", short_help="List built-in libraries")
|
@cli.command("builtin", short_help="List built-in libraries")
|
||||||
@click.option("--storage", multiple=True)
|
@click.option("--storage", multiple=True)
|
||||||
@click.option("--json-output", is_flag=True)
|
@click.option("--json-output", is_flag=True)
|
||||||
def lib_builtin(storage, json_output):
|
def lib_builtin(storage, json_output):
|
||||||
items = get_builtin_libs(storage)
|
items = LibraryPackageManager.get_builtin_libs(storage)
|
||||||
if json_output:
|
if json_output:
|
||||||
return click.echo(json.dumps(items))
|
return click.echo(json.dumps(items))
|
||||||
|
|
||||||
@ -465,13 +371,16 @@ def lib_builtin(storage, json_output):
|
|||||||
@cli.command("show", short_help="Show detailed info about a library")
|
@cli.command("show", short_help="Show detailed info about a library")
|
||||||
@click.argument("library", metavar="[LIBRARY]")
|
@click.argument("library", metavar="[LIBRARY]")
|
||||||
@click.option("--json-output", is_flag=True)
|
@click.option("--json-output", is_flag=True)
|
||||||
def lib_show(library, json_output):
|
@click.pass_context
|
||||||
|
def lib_show(ctx, library, json_output):
|
||||||
if not json_output:
|
if not json_output:
|
||||||
click.secho(
|
click.secho(
|
||||||
"\nWARNING: This command is deprecated and will be removed in "
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
"the next releases. \nPlease use `pio pkg show` instead.\n",
|
"the next releases. \nPlease use `pio pkg show` instead.\n",
|
||||||
fg="yellow",
|
fg="yellow",
|
||||||
)
|
)
|
||||||
|
return ctx.invoke(package_show_cmd, pkg_type="library", spec=library)
|
||||||
|
|
||||||
lm = LibraryPackageManager()
|
lm = LibraryPackageManager()
|
||||||
lm.set_log_level(logging.ERROR if json_output else logging.DEBUG)
|
lm.set_log_level(logging.ERROR if json_output else logging.DEBUG)
|
||||||
lib_id = lm.reveal_registry_package_id(library)
|
lib_id = lm.reveal_registry_package_id(library)
|
||||||
@ -479,86 +388,7 @@ def lib_show(library, json_output):
|
|||||||
lib = regclient.fetch_json_data(
|
lib = regclient.fetch_json_data(
|
||||||
"get", "/v2/lib/info/%d" % lib_id, x_cache_valid="1h"
|
"get", "/v2/lib/info/%d" % lib_id, x_cache_valid="1h"
|
||||||
)
|
)
|
||||||
if json_output:
|
return click.echo(json.dumps(lib))
|
||||||
return click.echo(json.dumps(lib))
|
|
||||||
|
|
||||||
title = "{ownername}/{name}".format(**lib)
|
|
||||||
click.secho(title, fg="cyan")
|
|
||||||
click.echo("=" * len(title))
|
|
||||||
click.echo(lib["description"])
|
|
||||||
click.echo()
|
|
||||||
|
|
||||||
click.secho("ID: %d" % lib["id"])
|
|
||||||
click.echo(
|
|
||||||
"Version: %s, released %s"
|
|
||||||
% (
|
|
||||||
lib["version"]["name"],
|
|
||||||
util.parse_datetime(lib["version"]["released"]).strftime("%c"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
click.echo("Manifest: %s" % lib["confurl"])
|
|
||||||
for key in ("homepage", "repository", "license"):
|
|
||||||
if key not in lib or not lib[key]:
|
|
||||||
continue
|
|
||||||
if isinstance(lib[key], list):
|
|
||||||
click.echo("%s: %s" % (key.capitalize(), ", ".join(lib[key])))
|
|
||||||
else:
|
|
||||||
click.echo("%s: %s" % (key.capitalize(), lib[key]))
|
|
||||||
|
|
||||||
blocks = []
|
|
||||||
|
|
||||||
_authors = []
|
|
||||||
for author in lib.get("authors", []):
|
|
||||||
_data = []
|
|
||||||
for key in ("name", "email", "url", "maintainer"):
|
|
||||||
if not author.get(key):
|
|
||||||
continue
|
|
||||||
if key == "email":
|
|
||||||
_data.append("<%s>" % author[key])
|
|
||||||
elif key == "maintainer":
|
|
||||||
_data.append("(maintainer)")
|
|
||||||
else:
|
|
||||||
_data.append(author[key])
|
|
||||||
_authors.append(" ".join(_data))
|
|
||||||
if _authors:
|
|
||||||
blocks.append(("Authors", _authors))
|
|
||||||
|
|
||||||
blocks.append(("Keywords", lib["keywords"]))
|
|
||||||
for key in ("frameworks", "platforms"):
|
|
||||||
if key not in lib or not lib[key]:
|
|
||||||
continue
|
|
||||||
blocks.append(("Compatible %s" % key, [i["title"] for i in lib[key]]))
|
|
||||||
blocks.append(("Headers", lib["headers"]))
|
|
||||||
blocks.append(("Examples", lib["examples"]))
|
|
||||||
blocks.append(
|
|
||||||
(
|
|
||||||
"Versions",
|
|
||||||
[
|
|
||||||
"%s, released %s"
|
|
||||||
% (v["name"], util.parse_datetime(v["released"]).strftime("%c"))
|
|
||||||
for v in lib["versions"]
|
|
||||||
],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
blocks.append(
|
|
||||||
(
|
|
||||||
"Unique Downloads",
|
|
||||||
[
|
|
||||||
"Today: %s" % lib["dlstats"]["day"],
|
|
||||||
"Week: %s" % lib["dlstats"]["week"],
|
|
||||||
"Month: %s" % lib["dlstats"]["month"],
|
|
||||||
],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
for (title, rows) in blocks:
|
|
||||||
click.echo()
|
|
||||||
click.secho(title, bold=True)
|
|
||||||
click.echo("-" * len(title))
|
|
||||||
for row in rows:
|
|
||||||
click.echo(row)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("register", short_help="Deprecated")
|
@cli.command("register", short_help="Deprecated")
|
||||||
@ -572,76 +402,18 @@ def lib_register(config_url): # pylint: disable=unused-argument
|
|||||||
@cli.command("stats", short_help="Library Registry Statistics")
|
@cli.command("stats", short_help="Library Registry Statistics")
|
||||||
@click.option("--json-output", is_flag=True)
|
@click.option("--json-output", is_flag=True)
|
||||||
def lib_stats(json_output):
|
def lib_stats(json_output):
|
||||||
|
if not json_output:
|
||||||
|
click.secho(
|
||||||
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
|
"the next releases. \nPlease visit "
|
||||||
|
"https://registry.platformio.org\n",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
regclient = LibraryPackageManager().get_registry_client_instance()
|
regclient = LibraryPackageManager().get_registry_client_instance()
|
||||||
result = regclient.fetch_json_data("get", "/v2/lib/stats", x_cache_valid="1h")
|
result = regclient.fetch_json_data("get", "/v2/lib/stats", x_cache_valid="1h")
|
||||||
|
return click.echo(json.dumps(result))
|
||||||
if json_output:
|
|
||||||
return click.echo(json.dumps(result))
|
|
||||||
|
|
||||||
for key in ("updated", "added"):
|
|
||||||
tabular_data = [
|
|
||||||
(
|
|
||||||
click.style(item["name"], fg="cyan"),
|
|
||||||
util.parse_datetime(item["date"]).strftime("%c"),
|
|
||||||
"https://platformio.org/lib/show/%s/%s"
|
|
||||||
% (item["id"], quote(item["name"])),
|
|
||||||
)
|
|
||||||
for item in result.get(key, [])
|
|
||||||
]
|
|
||||||
table = tabulate(
|
|
||||||
tabular_data,
|
|
||||||
headers=[click.style("RECENTLY " + key.upper(), bold=True), "Date", "URL"],
|
|
||||||
)
|
|
||||||
click.echo(table)
|
|
||||||
click.echo()
|
|
||||||
|
|
||||||
for key in ("lastkeywords", "topkeywords"):
|
|
||||||
tabular_data = [
|
|
||||||
(
|
|
||||||
click.style(name, fg="cyan"),
|
|
||||||
"https://platformio.org/lib/search?query=" + quote("keyword:%s" % name),
|
|
||||||
)
|
|
||||||
for name in result.get(key, [])
|
|
||||||
]
|
|
||||||
table = tabulate(
|
|
||||||
tabular_data,
|
|
||||||
headers=[
|
|
||||||
click.style(
|
|
||||||
("RECENT" if key == "lastkeywords" else "POPULAR") + " KEYWORDS",
|
|
||||||
bold=True,
|
|
||||||
),
|
|
||||||
"URL",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
click.echo(table)
|
|
||||||
click.echo()
|
|
||||||
|
|
||||||
for key, title in (("dlday", "Today"), ("dlweek", "Week"), ("dlmonth", "Month")):
|
|
||||||
tabular_data = [
|
|
||||||
(
|
|
||||||
click.style(item["name"], fg="cyan"),
|
|
||||||
"https://platformio.org/lib/show/%s/%s"
|
|
||||||
% (item["id"], quote(item["name"])),
|
|
||||||
)
|
|
||||||
for item in result.get(key, [])
|
|
||||||
]
|
|
||||||
table = tabulate(
|
|
||||||
tabular_data,
|
|
||||||
headers=[click.style("FEATURED: " + title.upper(), bold=True), "URL"],
|
|
||||||
)
|
|
||||||
click.echo(table)
|
|
||||||
click.echo()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def print_storage_header(storage_dirs, storage_dir):
|
|
||||||
if storage_dirs and storage_dirs[0] != storage_dir:
|
|
||||||
click.echo("")
|
|
||||||
click.echo(
|
|
||||||
click.style("Library Storage: ", bold=True)
|
|
||||||
+ click.style(storage_dir, fg="blue")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def print_lib_item(item):
|
def print_lib_item(item):
|
@ -1,13 +0,0 @@
|
|||||||
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
|
||||||
#
|
|
||||||
# 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.
|
|
@ -1,104 +0,0 @@
|
|||||||
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
|
||||||
#
|
|
||||||
# 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 os
|
|
||||||
|
|
||||||
from platformio import util
|
|
||||||
from platformio.compat import ci_strings_are_equal
|
|
||||||
from platformio.package.manager.platform import PlatformPackageManager
|
|
||||||
from platformio.package.meta import PackageSpec
|
|
||||||
from platformio.platform.factory import PlatformFactory
|
|
||||||
from platformio.project.config import ProjectConfig
|
|
||||||
from platformio.project.exception import InvalidProjectConfError
|
|
||||||
|
|
||||||
|
|
||||||
@util.memoized(expire="60s")
|
|
||||||
def get_builtin_libs(storage_names=None):
|
|
||||||
# pylint: disable=import-outside-toplevel
|
|
||||||
from platformio.package.manager.library import LibraryPackageManager
|
|
||||||
|
|
||||||
items = []
|
|
||||||
storage_names = storage_names or []
|
|
||||||
pm = PlatformPackageManager()
|
|
||||||
for pkg in pm.get_installed():
|
|
||||||
p = PlatformFactory.new(pkg)
|
|
||||||
for storage in p.get_lib_storages():
|
|
||||||
if storage_names and storage["name"] not in storage_names:
|
|
||||||
continue
|
|
||||||
lm = LibraryPackageManager(storage["path"])
|
|
||||||
items.append(
|
|
||||||
{
|
|
||||||
"name": storage["name"],
|
|
||||||
"path": storage["path"],
|
|
||||||
"items": lm.legacy_get_installed(),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return items
|
|
||||||
|
|
||||||
|
|
||||||
def is_builtin_lib(name):
|
|
||||||
for storage in get_builtin_libs():
|
|
||||||
for lib in storage["items"]:
|
|
||||||
if lib.get("name") == name:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def ignore_deps_by_specs(deps, specs):
|
|
||||||
result = []
|
|
||||||
for dep in deps:
|
|
||||||
depspec = PackageSpec(dep)
|
|
||||||
if depspec.external:
|
|
||||||
result.append(dep)
|
|
||||||
continue
|
|
||||||
ignore_conditions = []
|
|
||||||
for spec in specs:
|
|
||||||
if depspec.owner:
|
|
||||||
ignore_conditions.append(
|
|
||||||
ci_strings_are_equal(depspec.owner, spec.owner)
|
|
||||||
and ci_strings_are_equal(depspec.name, spec.name)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
ignore_conditions.append(ci_strings_are_equal(depspec.name, spec.name))
|
|
||||||
if not any(ignore_conditions):
|
|
||||||
result.append(dep)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def save_project_libdeps(project_dir, specs, environments=None, action="add"):
|
|
||||||
config = ProjectConfig.get_instance(os.path.join(project_dir, "platformio.ini"))
|
|
||||||
config.validate(environments)
|
|
||||||
for env in config.envs():
|
|
||||||
if environments and env not in environments:
|
|
||||||
continue
|
|
||||||
config.expand_interpolations = False
|
|
||||||
candidates = []
|
|
||||||
try:
|
|
||||||
candidates = ignore_deps_by_specs(
|
|
||||||
config.get("env:" + env, "lib_deps"), specs
|
|
||||||
)
|
|
||||||
except InvalidProjectConfError:
|
|
||||||
pass
|
|
||||||
if action == "add":
|
|
||||||
candidates.extend(spec.as_dependency() for spec in specs)
|
|
||||||
if candidates:
|
|
||||||
result = []
|
|
||||||
for item in candidates:
|
|
||||||
item = item.strip()
|
|
||||||
if item and item not in result:
|
|
||||||
result.append(item)
|
|
||||||
config.set("env:" + env, "lib_deps", result)
|
|
||||||
elif config.has_option("env:" + env, "lib_deps"):
|
|
||||||
config.remove_option("env:" + env, "lib_deps")
|
|
||||||
config.save()
|
|
@ -74,8 +74,8 @@ def platform_frameworks(query, json_output):
|
|||||||
if not json_output:
|
if not json_output:
|
||||||
click.secho(
|
click.secho(
|
||||||
"\nWARNING: This command is deprecated and will be removed in "
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
"the next releases. \nPlease https://docs.platformio.org"
|
"the next releases. \nPlease visit https://docs.platformio.org"
|
||||||
"/en/latest/frameworks/index.html.\n",
|
"/en/latest/frameworks/index.html\n",
|
||||||
fg="yellow",
|
fg="yellow",
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -129,7 +129,11 @@ def fetch_package_data(spec, pkg_type=None):
|
|||||||
return client.get_package(
|
return client.get_package(
|
||||||
pkg_type, spec.owner, spec.name, version=spec.requirements
|
pkg_type, spec.owner, spec.name, version=spec.requirements
|
||||||
)
|
)
|
||||||
qualifiers = dict(names=spec.name.lower())
|
qualifiers = {}
|
||||||
|
if spec.id:
|
||||||
|
qualifiers["ids"] = str(spec.id)
|
||||||
|
if spec.name:
|
||||||
|
qualifiers["names"] = spec.name.lower()
|
||||||
if pkg_type:
|
if pkg_type:
|
||||||
qualifiers["types"] = pkg_type
|
qualifiers["types"] = pkg_type
|
||||||
if spec.owner:
|
if spec.owner:
|
||||||
|
@ -15,10 +15,11 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from platformio.commands.lib.helpers import is_builtin_lib
|
from platformio import util
|
||||||
from platformio.package.exception import MissingPackageManifestError
|
from platformio.package.exception import MissingPackageManifestError
|
||||||
from platformio.package.manager.base import BasePackageManager
|
from platformio.package.manager.base import BasePackageManager
|
||||||
from platformio.package.meta import PackageSpec, PackageType
|
from platformio.package.meta import PackageSpec, PackageType
|
||||||
|
from platformio.platform.factory import PlatformFactory
|
||||||
from platformio.project.config import ProjectConfig
|
from platformio.project.config import ProjectConfig
|
||||||
|
|
||||||
|
|
||||||
@ -84,7 +85,39 @@ class LibraryPackageManager(BasePackageManager): # pylint: disable=too-many-anc
|
|||||||
# skip built-in dependencies
|
# skip built-in dependencies
|
||||||
not_builtin_conds = [spec.external, spec.owner]
|
not_builtin_conds = [spec.external, spec.owner]
|
||||||
if not any(not_builtin_conds):
|
if not any(not_builtin_conds):
|
||||||
not_builtin_conds.append(not is_builtin_lib(spec.name))
|
not_builtin_conds.append(not self.is_builtin_lib(spec.name))
|
||||||
if any(not_builtin_conds):
|
if any(not_builtin_conds):
|
||||||
return super().install_dependency(dependency)
|
return super().install_dependency(dependency)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@util.memoized(expire="60s")
|
||||||
|
def get_builtin_libs(storage_names=None):
|
||||||
|
# pylint: disable=import-outside-toplevel
|
||||||
|
from platformio.package.manager.platform import PlatformPackageManager
|
||||||
|
|
||||||
|
items = []
|
||||||
|
storage_names = storage_names or []
|
||||||
|
pm = PlatformPackageManager()
|
||||||
|
for pkg in pm.get_installed():
|
||||||
|
p = PlatformFactory.new(pkg)
|
||||||
|
for storage in p.get_lib_storages():
|
||||||
|
if storage_names and storage["name"] not in storage_names:
|
||||||
|
continue
|
||||||
|
lm = LibraryPackageManager(storage["path"])
|
||||||
|
items.append(
|
||||||
|
{
|
||||||
|
"name": storage["name"],
|
||||||
|
"path": storage["path"],
|
||||||
|
"items": lm.legacy_get_installed(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return items
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_builtin_lib(cls, name):
|
||||||
|
for storage in cls.get_builtin_libs():
|
||||||
|
for lib in storage["items"]:
|
||||||
|
if lib.get("name") == name:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
from os.path import isfile, join
|
from os.path import isfile, join
|
||||||
|
|
||||||
from platformio.commands.ci import cli as cmd_ci
|
from platformio.commands.ci import cli as cmd_ci
|
||||||
from platformio.commands.lib.command import cli as cmd_lib
|
from platformio.package.commands.install import package_install_cmd
|
||||||
|
|
||||||
|
|
||||||
def test_ci_empty(clirunner):
|
def test_ci_empty(clirunner):
|
||||||
@ -170,7 +170,8 @@ def test_ci_project_conf(clirunner, validate_cliresult):
|
|||||||
def test_ci_lib_and_board(clirunner, tmpdir_factory, validate_cliresult):
|
def test_ci_lib_and_board(clirunner, tmpdir_factory, validate_cliresult):
|
||||||
storage_dir = str(tmpdir_factory.mktemp("lib"))
|
storage_dir = str(tmpdir_factory.mktemp("lib"))
|
||||||
result = clirunner.invoke(
|
result = clirunner.invoke(
|
||||||
cmd_lib, ["--storage-dir", storage_dir, "install", "1@2.3.2"]
|
package_install_cmd,
|
||||||
|
["--global", "--storage-dir", storage_dir, "--library", "1"],
|
||||||
)
|
)
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
|
|
||||||
@ -182,7 +183,7 @@ def test_ci_lib_and_board(clirunner, tmpdir_factory, validate_cliresult):
|
|||||||
"OneWire",
|
"OneWire",
|
||||||
"examples",
|
"examples",
|
||||||
"DS2408_Switch",
|
"DS2408_Switch",
|
||||||
"DS2408_Switch.pde",
|
"DS2408_Switch.ino",
|
||||||
),
|
),
|
||||||
"-l",
|
"-l",
|
||||||
join(storage_dir, "OneWire"),
|
join(storage_dir, "OneWire"),
|
||||||
|
@ -20,7 +20,7 @@ import os
|
|||||||
import pytest
|
import pytest
|
||||||
import semantic_version
|
import semantic_version
|
||||||
|
|
||||||
from platformio.commands.lib.command import cli as cmd_lib
|
from platformio.commands.lib import cli as cmd_lib
|
||||||
from platformio.package.meta import PackageType
|
from platformio.package.meta import PackageType
|
||||||
from platformio.package.vcsclient import VCSClientFactory
|
from platformio.package.vcsclient import VCSClientFactory
|
||||||
from platformio.project.config import ProjectConfig
|
from platformio.project.config import ProjectConfig
|
||||||
@ -137,11 +137,7 @@ lib_deps =
|
|||||||
# test list
|
# test list
|
||||||
result = clirunner.invoke(cmd_lib, ["-d", str(project_dir), "list"])
|
result = clirunner.invoke(cmd_lib, ["-d", str(project_dir), "list"])
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
assert "Version: 0.8.3+sha." in result.stdout
|
assert "AsyncMqttClient-esphome @ 0.8.3+sha.f5aa899" in result.stdout
|
||||||
assert (
|
|
||||||
"Source: git+https://github.com/OttoWinter/async-mqtt-client.git#v0.8.3"
|
|
||||||
in result.stdout
|
|
||||||
)
|
|
||||||
result = clirunner.invoke(
|
result = clirunner.invoke(
|
||||||
cmd_lib, ["-d", str(project_dir), "list", "--json-output"]
|
cmd_lib, ["-d", str(project_dir), "list", "--json-output"]
|
||||||
)
|
)
|
||||||
|
@ -18,7 +18,7 @@ import json
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from platformio.cli import PlatformioCLI
|
from platformio.cli import PlatformioCLI
|
||||||
from platformio.commands.lib.command import cli as cmd_lib
|
from platformio.commands.lib import cli as cmd_lib
|
||||||
from platformio.package.exception import UnknownPackageError
|
from platformio.package.exception import UnknownPackageError
|
||||||
from platformio.util import strip_ansi_codes
|
from platformio.util import strip_ansi_codes
|
||||||
|
|
||||||
@ -28,12 +28,12 @@ PlatformioCLI.leftover_args = ["--json-output"] # hook for click
|
|||||||
def test_search(clirunner, validate_cliresult):
|
def test_search(clirunner, validate_cliresult):
|
||||||
result = clirunner.invoke(cmd_lib, ["search", "DHT22"])
|
result = clirunner.invoke(cmd_lib, ["search", "DHT22"])
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
match = re.search(r"Found\s+(\d+)\slibraries:", result.output)
|
match = re.search(r"Found\s+(\d+)\spackages", result.output)
|
||||||
assert int(match.group(1)) > 2
|
assert int(match.group(1)) > 2
|
||||||
|
|
||||||
result = clirunner.invoke(cmd_lib, ["search", "DHT22", "--platform=timsp430"])
|
result = clirunner.invoke(cmd_lib, ["search", "DHT22", "--platform=timsp430"])
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
match = re.search(r"Found\s+(\d+)\slibraries:", result.output)
|
match = re.search(r"Found\s+(\d+)\spackages", result.output)
|
||||||
assert int(match.group(1)) > 1
|
assert int(match.group(1)) > 1
|
||||||
|
|
||||||
|
|
||||||
@ -175,10 +175,10 @@ def test_global_lib_list(clirunner, validate_cliresult):
|
|||||||
assert all(
|
assert all(
|
||||||
n in result.output
|
n in result.output
|
||||||
for n in (
|
for n in (
|
||||||
"Source: https://github.com/Pedroalbuquerque/ESP32WebServer/archive/master.zip",
|
"required: https://github.com/Pedroalbuquerque/ESP32WebServer/archive/master.zip",
|
||||||
"Version: 5.10.1",
|
"ArduinoJson @ 5.10.1",
|
||||||
"Source: git+https://github.com/gioblu/PJON.git#3.0",
|
"required: git+https://github.com/gioblu/PJON.git#3.0",
|
||||||
"Version: 3.0.0+sha.1fb26fd",
|
"PJON @ 3.0.0+sha.1fb26f",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -251,11 +251,12 @@ def test_global_lib_update(clirunner, validate_cliresult):
|
|||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
assert "Removing NeoPixelBus @ 2.2.4" in strip_ansi_codes(result.output)
|
assert "Removing NeoPixelBus @ 2.2.4" in strip_ansi_codes(result.output)
|
||||||
|
|
||||||
# update rest libraries
|
# update all libraries
|
||||||
result = clirunner.invoke(cmd_lib, ["-g", "update"])
|
result = clirunner.invoke(
|
||||||
|
cmd_lib,
|
||||||
|
["-g", "update", "adafruit/Adafruit PN532", "marvinroger/AsyncMqttClient"],
|
||||||
|
)
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
assert result.output.count("+sha.") == 4
|
|
||||||
assert result.output.count("already up-to-date") == 14
|
|
||||||
|
|
||||||
# update unknown library
|
# update unknown library
|
||||||
result = clirunner.invoke(cmd_lib, ["-g", "update", "Unknown"])
|
result = clirunner.invoke(cmd_lib, ["-g", "update", "Unknown"])
|
||||||
@ -314,7 +315,7 @@ def test_global_lib_uninstall(clirunner, validate_cliresult, isolated_pio_core):
|
|||||||
def test_lib_show(clirunner, validate_cliresult):
|
def test_lib_show(clirunner, validate_cliresult):
|
||||||
result = clirunner.invoke(cmd_lib, ["show", "64"])
|
result = clirunner.invoke(cmd_lib, ["show", "64"])
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
assert all(s in result.output for s in ("ArduinoJson", "Arduino", "Atmel AVR"))
|
assert all(s in result.output for s in ("ArduinoJson", "Arduino"))
|
||||||
result = clirunner.invoke(cmd_lib, ["show", "OneWire", "--json-output"])
|
result = clirunner.invoke(cmd_lib, ["show", "OneWire", "--json-output"])
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
assert "OneWire" in result.output
|
assert "OneWire" in result.output
|
||||||
@ -328,13 +329,6 @@ def test_lib_builtin(clirunner, validate_cliresult):
|
|||||||
|
|
||||||
|
|
||||||
def test_lib_stats(clirunner, validate_cliresult):
|
def test_lib_stats(clirunner, validate_cliresult):
|
||||||
result = clirunner.invoke(cmd_lib, ["stats"])
|
|
||||||
validate_cliresult(result)
|
|
||||||
assert all(
|
|
||||||
s in result.output
|
|
||||||
for s in ("UPDATED", "POPULAR", "https://platformio.org/lib/show")
|
|
||||||
)
|
|
||||||
|
|
||||||
result = clirunner.invoke(cmd_lib, ["stats", "--json-output"])
|
result = clirunner.invoke(cmd_lib, ["stats", "--json-output"])
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
assert set(
|
assert set(
|
||||||
|
Reference in New Issue
Block a user