Merge pull request #216 from FoamyGuy/local_install
Support Local Path Install
This commit is contained in:
commit
eacc3199fc
3 changed files with 87 additions and 29 deletions
|
|
@ -90,7 +90,13 @@ class Backend:
|
|||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
# pylint: disable=too-many-locals,too-many-branches,too-many-arguments,too-many-nested-blocks
|
||||
def copy_file(self, target_file, location_to_paste):
|
||||
"""Paste a copy of the specified file at the location given
|
||||
To be overridden by subclass
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
# pylint: disable=too-many-locals,too-many-branches,too-many-arguments,too-many-nested-blocks,too-many-statements
|
||||
def install_module(
|
||||
self, device_path, device_modules, name, pyext, mod_names, upgrade=False
|
||||
): # pragma: no cover
|
||||
|
|
@ -109,9 +115,19 @@ class Backend:
|
|||
with get_bundle_versions()
|
||||
:param bool upgrade: Upgrade the specified modules if they're already installed.
|
||||
"""
|
||||
local_path = None
|
||||
if os.path.exists(name):
|
||||
# local file exists use that.
|
||||
local_path = name
|
||||
name = local_path.split(os.path.sep)[-1]
|
||||
name = name.replace(".py", "").replace(".mpy", "")
|
||||
click.echo(f"Installing from local path: {local_path}")
|
||||
|
||||
if not name:
|
||||
click.echo("No module name(s) provided.")
|
||||
elif name in mod_names:
|
||||
return
|
||||
if name in mod_names or local_path is not None:
|
||||
|
||||
# Grab device modules to check if module already installed
|
||||
if name in device_modules:
|
||||
if not upgrade:
|
||||
|
|
@ -129,14 +145,19 @@ class Backend:
|
|||
module_path = _metadata["path"]
|
||||
self.uninstall(device_path, module_path)
|
||||
|
||||
new_module_size = 0
|
||||
library_path = (
|
||||
os.path.join(device_path, self.LIB_DIR_PATH)
|
||||
if not isinstance(self, WebBackend)
|
||||
else urljoin(device_path, self.LIB_DIR_PATH)
|
||||
)
|
||||
metadata = mod_names[name]
|
||||
bundle = metadata["bundle"]
|
||||
bundle.size = os.path.getsize(metadata["path"])
|
||||
if local_path is None:
|
||||
metadata = mod_names[name]
|
||||
bundle = metadata["bundle"]
|
||||
else:
|
||||
metadata = {"path": local_path}
|
||||
|
||||
new_module_size = os.path.getsize(metadata["path"])
|
||||
if os.path.isdir(metadata["path"]):
|
||||
# pylint: disable=unused-variable
|
||||
for dirpath, dirnames, filenames in os.walk(metadata["path"]):
|
||||
|
|
@ -144,7 +165,7 @@ class Backend:
|
|||
fp = os.path.join(dirpath, f)
|
||||
try:
|
||||
if not os.path.islink(fp): # Ignore symbolic links
|
||||
bundle.size += os.path.getsize(fp)
|
||||
new_module_size += os.path.getsize(fp)
|
||||
else:
|
||||
self.logger.warning(
|
||||
f"Skipping symbolic link in space calculation: {fp}"
|
||||
|
|
@ -154,27 +175,29 @@ class Backend:
|
|||
f"Error: {e} - Skipping file in space calculation: {fp}"
|
||||
)
|
||||
|
||||
if self.get_free_space() < bundle.size:
|
||||
if self.get_free_space() < new_module_size:
|
||||
self.logger.error(
|
||||
f"Aborted installing module {name} - "
|
||||
f"not enough free space ({bundle.size} < {self.get_free_space()})"
|
||||
f"not enough free space ({new_module_size} < {self.get_free_space()})"
|
||||
)
|
||||
click.secho(
|
||||
f"Aborted installing module {name} - "
|
||||
f"not enough free space ({bundle.size} < {self.get_free_space()})",
|
||||
f"not enough free space ({new_module_size} < {self.get_free_space()})",
|
||||
fg="red",
|
||||
)
|
||||
return
|
||||
|
||||
# Create the library directory first.
|
||||
self._create_library_directory(device_path, library_path)
|
||||
|
||||
if pyext:
|
||||
# Use Python source for module.
|
||||
self.install_module_py(metadata)
|
||||
if local_path is None:
|
||||
if pyext:
|
||||
# Use Python source for module.
|
||||
self.install_module_py(metadata)
|
||||
else:
|
||||
# Use pre-compiled mpy modules.
|
||||
self.install_module_mpy(bundle, metadata)
|
||||
else:
|
||||
# Use pre-compiled mpy modules.
|
||||
self.install_module_mpy(bundle, metadata)
|
||||
self.copy_file(metadata["path"], "lib")
|
||||
click.echo("Installed '{}'.".format(name))
|
||||
else:
|
||||
click.echo("Unknown module named, '{}'.".format(name))
|
||||
|
|
@ -520,6 +543,17 @@ class WebBackend(Backend):
|
|||
_writeable_error()
|
||||
r.raise_for_status()
|
||||
|
||||
def copy_file(self, target_file, location_to_paste):
|
||||
if os.path.isdir(target_file):
|
||||
create_directory_url = urljoin(
|
||||
self.device_location,
|
||||
"/".join(("fs", location_to_paste, target_file, "")),
|
||||
)
|
||||
self._create_library_directory(self.device_location, create_directory_url)
|
||||
self.install_dir_http(target_file)
|
||||
else:
|
||||
self.install_file_http(target_file)
|
||||
|
||||
def install_module_mpy(self, bundle, metadata):
|
||||
"""
|
||||
:param bundle library bundle.
|
||||
|
|
@ -775,6 +809,19 @@ class DiskBackend(Backend):
|
|||
if not os.path.exists(library_path): # pragma: no cover
|
||||
os.makedirs(library_path)
|
||||
|
||||
def copy_file(self, target_file, location_to_paste):
|
||||
target_filename = target_file.split(os.path.sep)[-1]
|
||||
if os.path.isdir(target_file):
|
||||
shutil.copytree(
|
||||
target_file,
|
||||
os.path.join(self.device_location, location_to_paste, target_filename),
|
||||
)
|
||||
else:
|
||||
shutil.copyfile(
|
||||
target_file,
|
||||
os.path.join(self.device_location, location_to_paste, target_filename),
|
||||
)
|
||||
|
||||
def install_module_mpy(self, bundle, metadata):
|
||||
"""
|
||||
:param bundle library bundle.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ Functions called from commands in order to provide behaviors and return informat
|
|||
"""
|
||||
|
||||
import ctypes
|
||||
import glob
|
||||
import os
|
||||
|
||||
from subprocess import check_output
|
||||
|
|
@ -90,6 +91,7 @@ def completion_for_install(ctx, param, incomplete):
|
|||
module_names = {m.replace(".py", "") for m in available_modules}
|
||||
if incomplete:
|
||||
module_names = [name for name in module_names if name.startswith(incomplete)]
|
||||
module_names.extend(glob.glob(f"{incomplete}*"))
|
||||
return sorted(module_names)
|
||||
|
||||
|
||||
|
|
@ -446,6 +448,7 @@ def get_dependencies(*requested_libraries, mod_names, to_install=()):
|
|||
:param list(str) to_install: Modules already selected for installation.
|
||||
:return: tuple of module names to install which we build
|
||||
"""
|
||||
# pylint: disable=too-many-branches
|
||||
# Internal variables
|
||||
_to_install = to_install
|
||||
_requested_libraries = []
|
||||
|
|
@ -471,10 +474,14 @@ def get_dependencies(*requested_libraries, mod_names, to_install=()):
|
|||
_requested_libraries.append(canonical_lib_name)
|
||||
except KeyError:
|
||||
if canonical_lib_name not in WARNING_IGNORE_MODULES:
|
||||
click.secho(
|
||||
f"WARNING:\n\t{canonical_lib_name} is not a known CircuitPython library.",
|
||||
fg="yellow",
|
||||
)
|
||||
if os.path.exists(canonical_lib_name):
|
||||
_requested_libraries.append(canonical_lib_name)
|
||||
else:
|
||||
click.secho(
|
||||
f"WARNING:\n\t{canonical_lib_name} "
|
||||
f"is not a known CircuitPython library.",
|
||||
fg="yellow",
|
||||
)
|
||||
|
||||
if not _requested_libraries:
|
||||
# If nothing is requested, we're done
|
||||
|
|
@ -484,16 +491,20 @@ def get_dependencies(*requested_libraries, mod_names, to_install=()):
|
|||
if library not in _to_install:
|
||||
_to_install = _to_install + (library,)
|
||||
# get the requirements.txt from bundle
|
||||
bundle = mod_names[library]["bundle"]
|
||||
requirements_txt = bundle.requirements_for(library)
|
||||
if requirements_txt:
|
||||
_requested_libraries.extend(
|
||||
libraries_from_requirements(requirements_txt)
|
||||
)
|
||||
try:
|
||||
bundle = mod_names[library]["bundle"]
|
||||
requirements_txt = bundle.requirements_for(library)
|
||||
if requirements_txt:
|
||||
_requested_libraries.extend(
|
||||
libraries_from_requirements(requirements_txt)
|
||||
)
|
||||
|
||||
circup_dependencies = get_circup_dependencies(bundle, library)
|
||||
for circup_dependency in circup_dependencies:
|
||||
_requested_libraries.append(circup_dependency)
|
||||
circup_dependencies = get_circup_dependencies(bundle, library)
|
||||
for circup_dependency in circup_dependencies:
|
||||
_requested_libraries.append(circup_dependency)
|
||||
except KeyError:
|
||||
# don't check local file for further dependencies
|
||||
pass
|
||||
|
||||
# we've processed this library, remove it from the list
|
||||
_requested_libraries.remove(library)
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ def install(
|
|||
"""
|
||||
Install a named module(s) onto the device. Multiple modules
|
||||
can be installed at once by providing more than one module name, each
|
||||
separated by a space.
|
||||
separated by a space. Modules can be from a Bundle or local filepaths.
|
||||
"""
|
||||
|
||||
# TODO: Ensure there's enough space on the device
|
||||
|
|
|
|||
Loading…
Reference in a new issue