Allow to skip saving of package dependencies to the "platformio.ini" // Issue #3373

This commit is contained in:
Ivan Kravets
2022-03-09 19:07:11 +02:00
parent eba4231cdc
commit 2201214717
5 changed files with 256 additions and 7 deletions

2
docs

Submodule docs updated: 0c41108fe3...4c8e6f1fbf

View File

@ -21,7 +21,9 @@ from platformio import fs
from platformio.package.manager.library import LibraryPackageManager from platformio.package.manager.library import LibraryPackageManager
from platformio.package.manager.platform import PlatformPackageManager from platformio.package.manager.platform import PlatformPackageManager
from platformio.package.manager.tool import ToolPackageManager from platformio.package.manager.tool import ToolPackageManager
from platformio.package.meta import PackageSpec
from platformio.project.config import ProjectConfig from platformio.project.config import ProjectConfig
from platformio.project.savedeps import save_project_dependencies
@click.command( @click.command(
@ -37,13 +39,18 @@ from platformio.project.config import ProjectConfig
@click.option("-p", "--platform", "platforms", multiple=True) @click.option("-p", "--platform", "platforms", multiple=True)
@click.option("-t", "--tool", "tools", multiple=True) @click.option("-t", "--tool", "tools", multiple=True)
@click.option("-l", "--library", "libraries", 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("--skip-dependencies", is_flag=True, help="Skip package dependencies")
@click.option("-g", "--global", is_flag=True, help="Install package globally") @click.option("-g", "--global", is_flag=True, help="Install package globally")
@click.option( @click.option(
"--storage-dir", "--storage-dir",
default=None, default=None,
type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True), type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True),
help="Custom package storage directory", help="Custom Package Manager storage for global packages",
) )
@click.option("-f", "--force", is_flag=True, help="Reinstall package if it exists") @click.option("-f", "--force", is_flag=True, help="Reinstall package if it exists")
@click.option("-s", "--silent", is_flag=True, help="Suppress progress reporting") @click.option("-s", "--silent", is_flag=True, help="Suppress progress reporting")
@ -168,21 +175,33 @@ def _install_project_env_libraries(project_env, options):
if options.get("libraries"): if options.get("libraries"):
if not options.get("silent"): if not options.get("silent"):
lm.set_log_level(logging.DEBUG) lm.set_log_level(logging.DEBUG)
for spec in options.get("libraries", []): specs_to_save = []
lm.install( for library in options.get("libraries", []):
spec = PackageSpec(library)
pkg = lm.install(
spec, spec,
skip_dependencies=options.get("skip_dependencies"), skip_dependencies=options.get("skip_dependencies"),
force=options.get("force"), force=options.get("force"),
) )
specs_to_save.append(_pkg_to_save_spec(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 return not already_up_to_date
if options.get("platforms") or options.get("tools"): if options.get("platforms") or options.get("tools"):
return False return False
# if not custom platforms/tools, install declared libraries # if not custom platforms/tools, install declared libraries
for spec in config.get(f"env:{project_env}", "lib_deps"): for library in config.get(f"env:{project_env}", "lib_deps"):
spec = PackageSpec(library)
# skip built-in dependencies # skip built-in dependencies
if "/" not in spec: if not spec.external and not spec.owner:
continue continue
if not lm.get_package(spec): if not lm.get_package(spec):
already_up_to_date = False already_up_to_date = False
@ -192,3 +211,19 @@ def _install_project_env_libraries(project_env, options):
force=options.get("force"), force=options.get("force"),
) )
return not already_up_to_date return not already_up_to_date
def _pkg_to_save_spec(pkg, user_spec):
assert isinstance(user_spec, PackageSpec)
if user_spec.external:
return user_spec
return PackageSpec(
owner=pkg.metadata.spec.owner,
name=pkg.metadata.spec.name,
requirements=user_spec.requirements
or (
("^%s" % pkg.metadata.version)
if not pkg.metadata.version.build
else pkg.metadata.version
),
)

View File

@ -0,0 +1,71 @@
# 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.compat import ci_strings_are_equal
from platformio.package.meta import PackageSpec
from platformio.project.config import ProjectConfig
from platformio.project.exception import InvalidProjectConfError
def save_project_dependencies(
project_dir, specs, scope, action="add", environments=None
):
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, scope), 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, scope, result)
elif config.has_option("env:" + env, scope):
config.remove_option("env:" + env, scope)
config.save()
def ignore_deps_by_specs(deps, specs):
result = []
for dep in deps:
ignore_conditions = []
depspec = PackageSpec(dep)
if depspec.external:
ignore_conditions.append(depspec in specs)
else:
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

View File

@ -89,14 +89,18 @@ def test_project(clirunner, validate_cliresult, isolated_pio_core, tmp_path):
) )
validate_cliresult(result) validate_cliresult(result)
with fs.cd(str(project_dir)): with fs.cd(str(project_dir)):
config = ProjectConfig()
lm = LibraryPackageManager( lm = LibraryPackageManager(
os.path.join(ProjectConfig().get("platformio", "libdeps_dir"), "devkit") os.path.join(config.get("platformio", "libdeps_dir"), "devkit")
) )
assert pkgs_to_names(lm.get_installed()) == ["DallasTemperature", "OneWire"] assert pkgs_to_names(lm.get_installed()) == ["DallasTemperature", "OneWire"]
assert pkgs_to_names(ToolPackageManager().get_installed()) == [ assert pkgs_to_names(ToolPackageManager().get_installed()) == [
"framework-arduino-avr-attiny", "framework-arduino-avr-attiny",
"toolchain-atmelavr", "toolchain-atmelavr",
] ]
assert config.get("env:devkit", "lib_deps") == [
"milesburton/DallasTemperature@^3.9.1"
]
def test_unknown_project_dependencies( def test_unknown_project_dependencies(
@ -175,6 +179,25 @@ def test_custom_project_libraries(
# do not expect any platforms/tools # do not expect any platforms/tools
assert not os.path.exists(config.get("platformio", "platforms_dir")) assert not os.path.exists(config.get("platformio", "platforms_dir"))
assert not os.path.exists(config.get("platformio", "packages_dir")) assert not os.path.exists(config.get("platformio", "packages_dir"))
# check saved deps
assert config.get("env:devkit", "lib_deps") == [
"bblanchon/ArduinoJson@^6.19.2",
]
# install library without saving to config
result = clirunner.invoke(
package_install_cmd,
["-e", "devkit", "-l", "nanopb/Nanopb@^0.4.6", "--no-save"],
)
validate_cliresult(result)
config = ProjectConfig()
lm = LibraryPackageManager(
os.path.join(config.get("platformio", "libdeps_dir"), "devkit")
)
assert pkgs_to_names(lm.get_installed()) == ["ArduinoJson", "Nanopb"]
assert config.get("env:devkit", "lib_deps") == [
"bblanchon/ArduinoJson@^6.19.2",
]
# unknown libraries # unknown libraries
result = clirunner.invoke( result = clirunner.invoke(

View File

@ -0,0 +1,120 @@
# 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 platformio.package.meta import PackageSpec
from platformio.project.config import ProjectConfig
from platformio.project.savedeps import save_project_dependencies
PROJECT_CONFIG_TPL = """
[env]
board = uno
framework = arduino
[env:bare]
[env:release]
platform = platformio/atmelavr
lib_deps =
milesburton/DallasTemperature@^3.8
[env:debug]
platform = platformio/atmelavr@^3.4.0
lib_deps =
milesburton/DallasTemperature@^3.9.1
bblanchon/ArduinoJson
"""
def test_save_libraries(tmp_path):
project_dir = tmp_path / "project"
project_dir.mkdir()
(project_dir / "platformio.ini").write_text(PROJECT_CONFIG_TPL)
specs = [
PackageSpec("milesburton/DallasTemperature@^3.9"),
PackageSpec("adafruit/Adafruit GPS Library@^1.6.0"),
PackageSpec("https://github.com/nanopb/nanopb.git"),
]
# add to the sepcified environment
save_project_dependencies(
str(project_dir), specs, scope="lib_deps", action="add", environments=["debug"]
)
config = ProjectConfig.get_instance(str(project_dir / "platformio.ini"))
assert config.get("env:debug", "lib_deps") == [
"bblanchon/ArduinoJson",
"milesburton/DallasTemperature@^3.9",
"adafruit/Adafruit GPS Library@^1.6.0",
"https://github.com/nanopb/nanopb.git",
]
assert config.get("env:bare", "lib_deps") == []
assert config.get("env:release", "lib_deps") == [
"milesburton/DallasTemperature@^3.8"
]
# add to the the all environments
save_project_dependencies(str(project_dir), specs, scope="lib_deps", action="add")
config = ProjectConfig.get_instance(str(project_dir / "platformio.ini"))
assert config.get("env:debug", "lib_deps") == [
"bblanchon/ArduinoJson",
"milesburton/DallasTemperature@^3.9",
"adafruit/Adafruit GPS Library@^1.6.0",
"https://github.com/nanopb/nanopb.git",
]
assert config.get("env:bare", "lib_deps") == [
"milesburton/DallasTemperature@^3.9",
"adafruit/Adafruit GPS Library@^1.6.0",
"https://github.com/nanopb/nanopb.git",
]
assert config.get("env:release", "lib_deps") == [
"milesburton/DallasTemperature@^3.9",
"adafruit/Adafruit GPS Library@^1.6.0",
"https://github.com/nanopb/nanopb.git",
]
# remove deps from env
save_project_dependencies(
str(project_dir),
[PackageSpec("milesburton/DallasTemperature")],
scope="lib_deps",
action="remove",
environments=["release"],
)
config = ProjectConfig.get_instance(str(project_dir / "platformio.ini"))
assert config.get("env:release", "lib_deps") == [
"adafruit/Adafruit GPS Library@^1.6.0",
"https://github.com/nanopb/nanopb.git",
]
# invalid requirements
save_project_dependencies(
str(project_dir),
[PackageSpec("adafruit/Adafruit GPS Library@^9.9.9")],
scope="lib_deps",
action="remove",
environments=["release"],
)
config = ProjectConfig.get_instance(str(project_dir / "platformio.ini"))
assert config.get("env:release", "lib_deps") == [
"https://github.com/nanopb/nanopb.git",
]
# remove deps from all envs
save_project_dependencies(
str(project_dir), specs, scope="lib_deps", action="remove"
)
config = ProjectConfig.get_instance(str(project_dir / "platformio.ini"))
assert config.get("env:debug", "lib_deps") == [
"bblanchon/ArduinoJson",
]
assert config.get("env:bare", "lib_deps") == []
assert config.get("env:release", "lib_deps") == []