Implement pio pkg update command // Issue #3373

This commit is contained in:
Ivan Kravets
2022-03-20 15:40:44 +02:00
parent 346580d955
commit 435a526140
16 changed files with 703 additions and 145 deletions

View File

@ -8,7 +8,7 @@ PlatformIO Core 5
**A professional collaborative platform for embedded development**
5.3.0 (2022-02-??)
5.3.0 (2022-??-??)
~~~~~~~~~~~~~~~~~~
* **Package Management**
@ -17,7 +17,9 @@ 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 outdated <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_pack.html>`__ - check for project outdated 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 uninstall <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_uninstall.html>`_ - uninstall 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: 7aa5b89963...cbf179f826

View File

@ -237,8 +237,13 @@ def lib_uninstall(ctx, libraries, save, silent):
def lib_update( # pylint: disable=too-many-arguments
ctx, libraries, only_check, dry_run, silent, json_output
):
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
only_check = dry_run or only_check
if only_check and not json_output:
raise exception.UserSideException(
"This command is deprecated, please use `pio pkg outdated` instead"
)
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
json_result = {}
for storage_dir in storage_dirs:
if not json_output:
@ -278,7 +283,7 @@ def lib_update( # pylint: disable=too-many-arguments
None if isinstance(library, PackageItem) else PackageSpec(library)
)
try:
lm.update(library, to_spec=to_spec, only_check=only_check)
lm.update(library, to_spec=to_spec)
except UnknownPackageError as e:
if library not in lib_deps:
raise e
@ -529,7 +534,7 @@ def lib_show(library, json_output):
@click.argument("config_url")
def lib_register(config_url): # pylint: disable=unused-argument
raise exception.UserSideException(
"This command is deprecated. Please use `pio package publish` command."
"This command is deprecated. Please use `pio pkg publish` command."
)

View File

@ -21,6 +21,7 @@ from platformio.package.commands.pack import package_pack_cmd
from platformio.package.commands.publish import package_publish_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
@click.group(
@ -28,11 +29,12 @@ from platformio.package.commands.unpublish import package_unpublish_cmd
commands=[
package_exec_cmd,
package_install_cmd,
package_uninstall_cmd,
package_outdated_cmd,
package_pack_cmd,
package_publish_cmd,
package_uninstall_cmd,
package_unpublish_cmd,
package_update_cmd,
],
short_help="Package Manager",
)

View File

@ -273,8 +273,13 @@ def platform_uninstall(platforms):
@click.option("-s", "--silent", is_flag=True, help="Suppress progress reporting")
@click.option("--json-output", is_flag=True)
def platform_update( # pylint: disable=too-many-locals, too-many-arguments
platforms, only_packages, only_check, dry_run, silent, json_output
platforms, only_check, dry_run, silent, json_output, **_
):
if only_check and not json_output:
raise UserSideException(
"This command is deprecated, please use `pio pkg outdated` instead"
)
pm = PlatformPackageManager()
pm.set_log_level(logging.WARN if silent else logging.DEBUG)
platforms = platforms or pm.get_installed()
@ -322,7 +327,7 @@ def platform_update( # pylint: disable=too-many-locals, too-many-arguments
)
)
click.echo("--------")
pm.update(platform, only_packages=only_packages, only_check=only_check)
pm.update(platform)
click.echo()
return True

View File

@ -42,7 +42,8 @@ def cli(ctx, core_packages, only_check, dry_run):
only_check = dry_run or only_check
update_core_packages(only_check)
if not only_check:
update_core_packages()
if core_packages:
return

View File

@ -22,6 +22,7 @@ import click
from platformio import VERSION, __version__, app, exception
from platformio.clients.http import fetch_remote_content
from platformio.compat import IS_WINDOWS
from platformio.package.manager.core import update_core_packages
from platformio.proc import exec_command, get_pythonexe_path
from platformio.project.helpers import get_project_cache_dir
@ -29,6 +30,7 @@ from platformio.project.helpers import get_project_cache_dir
@click.command("upgrade", short_help="Upgrade PlatformIO to the latest version")
@click.option("--dev", is_flag=True, help="Use development branch")
def cli(dev):
update_core_packages()
if not dev and __version__ == get_latest_version():
return click.secho(
"You're up-to-date!\nPlatformIO %s is currently the "

View File

@ -150,13 +150,10 @@ def after_upgrade(ctx):
return
else:
click.secho("Please wait while upgrading PlatformIO...", fg="yellow")
try:
cleanup_content_cache("http")
except: # pylint: disable=bare-except
pass
# Update PlatformIO's Core packages
update_core_packages(silent=True)
cleanup_content_cache("http")
update_core_packages()
u = Upgrader(last_version, __version__)
if u.run(ctx):
@ -219,7 +216,7 @@ def check_platformio_upgrade():
http.ensure_internet_on(raise_exception=True)
# Update PlatformIO Core packages
update_core_packages(silent=True)
update_core_packages()
latest_version = get_latest_version()
if pepver_to_semver(latest_version) <= pepver_to_semver(__version__):

View File

@ -0,0 +1,252 @@
# 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 logging
import os
import click
from platformio import fs
from platformio.package.manager.library import LibraryPackageManager
from platformio.package.manager.platform import PlatformPackageManager
from platformio.package.manager.tool import ToolPackageManager
from platformio.package.meta import PackageSpec
from platformio.project.config import ProjectConfig
from platformio.project.savedeps import pkg_to_save_spec, save_project_dependencies
@click.command(
"update", short_help="Update the project dependencies or custom packages"
)
@click.option(
"-d",
"--project-dir",
default=os.getcwd,
type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True),
)
@click.option("-e", "--environment", "environments", multiple=True)
@click.option("-p", "--platform", "platforms", multiple=True)
@click.option("-t", "--tool", "tools", multiple=True)
@click.option("-l", "--library", "libraries", multiple=True)
@click.option(
"--no-save",
is_flag=True,
help="Prevent saving specified packages to `platformio.ini`",
)
@click.option("--skip-dependencies", is_flag=True, help="Skip package dependencies")
@click.option("-g", "--global", is_flag=True, help="Update global packages")
@click.option(
"--storage-dir",
default=None,
type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True),
help="Custom Package Manager storage for global packages",
)
@click.option("-s", "--silent", is_flag=True, help="Suppress progress reporting")
def package_update_cmd(**options):
if options.get("global"):
update_global_dependencies(options)
else:
update_project_dependencies(options)
def update_global_dependencies(options):
pm = PlatformPackageManager(options.get("storage_dir"))
tm = ToolPackageManager(options.get("storage_dir"))
lm = LibraryPackageManager(options.get("storage_dir"))
for obj in (pm, tm, lm):
obj.set_log_level(logging.WARN if options.get("silent") else logging.DEBUG)
for spec in options.get("platforms"):
pm.update(
from_spec=spec,
to_spec=spec,
skip_dependencies=options.get("skip_dependencies"),
)
for spec in options.get("tools"):
tm.update(
from_spec=spec,
to_spec=spec,
skip_dependencies=options.get("skip_dependencies"),
)
for spec in options.get("libraries", []):
lm.update(
from_spec=spec,
to_spec=spec,
skip_dependencies=options.get("skip_dependencies"),
)
def update_project_dependencies(options):
environments = options["environments"]
with fs.cd(options["project_dir"]):
config = ProjectConfig.get_instance()
config.validate(environments)
for env in config.envs():
if environments and env not in environments:
continue
if not options["silent"]:
click.echo(
"Resolving %s environment packages..." % click.style(env, fg="cyan")
)
already_up_to_date = not update_project_env_dependencies(env, options)
if not options["silent"] and already_up_to_date:
click.secho("Already up-to-date.", fg="green")
def update_project_env_dependencies(project_env, options=None):
options = options or {}
updated_conds = []
# custom platforms
if options.get("platforms"):
updated_conds.append(_update_project_env_custom_platforms(project_env, options))
# custom tools
if options.get("tools"):
updated_conds.append(_update_project_env_custom_tools(project_env, options))
# custom ibraries
if options.get("libraries"):
updated_conds.append(_update_project_env_custom_libraries(project_env, options))
# declared dependencies
if not updated_conds:
updated_conds = [
_update_project_env_platform(project_env, options),
_update_project_env_libraries(project_env, options),
]
return any(updated_conds)
def _update_project_env_platform(project_env, options):
config = ProjectConfig.get_instance()
pm = PlatformPackageManager()
if options.get("silent"):
pm.set_log_level(logging.WARN)
spec = config.get(f"env:{project_env}", "platform")
if not spec:
return None
cur_pkg = pm.get_package(spec)
if not cur_pkg:
return None
new_pkg = PlatformPackageManager().update(
cur_pkg,
to_spec=spec,
project_env=project_env,
skip_dependencies=options.get("skip_dependencies"),
)
return cur_pkg != new_pkg
def _update_project_env_custom_platforms(project_env, options):
already_up_to_date = True
pm = PlatformPackageManager()
if not options.get("silent"):
pm.set_log_level(logging.DEBUG)
for spec in options.get("platforms"):
cur_pkg = pm.get_package(spec)
new_pkg = pm.update(
cur_pkg,
to_spec=spec,
project_env=project_env,
skip_dependencies=options.get("skip_dependencies"),
)
if cur_pkg != new_pkg:
already_up_to_date = False
return not already_up_to_date
def _update_project_env_custom_tools(project_env, options):
already_up_to_date = True
tm = ToolPackageManager()
if not options.get("silent"):
tm.set_log_level(logging.DEBUG)
specs_to_save = []
for tool in options.get("tools"):
spec = PackageSpec(tool)
cur_pkg = tm.get_package(spec)
new_pkg = tm.update(
cur_pkg,
to_spec=spec,
skip_dependencies=options.get("skip_dependencies"),
)
if cur_pkg != new_pkg:
already_up_to_date = False
specs_to_save.append(pkg_to_save_spec(new_pkg, spec))
if not options.get("no_save") and specs_to_save:
save_project_dependencies(
os.getcwd(),
specs_to_save,
scope="platform_packages",
action="add",
environments=[project_env],
)
return not already_up_to_date
def _update_project_env_libraries(project_env, options):
already_up_to_date = True
config = ProjectConfig.get_instance()
lm = LibraryPackageManager(
os.path.join(config.get("platformio", "libdeps_dir"), project_env)
)
if options.get("silent"):
lm.set_log_level(logging.WARN)
for library in config.get(f"env:{project_env}", "lib_deps"):
spec = PackageSpec(library)
# skip built-in dependencies
if not spec.external and not spec.owner:
continue
cur_pkg = lm.get_package(spec)
if cur_pkg:
new_pkg = lm.update(
cur_pkg,
to_spec=spec,
skip_dependencies=options.get("skip_dependencies"),
)
if cur_pkg != new_pkg:
already_up_to_date = False
return not already_up_to_date
def _update_project_env_custom_libraries(project_env, options):
already_up_to_date = True
config = ProjectConfig.get_instance()
lm = LibraryPackageManager(
os.path.join(config.get("platformio", "libdeps_dir"), project_env)
)
if not options.get("silent"):
lm.set_log_level(logging.DEBUG)
specs_to_save = []
for library in options.get("libraries") or []:
spec = PackageSpec(library)
cur_pkg = lm.get_package(spec)
new_pkg = lm.update(
cur_pkg,
to_spec=spec,
skip_dependencies=options.get("skip_dependencies"),
)
if cur_pkg != new_pkg:
already_up_to_date = False
specs_to_save.append(pkg_to_save_spec(new_pkg, spec))
if not options.get("no_save") and specs_to_save:
save_project_dependencies(
os.getcwd(),
specs_to_save,
scope="lib_deps",
action="add",
environments=[project_env],
)
return not already_up_to_date

View File

@ -12,12 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import os
import click
from platformio.clients.http import ensure_internet_on
from platformio.package.exception import UnknownPackageError
from platformio.package.meta import PackageItem, PackageOutdatedResult, PackageSpec
from platformio.package.vcsclient import VCSBaseException, VCSClientFactory
@ -26,9 +24,11 @@ from platformio.package.vcsclient import VCSBaseException, VCSClientFactory
class PackageManagerUpdateMixin(object):
def outdated(self, pkg, spec=None):
assert isinstance(pkg, PackageItem)
assert not spec or isinstance(spec, PackageSpec)
assert pkg.metadata
if spec and not isinstance(spec, PackageSpec):
spec = PackageSpec(spec)
if not os.path.isdir(pkg.path):
return PackageOutdatedResult(current=pkg.metadata.version)
@ -82,82 +82,35 @@ class PackageManagerUpdateMixin(object):
self,
from_spec,
to_spec=None,
only_check=False,
show_incompatible=True,
skip_dependencies=False,
):
pkg = self.get_package(from_spec)
if not pkg or not pkg.metadata:
raise UnknownPackageError(from_spec)
silent = not self.log.isEnabledFor(logging.INFO)
if not silent:
click.echo(
"{} {:<45} {:<35}".format(
"Checking" if only_check else "Updating",
click.style(pkg.metadata.spec.humanize(), fg="cyan"),
"%s @ %s" % (pkg.metadata.version, to_spec.requirements)
if to_spec and to_spec.requirements
else str(pkg.metadata.version),
),
nl=False,
)
if not ensure_internet_on():
if not silent:
click.echo("[%s]" % (click.style("Off-line", fg="yellow")))
return pkg
outdated = self.outdated(pkg, to_spec)
if not silent:
self.print_outdated_state(outdated, only_check, show_incompatible)
if only_check or not outdated.is_outdated(allow_incompatible=False):
if not outdated.is_outdated(allow_incompatible=False):
self.log.debug(
click.style(
"{name} @ {version} is already up-to-date".format(
**pkg.metadata.as_dict()
),
fg="yellow",
)
)
return pkg
self.log.info(
"Updating %s @ %s"
% (click.style(pkg.metadata.name, fg="cyan"), pkg.metadata.version)
)
try:
self.lock()
return self._update(pkg, outdated)
return self._update(pkg, outdated, skip_dependencies)
finally:
self.unlock()
@staticmethod
def print_outdated_state(outdated, only_check, show_incompatible):
if outdated.detached:
return click.echo("[%s]" % (click.style("Detached", fg="yellow")))
if (
not outdated.latest
or outdated.current == outdated.latest
or (not show_incompatible and outdated.current == outdated.wanted)
):
return click.echo("[%s]" % (click.style("Up-to-date", fg="green")))
if outdated.wanted and outdated.current == outdated.wanted:
return click.echo(
"[%s]" % (click.style("Incompatible %s" % outdated.latest, fg="yellow"))
)
if only_check:
return click.echo(
"[%s]"
% (
click.style(
"Outdated %s" % str(outdated.wanted or outdated.latest),
fg="red",
)
)
)
return click.echo(
"[%s]"
% (
click.style(
"Updating to %s" % str(outdated.wanted or outdated.latest),
fg="green",
)
)
)
def _update(self, pkg, outdated):
def _update(self, pkg, outdated, skip_dependencies=False):
if pkg.metadata.spec.external:
vcs = VCSClientFactory.new(pkg.path, pkg.metadata.spec.url)
assert vcs.update()
@ -165,23 +118,15 @@ class PackageManagerUpdateMixin(object):
pkg.dump_meta()
return pkg
new_pkg = self.install(
# uninstall existing version
self.uninstall(pkg, skip_dependencies=True)
return self.install(
PackageSpec(
id=pkg.metadata.spec.id,
owner=pkg.metadata.spec.owner,
name=pkg.metadata.spec.name,
requirements=outdated.wanted or outdated.latest,
)
),
skip_dependencies=skip_dependencies,
)
if new_pkg:
old_pkg = self.get_package(
PackageSpec(
id=pkg.metadata.spec.id,
owner=pkg.metadata.spec.owner,
name=pkg.metadata.name,
requirements=pkg.metadata.version,
)
)
if old_pkg:
self.uninstall(old_pkg, skip_dependencies=True)
return new_pkg

View File

@ -55,17 +55,15 @@ def get_core_package_dir(name, auto_install=True):
return pm.get_package(spec).path
def update_core_packages(only_check=False, silent=False):
def update_core_packages():
pm = ToolPackageManager()
for name, requirements in __core_packages__.items():
spec = PackageSpec(owner="platformio", name=name, requirements=requirements)
pkg = pm.get_package(spec)
if not pkg:
continue
if not silent or pm.outdated(pkg, spec).is_outdated():
pm.update(pkg, spec, only_check=only_check)
if not only_check:
remove_unnecessary_core_packages()
try:
pm.update(spec, spec)
except UnknownPackageError:
pass
remove_unnecessary_core_packages()
return True

View File

@ -85,45 +85,28 @@ class PlatformPackageManager(BasePackageManager): # pylint: disable=too-many-an
p.on_uninstalled()
return pkg
def update( # pylint: disable=arguments-differ, too-many-arguments
def update( # pylint: disable=arguments-differ
self,
from_spec,
to_spec=None,
only_check=False,
show_incompatible=True,
only_packages=False,
skip_dependencies=False,
project_env=None,
):
pkg = self.get_package(from_spec)
if not pkg or not pkg.metadata:
raise UnknownPackageError(from_spec)
pkg = super(PlatformPackageManager, self).update(
from_spec,
to_spec,
)
p = PlatformFactory.new(pkg)
# set logging level for underlying tool manager
p.pm.set_log_level(self.log.getEffectiveLevel())
pkgs_before = [item.metadata.name for item in p.get_installed_packages()]
new_pkg = None
missed_pkgs = set()
if not only_packages:
new_pkg = super(PlatformPackageManager, self).update(
from_spec,
to_spec,
only_check=only_check,
show_incompatible=show_incompatible,
)
p = PlatformFactory.new(new_pkg)
missed_pkgs = set(pkgs_before) & set(p.packages)
missed_pkgs -= set(
item.metadata.name for item in p.get_installed_packages()
)
p.update_packages(only_check)
if missed_pkgs:
p.install_packages(
with_packages=list(missed_pkgs), skip_default_package=True
)
return new_pkg or pkg
if project_env:
p.configure_project_packages(project_env)
if not skip_dependencies:
p.update_packages()
return pkg
@util.memoized(expire="5s")
def get_installed_boards(self):

View File

@ -0,0 +1,356 @@
# 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.
# pylint: disable=unused-argument
import os
from platformio import fs
from platformio.package.commands.install import package_install_cmd
from platformio.package.commands.update import package_update_cmd
from platformio.package.exception import UnknownPackageError
from platformio.package.manager.library import LibraryPackageManager
from platformio.package.manager.platform import PlatformPackageManager
from platformio.package.manager.tool import ToolPackageManager
from platformio.package.meta import PackageSpec
from platformio.project.config import ProjectConfig
PROJECT_OUTDATED_CONFIG_TPL = """
[env:devkit]
platform = platformio/atmelavr@^2
framework = arduino
board = attiny88
lib_deps = milesburton/DallasTemperature@~3.8.0
"""
PROJECT_UPDATED_CONFIG_TPL = """
[env:devkit]
platform = platformio/atmelavr@<4
framework = arduino
board = attiny88
lib_deps = milesburton/DallasTemperature@^3.8.0
"""
def pkgs_to_specs(pkgs):
return [
PackageSpec(name=pkg.metadata.name, requirements=pkg.metadata.version)
for pkg in pkgs
]
def test_global_packages(
clirunner, validate_cliresult, func_isolated_pio_core, tmp_path
):
# libraries
result = clirunner.invoke(
package_install_cmd,
["--global", "-l", "bblanchon/ArduinoJson@^5"],
)
validate_cliresult(result)
assert pkgs_to_specs(LibraryPackageManager().get_installed()) == [
PackageSpec("ArduinoJson@5.13.4")
]
# update to the latest version
result = clirunner.invoke(
package_update_cmd,
["--global", "-l", "bblanchon/ArduinoJson"],
)
validate_cliresult(result)
pkgs = LibraryPackageManager().get_installed()
assert len(pkgs) == 1
assert pkgs[0].metadata.version.major > 5
# custom storage
storage_dir = tmp_path / "custom_lib_storage"
storage_dir.mkdir()
result = clirunner.invoke(
package_install_cmd,
[
"--global",
"--storage-dir",
str(storage_dir),
"-l",
"bblanchon/ArduinoJson@^5",
],
)
validate_cliresult(result)
assert pkgs_to_specs(LibraryPackageManager(storage_dir).get_installed()) == [
PackageSpec("ArduinoJson@5.13.4")
]
# update to the latest version
result = clirunner.invoke(
package_update_cmd,
["--global", "--storage-dir", str(storage_dir), "-l", "bblanchon/ArduinoJson"],
)
validate_cliresult(result)
pkgs = LibraryPackageManager(storage_dir).get_installed()
assert len(pkgs) == 1
assert pkgs[0].metadata.version.major > 5
# tools
result = clirunner.invoke(
package_install_cmd,
["--global", "-t", "platformio/framework-arduino-avr-attiny@~1.4"],
)
validate_cliresult(result)
assert pkgs_to_specs(ToolPackageManager().get_installed()) == [
PackageSpec("framework-arduino-avr-attiny@1.4.1")
]
# update to the latest version
result = clirunner.invoke(
package_update_cmd,
["--global", "-t", "platformio/framework-arduino-avr-attiny@^1"],
)
validate_cliresult(result)
pkgs = ToolPackageManager().get_installed()
assert len(pkgs) == 1
assert pkgs[0].metadata.version.major == 1
assert pkgs[0].metadata.version.minor > 4
# platforms
result = clirunner.invoke(
package_install_cmd,
["--global", "-p", "platformio/atmelavr@^2", "--skip-dependencies"],
)
validate_cliresult(result)
assert pkgs_to_specs(PlatformPackageManager().get_installed()) == [
PackageSpec("atmelavr@2.2.0")
]
# update to the latest version
result = clirunner.invoke(
package_update_cmd,
["--global", "-p", "platformio/atmelavr", "--skip-dependencies"],
)
validate_cliresult(result)
pkgs = PlatformPackageManager().get_installed()
assert len(pkgs) == 1
assert pkgs[0].metadata.version.major > 2
# update unknown package
result = clirunner.invoke(
package_update_cmd,
["--global", "-l", "platformio/unknown_package_for_update"],
)
assert isinstance(result.exception, UnknownPackageError)
def test_project(clirunner, validate_cliresult, isolated_pio_core, tmp_path):
project_dir = tmp_path / "project"
project_dir.mkdir()
(project_dir / "platformio.ini").write_text(PROJECT_OUTDATED_CONFIG_TPL)
result = clirunner.invoke(
package_install_cmd,
["-d", str(project_dir)],
)
validate_cliresult(result)
with fs.cd(str(project_dir)):
config = ProjectConfig()
lm = LibraryPackageManager(
os.path.join(config.get("platformio", "libdeps_dir"), "devkit")
)
assert pkgs_to_specs(lm.get_installed()) == [
PackageSpec("DallasTemperature@3.8.1"),
PackageSpec("OneWire@2.3.6"),
]
assert pkgs_to_specs(PlatformPackageManager().get_installed()) == [
PackageSpec("atmelavr@2.2.0")
]
assert pkgs_to_specs(ToolPackageManager().get_installed()) == [
PackageSpec("framework-arduino-avr-attiny@1.3.2"),
PackageSpec("toolchain-atmelavr@1.50400.190710"),
]
assert config.get("env:devkit", "lib_deps") == [
"milesburton/DallasTemperature@~3.8.0"
]
# update packages
(project_dir / "platformio.ini").write_text(PROJECT_UPDATED_CONFIG_TPL)
result = clirunner.invoke(package_update_cmd)
validate_cliresult(result)
config = ProjectConfig()
lm = LibraryPackageManager(
os.path.join(config.get("platformio", "libdeps_dir"), "devkit")
)
pkgs = PlatformPackageManager().get_installed()
assert len(pkgs) == 1
assert pkgs[0].metadata.name == "atmelavr"
assert pkgs[0].metadata.version.major == 3
assert pkgs_to_specs(lm.get_installed()) == [
PackageSpec("DallasTemperature@3.9.1"),
PackageSpec("OneWire@2.3.6"),
]
assert pkgs_to_specs(ToolPackageManager().get_installed()) == [
PackageSpec("framework-arduino-avr-attiny@1.3.2"),
PackageSpec("toolchain-atmelavr@1.70300.191015"),
PackageSpec("toolchain-atmelavr@1.50400.190710"),
]
assert config.get("env:devkit", "lib_deps") == [
"milesburton/DallasTemperature@^3.8.0"
]
# update again
result = clirunner.invoke(package_update_cmd)
validate_cliresult(result)
assert "Already up-to-date." in result.output
# update again in the silent ,pde
result = clirunner.invoke(package_update_cmd, ["--silent"])
validate_cliresult(result)
assert not result.output
def test_custom_project_libraries(
clirunner, validate_cliresult, isolated_pio_core, tmp_path
):
project_dir = tmp_path / "project"
project_dir.mkdir()
(project_dir / "platformio.ini").write_text(PROJECT_OUTDATED_CONFIG_TPL)
spec = "milesburton/DallasTemperature@~3.8.0"
result = clirunner.invoke(
package_install_cmd,
["-d", str(project_dir), "-e", "devkit", "-l", spec],
)
validate_cliresult(result)
with fs.cd(str(project_dir)):
config = ProjectConfig()
assert config.get("env:devkit", "lib_deps") == [spec]
lm = LibraryPackageManager(
os.path.join(config.get("platformio", "libdeps_dir"), "devkit")
)
assert pkgs_to_specs(lm.get_installed()) == [
PackageSpec("DallasTemperature@3.8.1"),
PackageSpec("OneWire@2.3.6"),
]
# update package
result = clirunner.invoke(
package_update_cmd,
["-e", "devkit", "-l", "milesburton/DallasTemperature@^3.8.0"],
)
assert ProjectConfig().get("env:devkit", "lib_deps") == [
"milesburton/DallasTemperature@^3.8.0"
]
# try again
result = clirunner.invoke(
package_update_cmd,
["-e", "devkit", "-l", "milesburton/DallasTemperature@^3.8.0"],
)
validate_cliresult(result)
assert "Already up-to-date." in result.output
# install library without saving to config
result = clirunner.invoke(
package_update_cmd,
["-e", "devkit", "-l", "milesburton/DallasTemperature@^3", "--no-save"],
)
validate_cliresult(result)
assert "Already up-to-date." in result.output
config = ProjectConfig()
lm = LibraryPackageManager(
os.path.join(config.get("platformio", "libdeps_dir"), "devkit")
)
assert pkgs_to_specs(lm.get_installed()) == [
PackageSpec("DallasTemperature@3.9.1"),
PackageSpec("OneWire@2.3.6"),
]
assert config.get("env:devkit", "lib_deps") == [
"milesburton/DallasTemperature@^3.8.0"
]
# unknown libraries
result = clirunner.invoke(
package_update_cmd, ["-l", "platformio/unknown_library"]
)
assert isinstance(result.exception, UnknownPackageError)
def test_custom_project_tools(
clirunner, validate_cliresult, func_isolated_pio_core, tmp_path
):
project_dir = tmp_path / "project"
project_dir.mkdir()
(project_dir / "platformio.ini").write_text(PROJECT_OUTDATED_CONFIG_TPL)
spec = "toolchain-atmelavr@~1.50400.0"
result = clirunner.invoke(
package_install_cmd,
["-d", str(project_dir), "-e", "devkit", "-t", spec],
)
validate_cliresult(result)
with fs.cd(str(project_dir)):
assert ProjectConfig().get("env:devkit", "platform_packages") == [
"platformio/toolchain-atmelavr@~1.50400.0"
]
assert pkgs_to_specs(ToolPackageManager().get_installed()) == [
PackageSpec("toolchain-atmelavr@1.50400.190710")
]
result = clirunner.invoke(
package_update_cmd,
["-e", "devkit", "-t", "toolchain-atmelavr@^1"],
)
validate_cliresult(result)
assert ProjectConfig().get("env:devkit", "platform_packages") == [
"platformio/toolchain-atmelavr@^1"
]
assert pkgs_to_specs(ToolPackageManager().get_installed()) == [
PackageSpec("toolchain-atmelavr@1.70300.191015")
]
# install without saving to config
result = clirunner.invoke(
package_update_cmd,
["-e", "devkit", "-t", "toolchain-atmelavr@~1.70300.191015", "--no-save"],
)
validate_cliresult(result)
assert "Already up-to-date." in result.output
assert ProjectConfig().get("env:devkit", "platform_packages") == [
"platformio/toolchain-atmelavr@^1"
]
# unknown tool
result = clirunner.invoke(package_update_cmd, ["-t", "platformio/unknown_tool"])
assert isinstance(result.exception, UnknownPackageError)
def test_custom_project_platforms(
clirunner, validate_cliresult, func_isolated_pio_core, tmp_path
):
project_dir = tmp_path / "project"
project_dir.mkdir()
(project_dir / "platformio.ini").write_text(PROJECT_OUTDATED_CONFIG_TPL)
spec = "atmelavr@^2"
result = clirunner.invoke(
package_install_cmd,
["-d", str(project_dir), "-e", "devkit", "-p", spec, "--skip-dependencies"],
)
validate_cliresult(result)
with fs.cd(str(project_dir)):
assert pkgs_to_specs(PlatformPackageManager().get_installed()) == [
PackageSpec("atmelavr@2.2.0")
]
assert ProjectConfig().get("env:devkit", "platform") == "platformio/atmelavr@^2"
# update
result = clirunner.invoke(
package_install_cmd,
["-e", "devkit", "-p", "platformio/atmelavr@^3", "--skip-dependencies"],
)
validate_cliresult(result)
assert pkgs_to_specs(PlatformPackageManager().get_installed()) == [
PackageSpec("atmelavr@3.4.0"),
PackageSpec("atmelavr@2.2.0"),
]
assert ProjectConfig().get("env:devkit", "platform") == "platformio/atmelavr@^2"
# unknown platform
result = clirunner.invoke(package_install_cmd, ["-p", "unknown_platform"])
assert isinstance(result.exception, UnknownPackageError)

View File

@ -17,6 +17,7 @@
import json
import os
import pytest
import semantic_version
from platformio.clients.registry import RegistryClient
@ -225,5 +226,13 @@ def test_update(clirunner, validate_cliresult, isolated_pio_core, tmpdir_factory
result = clirunner.invoke(
cmd_lib, ["-d", str(storage_dir), "update", "--dry-run", "ArduinoJson @ ^5"]
)
with pytest.raises(
AssertionError,
match="This command is deprecated",
):
validate_cliresult(result)
result = clirunner.invoke(
cmd_lib, ["-d", str(storage_dir), "update", "ArduinoJson @ ^5"]
)
validate_cliresult(result)
assert "Incompatible" in result.stdout
assert "ArduinoJson @ 5.13.4 is already up-to-date" in result.stdout

View File

@ -253,8 +253,8 @@ def test_global_lib_update(clirunner, validate_cliresult, strip_ansi):
# update rest libraries
result = clirunner.invoke(cmd_lib, ["-g", "update"])
validate_cliresult(result)
assert result.output.count("[Detached]") == 1
assert result.output.count("[Up-to-date]") == 13
assert result.output.count("+sha.") == 4
assert result.output.count("already up-to-date") == 14
# update unknown library
result = clirunner.invoke(cmd_lib, ["-g", "update", "Unknown"])
@ -290,17 +290,18 @@ def test_global_lib_uninstall(
items1 = [d.basename for d in isolated_pio_core.join("lib").listdir()]
items2 = [
"ArduinoJson",
"ArduinoJson@src-69ebddd821f771debe7ee734d3c7fa81",
"AsyncMqttClient",
"AsyncTCP",
"ESP32WebServer",
"ESPAsyncTCP",
"NeoPixelBus",
"PJON",
"PJON@src-79de467ebe19de18287becff0a1fb42d",
"platformio-libmirror",
"PubSubClient",
"ArduinoJson@src-69ebddd821f771debe7ee734d3c7fa81",
"ESPAsyncTCP@1.2.0",
"AsyncTCP",
"ArduinoJson",
"ESPAsyncTCP",
"ESP32WebServer",
"PJON",
"NeoPixelBus",
"PJON@src-79de467ebe19de18287becff0a1fb42d",
"SomeLib",
]
assert set(items1) == set(items2)

View File

@ -19,7 +19,7 @@ from platformio.commands.update import cli as cmd_update
def test_update(clirunner, validate_cliresult, isolated_pio_core):
matches = ("Platform Manager", "Library Manager")
result = clirunner.invoke(cmd_update, ["--only-check"])
result = clirunner.invoke(cmd_update)
validate_cliresult(result)
assert all(m in result.output for m in matches)
result = clirunner.invoke(cmd_update)