forked from platformio/platformio-core
Allow a forced package installation with removing existing package
This commit is contained in:
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ class PackageManagerDownloadMixin(object):
|
|||||||
raise e
|
raise e
|
||||||
if checksum:
|
if checksum:
|
||||||
fd.verify(checksum)
|
fd.verify(checksum)
|
||||||
os.rename(tmp_path, dl_path)
|
shutil.copyfile(tmp_path, dl_path)
|
||||||
finally:
|
finally:
|
||||||
if os.path.isfile(tmp_path):
|
if os.path.isfile(tmp_path):
|
||||||
os.remove(tmp_path)
|
os.remove(tmp_path)
|
||||||
|
@ -21,7 +21,6 @@ import click
|
|||||||
|
|
||||||
from platformio import app, compat, fs, util
|
from platformio import app, compat, fs, util
|
||||||
from platformio.package.exception import PackageException, UnknownPackageError
|
from platformio.package.exception import PackageException, UnknownPackageError
|
||||||
from platformio.package.lockfile import LockFile
|
|
||||||
from platformio.package.meta import PackageSourceItem, PackageSpec
|
from platformio.package.meta import PackageSourceItem, PackageSpec
|
||||||
from platformio.package.unpack import FileUnpacker
|
from platformio.package.unpack import FileUnpacker
|
||||||
from platformio.package.vcsclient import VCSClientFactory
|
from platformio.package.vcsclient import VCSClientFactory
|
||||||
@ -43,25 +42,33 @@ class PackageManagerInstallMixin(object):
|
|||||||
with FileUnpacker(src) as fu:
|
with FileUnpacker(src) as fu:
|
||||||
return fu.unpack(dst, with_progress=False)
|
return fu.unpack(dst, with_progress=False)
|
||||||
|
|
||||||
def install(self, spec, silent=False):
|
def install(self, spec, silent=False, force=False):
|
||||||
with LockFile(self.package_dir):
|
try:
|
||||||
pkg = self._install(spec, silent=silent)
|
self.lock()
|
||||||
|
pkg = self._install(spec, silent=silent, force=force)
|
||||||
self.memcache_reset()
|
self.memcache_reset()
|
||||||
self.cleanup_expired_downloads()
|
self.cleanup_expired_downloads()
|
||||||
return pkg
|
return pkg
|
||||||
|
finally:
|
||||||
|
self.unlock()
|
||||||
|
|
||||||
def _install(self, spec, search_filters=None, silent=False):
|
def _install(self, spec, search_filters=None, silent=False, force=False):
|
||||||
spec = self.ensure_spec(spec)
|
spec = self.ensure_spec(spec)
|
||||||
|
|
||||||
# avoid circle dependencies
|
# avoid circle dependencies
|
||||||
if not self.INSTALL_HISTORY:
|
if not self.INSTALL_HISTORY:
|
||||||
self.INSTALL_HISTORY = []
|
self.INSTALL_HISTORY = {}
|
||||||
if spec in self.INSTALL_HISTORY:
|
if spec in self.INSTALL_HISTORY:
|
||||||
return None
|
return self.INSTALL_HISTORY[spec]
|
||||||
self.INSTALL_HISTORY.append(spec)
|
|
||||||
|
|
||||||
# check if package is already installed
|
# check if package is already installed
|
||||||
pkg = self.get_package(spec)
|
pkg = self.get_package(spec)
|
||||||
|
|
||||||
|
# if a forced installation
|
||||||
|
if pkg and force:
|
||||||
|
self.uninstall(pkg, silent=silent)
|
||||||
|
pkg = None
|
||||||
|
|
||||||
if pkg:
|
if pkg:
|
||||||
if not silent:
|
if not silent:
|
||||||
click.secho(
|
click.secho(
|
||||||
@ -99,6 +106,7 @@ class PackageManagerInstallMixin(object):
|
|||||||
|
|
||||||
self.memcache_reset()
|
self.memcache_reset()
|
||||||
self.install_dependencies(pkg, silent)
|
self.install_dependencies(pkg, silent)
|
||||||
|
self.INSTALL_HISTORY[spec] = pkg
|
||||||
return pkg
|
return pkg
|
||||||
|
|
||||||
def install_dependencies(self, pkg, silent=False):
|
def install_dependencies(self, pkg, silent=False):
|
||||||
@ -240,15 +248,18 @@ class PackageManagerInstallMixin(object):
|
|||||||
shutil.move(tmp_pkg.path, dst_pkg.path)
|
shutil.move(tmp_pkg.path, dst_pkg.path)
|
||||||
return PackageSourceItem(dst_pkg.path)
|
return PackageSourceItem(dst_pkg.path)
|
||||||
|
|
||||||
def uninstall(self, path_or_spec, silent=False):
|
def uninstall(self, pkg, silent=False):
|
||||||
with LockFile(self.package_dir):
|
try:
|
||||||
pkg = (
|
self.lock()
|
||||||
PackageSourceItem(path_or_spec)
|
|
||||||
if os.path.isdir(path_or_spec)
|
if not isinstance(pkg, PackageSourceItem):
|
||||||
else self.get_package(path_or_spec)
|
pkg = (
|
||||||
)
|
PackageSourceItem(pkg)
|
||||||
|
if os.path.isdir(pkg)
|
||||||
|
else self.get_package(pkg)
|
||||||
|
)
|
||||||
if not pkg or not pkg.metadata:
|
if not pkg or not pkg.metadata:
|
||||||
raise UnknownPackageError(path_or_spec)
|
raise UnknownPackageError(pkg)
|
||||||
|
|
||||||
if not silent:
|
if not silent:
|
||||||
self.print_message(
|
self.print_message(
|
||||||
@ -276,7 +287,10 @@ class PackageManagerInstallMixin(object):
|
|||||||
os.path.join(self.package_dir, detached_pkg.get_safe_dirname()),
|
os.path.join(self.package_dir, detached_pkg.get_safe_dirname()),
|
||||||
)
|
)
|
||||||
self.memcache_reset()
|
self.memcache_reset()
|
||||||
|
finally:
|
||||||
|
self.unlock()
|
||||||
|
|
||||||
|
if not silent:
|
||||||
|
click.echo("[%s]" % click.style("OK", fg="green"))
|
||||||
|
|
||||||
if not silent:
|
|
||||||
click.echo("[%s]" % click.style("OK", fg="green"))
|
|
||||||
return True
|
return True
|
||||||
|
@ -37,7 +37,7 @@ class RegistryFileMirrorsIterator(object):
|
|||||||
self._base_url = "%s://%s" % (self._url_parts.scheme, self._url_parts.netloc)
|
self._base_url = "%s://%s" % (self._url_parts.scheme, self._url_parts.netloc)
|
||||||
self._visited_mirrors = []
|
self._visited_mirrors = []
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self): # pylint: disable=non-iterator-returned
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __next__(self):
|
def __next__(self):
|
||||||
|
@ -21,6 +21,7 @@ import semantic_version
|
|||||||
from platformio import fs, util
|
from platformio import fs, util
|
||||||
from platformio.commands import PlatformioCLI
|
from platformio.commands import PlatformioCLI
|
||||||
from platformio.package.exception import ManifestException, MissingPackageManifestError
|
from platformio.package.exception import ManifestException, MissingPackageManifestError
|
||||||
|
from platformio.package.lockfile import LockFile
|
||||||
from platformio.package.manager._download import PackageManagerDownloadMixin
|
from platformio.package.manager._download import PackageManagerDownloadMixin
|
||||||
from platformio.package.manager._install import PackageManagerInstallMixin
|
from platformio.package.manager._install import PackageManagerInstallMixin
|
||||||
from platformio.package.manager._registry import PackageManageRegistryMixin
|
from platformio.package.manager._registry import PackageManageRegistryMixin
|
||||||
@ -34,7 +35,7 @@ from platformio.package.meta import (
|
|||||||
from platformio.project.helpers import get_project_cache_dir
|
from platformio.project.helpers import get_project_cache_dir
|
||||||
|
|
||||||
|
|
||||||
class BasePackageManager(
|
class BasePackageManager( # pylint: disable=too-many-public-methods
|
||||||
PackageManagerDownloadMixin, PackageManageRegistryMixin, PackageManagerInstallMixin
|
PackageManagerDownloadMixin, PackageManageRegistryMixin, PackageManagerInstallMixin
|
||||||
):
|
):
|
||||||
MEMORY_CACHE = {}
|
MEMORY_CACHE = {}
|
||||||
@ -43,10 +44,26 @@ class BasePackageManager(
|
|||||||
self.pkg_type = pkg_type
|
self.pkg_type = pkg_type
|
||||||
self.package_dir = self.ensure_dir_exists(package_dir)
|
self.package_dir = self.ensure_dir_exists(package_dir)
|
||||||
self.MEMORY_CACHE = {}
|
self.MEMORY_CACHE = {}
|
||||||
|
|
||||||
|
self._lockfile = None
|
||||||
self._download_dir = None
|
self._download_dir = None
|
||||||
self._tmp_dir = None
|
self._tmp_dir = None
|
||||||
self._registry_client = None
|
self._registry_client = None
|
||||||
|
|
||||||
|
def lock(self):
|
||||||
|
if self._lockfile:
|
||||||
|
return
|
||||||
|
self._lockfile = LockFile(self.package_dir)
|
||||||
|
self._lockfile.acquire()
|
||||||
|
|
||||||
|
def unlock(self):
|
||||||
|
if hasattr(self, "_lockfile") and self._lockfile:
|
||||||
|
self._lockfile.release()
|
||||||
|
self._lockfile = None
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.unlock()
|
||||||
|
|
||||||
def memcache_get(self, key, default=None):
|
def memcache_get(self, key, default=None):
|
||||||
return self.MEMORY_CACHE.get(key, default)
|
return self.MEMORY_CACHE.get(key, default)
|
||||||
|
|
||||||
|
@ -16,10 +16,11 @@ import json
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import tarfile
|
import tarfile
|
||||||
|
from binascii import crc32
|
||||||
|
|
||||||
import semantic_version
|
import semantic_version
|
||||||
|
|
||||||
from platformio.compat import get_object_members, string_types
|
from platformio.compat import get_object_members, hashlib_encode_data, string_types
|
||||||
from platformio.package.manifest.parser import ManifestFileType
|
from platformio.package.manifest.parser import ManifestFileType
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -89,6 +90,14 @@ class PackageSpec(object):
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return crc32(
|
||||||
|
hashlib_encode_data(
|
||||||
|
"%s-%s-%s-%s-%s"
|
||||||
|
% (self.owner, self.id, self.name, self.requirements, self.url)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return (
|
return (
|
||||||
"PackageSpec <owner={owner} id={id} name={name} "
|
"PackageSpec <owner={owner} id={id} name={name} "
|
||||||
|
@ -202,6 +202,21 @@ def test_install_from_registry(isolated_pio_core, tmpdir_factory):
|
|||||||
assert util.get_systype() in manifest.get("system", [])
|
assert util.get_systype() in manifest.get("system", [])
|
||||||
|
|
||||||
|
|
||||||
|
def test_install_force(isolated_pio_core, tmpdir_factory):
|
||||||
|
lm = LibraryPackageManager(str(tmpdir_factory.mktemp("lib-storage")))
|
||||||
|
# install #64 ArduinoJson
|
||||||
|
pkg = lm.install("64 @ ^5", silent=True)
|
||||||
|
assert pkg.metadata.version.major == 5
|
||||||
|
# try install the latest without specification
|
||||||
|
pkg = lm.install("64", silent=True)
|
||||||
|
assert pkg.metadata.version.major == 5
|
||||||
|
assert len(lm.get_installed()) == 1
|
||||||
|
# re-install the latest
|
||||||
|
pkg = lm.install(64, silent=True, force=True)
|
||||||
|
assert len(lm.get_installed()) == 1
|
||||||
|
assert pkg.metadata.version.major > 5
|
||||||
|
|
||||||
|
|
||||||
def test_get_installed(isolated_pio_core, tmpdir_factory):
|
def test_get_installed(isolated_pio_core, tmpdir_factory):
|
||||||
storage_dir = tmpdir_factory.mktemp("storage")
|
storage_dir = tmpdir_factory.mktemp("storage")
|
||||||
lm = LibraryPackageManager(str(storage_dir))
|
lm = LibraryPackageManager(str(storage_dir))
|
||||||
@ -276,7 +291,7 @@ def test_uninstall(isolated_pio_core, tmpdir_factory):
|
|||||||
# foo @ 1.0.0
|
# foo @ 1.0.0
|
||||||
pkg_dir = tmp_dir.join("foo").mkdir()
|
pkg_dir = tmp_dir.join("foo").mkdir()
|
||||||
pkg_dir.join("library.json").write('{"name": "foo", "version": "1.0.0"}')
|
pkg_dir.join("library.json").write('{"name": "foo", "version": "1.0.0"}')
|
||||||
lm.install_from_url("file://%s" % pkg_dir, "foo")
|
foo_1_0_0_pkg = lm.install_from_url("file://%s" % pkg_dir, "foo")
|
||||||
# foo @ 1.3.0
|
# foo @ 1.3.0
|
||||||
pkg_dir = tmp_dir.join("foo-1.3.0").mkdir()
|
pkg_dir = tmp_dir.join("foo-1.3.0").mkdir()
|
||||||
pkg_dir.join("library.json").write('{"name": "foo", "version": "1.3.0"}')
|
pkg_dir.join("library.json").write('{"name": "foo", "version": "1.3.0"}')
|
||||||
@ -284,7 +299,7 @@ def test_uninstall(isolated_pio_core, tmpdir_factory):
|
|||||||
# bar
|
# bar
|
||||||
pkg_dir = tmp_dir.join("bar").mkdir()
|
pkg_dir = tmp_dir.join("bar").mkdir()
|
||||||
pkg_dir.join("library.json").write('{"name": "bar", "version": "1.0.0"}')
|
pkg_dir.join("library.json").write('{"name": "bar", "version": "1.0.0"}')
|
||||||
lm.install("file://%s" % pkg_dir, silent=True)
|
bar_pkg = lm.install("file://%s" % pkg_dir, silent=True)
|
||||||
|
|
||||||
assert len(lm.get_installed()) == 3
|
assert len(lm.get_installed()) == 3
|
||||||
assert os.path.isdir(os.path.join(str(storage_dir), "foo"))
|
assert os.path.isdir(os.path.join(str(storage_dir), "foo"))
|
||||||
@ -297,7 +312,7 @@ def test_uninstall(isolated_pio_core, tmpdir_factory):
|
|||||||
assert not os.path.isdir(os.path.join(str(storage_dir), "foo@1.0.0"))
|
assert not os.path.isdir(os.path.join(str(storage_dir), "foo@1.0.0"))
|
||||||
|
|
||||||
# uninstall the rest
|
# uninstall the rest
|
||||||
assert lm.uninstall("foo", silent=True)
|
assert lm.uninstall(foo_1_0_0_pkg.path, silent=True)
|
||||||
assert lm.uninstall("bar", silent=True)
|
assert lm.uninstall(bar_pkg, silent=True)
|
||||||
|
|
||||||
assert len(lm.get_installed()) == 0
|
assert len(lm.get_installed()) == 0
|
||||||
|
Reference in New Issue
Block a user