move libraries_from_code_py out of backend. fix CPY_VERSION issue for web backend

This commit is contained in:
foamyguy 2023-11-30 06:44:22 -06:00
parent fb6cd847a8
commit 499dee6e03
3 changed files with 53 additions and 40 deletions

View file

@ -30,9 +30,12 @@ import update_checker
from requests.auth import HTTPBasicAuth
from semver import VersionInfo
from circup.shared import DATA_DIR, BAD_FILE_FORMAT, extract_metadata, CPY_VERSION, _get_modules_file
from circup.shared import DATA_DIR, BAD_FILE_FORMAT, extract_metadata, _get_modules_file
from circup.backends import WebBackend, DiskBackend
#: The version of CircuitPython found on the connected device.
CPY_VERSION = ""
# Useful constants.
#: Flag to indicate if the command is being run in verbose mode.
VERBOSE = False
@ -410,13 +413,6 @@ class Module:
)
def clean_library_name(assumed_library_name):
"""
Most CP repos and library names are look like this:
@ -505,9 +501,6 @@ def ensure_latest_bundle(bundle):
logger.info("Current bundle up to date %s.", tag)
def find_device():
"""
Return the location on the filesystem for the connected CircuitPython device.
@ -936,6 +929,25 @@ def tags_data_save_tag(key, tag):
json.dump(tags_data, data)
def libraries_from_code_py(code_py, mod_names):
"""
Parse the given code.py file and return the imported libraries
:param str code_py: Full path of the code.py file
:return: sequence of library names
"""
# pylint: disable=broad-except
try:
found_imports = findimports.find_imports(code_py)
except Exception as ex: # broad exception because anything could go wrong
self.logger.exception(ex)
click.secho('Unable to read the auto file: "{}"'.format(str(ex)), fg="red")
sys.exit(2)
# pylint: enable=broad-except
imports = [info.name.split(".", 1)[0] for info in found_imports]
return [r for r in imports if r in mod_names]
# ----------- CLI command definitions ----------- #
# The following functions have IO side effects (for instance they emit to
@ -1014,7 +1026,6 @@ def main(ctx, verbose, path, host, password, board_id, cpy_version): # pragma:
if ctx.invoked_subcommand in BOARDLESS_COMMANDS:
return
ctx.obj["DEVICE_PATH"] = device_path
latest_version = get_latest_release_from_url(
"https://github.com/adafruit/circuitpython/releases/latest"
@ -1213,9 +1224,10 @@ def install(ctx, modules, pyext, requirement, auto, auto_file): # pragma: no co
if not os.path.isfile(auto_file) and not ctx.obj["using_webworkflow"]:
click.secho(f"Auto file not found: {auto_file}", fg="red")
sys.exit(1)
requested_installs = ctx.obj["backend"].libraries_from_imports(
auto_file, mod_names
)
auto_file_path = ctx.obj["backend"].get_auto_file_path(auto_file)
requested_installs = libraries_from_code_py(auto_file_path, mod_names)
else:
requested_installs = modules
requested_installs = sorted(set(requested_installs))

View file

@ -9,12 +9,13 @@ import findimports
import requests
from requests.auth import HTTPBasicAuth
from circup.shared import DATA_DIR, BAD_FILE_FORMAT, extract_metadata, CPY_VERSION, _get_modules_file
from circup.shared import DATA_DIR, BAD_FILE_FORMAT, extract_metadata, _get_modules_file
#: The location to store a local copy of code.py for use with --auto and
# web workflow
LOCAL_CODE_PY_COPY = os.path.join(DATA_DIR, "code.tmp.py")
class Backend:
"""
Backend parent class to be extended for workflow specific
@ -142,23 +143,6 @@ class Backend:
"""
raise NotImplementedError
def libraries_from_code_py(self, code_py, mod_names):
"""
Parse the given code.py file and return the imported libraries
:param str code_py: Full path of the code.py file
:return: sequence of library names
"""
# pylint: disable=broad-except
try:
found_imports = findimports.find_imports(code_py)
except Exception as ex: # broad exception because anything could go wrong
self.logger.exception(ex)
click.secho('Unable to read the auto file: "{}"'.format(str(ex)), fg="red")
sys.exit(2)
# pylint: enable=broad-except
imports = [info.name.split(".", 1)[0] for info in found_imports]
return [r for r in imports if r in mod_names]
class WebBackend(Backend):
"""
@ -170,6 +154,7 @@ class WebBackend(Backend):
self.LIB_DIR_PATH = "fs/lib/"
self.host = host
self.password = password
self.device_location = f"http://:{self.password}@{self.host}"
def install_file_http(self, source, target):
"""
@ -348,7 +333,9 @@ class WebBackend(Backend):
if not module_name:
# Must be a directory based module.
module_name = os.path.basename(os.path.dirname(metadata["path"]))
major_version = CPY_VERSION.split(".")[0]
major_version = self.get_circuitpython_version(self.device_location)[0].split(
"."
)[0]
bundle_platform = "{}mpy".format(major_version)
bundle_path = os.path.join(bundle.lib_dir(bundle_platform), module_name)
if os.path.isdir(bundle_path):
@ -378,6 +365,16 @@ class WebBackend(Backend):
target = os.path.basename(source_path)
self.install_file_http(source_path, library_path + target)
def get_auto_file_path(self, auto_file_path):
url = auto_file_path
auth = HTTPBasicAuth("", self.password)
r = requests.get(url, auth=auth)
r.raise_for_status()
with open(LOCAL_CODE_PY_COPY, "w", encoding="utf-8") as f:
f.write(r.text)
LOCAL_CODE_PY_COPY
return LOCAL_CODE_PY_COPY
def libraries_from_imports(self, code_py, mod_names):
"""
Parse the given code.py file and return the imported libraries
@ -428,6 +425,7 @@ class WebBackend(Backend):
r.raise_for_status()
self.install_dir_http(module.bundle_path, module.path)
class DiskBackend(Backend):
"""
Backend for interacting with a device via USB Workflow
@ -500,7 +498,9 @@ class DiskBackend(Backend):
# Must be a directory based module.
module_name = os.path.basename(os.path.dirname(metadata["path"]))
major_version = self.get_circuitpython_version(self.device_location)[0].split(".")[0]
major_version = self.get_circuitpython_version(self.device_location)[0].split(
"."
)[0]
bundle_platform = "{}mpy".format(major_version)
bundle_path = os.path.join(bundle.lib_dir(bundle_platform), module_name)
if os.path.isdir(bundle_path):
@ -534,6 +534,9 @@ class DiskBackend(Backend):
# Copy file.
shutil.copyfile(source_path, target_path)
def get_auto_file_path(self, auto_file_path):
return auto_file_path
def libraries_from_imports(self, code_py, mod_names):
"""
Parse the given code.py file and return the imported libraries
@ -579,4 +582,4 @@ class DiskBackend(Backend):
else:
# Delete and copy file.
os.remove(module.path)
shutil.copyfile(module.bundle_path, module.path)
shutil.copyfile(module.bundle_path, module.path)

View file

@ -10,9 +10,6 @@ BAD_FILE_FORMAT = "Invalid"
#: The location of data files used by circup (following OS conventions).
DATA_DIR = appdirs.user_data_dir(appname="circup", appauthor="adafruit")
#: The version of CircuitPython found on the connected device.
CPY_VERSION = ""
def _get_modules_file(path, logger):
"""
@ -55,6 +52,7 @@ def _get_modules_file(path, logger):
break
return result
def extract_metadata(path, logger):
"""
Given a file path, return a dictionary containing metadata extracted from
@ -124,4 +122,4 @@ def extract_metadata(path, logger):
if result:
logger.info("Extracted metadata: %s", result)
return result
return result