This commit is contained in:
2026-06-01 22:49:13 +03:00
parent 1b46ef6085
commit c1979b660a
9 changed files with 0 additions and 482 deletions
-2
View File
@@ -24,8 +24,6 @@ from platformio import exception, fs
from platformio.cli import PlatformioCLI
from platformio.package.commands.install import package_install_cmd
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
-2
View File
@@ -21,8 +21,6 @@ import click
from platformio.exception import UserSideException
from platformio.package.commands.install import package_install_cmd
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.manager.platform import PlatformPackageManager
-31
View File
@@ -1,31 +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.
from ajsonrpc.core import JSONRPC20DispatchException
from platformio.compat import aio_to_thread
from platformio.home.rpc.handlers.base import BaseRPCHandler
from platformio.registry.client import RegistryClient
class RegistryRPC(BaseRPCHandler):
@staticmethod
async def call_client(method, *args, **kwargs):
try:
client = RegistryClient()
return await aio_to_thread(getattr(client, method), *args, **kwargs)
except Exception as exc: # pylint: disable=bare-except
raise JSONRPC20DispatchException(
code=5000, message="Registry Call Error", data=str(exc)
) from exc
-4
View File
@@ -26,7 +26,6 @@ from starlette.status import HTTP_403_FORBIDDEN
from platformio.compat import aio_get_running_loop
from platformio.exception import PlatformioException
from platformio.home.rpc.handlers.account import AccountRPC
from platformio.home.rpc.handlers.app import AppRPC
from platformio.home.rpc.handlers.ide import IDERPC
from platformio.home.rpc.handlers.misc import MiscRPC
@@ -34,7 +33,6 @@ from platformio.home.rpc.handlers.os import OSRPC
from platformio.home.rpc.handlers.piocore import PIOCoreRPC
from platformio.home.rpc.handlers.platform import PlatformRPC
from platformio.home.rpc.handlers.project import ProjectRPC
from platformio.home.rpc.handlers.registry import RegistryRPC
from platformio.home.rpc.server import WebSocketJSONRPCServerFactory
from platformio.package.manager.core import get_core_package_dir
from platformio.proc import force_exit
@@ -70,7 +68,6 @@ def run_server(host, port, no_open, shutdown_timeout, home_url):
)
ws_rpc_factory = WebSocketJSONRPCServerFactory(shutdown_timeout)
ws_rpc_factory.add_object_handler(AccountRPC(), namespace="account")
ws_rpc_factory.add_object_handler(AppRPC(), namespace="app")
ws_rpc_factory.add_object_handler(IDERPC(), namespace="ide")
ws_rpc_factory.add_object_handler(MiscRPC(), namespace="misc")
@@ -78,7 +75,6 @@ def run_server(host, port, no_open, shutdown_timeout, home_url):
ws_rpc_factory.add_object_handler(PIOCoreRPC(), namespace="core")
ws_rpc_factory.add_object_handler(ProjectRPC(), namespace="project")
ws_rpc_factory.add_object_handler(PlatformRPC(), namespace="platform")
ws_rpc_factory.add_object_handler(RegistryRPC(), namespace="registry")
path = urlparse(home_url).path
routes = [
-8
View File
@@ -19,11 +19,7 @@ from platformio.package.commands.install import package_install_cmd
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.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.unpublish import package_unpublish_cmd
from platformio.package.commands.update import package_update_cmd
@@ -35,11 +31,7 @@ from platformio.package.commands.update import package_update_cmd
package_list_cmd,
package_outdated_cmd,
package_pack_cmd,
package_publish_cmd,
package_search_cmd,
package_show_cmd,
package_uninstall_cmd,
package_unpublish_cmd,
package_update_cmd,
],
short_help="Unified Package Manager",
-79
View File
@@ -1,79 +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 math
import click
from platformio import util
from platformio.registry.client import RegistryClient
@click.command("search", short_help="Search for packages")
@click.argument("query")
@click.option("-p", "--page", type=click.IntRange(min=1))
@click.option(
"-s",
"--sort",
type=click.Choice(["relevance", "popularity", "trending", "added", "updated"]),
)
def package_search_cmd(query, page, sort):
client = RegistryClient()
result = client.list_packages(query, page=page, sort=sort)
if not result["total"]:
click.secho("Nothing has been found by your request", fg="yellow")
click.echo(
"Try a less-specific search or use truncation (or wildcard) operator *"
)
return
print_search_result(result)
def print_search_result(result):
click.echo(
"Found %d packages (page %d of %d)"
% (
result["total"],
result["page"],
math.ceil(result["total"] / result["limit"]),
)
)
for item in result["items"]:
click.echo()
print_search_item(item)
def print_search_item(item):
click.echo(
"%s/%s"
% (
click.style(item["owner"]["username"], fg="cyan"),
click.style(item["name"], fg="cyan", bold=True),
)
)
click.echo(
"%s%s • Published on %s"
% (
(
item["type"].capitalize()
if item["tier"] == "community"
else click.style(
("%s %s" % (item["tier"], item["type"])).title(), bold=True
)
),
item["version"]["name"],
util.parse_datetime(item["version"]["released_at"]).strftime("%c"),
)
)
click.echo(item["description"])
-154
View File
@@ -1,154 +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.
from urllib.parse import quote
import click
from tabulate import tabulate
from platformio import fs, util
from platformio.exception import UserSideException
from platformio.package.manager._registry import PackageManagerRegistryMixin
from platformio.package.meta import PackageSpec, PackageType
from platformio.registry.client import RegistryClient
@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()
)
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 on %s"
% (
data["type"].capitalize(),
data["version"]["name"],
"Private" if data.get("private") else "Public",
util.parse_datetime(data["version"]["released_at"]).strftime("%c"),
)
)
# 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"),
]
type_plural = "libraries" if data["type"] == "library" else (data["type"] + "s")
extra = [
(
"Registry",
click.style(
"https://registry.platformio.org/%s/%s/%s"
% (type_plural, data["owner"]["username"], quote(data["name"])),
fg="blue",
),
)
]
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
)
qualifiers = {}
if spec.id:
qualifiers["ids"] = str(spec.id)
if spec.name:
qualifiers["names"] = spec.name.lower()
if pkg_type:
qualifiers["types"] = pkg_type
if spec.owner:
qualifiers["owners"] = spec.owner.lower()
packages = client.list_packages(qualifiers=qualifiers)["items"]
if not packages:
return None
if len(packages) > 1:
PackageManagerRegistryMixin.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,
)
-200
View File
@@ -1,200 +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 time
import click
from platformio import util
from platformio.package.exception import IncompatiblePackageError, UnknownPackageError
from platformio.package.meta import PackageSpec, PackageType
from platformio.package.version import cast_version_to_semver
from platformio.registry.client import RegistryClient
from platformio.registry.mirror import RegistryFileMirrorIterator
class PackageManagerRegistryMixin:
def install_from_registry(self, spec, search_qualifiers=None):
package = version = None
if spec.owner and spec.name and not search_qualifiers:
package = self.fetch_registry_package(spec)
if not package:
raise UnknownPackageError(spec.humanize())
version = self.pick_best_registry_version(package["versions"], spec)
elif spec.id or spec.name:
packages = self.search_registry_packages(spec, search_qualifiers)
if not packages:
raise UnknownPackageError(spec.humanize())
if len(packages) > 1:
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:
raise UnknownPackageError(spec.humanize())
pkgfile = self.pick_compatible_pkg_file(version["files"]) if version else None
if not pkgfile:
if self.pkg_type == PackageType.TOOL:
raise IncompatiblePackageError(spec.humanize(), util.get_systype())
raise UnknownPackageError(spec.humanize())
for url, checksum in RegistryFileMirrorIterator(pkgfile["download_url"]):
try:
return self.install_from_uri(
url,
PackageSpec(
owner=package["owner"]["username"],
id=package["id"],
name=package["name"],
),
checksum or pkgfile["checksum"]["sha256"],
)
except Exception as exc: # pylint: disable=broad-except
self.log.warning(
click.style("Warning! Package Mirror: %s" % exc, fg="yellow")
)
self.log.warning(
click.style("Looking for another mirror...", fg="yellow")
)
return None
def get_registry_client_instance(self):
if not self._registry_client:
self._registry_client = RegistryClient()
return self._registry_client
def search_registry_packages(self, spec, qualifiers=None):
assert isinstance(spec, PackageSpec)
qualifiers = qualifiers or {}
if spec.id:
qualifiers["ids"] = str(spec.id)
else:
qualifiers["types"] = self.pkg_type
qualifiers["names"] = spec.name.lower()
if spec.owner:
qualifiers["owners"] = spec.owner.lower()
return self.get_registry_client_instance().list_packages(qualifiers=qualifiers)[
"items"
]
def fetch_registry_package(self, spec):
assert isinstance(spec, PackageSpec)
result = None
regclient = self.get_registry_client_instance()
if spec.owner and spec.name:
result = regclient.get_package(self.pkg_type, spec.owner, spec.name)
if not result and (spec.id or (spec.name and not spec.owner)):
packages = self.search_registry_packages(spec)
if packages:
result = regclient.get_package(
self.pkg_type, packages[0]["owner"]["username"], packages[0]["name"]
)
if not result:
raise UnknownPackageError(spec.humanize())
return result
def reveal_registry_package_id(self, spec):
spec = self.ensure_spec(spec)
if spec.id:
return spec.id
packages = self.search_registry_packages(spec)
if not packages:
raise UnknownPackageError(spec.humanize())
if len(packages) > 1:
self.print_multi_package_issue(self.log.warning, packages, spec)
self.log.info("")
return packages[0]["id"]
@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"
)
+ click.style(spec.humanize(), fg="cyan")
+ click.style(" requirements:", fg="yellow")
)
for item in packages:
print_func(
" - {owner}/{name}@{version}".format(
owner=click.style(item["owner"]["username"], fg="cyan"),
name=item["name"],
version=item["version"]["name"],
)
)
print_func(
click.style(
"Please specify detailed REQUIREMENTS using package owner and version "
"(shown above) to avoid name conflicts",
fg="yellow",
)
)
def find_best_registry_version(self, packages, spec):
for package in packages:
# find compatible version within the latest package versions
version = self.pick_best_registry_version([package["version"]], spec)
if version:
return (package, version)
# if the custom version requirements, check ALL package versions
version = self.pick_best_registry_version(
self.fetch_registry_package(
PackageSpec(
id=package["id"],
owner=package["owner"]["username"],
name=package["name"],
)
).get("versions"),
spec,
)
if version:
return (package, version)
time.sleep(1)
return (None, None)
def get_compatible_registry_versions(self, versions, spec=None, custom_system=None):
assert not spec or isinstance(spec, PackageSpec)
result = []
for version in versions:
semver = cast_version_to_semver(version["name"])
if spec and spec.requirements and semver not in spec.requirements:
continue
if not any(
self.is_system_compatible(f.get("system"), custom_system=custom_system)
for f in version["files"]
):
continue
result.append(version)
return result
def pick_best_registry_version(self, versions, spec=None, custom_system=None):
best = None
for version in self.get_compatible_registry_versions(
versions, spec, custom_system
):
semver = cast_version_to_semver(version["name"])
if not best or (semver > cast_version_to_semver(best["name"])):
best = version
return best
def pick_compatible_pkg_file(self, version_files, custom_system=None):
for item in version_files:
if self.is_system_compatible(
item.get("system"), custom_system=custom_system
):
return item
return None
-2
View File
@@ -28,7 +28,6 @@ from platformio.package.lockfile import LockFile
from platformio.package.manager._download import PackageManagerDownloadMixin
from platformio.package.manager._install import PackageManagerInstallMixin
from platformio.package.manager._legacy import PackageManagerLegacyMixin
from platformio.package.manager._registry import PackageManagerRegistryMixin
from platformio.package.manager._symlink import PackageManagerSymlinkMixin
from platformio.package.manager._uninstall import PackageManagerUninstallMixin
from platformio.package.manager._update import PackageManagerUpdateMixin
@@ -50,7 +49,6 @@ class ClickLoggingHandler(logging.Handler):
class BasePackageManager( # pylint: disable=too-many-public-methods,too-many-instance-attributes
PackageManagerDownloadMixin,
PackageManagerRegistryMixin,
PackageManagerSymlinkMixin,
PackageManagerInstallMixin,
PackageManagerUninstallMixin,