mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-30 10:07:14 +02:00
Allow to install development platform from local directory // Issue #479
This commit is contained in:
@ -21,14 +21,17 @@ Usage
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# install platform by name
|
||||||
platformio platform install [OPTIONS] [PLATFORMS]
|
platformio platform install [OPTIONS] [PLATFORMS]
|
||||||
|
|
||||||
|
# install platform from local directory
|
||||||
|
platformio platform install [OPTIONS] [file:///local/path/to/platform/dir]
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Install pre-built development :ref:`platforms` with related
|
Install development :ref:`platforms` and dependent packages.
|
||||||
packages.
|
|
||||||
|
|
||||||
There are several predefined aliases for packages, such as:
|
There are several predefined aliases for packages, such as:
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ class FileDownloader(object):
|
|||||||
return self._destination
|
return self._destination
|
||||||
|
|
||||||
def get_lmtime(self):
|
def get_lmtime(self):
|
||||||
return self._request.headers['last-modified']
|
return self._request.headers.get("last-modified")
|
||||||
|
|
||||||
def get_size(self):
|
def get_size(self):
|
||||||
if "content-length" not in self._request.headers:
|
if "content-length" not in self._request.headers:
|
||||||
@ -77,7 +77,8 @@ class FileDownloader(object):
|
|||||||
f.close()
|
f.close()
|
||||||
self._request.close()
|
self._request.close()
|
||||||
|
|
||||||
self._preserve_filemtime(self.get_lmtime())
|
if self.get_lmtime():
|
||||||
|
self._preserve_filemtime(self.get_lmtime())
|
||||||
|
|
||||||
def verify(self, sha1=None):
|
def verify(self, sha1=None):
|
||||||
_dlsize = getsize(self._destination)
|
_dlsize = getsize(self._destination)
|
||||||
|
@ -70,6 +70,11 @@ class UnknownPackage(PlatformioException):
|
|||||||
MESSAGE = "Detected unknown package '{0}'"
|
MESSAGE = "Detected unknown package '{0}'"
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidLocalPackage(PlatformioException):
|
||||||
|
|
||||||
|
MESSAGE = "Invalid local package '{0}'. Can not find manifest '{1}'"
|
||||||
|
|
||||||
|
|
||||||
class UndefinedPackageVersion(PlatformioException):
|
class UndefinedPackageVersion(PlatformioException):
|
||||||
|
|
||||||
MESSAGE = "Can not find package '{0}' with version requirements '{1}'"\
|
MESSAGE = "Can not find package '{0}' with version requirements '{1}'"\
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
from os.path import dirname, isdir, isfile, join
|
from os.path import dirname, isdir, isfile, join
|
||||||
from shutil import rmtree
|
from shutil import copyfile, copytree, rmtree
|
||||||
|
|
||||||
import click
|
import click
|
||||||
import requests
|
import requests
|
||||||
@ -41,6 +41,10 @@ class PackageManager(object):
|
|||||||
def reset_cache():
|
def reset_cache():
|
||||||
PackageManager._INSTALLED_CACHE = {}
|
PackageManager._INSTALLED_CACHE = {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_manifest_name():
|
||||||
|
return "package.json"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def download(url, dest_dir, sha1=None):
|
def download(url, dest_dir, sha1=None):
|
||||||
fd = FileDownloader(url, dest_dir)
|
fd = FileDownloader(url, dest_dir)
|
||||||
@ -50,13 +54,56 @@ class PackageManager(object):
|
|||||||
return fd.get_filepath()
|
return fd.get_filepath()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def unpack(pkgpath, dest_dir):
|
def unpack(source_path, dest_dir):
|
||||||
fu = FileUnpacker(pkgpath, dest_dir)
|
fu = FileUnpacker(source_path, dest_dir)
|
||||||
return fu.start()
|
return fu.start()
|
||||||
|
|
||||||
@staticmethod
|
def check_structure(self, pkg_dir):
|
||||||
def get_manifest_name():
|
if isfile(join(pkg_dir, self.get_manifest_name())):
|
||||||
return "package.json"
|
return True
|
||||||
|
|
||||||
|
for root, _, files in os.walk(pkg_dir):
|
||||||
|
if self.get_manifest_name() not in files:
|
||||||
|
continue
|
||||||
|
# copy contents to the root of package directory
|
||||||
|
for item in os.listdir(root):
|
||||||
|
item_path = join(root, item)
|
||||||
|
if isfile(item_path):
|
||||||
|
copyfile(item_path, join(pkg_dir, item))
|
||||||
|
elif isdir(item_path):
|
||||||
|
copytree(item_path, join(pkg_dir, item), symlinks=True)
|
||||||
|
# remove not used contents
|
||||||
|
while True:
|
||||||
|
rmtree(root)
|
||||||
|
root = dirname(root)
|
||||||
|
if root == pkg_dir:
|
||||||
|
break
|
||||||
|
break
|
||||||
|
|
||||||
|
if isfile(join(pkg_dir, self.get_manifest_name())):
|
||||||
|
return True
|
||||||
|
|
||||||
|
raise exception.PlatformioException(
|
||||||
|
"Could not find '%s' manifest file in the package" %
|
||||||
|
self.get_manifest_name())
|
||||||
|
|
||||||
|
def make_pkg_dir(self, name, version):
|
||||||
|
pkg_dir = join(self.package_dir, name)
|
||||||
|
if isfile(join(pkg_dir, self.get_manifest_name())):
|
||||||
|
_manifest = util.load_json(
|
||||||
|
join(pkg_dir, self.get_manifest_name()))
|
||||||
|
if (_manifest['name'] == name and
|
||||||
|
_manifest['version'] != version):
|
||||||
|
pkg_dir = join(
|
||||||
|
self.package_dir, "%s@%s" % (name, version))
|
||||||
|
|
||||||
|
# remove previous/not-satisfied package
|
||||||
|
if isdir(pkg_dir):
|
||||||
|
rmtree(pkg_dir)
|
||||||
|
os.makedirs(pkg_dir)
|
||||||
|
assert isdir(pkg_dir)
|
||||||
|
|
||||||
|
return pkg_dir
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def max_satisfying_version(versions, requirements=None):
|
def max_satisfying_version(versions, requirements=None):
|
||||||
@ -114,7 +161,8 @@ class PackageManager(object):
|
|||||||
def install(self, name, requirements, silent=False, trigger_event=True):
|
def install(self, name, requirements, silent=False, trigger_event=True):
|
||||||
installed = self.is_installed(name, requirements)
|
installed = self.is_installed(name, requirements)
|
||||||
if not installed or not silent:
|
if not installed or not silent:
|
||||||
click.echo("Installing package %s @ %s:" % (
|
click.echo("Installing %s %s @ %s:" % (
|
||||||
|
self.get_manifest_name().split(".")[0],
|
||||||
click.style(name, fg="cyan"),
|
click.style(name, fg="cyan"),
|
||||||
requirements if requirements else "latest"))
|
requirements if requirements else "latest"))
|
||||||
if installed:
|
if installed:
|
||||||
@ -122,18 +170,24 @@ class PackageManager(object):
|
|||||||
click.secho("Already installed", fg="yellow")
|
click.secho("Already installed", fg="yellow")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self._install_from_piorepo(name, requirements):
|
manifest_path = None
|
||||||
|
if name.startswith("file://"):
|
||||||
|
manifest_path = self._install_from_local_dir(name[7:])
|
||||||
|
else:
|
||||||
|
manifest_path = self._install_from_piorepo(name, requirements)
|
||||||
|
if not isfile(manifest_path):
|
||||||
raise exception.PackageInstallError(
|
raise exception.PackageInstallError(
|
||||||
name, requirements, util.get_systype())
|
name, requirements or "latest", util.get_systype())
|
||||||
|
|
||||||
self.reset_cache()
|
self.reset_cache()
|
||||||
if trigger_event:
|
if trigger_event:
|
||||||
telemetry.on_event(
|
telemetry.on_event(
|
||||||
category="PackageManager", action="Install", label=name)
|
category="PackageManager", action="Install", label=name)
|
||||||
|
|
||||||
|
return manifest_path
|
||||||
|
|
||||||
def _install_from_piorepo(self, name, requirements):
|
def _install_from_piorepo(self, name, requirements):
|
||||||
pkg_dir = None
|
pkg_dir = None
|
||||||
success = False
|
|
||||||
pkgdata = None
|
pkgdata = None
|
||||||
versions = None
|
versions = None
|
||||||
for versions in PackageRepoIterator(name, self.repositories):
|
for versions in PackageRepoIterator(name, self.repositories):
|
||||||
@ -142,26 +196,17 @@ class PackageManager(object):
|
|||||||
if not pkgdata:
|
if not pkgdata:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
pkg_dir = join(self.package_dir, name)
|
pkg_dir = self.make_pkg_dir(name, pkgdata['version'])
|
||||||
if isfile(join(pkg_dir, self.get_manifest_name())):
|
|
||||||
pkg_dir = join(
|
|
||||||
self.package_dir, "%s@%s" % (name, pkgdata['version']))
|
|
||||||
|
|
||||||
# remove previous/not-satisfied package
|
|
||||||
if isdir(pkg_dir):
|
|
||||||
rmtree(pkg_dir)
|
|
||||||
os.makedirs(pkg_dir)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
dlpath = self.download(
|
dlpath = self.download(
|
||||||
pkgdata['url'], pkg_dir, pkgdata.get("sha1"))
|
pkgdata['url'], pkg_dir, pkgdata.get("sha1"))
|
||||||
assert isfile(dlpath)
|
assert isfile(dlpath)
|
||||||
self.unpack(dlpath, pkg_dir)
|
self.unpack(dlpath, pkg_dir)
|
||||||
success = True
|
self.check_structure(pkg_dir)
|
||||||
break
|
break
|
||||||
except Exception as e: # pylint: disable=broad-except
|
except Exception as e: # pylint: disable=broad-except
|
||||||
click.secho("Warning! Package Mirror: %s" % e, fg="yellow")
|
click.secho("Warning! Package Mirror: %s" % e, fg="yellow")
|
||||||
click.secho("Looking for other Package Mirror...", fg="yellow")
|
click.secho("Looking for another mirror...", fg="yellow")
|
||||||
finally:
|
finally:
|
||||||
if dlpath and isfile(dlpath):
|
if dlpath and isfile(dlpath):
|
||||||
os.remove(dlpath)
|
os.remove(dlpath)
|
||||||
@ -170,12 +215,26 @@ class PackageManager(object):
|
|||||||
raise exception.UnknownPackage(name)
|
raise exception.UnknownPackage(name)
|
||||||
elif not pkgdata:
|
elif not pkgdata:
|
||||||
raise exception.UndefinedPackageVersion(
|
raise exception.UndefinedPackageVersion(
|
||||||
name, requirements, util.get_systype())
|
name, requirements or "latest", util.get_systype())
|
||||||
|
|
||||||
return success
|
return join(pkg_dir, self.get_manifest_name())
|
||||||
|
|
||||||
|
def _install_from_local_dir(self, local_dir):
|
||||||
|
if not isfile(join(local_dir, self.get_manifest_name())):
|
||||||
|
raise exception.InvalidLocalPackage(
|
||||||
|
local_dir, self.get_manifest_name())
|
||||||
|
|
||||||
|
manifest = util.load_json(join(local_dir, self.get_manifest_name()))
|
||||||
|
assert set(["name", "version"]) <= set(manifest.keys())
|
||||||
|
pkg_dir = self.make_pkg_dir(manifest['name'], manifest['version'])
|
||||||
|
rmtree(pkg_dir)
|
||||||
|
copytree(local_dir, pkg_dir, symlinks=True)
|
||||||
|
|
||||||
|
return join(pkg_dir, self.get_manifest_name())
|
||||||
|
|
||||||
def uninstall(self, name, requirements=None, trigger_event=True):
|
def uninstall(self, name, requirements=None, trigger_event=True):
|
||||||
click.echo("Uninstalling package %s @ %s: \t" % (
|
click.echo("Uninstalling %s %s @ %s: \t" % (
|
||||||
|
self.get_manifest_name().split(".")[0],
|
||||||
click.style(name, fg="cyan"),
|
click.style(name, fg="cyan"),
|
||||||
requirements if requirements else "latest"), nl=False)
|
requirements if requirements else "latest"), nl=False)
|
||||||
found = False
|
found = False
|
||||||
@ -201,7 +260,8 @@ class PackageManager(object):
|
|||||||
category="PackageManager", action="Uninstall", label=name)
|
category="PackageManager", action="Uninstall", label=name)
|
||||||
|
|
||||||
def update(self, name, requirements=None, keep_versions=None):
|
def update(self, name, requirements=None, keep_versions=None):
|
||||||
click.echo("Updating package %s @ %s:" % (
|
click.echo("Updating %s %s @ %s:" % (
|
||||||
|
self.get_manifest_name().split(".")[0],
|
||||||
click.style(name, fg="yellow"),
|
click.style(name, fg="yellow"),
|
||||||
requirements if requirements else "latest"))
|
requirements if requirements else "latest"))
|
||||||
|
|
||||||
|
@ -56,9 +56,9 @@ class PlatformManager(PackageManager):
|
|||||||
def install(self, # pylint: disable=too-many-arguments,arguments-differ
|
def install(self, # pylint: disable=too-many-arguments,arguments-differ
|
||||||
name, requirements=None, with_packages=None,
|
name, requirements=None, with_packages=None,
|
||||||
without_packages=None, skip_default_packages=False):
|
without_packages=None, skip_default_packages=False):
|
||||||
PackageManager.install(self, name, requirements)
|
manifest_path = PackageManager.install(self, name, requirements)
|
||||||
return PlatformFactory.newPlatform(
|
return PlatformFactory.newPlatform(
|
||||||
name, requirements).install_packages(
|
manifest_path, requirements).install_packages(
|
||||||
with_packages, without_packages, skip_default_packages)
|
with_packages, without_packages, skip_default_packages)
|
||||||
|
|
||||||
def uninstall(self, # pylint: disable=arguments-differ
|
def uninstall(self, # pylint: disable=arguments-differ
|
||||||
|
Reference in New Issue
Block a user