mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-30 01:57:13 +02:00
Significantly improve Package Manager // Resolve #913
* Handle dependencies when installing non-registry package/library (VCS, archive, local folder)
This commit is contained in:
@ -38,6 +38,7 @@ PlatformIO 3.0
|
|||||||
* Escape project path when Glob matching is used
|
* Escape project path when Glob matching is used
|
||||||
* Do not overwrite project configuration variables when system environment
|
* Do not overwrite project configuration variables when system environment
|
||||||
variables are set
|
variables are set
|
||||||
|
* Handle dependencies when installing non-registry package/library (VCS, archive, local folder)
|
||||||
* Fixed package installing with VCS branch for Python 2.7.3
|
* Fixed package installing with VCS branch for Python 2.7.3
|
||||||
(`issue #885 <https://github.com/platformio/platformio-core/issues/885>`_)
|
(`issue #885 <https://github.com/platformio/platformio-core/issues/885>`_)
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
# pylint: disable=too-many-branches, too-many-locals
|
# pylint: disable=too-many-branches, too-many-locals
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from os.path import join
|
from os.path import isdir, join
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from urllib import quote
|
from urllib import quote
|
||||||
|
|
||||||
@ -116,22 +116,23 @@ def lib_uninstall(lm, libraries):
|
|||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
def lib_update(lm, libraries, only_check, json_output):
|
def lib_update(lm, libraries, only_check, json_output):
|
||||||
if not libraries:
|
if not libraries:
|
||||||
libraries = []
|
libraries = [manifest['__pkg_dir'] for manifest in lm.get_installed()]
|
||||||
for manifest in lm.get_installed():
|
|
||||||
if "@vcs-" in manifest['__pkg_dir']:
|
|
||||||
libraries.append("%s=%s" % (manifest['name'], manifest['url']))
|
|
||||||
else:
|
|
||||||
libraries.append(str(manifest.get("id", manifest['name'])))
|
|
||||||
|
|
||||||
if only_check and json_output:
|
if only_check and json_output:
|
||||||
result = []
|
result = []
|
||||||
for library in libraries:
|
for library in libraries:
|
||||||
name, requirements, url = lm.parse_pkg_name(library)
|
pkg_dir = library if isdir(library) else None
|
||||||
latest = lm.outdated(name, requirements, url)
|
requirements = None
|
||||||
|
url = None
|
||||||
|
if not pkg_dir:
|
||||||
|
name, requirements, url = lm.parse_pkg_input(library)
|
||||||
|
pkg_dir = lm.get_package_dir(name, requirements, url)
|
||||||
|
if not pkg_dir:
|
||||||
|
continue
|
||||||
|
latest = lm.outdated(pkg_dir, requirements)
|
||||||
if not latest:
|
if not latest:
|
||||||
continue
|
continue
|
||||||
manifest = lm.load_manifest(
|
manifest = lm.load_manifest(pkg_dir)
|
||||||
lm.get_package_dir(name, requirements, url))
|
|
||||||
manifest['versionLatest'] = latest
|
manifest['versionLatest'] = latest
|
||||||
result.append(manifest)
|
result.append(manifest)
|
||||||
return click.echo(json.dumps(result))
|
return click.echo(json.dumps(result))
|
||||||
@ -167,6 +168,9 @@ def print_lib_item(item):
|
|||||||
click.echo("Authors: %s" % ", ".join(
|
click.echo("Authors: %s" % ", ".join(
|
||||||
item.get("authornames",
|
item.get("authornames",
|
||||||
[a.get("name", "") for a in item.get("authors", [])])))
|
[a.get("name", "") for a in item.get("authors", [])])))
|
||||||
|
|
||||||
|
if "__src_url" in item:
|
||||||
|
click.secho("Source: %s" % item['__src_url'])
|
||||||
click.echo()
|
click.echo()
|
||||||
|
|
||||||
|
|
||||||
@ -270,8 +274,7 @@ def get_builtin_libs(storage_names=None):
|
|||||||
storage_names = storage_names or []
|
storage_names = storage_names or []
|
||||||
pm = PlatformManager()
|
pm = PlatformManager()
|
||||||
for manifest in pm.get_installed():
|
for manifest in pm.get_installed():
|
||||||
p = PlatformFactory.newPlatform(
|
p = PlatformFactory.newPlatform(manifest['__pkg_dir'])
|
||||||
pm.get_manifest_path(manifest['__pkg_dir']))
|
|
||||||
for storage in p.get_lib_storages():
|
for storage in p.get_lib_storages():
|
||||||
if storage_names and storage['name'] not in storage_names:
|
if storage_names and storage['name'] not in storage_names:
|
||||||
continue
|
continue
|
||||||
@ -308,7 +311,7 @@ def lib_builtin(storage, json_output):
|
|||||||
@click.option("--json-output", is_flag=True)
|
@click.option("--json-output", is_flag=True)
|
||||||
def lib_show(library, json_output):
|
def lib_show(library, json_output):
|
||||||
lm = LibraryManager()
|
lm = LibraryManager()
|
||||||
name, requirements, _ = lm.parse_pkg_name(library)
|
name, requirements, _ = lm.parse_pkg_input(library)
|
||||||
lib_id = lm.get_pkg_id_by_name(
|
lib_id = lm.get_pkg_id_by_name(
|
||||||
name, requirements, silent=json_output, interactive=not json_output)
|
name, requirements, silent=json_output, interactive=not json_output)
|
||||||
lib = get_api_result("/lib/info/%d" % lib_id, cache_valid="1d")
|
lib = get_api_result("/lib/info/%d" % lib_id, cache_valid="1d")
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from os.path import dirname, isfile, join
|
from os.path import dirname, isdir
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
@ -94,10 +94,12 @@ def _get_installed_platform_data(platform,
|
|||||||
# del data['version']
|
# del data['version']
|
||||||
# return data
|
# return data
|
||||||
|
|
||||||
data['__pkg_dir'] = dirname(p.manifest_path)
|
# overwrite VCS version and add extra fields
|
||||||
# if VCS cloned platform
|
manifest = PlatformManager().load_manifest(dirname(p.manifest_path))
|
||||||
if not isfile(join(data['__pkg_dir'], "platform.json")):
|
assert manifest
|
||||||
data['__pkg_dir'] = dirname(data['__pkg_dir'])
|
for key in manifest:
|
||||||
|
if key == "version" or key.startswith("__"):
|
||||||
|
data[key] = manifest[key]
|
||||||
|
|
||||||
if with_boards:
|
if with_boards:
|
||||||
data['boards'] = [c.get_brief_data() for c in p.get_boards().values()]
|
data['boards'] = [c.get_brief_data() for c in p.get_boards().values()]
|
||||||
@ -214,7 +216,7 @@ def platform_list(json_output):
|
|||||||
for manifest in pm.get_installed():
|
for manifest in pm.get_installed():
|
||||||
platforms.append(
|
platforms.append(
|
||||||
_get_installed_platform_data(
|
_get_installed_platform_data(
|
||||||
pm.get_manifest_path(manifest['__pkg_dir']),
|
manifest['__pkg_dir'],
|
||||||
with_boards=False,
|
with_boards=False,
|
||||||
expose_packages=False))
|
expose_packages=False))
|
||||||
if json_output:
|
if json_output:
|
||||||
@ -336,22 +338,25 @@ def platform_update(platforms, only_packages, only_check, json_output):
|
|||||||
pm = PlatformManager()
|
pm = PlatformManager()
|
||||||
if not platforms:
|
if not platforms:
|
||||||
platforms = []
|
platforms = []
|
||||||
for manifest in pm.get_installed():
|
platforms = [manifest['__pkg_dir'] for manifest in pm.get_installed()]
|
||||||
if "@vcs-" in manifest['__pkg_dir']:
|
|
||||||
platforms.append("%s=%s" % (manifest['name'], manifest['url']))
|
|
||||||
else:
|
|
||||||
platforms.append(manifest['name'])
|
|
||||||
|
|
||||||
if only_check and json_output:
|
if only_check and json_output:
|
||||||
result = []
|
result = []
|
||||||
for platform in platforms:
|
for platform in platforms:
|
||||||
name, requirements, url = pm.parse_pkg_name(platform)
|
pkg_dir = platform if isdir(platform) else None
|
||||||
latest = pm.outdated(name, requirements, url)
|
requirements = None
|
||||||
|
url = None
|
||||||
|
if not pkg_dir:
|
||||||
|
name, requirements, url = pm.parse_pkg_input(platform)
|
||||||
|
pkg_dir = pm.get_package_dir(name, requirements, url)
|
||||||
|
if not pkg_dir:
|
||||||
|
continue
|
||||||
|
latest = pm.outdated(pkg_dir, requirements)
|
||||||
if not latest:
|
if not latest:
|
||||||
continue
|
continue
|
||||||
data = _get_installed_platform_data(
|
data = _get_installed_platform_data(
|
||||||
name, with_boards=False, expose_packages=False)
|
pkg_dir, with_boards=False, expose_packages=False)
|
||||||
data['versionLatest'] = latest or "Unknown"
|
data['versionLatest'] = latest
|
||||||
result.append(data)
|
result.append(data)
|
||||||
return click.echo(json.dumps(result))
|
return click.echo(json.dumps(result))
|
||||||
else:
|
else:
|
||||||
|
@ -163,8 +163,7 @@ def after_upgrade(ctx):
|
|||||||
# update development platforms
|
# update development platforms
|
||||||
pm = PlatformManager()
|
pm = PlatformManager()
|
||||||
for manifest in pm.get_installed():
|
for manifest in pm.get_installed():
|
||||||
# pm.update(manifest['name'], "^" + manifest['version'])
|
pm.update(manifest['__pkg_dir'])
|
||||||
pm.update(manifest['name'])
|
|
||||||
|
|
||||||
# update PlatformIO Plus tool if installed
|
# update PlatformIO Plus tool if installed
|
||||||
pioplus_update()
|
pioplus_update()
|
||||||
@ -262,7 +261,7 @@ def check_internal_updates(ctx, what):
|
|||||||
outdated_items = []
|
outdated_items = []
|
||||||
for manifest in pm.get_installed():
|
for manifest in pm.get_installed():
|
||||||
if manifest['name'] not in outdated_items and \
|
if manifest['name'] not in outdated_items and \
|
||||||
pm.outdated(manifest['name']):
|
pm.outdated(manifest['__pkg_dir']):
|
||||||
outdated_items.append(manifest['name'])
|
outdated_items.append(manifest['name'])
|
||||||
|
|
||||||
if not outdated_items:
|
if not outdated_items:
|
||||||
|
@ -15,10 +15,8 @@
|
|||||||
# pylint: disable=too-many-arguments, too-many-locals, too-many-branches
|
# pylint: disable=too-many-arguments, too-many-locals, too-many-branches
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
|
||||||
import re
|
import re
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from hashlib import md5
|
|
||||||
from os.path import isdir, join
|
from os.path import isdir, join
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
@ -61,8 +59,8 @@ class LibraryManager(BasePkgManager):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def load_manifest(self, path):
|
def load_manifest(self, pkg_dir):
|
||||||
manifest = BasePkgManager.load_manifest(self, path)
|
manifest = BasePkgManager.load_manifest(self, pkg_dir)
|
||||||
if not manifest:
|
if not manifest:
|
||||||
return manifest
|
return manifest
|
||||||
|
|
||||||
@ -76,6 +74,9 @@ class LibraryManager(BasePkgManager):
|
|||||||
manifest['authors'] = [{"name": manifest['author']}]
|
manifest['authors'] = [{"name": manifest['author']}]
|
||||||
del manifest['author']
|
del manifest['author']
|
||||||
|
|
||||||
|
if "authors" in manifest and not isinstance(manifest['authors'], list):
|
||||||
|
manifest['authors'] = [manifest['authors']]
|
||||||
|
|
||||||
if "keywords" not in manifest:
|
if "keywords" not in manifest:
|
||||||
keywords = []
|
keywords = []
|
||||||
for keyword in re.split(r"[\s/]+",
|
for keyword in re.split(r"[\s/]+",
|
||||||
@ -123,31 +124,6 @@ class LibraryManager(BasePkgManager):
|
|||||||
|
|
||||||
return manifest
|
return manifest
|
||||||
|
|
||||||
def check_pkg_structure(self, pkg_dir):
|
|
||||||
try:
|
|
||||||
return BasePkgManager.check_pkg_structure(self, pkg_dir)
|
|
||||||
except exception.MissingPackageManifest:
|
|
||||||
# we will generate manifest automatically
|
|
||||||
# if library doesn't contain any
|
|
||||||
pass
|
|
||||||
|
|
||||||
manifest = {
|
|
||||||
"name": "Library_" + md5(pkg_dir).hexdigest()[:5],
|
|
||||||
"version": "0.0.0"
|
|
||||||
}
|
|
||||||
for root, dirs, files in os.walk(pkg_dir):
|
|
||||||
if len(dirs) == 1 and not files:
|
|
||||||
manifest['name'] = dirs[0]
|
|
||||||
continue
|
|
||||||
if dirs or files:
|
|
||||||
pkg_dir = root
|
|
||||||
break
|
|
||||||
|
|
||||||
with open(join(pkg_dir, self.manifest_names[0]), "w") as fp:
|
|
||||||
json.dump(manifest, fp)
|
|
||||||
|
|
||||||
return pkg_dir
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def normalize_dependencies(dependencies):
|
def normalize_dependencies(dependencies):
|
||||||
if not dependencies:
|
if not dependencies:
|
||||||
@ -239,7 +215,7 @@ class LibraryManager(BasePkgManager):
|
|||||||
}, silent, interactive)['id'])
|
}, silent, interactive)['id'])
|
||||||
|
|
||||||
def _install_from_piorepo(self, name, requirements):
|
def _install_from_piorepo(self, name, requirements):
|
||||||
assert name.startswith("id=")
|
assert name.startswith("id="), name
|
||||||
version = self.get_latest_repo_version(name, requirements)
|
version = self.get_latest_repo_version(name, requirements)
|
||||||
if not version:
|
if not version:
|
||||||
raise exception.UndefinedPackageVersion(requirements or "latest",
|
raise exception.UndefinedPackageVersion(requirements or "latest",
|
||||||
@ -260,28 +236,23 @@ class LibraryManager(BasePkgManager):
|
|||||||
silent=False,
|
silent=False,
|
||||||
trigger_event=True,
|
trigger_event=True,
|
||||||
interactive=False):
|
interactive=False):
|
||||||
already_installed = False
|
|
||||||
_name, _requirements, _url = self.parse_pkg_name(name, requirements)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
_name, _requirements, _url = self.parse_pkg_input(name,
|
||||||
|
requirements)
|
||||||
if not _url:
|
if not _url:
|
||||||
_name = "id=%d" % self.get_pkg_id_by_name(
|
name = "id=%d" % self.get_pkg_id_by_name(
|
||||||
_name,
|
_name,
|
||||||
_requirements,
|
_requirements,
|
||||||
silent=silent,
|
silent=silent,
|
||||||
interactive=interactive)
|
interactive=interactive)
|
||||||
already_installed = self.get_package(_name, _requirements, _url)
|
requirements = _requirements
|
||||||
pkg_dir = BasePkgManager.install(
|
pkg_dir = BasePkgManager.install(self, name, requirements, silent,
|
||||||
self, _name
|
trigger_event)
|
||||||
if not _url else name, _requirements, silent, trigger_event)
|
|
||||||
except exception.InternetIsOffline as e:
|
except exception.InternetIsOffline as e:
|
||||||
if not silent:
|
if not silent:
|
||||||
click.secho(str(e), fg="yellow")
|
click.secho(str(e), fg="yellow")
|
||||||
return
|
return
|
||||||
|
|
||||||
if already_installed:
|
|
||||||
return
|
|
||||||
|
|
||||||
manifest = self.load_manifest(pkg_dir)
|
manifest = self.load_manifest(pkg_dir)
|
||||||
if "dependencies" not in manifest:
|
if "dependencies" not in manifest:
|
||||||
return pkg_dir
|
return pkg_dir
|
||||||
|
@ -17,7 +17,7 @@ import hashlib
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
from os.path import basename, dirname, getsize, isdir, isfile, islink, join
|
from os.path import basename, getsize, isdir, isfile, islink, join
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
|
|
||||||
import click
|
import click
|
||||||
@ -127,16 +127,36 @@ class PkgRepoMixin(object):
|
|||||||
|
|
||||||
class PkgInstallerMixin(object):
|
class PkgInstallerMixin(object):
|
||||||
|
|
||||||
VCS_MANIFEST_NAME = ".piopkgmanager.json"
|
SRC_MANIFEST_NAME = ".piopkgmanager.json"
|
||||||
|
|
||||||
FILE_CACHE_VALID = "1m" # 1 month
|
FILE_CACHE_VALID = "1m" # 1 month
|
||||||
FILE_CACHE_MAX_SIZE = 1024 * 1024
|
FILE_CACHE_MAX_SIZE = 1024 * 1024
|
||||||
|
|
||||||
_INSTALLED_CACHE = {}
|
MEMORY_CACHE = {}
|
||||||
|
|
||||||
def reset_cache(self):
|
@staticmethod
|
||||||
if self.package_dir in PkgInstallerMixin._INSTALLED_CACHE:
|
def cache_get(key, default=None):
|
||||||
del PkgInstallerMixin._INSTALLED_CACHE[self.package_dir]
|
return PkgInstallerMixin.MEMORY_CACHE.get(key, default)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def cache_set(key, value):
|
||||||
|
PkgInstallerMixin.MEMORY_CACHE[key] = value
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def cache_reset():
|
||||||
|
PkgInstallerMixin.MEMORY_CACHE = {}
|
||||||
|
|
||||||
|
def read_dirs(self, src_dir):
|
||||||
|
cache_key = "read_dirs-%s" % src_dir
|
||||||
|
result = self.cache_get(cache_key)
|
||||||
|
if result:
|
||||||
|
return result
|
||||||
|
result = [
|
||||||
|
join(src_dir, name) for name in sorted(os.listdir(src_dir))
|
||||||
|
if isdir(join(src_dir, name))
|
||||||
|
]
|
||||||
|
self.cache_set(cache_key, result)
|
||||||
|
return result
|
||||||
|
|
||||||
def download(self, url, dest_dir, sha1=None):
|
def download(self, url, dest_dir, sha1=None):
|
||||||
cache_key_fname = app.ContentCache.key_from_args(url, "fname")
|
cache_key_fname = app.ContentCache.key_from_args(url, "fname")
|
||||||
@ -171,26 +191,23 @@ class PkgInstallerMixin(object):
|
|||||||
return fu.start()
|
return fu.start()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def generate_install_dirname(manifest):
|
def get_install_dirname(manifest):
|
||||||
name = manifest['name']
|
name = manifest['name']
|
||||||
if "id" in manifest:
|
if "id" in manifest:
|
||||||
name += "_ID%d" % manifest['id']
|
name += "_ID%d" % manifest['id']
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def get_vcs_manifest_path(self, pkg_dir):
|
def get_src_manifest_path(self, pkg_dir):
|
||||||
for item in os.listdir(pkg_dir):
|
for item in os.listdir(pkg_dir):
|
||||||
if not isdir(join(pkg_dir, item)):
|
if not isdir(join(pkg_dir, item)):
|
||||||
continue
|
continue
|
||||||
if isfile(join(pkg_dir, item, self.VCS_MANIFEST_NAME)):
|
if isfile(join(pkg_dir, item, self.SRC_MANIFEST_NAME)):
|
||||||
return join(pkg_dir, item, self.VCS_MANIFEST_NAME)
|
return join(pkg_dir, item, self.SRC_MANIFEST_NAME)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_manifest_path(self, pkg_dir):
|
def get_manifest_path(self, pkg_dir):
|
||||||
if not isdir(pkg_dir):
|
if not isdir(pkg_dir):
|
||||||
return None
|
return None
|
||||||
manifest_path = self.get_vcs_manifest_path(pkg_dir)
|
|
||||||
if manifest_path:
|
|
||||||
return manifest_path
|
|
||||||
for name in self.manifest_names:
|
for name in self.manifest_names:
|
||||||
manifest_path = join(pkg_dir, name)
|
manifest_path = join(pkg_dir, name)
|
||||||
if isfile(manifest_path):
|
if isfile(manifest_path):
|
||||||
@ -198,73 +215,104 @@ class PkgInstallerMixin(object):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def manifest_exists(self, pkg_dir):
|
def manifest_exists(self, pkg_dir):
|
||||||
return self.get_manifest_path(pkg_dir) is not None
|
return self.get_manifest_path(pkg_dir) or \
|
||||||
|
self.get_src_manifest_path(pkg_dir)
|
||||||
|
|
||||||
def load_manifest(self, path): # pylint: disable=too-many-branches
|
def load_manifest(self, pkg_dir):
|
||||||
assert path
|
cache_key = "load_manifest-%s" % pkg_dir
|
||||||
pkg_dir = path
|
result = self.cache_get(cache_key)
|
||||||
if isdir(path):
|
if result:
|
||||||
path = self.get_manifest_path(path)
|
return result
|
||||||
if not path:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
pkg_dir = dirname(pkg_dir)
|
|
||||||
|
|
||||||
is_vcs_pkg = False
|
manifest_path = self.get_manifest_path(pkg_dir)
|
||||||
if isfile(path) and path.endswith(self.VCS_MANIFEST_NAME):
|
if not manifest_path:
|
||||||
is_vcs_pkg = True
|
return None
|
||||||
pkg_dir = dirname(dirname(path))
|
|
||||||
|
|
||||||
# return from cache
|
# if non-registry packages: VCS or archive
|
||||||
if self.package_dir in PkgInstallerMixin._INSTALLED_CACHE:
|
src_manifest_path = self.get_src_manifest_path(pkg_dir)
|
||||||
for manifest in PkgInstallerMixin._INSTALLED_CACHE[
|
src_manifest = None
|
||||||
self.package_dir]:
|
if src_manifest_path:
|
||||||
if not is_vcs_pkg and manifest['__pkg_dir'] == pkg_dir:
|
src_manifest = util.load_json(src_manifest_path)
|
||||||
return manifest
|
|
||||||
|
|
||||||
manifest = {}
|
manifest = {}
|
||||||
if path.endswith(".json"):
|
if manifest_path.endswith(".json"):
|
||||||
manifest = util.load_json(path)
|
manifest = util.load_json(manifest_path)
|
||||||
elif path.endswith(".properties"):
|
elif manifest_path.endswith(".properties"):
|
||||||
with codecs.open(path, encoding="utf-8") as fp:
|
with codecs.open(manifest_path, encoding="utf-8") as fp:
|
||||||
for line in fp.readlines():
|
for line in fp.readlines():
|
||||||
if "=" not in line:
|
if "=" not in line:
|
||||||
continue
|
continue
|
||||||
key, value = line.split("=", 1)
|
key, value = line.split("=", 1)
|
||||||
manifest[key.strip()] = value.strip()
|
manifest[key.strip()] = value.strip()
|
||||||
else:
|
|
||||||
|
if src_manifest:
|
||||||
if "name" not in manifest:
|
if "name" not in manifest:
|
||||||
manifest['name'] = basename(pkg_dir)
|
manifest['name'] = src_manifest['name']
|
||||||
if "version" not in manifest:
|
if "version" in src_manifest:
|
||||||
manifest['version'] = "0.0.0"
|
manifest['version'] = src_manifest['version']
|
||||||
|
manifest['__src_url'] = src_manifest['url']
|
||||||
|
|
||||||
|
if "name" not in manifest:
|
||||||
|
manifest['name'] = basename(pkg_dir)
|
||||||
|
if "version" not in manifest:
|
||||||
|
manifest['version'] = "0.0.0"
|
||||||
|
|
||||||
manifest['__pkg_dir'] = pkg_dir
|
manifest['__pkg_dir'] = pkg_dir
|
||||||
|
self.cache_set(cache_key, manifest)
|
||||||
return manifest
|
return manifest
|
||||||
|
|
||||||
def get_installed(self):
|
def get_installed(self):
|
||||||
if self.package_dir in PkgInstallerMixin._INSTALLED_CACHE:
|
|
||||||
return PkgInstallerMixin._INSTALLED_CACHE[self.package_dir]
|
|
||||||
items = []
|
items = []
|
||||||
for p in sorted(os.listdir(self.package_dir)):
|
for pkg_dir in self.read_dirs(self.package_dir):
|
||||||
pkg_dir = join(self.package_dir, p)
|
|
||||||
if not isdir(pkg_dir):
|
|
||||||
continue
|
|
||||||
manifest = self.load_manifest(pkg_dir)
|
manifest = self.load_manifest(pkg_dir)
|
||||||
if not manifest:
|
if not manifest:
|
||||||
continue
|
continue
|
||||||
assert "name" in manifest
|
assert "name" in manifest
|
||||||
items.append(manifest)
|
items.append(manifest)
|
||||||
PkgInstallerMixin._INSTALLED_CACHE[self.package_dir] = items
|
|
||||||
return items
|
return items
|
||||||
|
|
||||||
def check_pkg_structure(self, pkg_dir):
|
def get_package(self, name, requirements=None, url=None):
|
||||||
if self.manifest_exists(pkg_dir):
|
pkg_id = int(name[3:]) if name.startswith("id=") else 0
|
||||||
return pkg_dir
|
best = None
|
||||||
|
for manifest in self.get_installed():
|
||||||
|
if url:
|
||||||
|
if manifest.get("__src_url") != url:
|
||||||
|
continue
|
||||||
|
elif pkg_id and manifest.get("id") != pkg_id:
|
||||||
|
continue
|
||||||
|
elif not pkg_id and manifest['name'] != name:
|
||||||
|
continue
|
||||||
|
|
||||||
for root, _, _ in os.walk(pkg_dir):
|
# strict version or VCS HASH
|
||||||
|
if requirements and requirements == manifest['version']:
|
||||||
|
return manifest
|
||||||
|
|
||||||
|
try:
|
||||||
|
if requirements and not semantic_version.Spec(
|
||||||
|
requirements).match(
|
||||||
|
semantic_version.Version(
|
||||||
|
manifest['version'], partial=True)):
|
||||||
|
continue
|
||||||
|
elif not best or (semantic_version.Version(
|
||||||
|
manifest['version'], partial=True) >
|
||||||
|
semantic_version.Version(
|
||||||
|
best['version'], partial=True)):
|
||||||
|
best = manifest
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return best
|
||||||
|
|
||||||
|
def get_package_dir(self, name, requirements=None, url=None):
|
||||||
|
manifest = self.get_package(name, requirements, url)
|
||||||
|
return manifest.get("__pkg_dir") if manifest else None
|
||||||
|
|
||||||
|
def find_pkg_root(self, src_dir):
|
||||||
|
if self.manifest_exists(src_dir):
|
||||||
|
return src_dir
|
||||||
|
for root, _, _ in os.walk(src_dir):
|
||||||
if self.manifest_exists(root):
|
if self.manifest_exists(root):
|
||||||
return root
|
return root
|
||||||
|
|
||||||
raise exception.MissingPackageManifest(", ".join(self.manifest_names))
|
raise exception.MissingPackageManifest(", ".join(self.manifest_names))
|
||||||
|
|
||||||
def _install_from_piorepo(self, name, requirements):
|
def _install_from_piorepo(self, name, requirements):
|
||||||
@ -291,18 +339,25 @@ class PkgInstallerMixin(object):
|
|||||||
util.get_systype())
|
util.get_systype())
|
||||||
return pkg_dir
|
return pkg_dir
|
||||||
|
|
||||||
def _install_from_url(self, name, url, requirements=None, sha1=None):
|
def _install_from_url(self,
|
||||||
|
name,
|
||||||
|
url,
|
||||||
|
requirements=None,
|
||||||
|
sha1=None,
|
||||||
|
track=False):
|
||||||
pkg_dir = None
|
pkg_dir = None
|
||||||
tmp_dir = mkdtemp("-package", "installing-", self.package_dir)
|
tmp_dir = mkdtemp("-package", "installing-", self.package_dir)
|
||||||
|
src_manifest_dir = None
|
||||||
|
src_manifest = {"name": name, "url": url, "requirements": requirements}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if url.startswith("file://"):
|
if url.startswith("file://"):
|
||||||
url = url[7:]
|
_url = url[7:]
|
||||||
if isfile(url):
|
if isfile(_url):
|
||||||
self.unpack(url, tmp_dir)
|
self.unpack(_url, tmp_dir)
|
||||||
else:
|
else:
|
||||||
util.rmtree_(tmp_dir)
|
util.rmtree_(tmp_dir)
|
||||||
shutil.copytree(url, tmp_dir)
|
shutil.copytree(_url, tmp_dir)
|
||||||
elif url.startswith(("http://", "https://")):
|
elif url.startswith(("http://", "https://")):
|
||||||
dlpath = self.download(url, tmp_dir, sha1)
|
dlpath = self.download(url, tmp_dir, sha1)
|
||||||
assert isfile(dlpath)
|
assert isfile(dlpath)
|
||||||
@ -311,29 +366,52 @@ class PkgInstallerMixin(object):
|
|||||||
else:
|
else:
|
||||||
vcs = VCSClientFactory.newClient(tmp_dir, url)
|
vcs = VCSClientFactory.newClient(tmp_dir, url)
|
||||||
assert vcs.export()
|
assert vcs.export()
|
||||||
with open(join(vcs.storage_dir, self.VCS_MANIFEST_NAME),
|
src_manifest_dir = vcs.storage_dir
|
||||||
"w") as fp:
|
src_manifest['version'] = vcs.get_current_revision()
|
||||||
json.dump({
|
|
||||||
"name": name,
|
pkg_dir = self.find_pkg_root(tmp_dir)
|
||||||
"version": vcs.get_current_revision(),
|
|
||||||
"url": url,
|
# write source data to a special manifest
|
||||||
"requirements": requirements
|
if track:
|
||||||
}, fp)
|
if not src_manifest_dir:
|
||||||
|
src_manifest_dir = join(pkg_dir, ".pio")
|
||||||
|
self._update_src_manifest(src_manifest, src_manifest_dir)
|
||||||
|
|
||||||
pkg_dir = self.check_pkg_structure(tmp_dir)
|
|
||||||
pkg_dir = self._install_from_tmp_dir(pkg_dir, requirements)
|
pkg_dir = self._install_from_tmp_dir(pkg_dir, requirements)
|
||||||
finally:
|
finally:
|
||||||
if isdir(tmp_dir):
|
if isdir(tmp_dir):
|
||||||
util.rmtree_(tmp_dir)
|
util.rmtree_(tmp_dir)
|
||||||
return pkg_dir
|
return pkg_dir
|
||||||
|
|
||||||
def _install_from_tmp_dir(self, tmp_dir, requirements=None):
|
def _update_src_manifest(self, data, src_dir):
|
||||||
tmp_manifest_path = self.get_manifest_path(tmp_dir)
|
if not isdir(src_dir):
|
||||||
tmp_manifest = self.load_manifest(tmp_manifest_path)
|
os.makedirs(src_dir)
|
||||||
|
src_manifest_path = join(src_dir, self.SRC_MANIFEST_NAME)
|
||||||
|
_data = data
|
||||||
|
if isfile(src_manifest_path):
|
||||||
|
_data.update(util.load_json(src_manifest_path))
|
||||||
|
with open(src_manifest_path, "w") as fp:
|
||||||
|
json.dump(_data, fp)
|
||||||
|
|
||||||
|
def _install_from_tmp_dir( # pylint: disable=too-many-branches
|
||||||
|
self, tmp_dir, requirements=None):
|
||||||
|
tmp_manifest = self.load_manifest(tmp_dir)
|
||||||
assert set(["name", "version"]) <= set(tmp_manifest.keys())
|
assert set(["name", "version"]) <= set(tmp_manifest.keys())
|
||||||
|
|
||||||
name = self.generate_install_dirname(tmp_manifest)
|
pkg_dirname = self.get_install_dirname(tmp_manifest)
|
||||||
pkg_dir = join(self.package_dir, name)
|
pkg_dir = join(self.package_dir, pkg_dirname)
|
||||||
|
cur_manifest = self.load_manifest(pkg_dir)
|
||||||
|
|
||||||
|
tmp_semver = None
|
||||||
|
cur_semver = None
|
||||||
|
try:
|
||||||
|
tmp_semver = semantic_version.Version(
|
||||||
|
tmp_manifest['version'], partial=True)
|
||||||
|
if cur_manifest:
|
||||||
|
cur_semver = semantic_version.Version(
|
||||||
|
cur_manifest['version'], partial=True)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
# package should satisfy requirements
|
# package should satisfy requirements
|
||||||
if requirements:
|
if requirements:
|
||||||
@ -341,45 +419,51 @@ class PkgInstallerMixin(object):
|
|||||||
"Package version %s doesn't satisfy requirements %s" % (
|
"Package version %s doesn't satisfy requirements %s" % (
|
||||||
tmp_manifest['version'], requirements))
|
tmp_manifest['version'], requirements))
|
||||||
try:
|
try:
|
||||||
reqspec = semantic_version.Spec(requirements)
|
assert tmp_semver and tmp_semver in semantic_version.Spec(
|
||||||
tmp_version = semantic_version.Version(
|
requirements), mismatch_error
|
||||||
tmp_manifest['version'], partial=True)
|
except (AssertionError, ValueError):
|
||||||
assert tmp_version in reqspec, mismatch_error
|
|
||||||
except ValueError:
|
|
||||||
assert tmp_manifest['version'] == requirements, mismatch_error
|
assert tmp_manifest['version'] == requirements, mismatch_error
|
||||||
|
|
||||||
if self.manifest_exists(pkg_dir):
|
# check if package already exists
|
||||||
cur_manifest_path = self.get_manifest_path(pkg_dir)
|
if cur_manifest:
|
||||||
cur_manifest = self.load_manifest(cur_manifest_path)
|
# 0-overwrite, 1-rename, 2-fix to a version
|
||||||
|
action = 0
|
||||||
if tmp_manifest_path.endswith(self.VCS_MANIFEST_NAME):
|
if "__src_url" in cur_manifest:
|
||||||
if cur_manifest.get("url") != tmp_manifest['url']:
|
if cur_manifest['__src_url'] != tmp_manifest.get("__src_url"):
|
||||||
pkg_dir = join(self.package_dir, "%s@vcs-%s" % (
|
action = 1
|
||||||
name, hashlib.md5(tmp_manifest['url']).hexdigest()))
|
elif "__src_url" in tmp_manifest:
|
||||||
|
action = 2
|
||||||
else:
|
else:
|
||||||
try:
|
if tmp_semver and (not cur_semver or tmp_semver > cur_semver):
|
||||||
tmp_version = semantic_version.Version(
|
action = 1
|
||||||
tmp_manifest['version'], partial=True)
|
elif tmp_semver and cur_semver and tmp_semver != cur_semver:
|
||||||
cur_version = semantic_version.Version(
|
action = 2
|
||||||
cur_manifest['version'], partial=True)
|
|
||||||
|
|
||||||
# if current package version < new package, backup it
|
# rename
|
||||||
if tmp_version > cur_version:
|
if action == 1:
|
||||||
os.rename(pkg_dir,
|
target_dirname = "%s@%s" % (pkg_dirname,
|
||||||
join(self.package_dir, "%s@%s" %
|
cur_manifest['version'])
|
||||||
(name, cur_manifest['version'])))
|
if "__src_url" in cur_manifest:
|
||||||
elif tmp_version < cur_version:
|
target_dirname = "%s@src-%s" % (
|
||||||
pkg_dir = join(self.package_dir, "%s@%s" %
|
pkg_dirname,
|
||||||
(name, tmp_manifest['version']))
|
hashlib.md5(cur_manifest['__src_url']).hexdigest())
|
||||||
except ValueError:
|
os.rename(pkg_dir, join(self.package_dir, target_dirname))
|
||||||
pkg_dir = join(self.package_dir,
|
# fix to a version
|
||||||
"%s@%s" % (name, tmp_manifest['version']))
|
elif action == 2:
|
||||||
|
target_dirname = "%s@%s" % (pkg_dirname,
|
||||||
|
tmp_manifest['version'])
|
||||||
|
if "__src_url" in tmp_manifest:
|
||||||
|
target_dirname = "%s@src-%s" % (
|
||||||
|
pkg_dirname,
|
||||||
|
hashlib.md5(tmp_manifest['__src_url']).hexdigest())
|
||||||
|
pkg_dir = join(self.package_dir, target_dirname)
|
||||||
|
|
||||||
# remove previous/not-satisfied package
|
# remove previous/not-satisfied package
|
||||||
if isdir(pkg_dir):
|
if isdir(pkg_dir):
|
||||||
util.rmtree_(pkg_dir)
|
util.rmtree_(pkg_dir)
|
||||||
os.rename(tmp_dir, pkg_dir)
|
os.rename(tmp_dir, pkg_dir)
|
||||||
assert isdir(pkg_dir)
|
assert isdir(pkg_dir)
|
||||||
|
self.cache_reset()
|
||||||
return pkg_dir
|
return pkg_dir
|
||||||
|
|
||||||
|
|
||||||
@ -400,14 +484,20 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
|||||||
click.echo("%s: %s" % (self.__class__.__name__, message), nl=nl)
|
click.echo("%s: %s" % (self.__class__.__name__, message), nl=nl)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_pkg_name( # pylint: disable=too-many-branches
|
def parse_pkg_input( # pylint: disable=too-many-branches
|
||||||
text, requirements=None):
|
text, requirements=None):
|
||||||
text = str(text)
|
text = str(text)
|
||||||
url_marker = "://"
|
# git@github.com:user/package.git
|
||||||
if not any([
|
url_marker = text[:4]
|
||||||
requirements, "@" not in text, text.startswith("git@"),
|
if url_marker not in ("git@", "git+") or ":" not in text:
|
||||||
url_marker in text
|
url_marker = "://"
|
||||||
]):
|
|
||||||
|
req_conditions = [
|
||||||
|
not requirements, "@" in text,
|
||||||
|
(url_marker != "git@" and "://git@" not in text) or
|
||||||
|
text.count("@") > 1
|
||||||
|
]
|
||||||
|
if all(req_conditions):
|
||||||
text, requirements = text.rsplit("@", 1)
|
text, requirements = text.rsplit("@", 1)
|
||||||
if text.isdigit():
|
if text.isdigit():
|
||||||
text = "id=" + text
|
text = "id=" + text
|
||||||
@ -423,22 +513,18 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
|||||||
url.startswith("http") and
|
url.startswith("http") and
|
||||||
(url.split("#", 1)[0] if "#" in url else url).endswith(".git")
|
(url.split("#", 1)[0] if "#" in url else url).endswith(".git")
|
||||||
]
|
]
|
||||||
|
|
||||||
if any(git_conditions):
|
if any(git_conditions):
|
||||||
url = "git+" + url
|
url = "git+" + url
|
||||||
|
|
||||||
# Handle Developer Mbed URL
|
# Handle Developer Mbed URL
|
||||||
# (https://developer.mbed.org/users/user/code/package/)
|
# (https://developer.mbed.org/users/user/code/package/)
|
||||||
elif url.startswith("https://developer.mbed.org"):
|
if url.startswith("https://developer.mbed.org"):
|
||||||
url = "hg+" + url
|
url = "hg+" + url
|
||||||
|
|
||||||
# git@github.com:user/package.git
|
|
||||||
if url.startswith("git@"):
|
|
||||||
url_marker = "git@"
|
|
||||||
|
|
||||||
if any([s in url for s in ("\\", "/")]) and url_marker not in url:
|
if any([s in url for s in ("\\", "/")]) and url_marker not in url:
|
||||||
if isfile(url) or isdir(url):
|
if isfile(url) or isdir(url):
|
||||||
url = "file://" + url
|
url = "file://" + url
|
||||||
elif url.count("/") == 1 and not url.startswith("git@"):
|
elif url.count("/") == 1 and "git" not in url_marker:
|
||||||
url = "git+https://github.com/" + url
|
url = "git+https://github.com/" + url
|
||||||
|
|
||||||
# determine name
|
# determine name
|
||||||
@ -448,55 +534,13 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
|||||||
_url = _url[:-1]
|
_url = _url[:-1]
|
||||||
name = basename(_url)
|
name = basename(_url)
|
||||||
if "." in name and not name.startswith("."):
|
if "." in name and not name.startswith("."):
|
||||||
name = name.split(".", 1)[0]
|
name = name.rsplit(".", 1)[0]
|
||||||
|
|
||||||
if url_marker not in url:
|
if url_marker not in url:
|
||||||
url = None
|
url = None
|
||||||
return (name or text, requirements, url)
|
return (name or text, requirements, url)
|
||||||
|
|
||||||
def get_package(self, name, requirements=None, url=None):
|
def outdated(self, pkg_dir, requirements=None):
|
||||||
pkg_id = int(name[3:]) if name.startswith("id=") else 0
|
|
||||||
best = None
|
|
||||||
reqspec = None
|
|
||||||
if requirements:
|
|
||||||
try:
|
|
||||||
reqspec = semantic_version.Spec(requirements)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
for manifest in self.get_installed():
|
|
||||||
if pkg_id and manifest.get("id") != pkg_id:
|
|
||||||
continue
|
|
||||||
elif not pkg_id and manifest['name'] != name:
|
|
||||||
continue
|
|
||||||
elif not reqspec and (requirements or url):
|
|
||||||
conds = [
|
|
||||||
requirements == manifest['version'], url and
|
|
||||||
url in manifest.get("url", "")
|
|
||||||
]
|
|
||||||
if not best or any(conds):
|
|
||||||
best = manifest
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
if reqspec and not reqspec.match(
|
|
||||||
semantic_version.Version(
|
|
||||||
manifest['version'], partial=True)):
|
|
||||||
continue
|
|
||||||
elif not best or (semantic_version.Version(
|
|
||||||
manifest['version'], partial=True) >
|
|
||||||
semantic_version.Version(
|
|
||||||
best['version'], partial=True)):
|
|
||||||
best = manifest
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return best
|
|
||||||
|
|
||||||
def get_package_dir(self, name, requirements=None, url=None):
|
|
||||||
package = self.get_package(name, requirements, url)
|
|
||||||
return package.get("__pkg_dir") if package else None
|
|
||||||
|
|
||||||
def outdated(self, name, requirements=None, url=None):
|
|
||||||
"""
|
"""
|
||||||
Has 3 different results:
|
Has 3 different results:
|
||||||
`None` - unknown package, VCS is fixed to commit
|
`None` - unknown package, VCS is fixed to commit
|
||||||
@ -504,27 +548,26 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
|||||||
`String` - a found latest version
|
`String` - a found latest version
|
||||||
"""
|
"""
|
||||||
latest = None
|
latest = None
|
||||||
package_dir = self.get_package_dir(name, requirements, url)
|
manifest = self.load_manifest(pkg_dir)
|
||||||
if not package_dir or ("@" in package_dir and
|
# skip a fixed package to a specific version
|
||||||
"@vcs-" not in package_dir):
|
if "@" in pkg_dir and "__src_url" not in manifest:
|
||||||
return None
|
return None
|
||||||
is_vcs_pkg = False
|
if "__src_url" in manifest:
|
||||||
manifest_path = self.get_vcs_manifest_path(package_dir)
|
try:
|
||||||
if manifest_path:
|
vcs = VCSClientFactory.newClient(
|
||||||
is_vcs_pkg = True
|
pkg_dir, manifest['__src_url'], silent=True)
|
||||||
manifest = self.load_manifest(manifest_path)
|
except (AttributeError, exception.PlatformioException):
|
||||||
else:
|
return None
|
||||||
manifest = self.load_manifest(package_dir)
|
|
||||||
if is_vcs_pkg:
|
|
||||||
vcs = VCSClientFactory.newClient(
|
|
||||||
package_dir, manifest['url'], silent=True)
|
|
||||||
if not vcs.can_be_updated:
|
if not vcs.can_be_updated:
|
||||||
return None
|
return None
|
||||||
latest = vcs.get_latest_revision()
|
latest = vcs.get_latest_revision()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
latest = self.get_latest_repo_version(
|
latest = self.get_latest_repo_version(
|
||||||
name, requirements, silent=True)
|
"id=%d" % manifest['id']
|
||||||
|
if "id" in manifest else manifest['name'],
|
||||||
|
requirements,
|
||||||
|
silent=True)
|
||||||
except (exception.PlatformioException, ValueError):
|
except (exception.PlatformioException, ValueError):
|
||||||
return None
|
return None
|
||||||
if not latest:
|
if not latest:
|
||||||
@ -543,7 +586,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
|||||||
silent=False,
|
silent=False,
|
||||||
trigger_event=True,
|
trigger_event=True,
|
||||||
interactive=False): # pylint: disable=unused-argument
|
interactive=False): # pylint: disable=unused-argument
|
||||||
name, requirements, url = self.parse_pkg_name(name, requirements)
|
name, requirements, url = self.parse_pkg_input(name, requirements)
|
||||||
package_dir = self.get_package_dir(name, requirements, url)
|
package_dir = self.get_package_dir(name, requirements, url)
|
||||||
|
|
||||||
if not package_dir or not silent:
|
if not package_dir or not silent:
|
||||||
@ -560,15 +603,16 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
|||||||
return package_dir
|
return package_dir
|
||||||
|
|
||||||
if url:
|
if url:
|
||||||
pkg_dir = self._install_from_url(name, url, requirements)
|
pkg_dir = self._install_from_url(
|
||||||
|
name, url, requirements, track=True)
|
||||||
else:
|
else:
|
||||||
pkg_dir = self._install_from_piorepo(name, requirements)
|
pkg_dir = self._install_from_piorepo(name, requirements)
|
||||||
if not pkg_dir or not self.manifest_exists(pkg_dir):
|
if not pkg_dir or not self.manifest_exists(pkg_dir):
|
||||||
raise exception.PackageInstallError(name, requirements or "*",
|
raise exception.PackageInstallError(name, requirements or "*",
|
||||||
util.get_systype())
|
util.get_systype())
|
||||||
|
|
||||||
self.reset_cache()
|
|
||||||
manifest = self.load_manifest(pkg_dir)
|
manifest = self.load_manifest(pkg_dir)
|
||||||
|
assert manifest
|
||||||
|
|
||||||
if trigger_event:
|
if trigger_event:
|
||||||
telemetry.on_event(
|
telemetry.on_event(
|
||||||
@ -576,42 +620,45 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
|||||||
action="Install",
|
action="Install",
|
||||||
label=manifest['name'])
|
label=manifest['name'])
|
||||||
|
|
||||||
click.secho(
|
if not silent:
|
||||||
"{name} @ {version} has been successfully installed!".format(
|
click.secho(
|
||||||
**manifest),
|
"{name} @ {version} has been successfully installed!".format(
|
||||||
fg="green")
|
**manifest),
|
||||||
|
fg="green")
|
||||||
|
|
||||||
return pkg_dir
|
return pkg_dir
|
||||||
|
|
||||||
def uninstall(self, name, requirements=None, trigger_event=True):
|
def uninstall(self, package, requirements=None, trigger_event=True):
|
||||||
name, requirements, url = self.parse_pkg_name(name, requirements)
|
if isdir(package):
|
||||||
package_dir = self.get_package_dir(name, requirements, url)
|
pkg_dir = package
|
||||||
if not package_dir:
|
else:
|
||||||
click.secho(
|
name, requirements, url = self.parse_pkg_input(package,
|
||||||
"%s @ %s is not installed" % (name, requirements or "*"),
|
requirements)
|
||||||
fg="yellow")
|
pkg_dir = self.get_package_dir(name, requirements, url)
|
||||||
return
|
|
||||||
|
|
||||||
manifest = self.load_manifest(package_dir)
|
if not pkg_dir:
|
||||||
|
raise exception.UnknownPackage("%s @ %s" %
|
||||||
|
(package, requirements or "*"))
|
||||||
|
|
||||||
|
manifest = self.load_manifest(pkg_dir)
|
||||||
click.echo(
|
click.echo(
|
||||||
"Uninstalling %s @ %s: \t" % (click.style(
|
"Uninstalling %s @ %s: \t" % (click.style(
|
||||||
manifest['name'], fg="cyan"), manifest['version']),
|
manifest['name'], fg="cyan"), manifest['version']),
|
||||||
nl=False)
|
nl=False)
|
||||||
|
|
||||||
if isdir(package_dir):
|
if islink(pkg_dir):
|
||||||
if islink(package_dir):
|
os.unlink(pkg_dir)
|
||||||
os.unlink(package_dir)
|
else:
|
||||||
else:
|
util.rmtree_(pkg_dir)
|
||||||
util.rmtree_(package_dir)
|
self.cache_reset()
|
||||||
self.reset_cache()
|
|
||||||
|
|
||||||
# unfix package with the same name
|
# unfix package with the same name
|
||||||
package_dir = self.get_package_dir(manifest['name'])
|
pkg_dir = self.get_package_dir(manifest['name'])
|
||||||
if package_dir and "@" in package_dir:
|
if pkg_dir and "@" in pkg_dir:
|
||||||
os.rename(package_dir,
|
os.rename(
|
||||||
join(self.package_dir,
|
pkg_dir,
|
||||||
self.generate_install_dirname(manifest)))
|
join(self.package_dir, self.get_install_dirname(manifest)))
|
||||||
self.reset_cache()
|
self.cache_reset()
|
||||||
|
|
||||||
click.echo("[%s]" % click.style("OK", fg="green"))
|
click.echo("[%s]" % click.style("OK", fg="green"))
|
||||||
|
|
||||||
@ -624,25 +671,23 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
|||||||
|
|
||||||
def update( # pylint: disable=too-many-return-statements
|
def update( # pylint: disable=too-many-return-statements
|
||||||
self,
|
self,
|
||||||
name,
|
package,
|
||||||
requirements=None,
|
requirements=None,
|
||||||
only_check=False):
|
only_check=False):
|
||||||
name, requirements, url = self.parse_pkg_name(name, requirements)
|
if isdir(package):
|
||||||
package_dir = self.get_package_dir(name, requirements, url)
|
pkg_dir = package
|
||||||
if not package_dir:
|
|
||||||
click.secho(
|
|
||||||
"%s @ %s is not installed" % (name, requirements or "*"),
|
|
||||||
fg="yellow")
|
|
||||||
return
|
|
||||||
|
|
||||||
is_vcs_pkg = False
|
|
||||||
if self.get_vcs_manifest_path(package_dir):
|
|
||||||
is_vcs_pkg = True
|
|
||||||
manifest_path = self.get_vcs_manifest_path(package_dir)
|
|
||||||
else:
|
else:
|
||||||
manifest_path = self.get_manifest_path(package_dir)
|
name, requirements, url = self.parse_pkg_input(package,
|
||||||
|
requirements)
|
||||||
|
pkg_dir = self.get_package_dir(name, requirements, url)
|
||||||
|
|
||||||
|
if not pkg_dir:
|
||||||
|
raise exception.UnknownPackage("%s @ %s" %
|
||||||
|
(package, requirements or "*"))
|
||||||
|
|
||||||
|
manifest = self.load_manifest(pkg_dir)
|
||||||
|
name = manifest['name']
|
||||||
|
|
||||||
manifest = self.load_manifest(manifest_path)
|
|
||||||
click.echo(
|
click.echo(
|
||||||
"{} {:<40} @ {:<15}".format(
|
"{} {:<40} @ {:<15}".format(
|
||||||
"Checking" if only_check else "Updating",
|
"Checking" if only_check else "Updating",
|
||||||
@ -651,7 +696,8 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
|||||||
if not util.internet_on():
|
if not util.internet_on():
|
||||||
click.echo("[%s]" % (click.style("Off-line", fg="yellow")))
|
click.echo("[%s]" % (click.style("Off-line", fg="yellow")))
|
||||||
return
|
return
|
||||||
latest = self.outdated(name, requirements, url)
|
|
||||||
|
latest = self.outdated(pkg_dir, requirements)
|
||||||
if latest:
|
if latest:
|
||||||
click.echo("[%s]" % (click.style(latest, fg="red")))
|
click.echo("[%s]" % (click.style(latest, fg="red")))
|
||||||
elif latest is False:
|
elif latest is False:
|
||||||
@ -659,26 +705,18 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
|
|||||||
else:
|
else:
|
||||||
click.echo("[%s]" % (click.style("Skip", fg="yellow")))
|
click.echo("[%s]" % (click.style("Skip", fg="yellow")))
|
||||||
|
|
||||||
if only_check or latest is False or (not is_vcs_pkg and not latest):
|
if only_check or not latest:
|
||||||
return
|
return
|
||||||
|
|
||||||
if is_vcs_pkg:
|
if "__src_url" in manifest:
|
||||||
vcs = VCSClientFactory.newClient(package_dir, manifest['url'])
|
vcs = VCSClientFactory.newClient(pkg_dir, manifest['__vcs_url'])
|
||||||
if not vcs.can_be_updated:
|
|
||||||
click.secho(
|
|
||||||
"Skip update because repository is fixed "
|
|
||||||
"to %s revision" % manifest['version'],
|
|
||||||
fg="yellow")
|
|
||||||
return
|
|
||||||
assert vcs.update()
|
assert vcs.update()
|
||||||
with open(manifest_path, "w") as fp:
|
self._update_src_manifest(
|
||||||
manifest['version'] = vcs.get_current_revision()
|
dict(version=vcs.get_current_revision()), vcs.storage_dir)
|
||||||
json.dump(manifest, fp)
|
|
||||||
else:
|
else:
|
||||||
self.uninstall(name, manifest['version'], trigger_event=False)
|
self.uninstall(pkg_dir, trigger_event=False)
|
||||||
self.install(name, latest, trigger_event=False)
|
self.install(name, latest, trigger_event=False)
|
||||||
|
|
||||||
self.reset_cache()
|
|
||||||
telemetry.on_event(
|
telemetry.on_event(
|
||||||
category=self.__class__.__name__,
|
category=self.__class__.__name__,
|
||||||
action="Update",
|
action="Update",
|
||||||
|
@ -63,7 +63,7 @@ class PlatformManager(BasePkgManager):
|
|||||||
trigger_event=True,
|
trigger_event=True,
|
||||||
**_): # pylint: disable=too-many-arguments
|
**_): # pylint: disable=too-many-arguments
|
||||||
platform_dir = BasePkgManager.install(self, name, requirements)
|
platform_dir = BasePkgManager.install(self, name, requirements)
|
||||||
p = PlatformFactory.newPlatform(self.get_manifest_path(platform_dir))
|
p = PlatformFactory.newPlatform(platform_dir)
|
||||||
|
|
||||||
# @Hook: when 'update' operation (trigger_event is False),
|
# @Hook: when 'update' operation (trigger_event is False),
|
||||||
# don't cleanup packages or install them
|
# don't cleanup packages or install them
|
||||||
@ -75,10 +75,16 @@ class PlatformManager(BasePkgManager):
|
|||||||
self.cleanup_packages(p.packages.keys())
|
self.cleanup_packages(p.packages.keys())
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def uninstall(self, name, requirements=None, trigger_event=True):
|
def uninstall(self, package, requirements=None, trigger_event=True):
|
||||||
name, requirements, _ = self.parse_pkg_name(name, requirements)
|
if isdir(package):
|
||||||
p = PlatformFactory.newPlatform(name, requirements)
|
pkg_dir = package
|
||||||
BasePkgManager.uninstall(self, name, requirements)
|
else:
|
||||||
|
name, requirements, url = self.parse_pkg_input(package,
|
||||||
|
requirements)
|
||||||
|
pkg_dir = self.get_package_dir(name, requirements, url)
|
||||||
|
|
||||||
|
p = PlatformFactory.newPlatform(pkg_dir)
|
||||||
|
BasePkgManager.uninstall(self, pkg_dir, requirements)
|
||||||
|
|
||||||
# @Hook: when 'update' operation (trigger_event is False),
|
# @Hook: when 'update' operation (trigger_event is False),
|
||||||
# don't cleanup packages or install them
|
# don't cleanup packages or install them
|
||||||
@ -90,18 +96,23 @@ class PlatformManager(BasePkgManager):
|
|||||||
|
|
||||||
def update( # pylint: disable=arguments-differ
|
def update( # pylint: disable=arguments-differ
|
||||||
self,
|
self,
|
||||||
name,
|
package,
|
||||||
requirements=None,
|
requirements=None,
|
||||||
only_packages=False,
|
only_check=False,
|
||||||
only_check=False):
|
only_packages=False):
|
||||||
name, requirements, _ = self.parse_pkg_name(name, requirements)
|
if isdir(package):
|
||||||
|
pkg_dir = package
|
||||||
|
else:
|
||||||
|
name, requirements, url = self.parse_pkg_input(package,
|
||||||
|
requirements)
|
||||||
|
pkg_dir = self.get_package_dir(name, requirements, url)
|
||||||
|
|
||||||
p = PlatformFactory.newPlatform(name, requirements)
|
p = PlatformFactory.newPlatform(pkg_dir)
|
||||||
pkgs_before = pkgs_after = p.get_installed_packages().keys()
|
pkgs_before = pkgs_after = p.get_installed_packages().keys()
|
||||||
|
|
||||||
if not only_packages:
|
if not only_packages:
|
||||||
BasePkgManager.update(self, name, requirements, only_check)
|
BasePkgManager.update(self, pkg_dir, requirements, only_check)
|
||||||
p = PlatformFactory.newPlatform(name, requirements)
|
p = PlatformFactory.newPlatform(pkg_dir)
|
||||||
pkgs_after = p.get_installed_packages().keys()
|
pkgs_after = p.get_installed_packages().keys()
|
||||||
|
|
||||||
p.update_packages(only_check)
|
p.update_packages(only_check)
|
||||||
@ -115,11 +126,10 @@ class PlatformManager(BasePkgManager):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def cleanup_packages(self, names):
|
def cleanup_packages(self, names):
|
||||||
self.reset_cache()
|
self.cache_reset()
|
||||||
deppkgs = {}
|
deppkgs = {}
|
||||||
for manifest in PlatformManager().get_installed():
|
for manifest in PlatformManager().get_installed():
|
||||||
p = PlatformFactory.newPlatform(manifest['name'],
|
p = PlatformFactory.newPlatform(manifest['__pkg_dir'])
|
||||||
manifest['version'])
|
|
||||||
for pkgname, pkgmanifest in p.get_installed_packages().items():
|
for pkgname, pkgmanifest in p.get_installed_packages().items():
|
||||||
if pkgname not in deppkgs:
|
if pkgname not in deppkgs:
|
||||||
deppkgs[pkgname] = set()
|
deppkgs[pkgname] = set()
|
||||||
@ -131,17 +141,15 @@ class PlatformManager(BasePkgManager):
|
|||||||
continue
|
continue
|
||||||
if (manifest['name'] not in deppkgs or
|
if (manifest['name'] not in deppkgs or
|
||||||
manifest['version'] not in deppkgs[manifest['name']]):
|
manifest['version'] not in deppkgs[manifest['name']]):
|
||||||
pm.uninstall(
|
pm.uninstall(manifest['__pkg_dir'], trigger_event=False)
|
||||||
manifest['name'], manifest['version'], trigger_event=False)
|
|
||||||
|
|
||||||
self.reset_cache()
|
self.cache_reset()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_installed_boards(self):
|
def get_installed_boards(self):
|
||||||
boards = []
|
boards = []
|
||||||
for manifest in self.get_installed():
|
for manifest in self.get_installed():
|
||||||
p = PlatformFactory.newPlatform(
|
p = PlatformFactory.newPlatform(manifest['__pkg_dir'])
|
||||||
self.get_manifest_path(manifest['__pkg_dir']))
|
|
||||||
for config in p.get_boards().values():
|
for config in p.get_boards().values():
|
||||||
board = config.get_brief_data()
|
board = config.get_brief_data()
|
||||||
if board not in boards:
|
if board not in boards:
|
||||||
@ -183,7 +191,10 @@ class PlatformFactory(object):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def newPlatform(cls, name, requirements=None):
|
def newPlatform(cls, name, requirements=None):
|
||||||
platform_dir = None
|
platform_dir = None
|
||||||
if name.endswith("platform.json") and isfile(name):
|
if isdir(name):
|
||||||
|
platform_dir = name
|
||||||
|
name = PlatformManager().load_manifest(platform_dir)['name']
|
||||||
|
elif name.endswith("platform.json") and isfile(name):
|
||||||
platform_dir = dirname(name)
|
platform_dir = dirname(name)
|
||||||
name = util.load_json(name)['name']
|
name = util.load_json(name)['name']
|
||||||
else:
|
else:
|
||||||
@ -249,8 +260,8 @@ class PlatformPackagesMixin(object):
|
|||||||
if self.is_valid_requirements(version):
|
if self.is_valid_requirements(version):
|
||||||
package = self.pm.get_package(name, version)
|
package = self.pm.get_package(name, version)
|
||||||
else:
|
else:
|
||||||
package = self.pm.get_package(*self._parse_pkg_name(name,
|
package = self.pm.get_package(*self._parse_pkg_input(name,
|
||||||
version))
|
version))
|
||||||
if package:
|
if package:
|
||||||
items[name] = package
|
items[name] = package
|
||||||
return items
|
return items
|
||||||
@ -267,46 +278,47 @@ class PlatformPackagesMixin(object):
|
|||||||
self.pm.update("%s=%s" % (name, version), requirements,
|
self.pm.update("%s=%s" % (name, version), requirements,
|
||||||
only_check)
|
only_check)
|
||||||
|
|
||||||
def are_outdated_packages(self):
|
# def are_outdated_packages(self):
|
||||||
latest = None
|
# latest = None
|
||||||
for name in self.get_installed_packages():
|
# for name in self.get_installed_packages():
|
||||||
version = self.packages[name].get("version", "")
|
# version = self.packages[name].get("version", "")
|
||||||
if self.is_valid_requirements(version):
|
# if self.is_valid_requirements(version):
|
||||||
latest = self.pm.outdated(name, version)
|
# latest = self.pm.outdated(name, version)
|
||||||
else:
|
# else:
|
||||||
requirements = None
|
# requirements = None
|
||||||
if "@" in version:
|
# if "@" in version:
|
||||||
version, requirements = version.rsplit("@", 1)
|
# version, requirements = version.rsplit("@", 1)
|
||||||
latest = self.pm.outdated(name, requirements, version)
|
# latest = self.pm.outdated(name, requirements, version)
|
||||||
if latest or latest is None:
|
# if latest or latest is None:
|
||||||
return True
|
# return True
|
||||||
return False
|
# return False
|
||||||
|
|
||||||
def get_package_dir(self, name):
|
def get_package_dir(self, name):
|
||||||
version = self.packages[name].get("version", "")
|
version = self.packages[name].get("version", "")
|
||||||
if self.is_valid_requirements(version):
|
if self.is_valid_requirements(version):
|
||||||
return self.pm.get_package_dir(name, version)
|
return self.pm.get_package_dir(name, version)
|
||||||
else:
|
else:
|
||||||
return self.pm.get_package_dir(*self._parse_pkg_name(name,
|
return self.pm.get_package_dir(*self._parse_pkg_input(name,
|
||||||
version))
|
version))
|
||||||
|
|
||||||
def get_package_version(self, name):
|
def get_package_version(self, name):
|
||||||
version = self.packages[name].get("version", "")
|
version = self.packages[name].get("version", "")
|
||||||
if self.is_valid_requirements(version):
|
if self.is_valid_requirements(version):
|
||||||
package = self.pm.get_package(name, version)
|
package = self.pm.get_package(name, version)
|
||||||
else:
|
else:
|
||||||
package = self.pm.get_package(*self._parse_pkg_name(name, version))
|
package = self.pm.get_package(*self._parse_pkg_input(name,
|
||||||
|
version))
|
||||||
return package['version'] if package else None
|
return package['version'] if package else None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_valid_requirements(requirements):
|
def is_valid_requirements(requirements):
|
||||||
return requirements and "://" not in requirements
|
return requirements and "://" not in requirements
|
||||||
|
|
||||||
def _parse_pkg_name(self, name, version):
|
def _parse_pkg_input(self, name, version):
|
||||||
requirements = None
|
requirements = None
|
||||||
if "@" in version:
|
if "@" in version:
|
||||||
version, requirements = version.rsplit("@", 1)
|
version, requirements = version.rsplit("@", 1)
|
||||||
return self.pm.parse_pkg_name("%s=%s" % (name, version), requirements)
|
return self.pm.parse_pkg_input("%s=%s" % (name, version), requirements)
|
||||||
|
|
||||||
|
|
||||||
class PlatformRunMixin(object):
|
class PlatformRunMixin(object):
|
||||||
|
@ -141,7 +141,12 @@ class memoized(object):
|
|||||||
|
|
||||||
def __get__(self, obj, objtype):
|
def __get__(self, obj, objtype):
|
||||||
'''Support instance methods.'''
|
'''Support instance methods.'''
|
||||||
return functools.partial(self.__call__, obj)
|
fn = functools.partial(self.__call__, obj)
|
||||||
|
fn.reset = self._reset
|
||||||
|
return fn
|
||||||
|
|
||||||
|
def _reset(self):
|
||||||
|
self.cache = {}
|
||||||
|
|
||||||
|
|
||||||
def singleton(cls):
|
def singleton(cls):
|
||||||
|
@ -16,7 +16,7 @@ import json
|
|||||||
import re
|
import re
|
||||||
from os.path import basename
|
from os.path import basename
|
||||||
|
|
||||||
from platformio import util
|
from platformio import exception, util
|
||||||
from platformio.commands.init import cli as cmd_init
|
from platformio.commands.init import cli as cmd_init
|
||||||
from platformio.commands.lib import cli as cmd_lib
|
from platformio.commands.lib import cli as cmd_lib
|
||||||
|
|
||||||
@ -37,15 +37,35 @@ def test_search(clirunner, validate_cliresult):
|
|||||||
def test_global_install_registry(clirunner, validate_cliresult,
|
def test_global_install_registry(clirunner, validate_cliresult,
|
||||||
isolated_pio_home):
|
isolated_pio_home):
|
||||||
result = clirunner.invoke(cmd_lib, [
|
result = clirunner.invoke(cmd_lib, [
|
||||||
"-g", "install", "58", "OneWire",
|
"-g", "install", "58", "547@2.2.4", "DallasTemperature",
|
||||||
"http://dl.platformio.org/libraries/archives/3/5174.tar.gz",
|
"http://dl.platformio.org/libraries/archives/3/5174.tar.gz",
|
||||||
"ArduinoJson@5.6.7", "ArduinoJson@~5.7.0"
|
"ArduinoJson@5.6.7", "ArduinoJson@~5.7.0", "1089@fee16e880b"
|
||||||
])
|
])
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
|
|
||||||
|
# check lib with duplicate URL
|
||||||
|
result = clirunner.invoke(cmd_lib, [
|
||||||
|
"-g", "install",
|
||||||
|
"http://dl.platformio.org/libraries/archives/3/5174.tar.gz"
|
||||||
|
])
|
||||||
|
validate_cliresult(result)
|
||||||
|
assert "is already installed" in result.output
|
||||||
|
|
||||||
|
# check lib with duplicate ID
|
||||||
|
result = clirunner.invoke(cmd_lib, ["-g", "install", "305"])
|
||||||
|
validate_cliresult(result)
|
||||||
|
assert "is already installed" in result.output
|
||||||
|
|
||||||
|
# install unknown library
|
||||||
|
result = clirunner.invoke(cmd_lib, ["-g", "install", "Unknown"])
|
||||||
|
assert result.exit_code != 0
|
||||||
|
assert isinstance(result.exception, exception.LibNotFound)
|
||||||
|
|
||||||
items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()]
|
items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()]
|
||||||
items2 = [
|
items2 = [
|
||||||
"DHT22_ID58", "ArduinoJson_ID64", "ArduinoJson_ID64@5.6.7",
|
"ArduinoJson_ID64", "ArduinoJson_ID64@5.6.7", "DallasTemperature_ID54",
|
||||||
"OneWire_ID1", "ESPAsyncTCP_ID305"
|
"DHT22_ID58", "ESPAsyncTCP_ID305", "NeoPixelBus_ID547", "OneWire_ID1",
|
||||||
|
"IRremoteESP8266_ID1089"
|
||||||
]
|
]
|
||||||
assert set(items1) == set(items2)
|
assert set(items1) == set(items2)
|
||||||
|
|
||||||
@ -55,11 +75,29 @@ def test_global_install_archive(clirunner, validate_cliresult,
|
|||||||
result = clirunner.invoke(cmd_lib, [
|
result = clirunner.invoke(cmd_lib, [
|
||||||
"-g", "install", "https://github.com/adafruit/Adafruit-ST7735-Library/"
|
"-g", "install", "https://github.com/adafruit/Adafruit-ST7735-Library/"
|
||||||
"archive/master.zip",
|
"archive/master.zip",
|
||||||
|
"http://www.airspayce.com/mikem/arduino/RadioHead/RadioHead-1.62.zip",
|
||||||
|
"https://github.com/bblanchon/ArduinoJson/archive/v5.8.2.zip",
|
||||||
|
"https://github.com/bblanchon/ArduinoJson/archive/v5.8.2.zip@5.8.2"
|
||||||
|
])
|
||||||
|
validate_cliresult(result)
|
||||||
|
|
||||||
|
# incorrect requirements
|
||||||
|
result = clirunner.invoke(cmd_lib, [
|
||||||
|
"-g", "install",
|
||||||
|
"https://github.com/bblanchon/ArduinoJson/archive/v5.8.2.zip@1.2.3"
|
||||||
|
])
|
||||||
|
assert result.exit_code != 0
|
||||||
|
|
||||||
|
# check lib with duplicate URL
|
||||||
|
result = clirunner.invoke(cmd_lib, [
|
||||||
|
"-g", "install",
|
||||||
"http://www.airspayce.com/mikem/arduino/RadioHead/RadioHead-1.62.zip"
|
"http://www.airspayce.com/mikem/arduino/RadioHead/RadioHead-1.62.zip"
|
||||||
])
|
])
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
|
assert "is already installed" in result.output
|
||||||
|
|
||||||
items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()]
|
items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()]
|
||||||
items2 = ["Adafruit ST7735 Library", "RadioHead"]
|
items2 = ["Adafruit ST7735 Library", "RadioHead-1.62"]
|
||||||
assert set(items1) >= set(items2)
|
assert set(items1) >= set(items2)
|
||||||
|
|
||||||
|
|
||||||
@ -71,14 +109,20 @@ def test_global_install_repository(clirunner, validate_cliresult,
|
|||||||
"-g",
|
"-g",
|
||||||
"install",
|
"install",
|
||||||
"https://github.com/gioblu/PJON.git#3.0",
|
"https://github.com/gioblu/PJON.git#3.0",
|
||||||
|
"https://github.com/gioblu/PJON.git#6.2",
|
||||||
|
"https://github.com/bblanchon/ArduinoJson.git",
|
||||||
"https://gitlab.com/ivankravets/rs485-nodeproto.git",
|
"https://gitlab.com/ivankravets/rs485-nodeproto.git",
|
||||||
# "https://developer.mbed.org/users/simon/code/TextLCD/",
|
# "https://developer.mbed.org/users/simon/code/TextLCD/",
|
||||||
"knolleary/pubsubclient"
|
"knolleary/pubsubclient"
|
||||||
])
|
])
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()]
|
items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()]
|
||||||
items2 = ["PJON", "ESPAsyncTCP", "PubSubClient"]
|
items2 = [
|
||||||
assert set(items2) & set(items1)
|
"PJON", "PJON@src-79de467ebe19de18287becff0a1fb42d",
|
||||||
|
"ArduinoJson@src-69ebddd821f771debe7ee734d3c7fa81", "rs485-nodeproto",
|
||||||
|
"PubSubClient"
|
||||||
|
]
|
||||||
|
assert set(items1) >= set(items2)
|
||||||
|
|
||||||
|
|
||||||
def test_global_lib_list(clirunner, validate_cliresult, isolated_pio_home):
|
def test_global_lib_list(clirunner, validate_cliresult, isolated_pio_home):
|
||||||
@ -89,13 +133,15 @@ def test_global_lib_list(clirunner, validate_cliresult, isolated_pio_home):
|
|||||||
result = clirunner.invoke(cmd_lib, ["-g", "list", "--json-output"])
|
result = clirunner.invoke(cmd_lib, ["-g", "list", "--json-output"])
|
||||||
assert all([
|
assert all([
|
||||||
n in result.output
|
n in result.output
|
||||||
for n in ("PJON", "git+https://github.com/knolleary/pubsubclient")
|
for n in ("PJON", "git+https://github.com/knolleary/pubsubclient",
|
||||||
|
"https://github.com/bblanchon/ArduinoJson/archive/v5.8.2.zip"
|
||||||
|
)
|
||||||
])
|
])
|
||||||
items1 = [i['name'] for i in json.loads(result.output)]
|
items1 = [i['name'] for i in json.loads(result.output)]
|
||||||
items2 = [
|
items2 = [
|
||||||
"OneWire", "DHT22", "PJON", "ESPAsyncTCP", "ArduinoJson",
|
"OneWire", "DHT22", "PJON", "ESPAsyncTCP", "ArduinoJson",
|
||||||
"pubsubclient", "rs485-nodeproto", "Adafruit ST7735 Library",
|
"PubSubClient", "rs485-nodeproto", "Adafruit ST7735 Library",
|
||||||
"RadioHead"
|
"RadioHead-1.62", "DallasTemperature", "NeoPixelBus", "IRremoteESP8266"
|
||||||
]
|
]
|
||||||
assert set(items1) == set(items2)
|
assert set(items1) == set(items2)
|
||||||
|
|
||||||
@ -106,31 +152,71 @@ def test_global_lib_update_check(clirunner, validate_cliresult,
|
|||||||
cmd_lib, ["-g", "update", "--only-check", "--json-output"])
|
cmd_lib, ["-g", "update", "--only-check", "--json-output"])
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
output = json.loads(result.output)
|
output = json.loads(result.output)
|
||||||
assert set(["ArduinoJson", "ESPAsyncTCP", "RadioHead"]) == set(
|
assert set(["ArduinoJson", "IRremoteESP8266", "NeoPixelBus"]) == set(
|
||||||
[l['name'] for l in output])
|
[l['name'] for l in output])
|
||||||
|
|
||||||
|
|
||||||
def test_global_lib_update(clirunner, validate_cliresult, isolated_pio_home):
|
def test_global_lib_update(clirunner, validate_cliresult, isolated_pio_home):
|
||||||
|
# update library using package directory
|
||||||
|
result = clirunner.invoke(
|
||||||
|
cmd_lib,
|
||||||
|
["-g", "update", "NeoPixelBus", "--only-check", "--json-output"])
|
||||||
|
validate_cliresult(result)
|
||||||
|
oudated = json.loads(result.output)
|
||||||
|
assert len(oudated) == 1
|
||||||
|
assert "__pkg_dir" in oudated[0]
|
||||||
|
result = clirunner.invoke(cmd_lib,
|
||||||
|
["-g", "update", oudated[0]['__pkg_dir']])
|
||||||
|
validate_cliresult(result)
|
||||||
|
assert "Uninstalling NeoPixelBus @ 2.2.4" in result.output
|
||||||
|
|
||||||
|
# update rest libraries
|
||||||
result = clirunner.invoke(cmd_lib, ["-g", "update"])
|
result = clirunner.invoke(cmd_lib, ["-g", "update"])
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
assert "[Up-to-date]" in result.output
|
validate_cliresult(result)
|
||||||
|
assert result.output.count("[Skip]") == 5
|
||||||
|
assert result.output.count("[Up-to-date]") == 9
|
||||||
assert "Uninstalling ArduinoJson @ 5.7.3" in result.output
|
assert "Uninstalling ArduinoJson @ 5.7.3" in result.output
|
||||||
|
assert "Uninstalling IRremoteESP8266 @ fee16e880b" in result.output
|
||||||
|
|
||||||
|
# update unknown library
|
||||||
|
result = clirunner.invoke(cmd_lib, ["-g", "update", "Unknown"])
|
||||||
|
assert result.exit_code != 0
|
||||||
|
assert isinstance(result.exception, exception.UnknownPackage)
|
||||||
|
|
||||||
|
|
||||||
def test_global_lib_uninstall(clirunner, validate_cliresult,
|
def test_global_lib_uninstall(clirunner, validate_cliresult,
|
||||||
isolated_pio_home):
|
isolated_pio_home):
|
||||||
|
# uninstall using package directory
|
||||||
|
result = clirunner.invoke(cmd_lib, ["-g", "list", "--json-output"])
|
||||||
|
validate_cliresult(result)
|
||||||
|
items = json.loads(result.output)
|
||||||
|
result = clirunner.invoke(cmd_lib,
|
||||||
|
["-g", "uninstall", items[0]['__pkg_dir']])
|
||||||
|
validate_cliresult(result)
|
||||||
|
assert "Uninstalling Adafruit ST7735 Library" in result.output
|
||||||
|
|
||||||
|
# uninstall the rest libraries
|
||||||
result = clirunner.invoke(cmd_lib, [
|
result = clirunner.invoke(cmd_lib, [
|
||||||
"-g", "uninstall", "1", "ArduinoJson@!=5.6.7", "TextLCD",
|
"-g", "uninstall", "1", "ArduinoJson@!=5.6.7",
|
||||||
"Adafruit ST7735 Library"
|
"https://github.com/bblanchon/ArduinoJson.git", "IRremoteESP8266@>=0.2"
|
||||||
])
|
])
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
|
|
||||||
items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()]
|
items1 = [d.basename for d in isolated_pio_home.join("lib").listdir()]
|
||||||
items2 = [
|
items2 = [
|
||||||
"DHT22_ID58", "ArduinoJson_ID64", "ESPAsyncTCP_ID305",
|
"ArduinoJson", "ArduinoJson_ID64@5.6.7", "DallasTemperature_ID54",
|
||||||
"pubsubclient", "PJON", "rs485-nodeproto", "RadioHead_ID124"
|
"DHT22_ID58", "ESPAsyncTCP_ID305", "NeoPixelBus_ID547", "PJON",
|
||||||
|
"PJON@src-79de467ebe19de18287becff0a1fb42d", "PubSubClient",
|
||||||
|
"RadioHead-1.62", "rs485-nodeproto"
|
||||||
]
|
]
|
||||||
assert set(items1) == set(items2)
|
assert set(items1) == set(items2)
|
||||||
|
|
||||||
|
# uninstall unknown library
|
||||||
|
result = clirunner.invoke(cmd_lib, ["-g", "uninstall", "Unknown"])
|
||||||
|
assert result.exit_code != 0
|
||||||
|
assert isinstance(result.exception, exception.UnknownPackage)
|
||||||
|
|
||||||
|
|
||||||
def test_lib_show(clirunner, validate_cliresult, isolated_pio_home):
|
def test_lib_show(clirunner, validate_cliresult, isolated_pio_home):
|
||||||
result = clirunner.invoke(cmd_lib, ["show", "64"])
|
result = clirunner.invoke(cmd_lib, ["show", "64"])
|
||||||
@ -142,31 +228,24 @@ def test_lib_show(clirunner, validate_cliresult, isolated_pio_home):
|
|||||||
assert "OneWire" in result.output
|
assert "OneWire" in result.output
|
||||||
|
|
||||||
|
|
||||||
def test_project_lib_complex(clirunner, validate_cliresult, tmpdir):
|
def test_lib_builtin(clirunner, validate_cliresult, isolated_pio_home):
|
||||||
with tmpdir.as_cwd():
|
result = clirunner.invoke(cmd_lib, ["builtin"])
|
||||||
# init
|
validate_cliresult(result)
|
||||||
result = clirunner.invoke(cmd_init)
|
result = clirunner.invoke(cmd_lib, ["builtin", "--json-output"])
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
|
|
||||||
# isntall
|
|
||||||
result = clirunner.invoke(cmd_lib, ["install", "54", "ArduinoJson"])
|
|
||||||
validate_cliresult(result)
|
|
||||||
items1 = [
|
|
||||||
d.basename
|
|
||||||
for d in tmpdir.join(basename(util.get_projectlibdeps_dir()))
|
|
||||||
.listdir()
|
|
||||||
]
|
|
||||||
items2 = ["DallasTemperature_ID54", "OneWire_ID1", "ArduinoJson_ID64"]
|
|
||||||
assert set(items1) == set(items2)
|
|
||||||
|
|
||||||
# list
|
def test_lib_stats(clirunner, validate_cliresult, isolated_pio_home):
|
||||||
result = clirunner.invoke(cmd_lib, ["list", "--json-output"])
|
result = clirunner.invoke(cmd_lib, ["stats"])
|
||||||
validate_cliresult(result)
|
validate_cliresult(result)
|
||||||
items1 = [i['name'] for i in json.loads(result.output)]
|
assert all([
|
||||||
items2 = ["DallasTemperature", "OneWire", "ArduinoJson"]
|
s in result.output
|
||||||
assert set(items1) == set(items2)
|
for s in ("UPDATED", "ago", "http://platformio.org/lib/show")
|
||||||
|
])
|
||||||
|
|
||||||
# update
|
result = clirunner.invoke(cmd_lib, ["stats", "--json-output"])
|
||||||
result = clirunner.invoke(cmd_lib, ["update"])
|
validate_cliresult(result)
|
||||||
validate_cliresult(result)
|
assert set([
|
||||||
assert "[Up-to-date]" in result.output
|
"dlweek", "added", "updated", "topkeywords", "dlmonth", "dlday",
|
||||||
|
"lastkeywords"
|
||||||
|
]) == set(json.loads(result.output).keys())
|
||||||
|
@ -156,7 +156,7 @@ def test_check_platform_updates(clirunner, validate_cliresult,
|
|||||||
manifest['version'] = "0.0.0"
|
manifest['version'] = "0.0.0"
|
||||||
manifest_path.write(json.dumps(manifest))
|
manifest_path.write(json.dumps(manifest))
|
||||||
# reset cached manifests
|
# reset cached manifests
|
||||||
PlatformManager().reset_cache()
|
PlatformManager().cache_reset()
|
||||||
|
|
||||||
# reset check time
|
# reset check time
|
||||||
interval = int(app.get_setting("check_platforms_interval")) * 3600 * 24
|
interval = int(app.get_setting("check_platforms_interval")) * 3600 * 24
|
||||||
|
@ -12,70 +12,118 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import json
|
||||||
|
from os.path import join
|
||||||
|
|
||||||
from platformio import util
|
from platformio import util
|
||||||
from platformio.managers.package import BasePkgManager
|
from platformio.managers.package import PackageManager
|
||||||
|
|
||||||
|
|
||||||
def test_pkg_name_parser():
|
def test_pkg_input_parser():
|
||||||
items = [
|
items = [
|
||||||
["PkgName", ("PkgName", None, None)],
|
["PkgName", ("PkgName", None, None)],
|
||||||
[("PkgName", "!=1.2.3,<2.0"), ("PkgName", "!=1.2.3,<2.0", None)],
|
[("PkgName", "!=1.2.3,<2.0"), ("PkgName", "!=1.2.3,<2.0", None)],
|
||||||
["PkgName@1.2.3", ("PkgName", "1.2.3", None)],
|
["PkgName@1.2.3", ("PkgName", "1.2.3", None)],
|
||||||
[("PkgName@1.2.3", "1.2.5"), ("PkgName@1.2.3", "1.2.5", None)],
|
[("PkgName@1.2.3", "1.2.5"), ("PkgName@1.2.3", "1.2.5", None)],
|
||||||
["id:13", ("id:13", None, None)],
|
["id:13", ("id:13", None, None)],
|
||||||
["id:13@~1.2.3", ("id:13", "~1.2.3", None)], [
|
["id:13@~1.2.3", ("id:13", "~1.2.3", None)],
|
||||||
|
[
|
||||||
util.get_home_dir(),
|
util.get_home_dir(),
|
||||||
(".platformio", None, "file://" + util.get_home_dir())
|
(".platformio", None, "file://" + util.get_home_dir())
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
"LocalName=" + util.get_home_dir(),
|
"LocalName=" + util.get_home_dir(),
|
||||||
("LocalName", None, "file://" + util.get_home_dir())
|
("LocalName", None, "file://" + util.get_home_dir())
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
|
"LocalName=%s@>2.3.0" % util.get_home_dir(),
|
||||||
|
("LocalName", ">2.3.0", "file://" + util.get_home_dir())
|
||||||
|
],
|
||||||
|
[
|
||||||
"https://github.com/user/package.git",
|
"https://github.com/user/package.git",
|
||||||
("package", None, "git+https://github.com/user/package.git")
|
("package", None, "git+https://github.com/user/package.git")
|
||||||
], [
|
],
|
||||||
"https://gitlab.com/user/package.git",
|
[
|
||||||
("package", None, "git+https://gitlab.com/user/package.git")
|
"MyPackage=https://gitlab.com/user/package.git",
|
||||||
], [
|
("MyPackage", None, "git+https://gitlab.com/user/package.git")
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"MyPackage=https://gitlab.com/user/package.git@3.2.1,!=2",
|
||||||
|
("MyPackage", "3.2.1,!=2",
|
||||||
|
"git+https://gitlab.com/user/package.git")
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"https://somedomain.com/path/LibraryName-1.2.3.zip",
|
||||||
|
("LibraryName-1.2.3", None,
|
||||||
|
"https://somedomain.com/path/LibraryName-1.2.3.zip")
|
||||||
|
],
|
||||||
|
[
|
||||||
"https://github.com/user/package/archive/branch.zip",
|
"https://github.com/user/package/archive/branch.zip",
|
||||||
("branch", None,
|
("branch", None,
|
||||||
"https://github.com/user/package/archive/branch.zip")
|
"https://github.com/user/package/archive/branch.zip")
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
|
"https://github.com/user/package/archive/branch.zip@~1.2.3",
|
||||||
|
("branch", "~1.2.3",
|
||||||
|
"https://github.com/user/package/archive/branch.zip")
|
||||||
|
],
|
||||||
|
[
|
||||||
"https://github.com/user/package/archive/branch.tar.gz",
|
"https://github.com/user/package/archive/branch.tar.gz",
|
||||||
("branch", None,
|
("branch.tar", None,
|
||||||
"https://github.com/user/package/archive/branch.tar.gz")
|
"https://github.com/user/package/archive/branch.tar.gz")
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
|
"https://github.com/user/package/archive/branch.tar.gz@!=5",
|
||||||
|
("branch.tar", "!=5",
|
||||||
|
"https://github.com/user/package/archive/branch.tar.gz")
|
||||||
|
],
|
||||||
|
[
|
||||||
"https://developer.mbed.org/users/user/code/package/",
|
"https://developer.mbed.org/users/user/code/package/",
|
||||||
("package", None,
|
("package", None,
|
||||||
"hg+https://developer.mbed.org/users/user/code/package/")
|
"hg+https://developer.mbed.org/users/user/code/package/")
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
"https://github.com/user/package#v1.2.3",
|
"https://github.com/user/package#v1.2.3",
|
||||||
("package", None, "git+https://github.com/user/package#v1.2.3")
|
("package", None, "git+https://github.com/user/package#v1.2.3")
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
"https://github.com/user/package.git#branch",
|
"https://github.com/user/package.git#branch",
|
||||||
("package", None, "git+https://github.com/user/package.git#branch")
|
("package", None, "git+https://github.com/user/package.git#branch")
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
"PkgName=https://github.com/user/package.git#a13d344fg56",
|
"PkgName=https://github.com/user/package.git#a13d344fg56",
|
||||||
("PkgName", None,
|
("PkgName", None,
|
||||||
"git+https://github.com/user/package.git#a13d344fg56")
|
"git+https://github.com/user/package.git#a13d344fg56")
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
|
"user/package",
|
||||||
|
("package", None, "git+https://github.com/user/package")
|
||||||
|
],
|
||||||
|
[
|
||||||
"PkgName=user/package",
|
"PkgName=user/package",
|
||||||
("PkgName", None, "git+https://github.com/user/package")
|
("PkgName", None, "git+https://github.com/user/package")
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
"PkgName=user/package#master",
|
"PkgName=user/package#master",
|
||||||
("PkgName", None, "git+https://github.com/user/package#master")
|
("PkgName", None, "git+https://github.com/user/package#master")
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
"git+https://github.com/user/package",
|
"git+https://github.com/user/package",
|
||||||
("package", None, "git+https://github.com/user/package")
|
("package", None, "git+https://github.com/user/package")
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
"hg+https://example.com/user/package",
|
"hg+https://example.com/user/package",
|
||||||
("package", None, "hg+https://example.com/user/package")
|
("package", None, "hg+https://example.com/user/package")
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
"git@github.com:user/package.git",
|
"git@github.com:user/package.git",
|
||||||
("package", None, "git@github.com:user/package.git")
|
("package", None, "git@github.com:user/package.git")
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
"git@github.com:user/package.git#v1.2.0",
|
"git@github.com:user/package.git#v1.2.0",
|
||||||
("package", None, "git@github.com:user/package.git#v1.2.0")
|
("package", None, "git@github.com:user/package.git#v1.2.0")
|
||||||
], [
|
],
|
||||||
|
[
|
||||||
"git+ssh://git@gitlab.private-server.com/user/package#1.2.0",
|
"git+ssh://git@gitlab.private-server.com/user/package#1.2.0",
|
||||||
("package", None,
|
("package", None,
|
||||||
"git+ssh://git@gitlab.private-server.com/user/package#1.2.0")
|
"git+ssh://git@gitlab.private-server.com/user/package#1.2.0")
|
||||||
@ -83,6 +131,72 @@ def test_pkg_name_parser():
|
|||||||
]
|
]
|
||||||
for params, result in items:
|
for params, result in items:
|
||||||
if isinstance(params, tuple):
|
if isinstance(params, tuple):
|
||||||
assert BasePkgManager.parse_pkg_name(*params) == result
|
assert PackageManager.parse_pkg_input(*params) == result
|
||||||
else:
|
else:
|
||||||
assert BasePkgManager.parse_pkg_name(params) == result
|
assert PackageManager.parse_pkg_input(params) == result
|
||||||
|
|
||||||
|
|
||||||
|
def test_install_packages(isolated_pio_home, tmpdir):
|
||||||
|
packages = [
|
||||||
|
dict(id=1, name="name_1", version="shasum"),
|
||||||
|
dict(id=1, name="name_1", version="2.0.0"),
|
||||||
|
dict(id=1, name="name_1", version="2.1.0"),
|
||||||
|
dict(id=1, name="name_1", version="1.2.0"),
|
||||||
|
dict(id=1, name="name_1", version="1.0.0"),
|
||||||
|
dict(name="name_2", version="1.0.0"),
|
||||||
|
dict(name="name_2", version="2.0.0",
|
||||||
|
__src_url="git+https://github.com"),
|
||||||
|
dict(name="name_2", version="3.0.0",
|
||||||
|
__src_url="git+https://github2.com"),
|
||||||
|
dict(name="name_2", version="4.0.0",
|
||||||
|
__src_url="git+https://github2.com")
|
||||||
|
]
|
||||||
|
|
||||||
|
pm = PackageManager(join(util.get_home_dir(), "packages"))
|
||||||
|
for package in packages:
|
||||||
|
tmp_dir = tmpdir.mkdir("tmp-package")
|
||||||
|
tmp_dir.join("package.json").write(json.dumps(package))
|
||||||
|
pm._install_from_url(package['name'], "file://%s" % str(tmp_dir))
|
||||||
|
tmp_dir.remove(rec=1)
|
||||||
|
|
||||||
|
assert len(pm.get_installed()) == len(packages) - 1
|
||||||
|
|
||||||
|
pkg_dirnames = [
|
||||||
|
'name_1_ID1', 'name_1_ID1@1.0.0', 'name_1_ID1@1.2.0',
|
||||||
|
'name_1_ID1@2.0.0', 'name_1_ID1@shasum', 'name_2',
|
||||||
|
'name_2@src-177cbce1f0705580d17790fda1cc2ef5',
|
||||||
|
'name_2@src-f863b537ab00f4c7b5011fc44b120e1f'
|
||||||
|
]
|
||||||
|
assert set([p.basename for p in isolated_pio_home.join(
|
||||||
|
"packages").listdir()]) == set(pkg_dirnames)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_package(isolated_pio_home):
|
||||||
|
tests = [
|
||||||
|
[("unknown", ), None],
|
||||||
|
[("1", ), None],
|
||||||
|
[("id=1", "shasum"), dict(id=1, name="name_1", version="shasum")],
|
||||||
|
[("id=1", "*"), dict(id=1, name="name_1", version="2.1.0")],
|
||||||
|
[("id=1", "^1"), dict(id=1, name="name_1", version="1.2.0")],
|
||||||
|
[("id=1", "^1"), dict(id=1, name="name_1", version="1.2.0")],
|
||||||
|
[("name_1", "<2"), dict(id=1, name="name_1", version="1.2.0")],
|
||||||
|
[("name_1", ">2"), None],
|
||||||
|
[("name_1", "2-0-0"), dict(id=1, name="name_1", version="2.1.0")],
|
||||||
|
[("name_1", "2-0-0"), dict(id=1, name="name_1", version="2.1.0")],
|
||||||
|
[("name_2", ), dict(name="name_2", version="4.0.0")],
|
||||||
|
[("url_has_higher_priority", None, "git+https://github.com"),
|
||||||
|
dict(name="name_2", version="2.0.0",
|
||||||
|
__src_url="git+https://github.com")],
|
||||||
|
[("name_2", None, "git+https://github.com"),
|
||||||
|
dict(name="name_2", version="2.0.0",
|
||||||
|
__src_url="git+https://github.com")],
|
||||||
|
]
|
||||||
|
|
||||||
|
pm = PackageManager(join(util.get_home_dir(), "packages"))
|
||||||
|
for test in tests:
|
||||||
|
manifest = pm.get_package(*test[0])
|
||||||
|
if test[1] is None:
|
||||||
|
assert manifest is None, test
|
||||||
|
continue
|
||||||
|
for key, value in test[1].items():
|
||||||
|
assert manifest[key] == value, test
|
||||||
|
@ -16,19 +16,6 @@ import pytest
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
|
||||||
def pytest_generate_tests(metafunc):
|
|
||||||
if "package_data" not in metafunc.fixturenames:
|
|
||||||
return
|
|
||||||
pkgs_manifest = requests.get(
|
|
||||||
"https://dl.bintray.com/platformio/dl-packages/manifest.json").json()
|
|
||||||
assert isinstance(pkgs_manifest, dict)
|
|
||||||
packages = []
|
|
||||||
for _, variants in pkgs_manifest.iteritems():
|
|
||||||
for item in variants:
|
|
||||||
packages.append(item)
|
|
||||||
metafunc.parametrize("package_data", packages)
|
|
||||||
|
|
||||||
|
|
||||||
def validate_response(req):
|
def validate_response(req):
|
||||||
assert req.status_code == 200
|
assert req.status_code == 200
|
||||||
assert int(req.headers['Content-Length']) > 0
|
assert int(req.headers['Content-Length']) > 0
|
||||||
@ -36,13 +23,22 @@ def validate_response(req):
|
|||||||
"application/octet-stream")
|
"application/octet-stream")
|
||||||
|
|
||||||
|
|
||||||
def test_package(package_data):
|
def test_packages():
|
||||||
assert package_data['url'].endswith(".tar.gz")
|
pkgs_manifest = requests.get(
|
||||||
|
"https://dl.bintray.com/platformio/dl-packages/manifest.json").json()
|
||||||
|
assert isinstance(pkgs_manifest, dict)
|
||||||
|
items = []
|
||||||
|
for _, variants in pkgs_manifest.iteritems():
|
||||||
|
for item in variants:
|
||||||
|
items.append(item)
|
||||||
|
|
||||||
r = requests.head(package_data['url'], allow_redirects=True)
|
for item in items:
|
||||||
validate_response(r)
|
assert item['url'].endswith(".tar.gz"), item
|
||||||
|
|
||||||
if "X-Checksum-Sha1" not in r.headers:
|
r = requests.head(item['url'], allow_redirects=True)
|
||||||
return pytest.skip("X-Checksum-Sha1 is not provided")
|
validate_response(r)
|
||||||
|
|
||||||
assert package_data['sha1'] == r.headers.get("X-Checksum-Sha1")
|
if "X-Checksum-Sha1" not in r.headers:
|
||||||
|
return pytest.skip("X-Checksum-Sha1 is not provided")
|
||||||
|
|
||||||
|
assert item['sha1'] == r.headers.get("X-Checksum-Sha1"), item
|
||||||
|
Reference in New Issue
Block a user