Implement pio pkg show command // Issue #3373

This commit is contained in:
Ivan Kravets
2022-03-29 16:39:48 +03:00
parent d2f857d176
commit 6c8173d1aa
6 changed files with 262 additions and 8 deletions

View File

@ -17,9 +17,11 @@ PlatformIO Core 5
* `pio pkg exec <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_exec.html>`_ - run command from package tool (`issue #4163 <https://github.com/platformio/platformio-core/issues/4163>`_)
* `pio pkg install <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_install.html>`_ - install the project dependencies or custom packages
* `pio pkg list <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_list.html>`__ - list installed packages
* `pio pkg outdated <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_outdated.html>`__ - check for project outdated packages
* `pio pkg update <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_update.html>`__ - update the project dependencies or custom packages
* `pio pkg show <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_show.html>`__ - show package information
* `pio pkg uninstall <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_uninstall.html>`_ - uninstall the project dependencies or custom packages
* `pio pkg update <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_update.html>`__ - update the project dependencies or custom packages
- Added support for dependencies declared in a "tool" type package
- Ignore files according to the patterns declared in ".gitignore" when using `pio package pack <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_pack.html>`__ command (`issue #4188 <https://github.com/platformio/platformio-core/issues/4188>`_)

2
docs

Submodule docs updated: a04cdef33c...af80042f8d

View File

@ -20,6 +20,7 @@ from platformio.package.commands.list import package_list_cmd
from platformio.package.commands.outdated import package_outdated_cmd
from platformio.package.commands.pack import package_pack_cmd
from platformio.package.commands.publish import package_publish_cmd
from platformio.package.commands.show import package_show_cmd
from platformio.package.commands.uninstall import package_uninstall_cmd
from platformio.package.commands.unpublish import package_unpublish_cmd
from platformio.package.commands.update import package_update_cmd
@ -34,6 +35,7 @@ from platformio.package.commands.update import package_update_cmd
package_outdated_cmd,
package_pack_cmd,
package_publish_cmd,
package_show_cmd,
package_uninstall_cmd,
package_unpublish_cmd,
package_update_cmd,

View File

@ -0,0 +1,146 @@
# 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.
from urllib.parse import quote
import click
from tabulate import tabulate
from platformio import fs, util
from platformio.clients.registry import RegistryClient
from platformio.exception import UserSideException
from platformio.package.manager._registry import PackageManageRegistryMixin
from platformio.package.meta import PackageSpec, PackageType
@click.command("show", short_help="Show package information")
@click.argument("spec", metavar="[<owner>/]<pkg>[@<version>]")
@click.option(
"-t",
"--type",
"pkg_type",
type=click.Choice(list(PackageType.items().values())),
help="Package type",
)
def package_show_cmd(spec, pkg_type):
spec = PackageSpec(spec)
data = fetch_package_data(spec, pkg_type)
if not data:
raise UserSideException(
"Could not find '%s' package in the PlatormIO Registry" % spec.humanize()
)
type_plural = "libraries" if data["type"] == "library" else (data["type"] + "s")
click.echo()
click.echo(
"%s/%s"
% (
click.style(data["owner"]["username"], fg="cyan"),
click.style(data["name"], fg="cyan", bold=True),
)
)
click.echo(
"%s%s%s • Published %s"
% (
data["type"].capitalize(),
data["version"]["name"],
"Private" if data.get("private") else "Public",
util.parse_datetime(data["version"]["released_at"]).strftime("%c"),
)
)
click.echo()
click.secho(
"https://registry.platformio.org/%s/%s/%s"
% (type_plural, data["owner"]["username"], quote(data["name"])),
fg="blue",
)
# Description
click.echo()
click.echo(data["description"])
# Extra info
click.echo()
fields = [
("homepage", "Homepage"),
("repository_url", "Repository"),
("license", "License"),
("popularity_rank", "Popularity"),
("stars_count", "Stars"),
("examples_count", "Examples"),
("version.unpacked_size", "Installed Size"),
("dependents_count", "Used By"),
("dependencies_count", "Dependencies"),
("platforms", "Compatible Platforms"),
("frameworks", "Compatible Frameworks"),
("keywords", "Keywords"),
]
extra = []
for key, title in fields:
if "." in key:
k1, k2 = key.split(".")
value = data.get(k1, {}).get(k2)
else:
value = data.get(key)
if not value:
continue
if isinstance(value, list):
value = ", ".join(value)
elif key.endswith("_size"):
value = fs.humanize_file_size(value)
extra.append((title, value))
click.echo(tabulate(extra))
# Versions
click.echo("")
table = tabulate(
[
(
version["name"],
fs.humanize_file_size(max(f["size"] for f in version["files"])),
util.parse_datetime(version["released_at"]),
)
for version in data["versions"]
],
headers=["Version", "Size", "Published"],
)
click.echo(table)
click.echo("")
def fetch_package_data(spec, pkg_type=None):
assert isinstance(spec, PackageSpec)
client = RegistryClient()
if pkg_type and spec.owner and spec.name:
return client.get_package(
pkg_type, spec.owner, spec.name, version=spec.requirements
)
filters = dict(names=spec.name.lower())
if pkg_type:
filters["types"] = pkg_type
if spec.owner:
filters["owners"] = spec.owner.lower()
packages = client.list_packages(filters=filters)["items"]
if not packages:
return None
if len(packages) > 1:
PackageManageRegistryMixin.print_multi_package_issue(click.echo, packages, spec)
return None
return client.get_package(
packages[0]["type"],
packages[0]["owner"]["username"],
packages[0]["name"],
version=spec.requirements,
)

View File

@ -90,7 +90,7 @@ class PackageManageRegistryMixin(object):
if not packages:
raise UnknownPackageError(spec.humanize())
if len(packages) > 1:
self.print_multi_package_issue(packages, spec)
self.print_multi_package_issue(self.log.warning, packages, spec)
package, version = self.find_best_registry_version(packages, spec)
if not package or not version:
@ -164,12 +164,13 @@ class PackageManageRegistryMixin(object):
if not packages:
raise UnknownPackageError(spec.humanize())
if len(packages) > 1:
self.print_multi_package_issue(packages, spec)
self.print_multi_package_issue(self.log.warning, packages, spec)
self.log.info("")
return packages[0]["id"]
def print_multi_package_issue(self, packages, spec):
self.log.warning(
@staticmethod
def print_multi_package_issue(print_func, packages, spec):
print_func(
click.style(
"Warning! More than one package has been found by ", fg="yellow"
)
@ -178,14 +179,14 @@ class PackageManageRegistryMixin(object):
)
for item in packages:
self.log.warning(
print_func(
" - {owner}/{name}@{version}".format(
owner=click.style(item["owner"]["username"], fg="cyan"),
name=item["name"],
version=item["version"]["name"],
)
)
self.log.warning(
print_func(
click.style(
"Please specify detailed REQUIREMENTS using package owner and version "
"(shown above) to avoid name conflicts",

View File

@ -0,0 +1,103 @@
# 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 pytest
from platformio.exception import UserSideException
from platformio.package.commands.show import package_show_cmd
def test_spec_name(clirunner, validate_cliresult):
# library
result = clirunner.invoke(
package_show_cmd,
["ArduinoJSON"],
)
validate_cliresult(result)
assert "bblanchon/ArduinoJson" in result.output
assert "Library" in result.output
# platform
result = clirunner.invoke(
package_show_cmd,
["espressif32"],
)
validate_cliresult(result)
assert "platformio/espressif32" in result.output
assert "Platform" in result.output
# tool
result = clirunner.invoke(
package_show_cmd,
["tool-jlink"],
)
validate_cliresult(result)
assert "platformio/tool-jlink" in result.output
assert "tool" in result.output
def test_spec_owner(clirunner, validate_cliresult):
result = clirunner.invoke(
package_show_cmd,
["bblanchon/ArduinoJSON"],
)
validate_cliresult(result)
assert "bblanchon/ArduinoJson" in result.output
assert "Library" in result.output
# test broken owner
result = clirunner.invoke(
package_show_cmd,
["unknown/espressif32"],
)
with pytest.raises(UserSideException, match="Could not find"):
raise result.exception
def test_complete_spec(clirunner, validate_cliresult):
result = clirunner.invoke(
package_show_cmd,
["bblanchon/ArduinoJSON", "-t", "library"],
)
validate_cliresult(result)
assert "bblanchon/ArduinoJson" in result.output
assert "Library" in result.output
# tool
result = clirunner.invoke(
package_show_cmd,
["platformio/tool-jlink", "-t", "tool"],
)
validate_cliresult(result)
assert "platformio/tool-jlink" in result.output
assert "tool" in result.output
def test_name_conflict(clirunner):
result = clirunner.invoke(
package_show_cmd,
["OneWire", "-t", "library"],
)
assert "More than one package" in result.output
assert isinstance(result.exception, UserSideException)
def test_spec_version(clirunner, validate_cliresult):
result = clirunner.invoke(
package_show_cmd,
["bblanchon/ArduinoJSON@5.13.4"],
)
validate_cliresult(result)
assert "bblanchon/ArduinoJson" in result.output
assert "Library • 5.13.4" in result.output