mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-29 17:47: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
|
||||
|
||||
# install platform by name
|
||||
platformio platform install [OPTIONS] [PLATFORMS]
|
||||
|
||||
# install platform from local directory
|
||||
platformio platform install [OPTIONS] [file:///local/path/to/platform/dir]
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
Install pre-built development :ref:`platforms` with related
|
||||
packages.
|
||||
Install development :ref:`platforms` and dependent packages.
|
||||
|
||||
There are several predefined aliases for packages, such as:
|
||||
|
||||
|
@ -53,7 +53,7 @@ class FileDownloader(object):
|
||||
return self._destination
|
||||
|
||||
def get_lmtime(self):
|
||||
return self._request.headers['last-modified']
|
||||
return self._request.headers.get("last-modified")
|
||||
|
||||
def get_size(self):
|
||||
if "content-length" not in self._request.headers:
|
||||
@ -77,7 +77,8 @@ class FileDownloader(object):
|
||||
f.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):
|
||||
_dlsize = getsize(self._destination)
|
||||
|
@ -70,6 +70,11 @@ class UnknownPackage(PlatformioException):
|
||||
MESSAGE = "Detected unknown package '{0}'"
|
||||
|
||||
|
||||
class InvalidLocalPackage(PlatformioException):
|
||||
|
||||
MESSAGE = "Invalid local package '{0}'. Can not find manifest '{1}'"
|
||||
|
||||
|
||||
class UndefinedPackageVersion(PlatformioException):
|
||||
|
||||
MESSAGE = "Can not find package '{0}' with version requirements '{1}'"\
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
import os
|
||||
from os.path import dirname, isdir, isfile, join
|
||||
from shutil import rmtree
|
||||
from shutil import copyfile, copytree, rmtree
|
||||
|
||||
import click
|
||||
import requests
|
||||
@ -41,6 +41,10 @@ class PackageManager(object):
|
||||
def reset_cache():
|
||||
PackageManager._INSTALLED_CACHE = {}
|
||||
|
||||
@staticmethod
|
||||
def get_manifest_name():
|
||||
return "package.json"
|
||||
|
||||
@staticmethod
|
||||
def download(url, dest_dir, sha1=None):
|
||||
fd = FileDownloader(url, dest_dir)
|
||||
@ -50,13 +54,56 @@ class PackageManager(object):
|
||||
return fd.get_filepath()
|
||||
|
||||
@staticmethod
|
||||
def unpack(pkgpath, dest_dir):
|
||||
fu = FileUnpacker(pkgpath, dest_dir)
|
||||
def unpack(source_path, dest_dir):
|
||||
fu = FileUnpacker(source_path, dest_dir)
|
||||
return fu.start()
|
||||
|
||||
@staticmethod
|
||||
def get_manifest_name():
|
||||
return "package.json"
|
||||
def check_structure(self, pkg_dir):
|
||||
if isfile(join(pkg_dir, self.get_manifest_name())):
|
||||
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
|
||||
def max_satisfying_version(versions, requirements=None):
|
||||
@ -114,7 +161,8 @@ class PackageManager(object):
|
||||
def install(self, name, requirements, silent=False, trigger_event=True):
|
||||
installed = self.is_installed(name, requirements)
|
||||
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"),
|
||||
requirements if requirements else "latest"))
|
||||
if installed:
|
||||
@ -122,18 +170,24 @@ class PackageManager(object):
|
||||
click.secho("Already installed", fg="yellow")
|
||||
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(
|
||||
name, requirements, util.get_systype())
|
||||
name, requirements or "latest", util.get_systype())
|
||||
|
||||
self.reset_cache()
|
||||
if trigger_event:
|
||||
telemetry.on_event(
|
||||
category="PackageManager", action="Install", label=name)
|
||||
|
||||
return manifest_path
|
||||
|
||||
def _install_from_piorepo(self, name, requirements):
|
||||
pkg_dir = None
|
||||
success = False
|
||||
pkgdata = None
|
||||
versions = None
|
||||
for versions in PackageRepoIterator(name, self.repositories):
|
||||
@ -142,26 +196,17 @@ class PackageManager(object):
|
||||
if not pkgdata:
|
||||
continue
|
||||
|
||||
pkg_dir = join(self.package_dir, name)
|
||||
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)
|
||||
|
||||
pkg_dir = self.make_pkg_dir(name, pkgdata['version'])
|
||||
try:
|
||||
dlpath = self.download(
|
||||
pkgdata['url'], pkg_dir, pkgdata.get("sha1"))
|
||||
assert isfile(dlpath)
|
||||
self.unpack(dlpath, pkg_dir)
|
||||
success = True
|
||||
self.check_structure(pkg_dir)
|
||||
break
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
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:
|
||||
if dlpath and isfile(dlpath):
|
||||
os.remove(dlpath)
|
||||
@ -170,12 +215,26 @@ class PackageManager(object):
|
||||
raise exception.UnknownPackage(name)
|
||||
elif not pkgdata:
|
||||
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):
|
||||
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"),
|
||||
requirements if requirements else "latest"), nl=False)
|
||||
found = False
|
||||
@ -201,7 +260,8 @@ class PackageManager(object):
|
||||
category="PackageManager", action="Uninstall", label=name)
|
||||
|
||||
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"),
|
||||
requirements if requirements else "latest"))
|
||||
|
||||
|
@ -56,9 +56,9 @@ class PlatformManager(PackageManager):
|
||||
def install(self, # pylint: disable=too-many-arguments,arguments-differ
|
||||
name, requirements=None, with_packages=None,
|
||||
without_packages=None, skip_default_packages=False):
|
||||
PackageManager.install(self, name, requirements)
|
||||
manifest_path = PackageManager.install(self, name, requirements)
|
||||
return PlatformFactory.newPlatform(
|
||||
name, requirements).install_packages(
|
||||
manifest_path, requirements).install_packages(
|
||||
with_packages, without_packages, skip_default_packages)
|
||||
|
||||
def uninstall(self, # pylint: disable=arguments-differ
|
||||
|
Reference in New Issue
Block a user