forked from platformio/platformio-core
Switch legacy platform manager to the new
This commit is contained in:
1 parent
bb6fb3fdf8
commit
04694b4126
25 files changed
+470
-1271
No files matched your search
@@ -42,17 +42,26 @@ class PackageManagerInstallMixin(object):
|
||||
with FileUnpacker(src) as fu:
|
||||
return fu.unpack(dst, with_progress=False)
|
||||
|
||||
def install(self, spec, silent=False, force=False):
|
||||
def install(self, spec, silent=False, skip_dependencies=False, force=False):
|
||||
try:
|
||||
self.lock()
|
||||
pkg = self._install(spec, silent=silent, force=force)
|
||||
pkg = self._install(
|
||||
spec, silent=silent, skip_dependencies=skip_dependencies, force=force
|
||||
)
|
||||
self.memcache_reset()
|
||||
self.cleanup_expired_downloads()
|
||||
return pkg
|
||||
finally:
|
||||
self.unlock()
|
||||
|
||||
def _install(self, spec, search_filters=None, silent=False, force=False):
|
||||
def _install( # pylint: disable=too-many-arguments
|
||||
self,
|
||||
spec,
|
||||
search_filters=None,
|
||||
silent=False,
|
||||
skip_dependencies=False,
|
||||
force=False,
|
||||
):
|
||||
spec = self.ensure_spec(spec)
|
||||
|
||||
# avoid circle dependencies
|
||||
@@ -104,11 +113,12 @@ class PackageManagerInstallMixin(object):
|
||||
)
|
||||
|
||||
self.memcache_reset()
|
||||
self._install_dependencies(pkg, silent)
|
||||
if not skip_dependencies:
|
||||
self.install_dependencies(pkg, silent)
|
||||
self._INSTALL_HISTORY[spec] = pkg
|
||||
return pkg
|
||||
|
||||
def _install_dependencies(self, pkg, silent=False):
|
||||
def install_dependencies(self, pkg, silent=False):
|
||||
assert isinstance(pkg, PackageItem)
|
||||
manifest = self.load_manifest(pkg)
|
||||
if not manifest.get("dependencies"):
|
||||
|
||||
@@ -91,6 +91,9 @@ class PackageManageRegistryMixin(object):
|
||||
self.print_multi_package_issue(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:
|
||||
raise UnknownPackageError(spec.humanize())
|
||||
@@ -189,7 +192,7 @@ class PackageManageRegistryMixin(object):
|
||||
return (package, version)
|
||||
|
||||
if not spec.requirements:
|
||||
return None
|
||||
return (None, None)
|
||||
|
||||
# if the custom version requirements, check ALL package versions
|
||||
for package in packages:
|
||||
@@ -206,7 +209,7 @@ class PackageManageRegistryMixin(object):
|
||||
if version:
|
||||
return (package, version)
|
||||
time.sleep(1)
|
||||
return None
|
||||
return (None, None)
|
||||
|
||||
def pick_best_registry_version(self, versions, spec=None):
|
||||
assert not spec or isinstance(spec, PackageSpec)
|
||||
|
||||
@@ -44,7 +44,7 @@ class PackageManagerUninstallMixin(object):
|
||||
|
||||
# firstly, remove dependencies
|
||||
if not skip_dependencies:
|
||||
self._uninstall_dependencies(pkg, silent)
|
||||
self.uninstall_dependencies(pkg, silent)
|
||||
|
||||
if os.path.islink(pkg.path):
|
||||
os.unlink(pkg.path)
|
||||
@@ -72,7 +72,7 @@ class PackageManagerUninstallMixin(object):
|
||||
|
||||
return pkg
|
||||
|
||||
def _uninstall_dependencies(self, pkg, silent=False):
|
||||
def uninstall_dependencies(self, pkg, silent=False):
|
||||
assert isinstance(pkg, PackageItem)
|
||||
manifest = self.load_manifest(pkg)
|
||||
if not manifest.get("dependencies"):
|
||||
|
||||
@@ -74,17 +74,24 @@ class PackageManagerUpdateMixin(object):
|
||||
).version
|
||||
)
|
||||
|
||||
def update(self, from_spec, to_spec=None, only_check=False, silent=False):
|
||||
def update( # pylint: disable=too-many-arguments
|
||||
self,
|
||||
from_spec,
|
||||
to_spec=None,
|
||||
only_check=False,
|
||||
silent=False,
|
||||
show_incompatible=True,
|
||||
):
|
||||
pkg = self.get_package(from_spec)
|
||||
if not pkg or not pkg.metadata:
|
||||
raise UnknownPackageError(from_spec)
|
||||
|
||||
if not silent:
|
||||
click.echo(
|
||||
"{} {:<45} {:<30}".format(
|
||||
"{} {:<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)
|
||||
"%s @ %s" % (pkg.metadata.version, to_spec.requirements)
|
||||
if to_spec and to_spec.requirements
|
||||
else str(pkg.metadata.version),
|
||||
),
|
||||
@@ -97,17 +104,9 @@ class PackageManagerUpdateMixin(object):
|
||||
|
||||
outdated = self.outdated(pkg, to_spec)
|
||||
if not silent:
|
||||
self.print_outdated_state(outdated)
|
||||
self.print_outdated_state(outdated, show_incompatible)
|
||||
|
||||
up_to_date = any(
|
||||
[
|
||||
outdated.detached,
|
||||
not outdated.latest,
|
||||
outdated.latest and outdated.current == outdated.latest,
|
||||
outdated.wanted and outdated.current == outdated.wanted,
|
||||
]
|
||||
)
|
||||
if only_check or up_to_date:
|
||||
if only_check or not outdated.is_outdated(allow_incompatible=False):
|
||||
return pkg
|
||||
|
||||
try:
|
||||
@@ -117,18 +116,26 @@ class PackageManagerUpdateMixin(object):
|
||||
self.unlock()
|
||||
|
||||
@staticmethod
|
||||
def print_outdated_state(outdated):
|
||||
def print_outdated_state(outdated, show_incompatible=True):
|
||||
if outdated.detached:
|
||||
return click.echo("[%s]" % (click.style("Detached", fg="yellow")))
|
||||
if not outdated.latest or outdated.current == outdated.latest:
|
||||
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"))
|
||||
"[%s]" % (click.style("Incompatible %s" % outdated.latest, fg="yellow"))
|
||||
)
|
||||
return click.echo(
|
||||
"[%s]" % (click.style(str(outdated.wanted or outdated.latest), fg="red"))
|
||||
"[%s]"
|
||||
% (
|
||||
click.style(
|
||||
"Outdated %s" % str(outdated.wanted or outdated.latest), fg="red"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def _update(self, pkg, outdated, silent=False):
|
||||
|
||||
@@ -190,6 +190,10 @@ class BasePackageManager( # pylint: disable=too-many-public-methods
|
||||
return metadata
|
||||
|
||||
def get_installed(self):
|
||||
cache_key = "get_installed"
|
||||
if self.memcache_get(cache_key):
|
||||
return self.memcache_get(cache_key)
|
||||
|
||||
result = []
|
||||
for name in sorted(os.listdir(self.package_dir)):
|
||||
pkg_dir = os.path.join(self.package_dir, name)
|
||||
@@ -213,6 +217,8 @@ class BasePackageManager( # pylint: disable=too-many-public-methods
|
||||
except MissingPackageManifestError:
|
||||
pass
|
||||
result.append(pkg)
|
||||
|
||||
self.memcache_set(cache_key, result)
|
||||
return result
|
||||
|
||||
def get_package(self, spec):
|
||||
|
||||
@@ -12,8 +12,14 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from platformio import util
|
||||
from platformio.exception import APIRequestError, InternetIsOffline
|
||||
from platformio.package.exception import UnknownPackageError
|
||||
from platformio.package.manager.base import BasePackageManager
|
||||
from platformio.package.manager.tool import ToolPackageManager
|
||||
from platformio.package.meta import PackageType
|
||||
from platformio.platform.exception import IncompatiblePlatform, UnknownBoard
|
||||
from platformio.platform.factory import PlatformFactory
|
||||
from platformio.project.config import ProjectConfig
|
||||
|
||||
|
||||
@@ -28,3 +34,161 @@ class PlatformPackageManager(BasePackageManager): # pylint: disable=too-many-an
|
||||
@property
|
||||
def manifest_names(self):
|
||||
return PackageType.get_manifest_map()[PackageType.PLATFORM]
|
||||
|
||||
def install( # pylint: disable=arguments-differ, too-many-arguments
|
||||
self,
|
||||
spec,
|
||||
with_packages=None,
|
||||
without_packages=None,
|
||||
skip_default_package=False,
|
||||
with_all_packages=False,
|
||||
silent=False,
|
||||
force=False,
|
||||
):
|
||||
pkg = super(PlatformPackageManager, self).install(
|
||||
spec, silent=silent, force=force, skip_dependencies=True
|
||||
)
|
||||
try:
|
||||
p = PlatformFactory.new(pkg)
|
||||
p.ensure_engine_compatible()
|
||||
except IncompatiblePlatform as e:
|
||||
super(PlatformPackageManager, self).uninstall(
|
||||
pkg, silent=silent, skip_dependencies=True
|
||||
)
|
||||
raise e
|
||||
|
||||
if with_all_packages:
|
||||
with_packages = list(p.packages)
|
||||
|
||||
p.install_packages(
|
||||
with_packages,
|
||||
without_packages,
|
||||
skip_default_package,
|
||||
silent=silent,
|
||||
force=force,
|
||||
)
|
||||
p.install_python_packages()
|
||||
p.on_installed()
|
||||
self.cleanup_packages(list(p.packages))
|
||||
return pkg
|
||||
|
||||
def uninstall(self, spec, silent=False, skip_dependencies=False):
|
||||
pkg = self.get_package(spec)
|
||||
if not pkg or not pkg.metadata:
|
||||
raise UnknownPackageError(spec)
|
||||
p = PlatformFactory.new(pkg)
|
||||
assert super(PlatformPackageManager, self).uninstall(
|
||||
pkg, silent=silent, skip_dependencies=True
|
||||
)
|
||||
if not skip_dependencies:
|
||||
p.uninstall_python_packages()
|
||||
p.on_uninstalled()
|
||||
self.cleanup_packages(list(p.packages))
|
||||
return pkg
|
||||
|
||||
def update( # pylint: disable=arguments-differ, too-many-arguments
|
||||
self,
|
||||
from_spec,
|
||||
to_spec=None,
|
||||
only_check=False,
|
||||
silent=False,
|
||||
show_incompatible=True,
|
||||
only_packages=False,
|
||||
):
|
||||
pkg = self.get_package(from_spec)
|
||||
if not pkg or not pkg.metadata:
|
||||
raise UnknownPackageError(from_spec)
|
||||
p = PlatformFactory.new(pkg)
|
||||
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,
|
||||
silent=silent,
|
||||
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)
|
||||
self.cleanup_packages(list(p.packages))
|
||||
|
||||
if missed_pkgs:
|
||||
p.install_packages(
|
||||
with_packages=list(missed_pkgs), skip_default_package=True
|
||||
)
|
||||
|
||||
return new_pkg or pkg
|
||||
|
||||
def cleanup_packages(self, names):
|
||||
self.memcache_reset()
|
||||
deppkgs = {}
|
||||
for platform in PlatformPackageManager().get_installed():
|
||||
p = PlatformFactory.new(platform)
|
||||
for pkg in p.get_installed_packages():
|
||||
if pkg.metadata.name not in deppkgs:
|
||||
deppkgs[pkg.metadata.name] = set()
|
||||
deppkgs[pkg.metadata.name].add(pkg.metadata.version)
|
||||
|
||||
pm = ToolPackageManager()
|
||||
for pkg in pm.get_installed():
|
||||
if pkg.metadata.name not in names:
|
||||
continue
|
||||
if (
|
||||
pkg.metadata.name not in deppkgs
|
||||
or pkg.metadata.version not in deppkgs[pkg.metadata.name]
|
||||
):
|
||||
try:
|
||||
pm.uninstall(pkg.metadata.spec)
|
||||
except UnknownPackageError:
|
||||
pass
|
||||
|
||||
self.memcache_reset()
|
||||
return True
|
||||
|
||||
@util.memoized(expire="5s")
|
||||
def get_installed_boards(self):
|
||||
boards = []
|
||||
for pkg in self.get_installed():
|
||||
p = PlatformFactory.new(pkg)
|
||||
for config in p.get_boards().values():
|
||||
board = config.get_brief_data()
|
||||
if board not in boards:
|
||||
boards.append(board)
|
||||
return boards
|
||||
|
||||
@staticmethod
|
||||
def get_registered_boards():
|
||||
return util.get_api_result("/boards", cache_valid="7d")
|
||||
|
||||
def get_all_boards(self):
|
||||
boards = self.get_installed_boards()
|
||||
know_boards = ["%s:%s" % (b["platform"], b["id"]) for b in boards]
|
||||
try:
|
||||
for board in self.get_registered_boards():
|
||||
key = "%s:%s" % (board["platform"], board["id"])
|
||||
if key not in know_boards:
|
||||
boards.append(board)
|
||||
except (APIRequestError, InternetIsOffline):
|
||||
pass
|
||||
return sorted(boards, key=lambda b: b["name"])
|
||||
|
||||
def board_config(self, id_, platform=None):
|
||||
for manifest in self.get_installed_boards():
|
||||
if manifest["id"] == id_ and (
|
||||
not platform or manifest["platform"] == platform
|
||||
):
|
||||
return manifest
|
||||
for manifest in self.get_registered_boards():
|
||||
if manifest["id"] == id_ and (
|
||||
not platform or manifest["platform"] == platform
|
||||
):
|
||||
return manifest
|
||||
raise UnknownBoard(id_)
|
||||
@@ -19,10 +19,9 @@ from platformio.project.config import ProjectConfig
|
||||
|
||||
class ToolPackageManager(BasePackageManager): # pylint: disable=too-many-ancestors
|
||||
def __init__(self, package_dir=None):
|
||||
self.config = ProjectConfig.get_instance()
|
||||
super(ToolPackageManager, self).__init__(
|
||||
PackageType.TOOL, package_dir or self.config.get_optional_dir("packages"),
|
||||
)
|
||||
if not package_dir:
|
||||
package_dir = ProjectConfig.get_instance().get_optional_dir("packages")
|
||||
super(ToolPackageManager, self).__init__(PackageType.TOOL, package_dir)
|
||||
|
||||
@property
|
||||
def manifest_names(self):
|
||||
|
||||
Reference in new issue
Block a user