Add --list and --rename options to example

Added caching of example library example metadata, to speed up tab completion and --list returns

--rename option will rename output to code.py if example resolves to single file

Changed connection announcement to include board name
This commit is contained in:
Brian K. Jackson(Arakkis) 2025-01-12 07:50:34 -05:00
parent da8f6c26c5
commit bd834c4603
3 changed files with 50 additions and 9 deletions

View file

@ -950,7 +950,10 @@ class DiskBackend(Backend):
# Copy the directory.
shutil.copytree(source_path, target_path)
else:
target = os.path.basename(source_path)
if "target_name" in metadata:
target = metadata["target_name"]
else:
target = os.path.basename(source_path)
target_path = os.path.join(location, target)
# Copy file.
shutil.copyfile(source_path, target_path)

View file

@ -8,6 +8,7 @@ Functions called from commands in order to provide behaviors and return informat
import ctypes
import glob
import os
import pickle
from subprocess import check_output
import sys
@ -100,6 +101,7 @@ def completion_for_example(ctx, param, incomplete):
Returns the list of available modules for the command line tab-completion
with the ``circup example`` command.
"""
# pylint: disable=unused-argument, consider-iterating-dictionary
available_examples = get_bundle_examples(get_bundles_list(), avoid_download=True)
@ -319,14 +321,22 @@ def get_bundle_examples(bundles_list, avoid_download=False):
:return: A dictionary of metadata about the examples available in the
library bundle.
"""
# pylint: disable=too-many-nested-blocks
# pylint: disable=too-many-nested-blocks,too-many-locals
all_the_examples = dict()
bundle_examples = dict()
try:
for bundle in bundles_list:
if not avoid_download or not os.path.isdir(bundle.lib_dir("py")):
ensure_latest_bundle(bundle)
path = bundle.examples_dir("py")
meta_saved = os.path.join(path, "../bundle_examples.pickle")
if os.path.exists(meta_saved):
with open(meta_saved, "rb") as f:
bundle_examples = pickle.load(f)
all_the_examples.update(bundle_examples)
bundle_examples.clear()
continue
path_examples = _get_modules_file(path, logger)
for lib_name, lib_metadata in path_examples.items():
for _dir_level in os.walk(lib_metadata["path"]):
@ -337,7 +347,11 @@ def get_bundle_examples(bundles_list, avoid_download=False):
if _dirs[-1] == "":
_dirs.pop(-1)
slug = f"{os.path.sep}".join(_dirs + [_file.replace(".py", "")])
bundle_examples[slug] = os.path.join(_dir_level[0], _file)
all_the_examples[slug] = os.path.join(_dir_level[0], _file)
with open(meta_saved, "wb") as f:
pickle.dump(bundle_examples, f)
bundle_examples.clear()
except NotADirectoryError:
# Bundle does not have new style examples directory

View file

@ -178,8 +178,8 @@ def main( # pylint: disable=too-many-locals
else (cpy_version, board_id)
)
click.echo(
"Found device at {}, running CircuitPython {}.".format(
device_path, cpy_version
"Found device {} at {}, running CircuitPython {}.".format(
board_id, device_path, cpy_version
)
)
try:
@ -406,31 +406,55 @@ def install(
@main.command()
@click.option("--overwrite", is_flag=True, help="Overwrite the file if it exists.")
@click.option("--list", "-ls", "op_list", is_flag=True, help="List available examples.")
@click.option("--rename", is_flag=True, help="Install the example as code.py.")
@click.argument(
"examples", required=True, nargs=-1, shell_complete=completion_for_example
"examples", required=False, nargs=-1, shell_complete=completion_for_example
)
@click.pass_context
def example(ctx, examples, overwrite):
def example(ctx, examples, op_list, rename, overwrite):
"""
Copy named example(s) from a bundle onto the device. Multiple examples
can be installed at once by providing more than one example name, each
separated by a space.
"""
if op_list:
if examples:
click.echo("\n".join(completion_for_example(ctx, "", examples)))
else:
click.echo("Available example libraries:")
available_examples = get_bundle_examples(
get_bundles_list(), avoid_download=True
)
lib_names = {
str(key.split(os.path.sep)[0]): value
for key, value in available_examples.items()
}
click.echo("\n".join(sorted(lib_names.keys())))
return
for example_arg in examples:
available_examples = get_bundle_examples(
get_bundles_list(), avoid_download=True
)
if example_arg in available_examples:
filename = available_examples[example_arg].split(os.path.sep)[-1]
install_metadata = {"path": available_examples[example_arg]}
# check of we are dealing with a file that needs to be pushed as code.py
# or a directory that needs to be copied raw
filename = available_examples[example_arg].split(os.path.sep)[-1]
if rename:
if os.path.isfile(available_examples[example_arg]):
filename = "code.py"
install_metadata["target_name"] = filename
if overwrite or not ctx.obj["backend"].file_exists(filename):
click.echo(
f"{'Copying' if not overwrite else 'Overwriting'}: {filename}"
)
ctx.obj["backend"].install_module_py(
{"path": available_examples[example_arg]}, location=""
)
ctx.obj["backend"].install_module_py(install_metadata, location="")
else:
click.secho(
f"File: {filename} already exists. Use --overwrite if you wish to replace it.",