From cbe4f8c83cf96030ba89f60dcf1f392399f00865 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 16 Sep 2021 11:41:36 -0600 Subject: [PATCH 1/3] ampy rm: allow multiple files --- ampy/cli.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/ampy/cli.py b/ampy/cli.py index 1ac4aab..52a9e9f 100644 --- a/ampy/cli.py +++ b/ampy/cli.py @@ -280,22 +280,21 @@ def put(local, remote): @cli.command() -@click.argument("remote_file") -def rm(remote_file): - """Remove a file from the board. +@click.argument("remote_files", metavar="remote_file", nargs=-1) +def rm(remote_files): + """Remove one or more files from the board. - Remove the specified file from the board's filesystem. Must specify one - argument which is the path to the file to delete. Note that this can't - delete directories which have files inside them, but can delete empty + Remove the specified file(s) from the board's filesystem. Note that this + can't delete directories which have files inside them, but can delete empty directories. - For example to delete main.py from the root of a board run: + For example to delete main.py and data.txt from the root of a board run: - ampy --port /board/serial/port rm main.py + ampy --port /board/serial/port rm main.py data.txt """ - # Delete the provided file/directory on the board. board_files = files.Files(_board) - board_files.rm(remote_file) + for filepath in remote_files: + board_files.rm(filepath) @cli.command() From a35b56c4b3e4162348cc97cb0dd801920dfb12ad Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 16 Sep 2021 12:10:15 -0600 Subject: [PATCH 2/3] ampy get: allow destination to be a directory --- ampy/cli.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/ampy/cli.py b/ampy/cli.py index 52a9e9f..e9ee4e5 100644 --- a/ampy/cli.py +++ b/ampy/cli.py @@ -21,6 +21,7 @@ # SOFTWARE. from __future__ import print_function import os +import pathlib import platform import posixpath import re @@ -101,8 +102,12 @@ def cli(port, baud, delay): @cli.command() @click.argument("remote_file") -@click.argument("local_file", type=click.File("wb"), required=False) -def get(remote_file, local_file): +@click.argument( + "local_path", + type=click.Path(writable=True, allow_dash=True, path_type=pathlib.Path), + required=False +) +def get(remote_file, local_path): """ Retrieve a file from the board. @@ -110,8 +115,9 @@ def get(remote_file, local_file): locally. You must pass at least one argument which is the path to the file to download from the board. If you don't specify a second argument then the file contents will be printed to standard output. However if you pass - a file name as the second argument then the contents of the downloaded file - will be saved to that file (overwriting anything inside it!). + a file name or a directory as the second argument then the contents of the + downloaded file will be saved to that file or directory respectively + (overwriting anything inside it!). For example to retrieve the boot.py and print it out run: @@ -119,16 +125,24 @@ def get(remote_file, local_file): Or to get main.py and save it as main.py locally run: - ampy --port /board/serial/port get main.py main.py + ampy --port /board/serial/port get main.py ./ + + You can also specify "-" as the destination to explicitly specify to output + to standard output. """ # Get the file contents. board_files = files.Files(_board) contents = board_files.get(remote_file) # Print the file out if no local file was provided, otherwise save it. - if local_file is None: + if local_path is None or str(local_path) == "-": print(contents.decode("utf-8")) + elif local_path.is_dir(): + remote_path = pathlib.Path(remote_file) + with local_path.joinpath(remote_path.name).open(mode='wb') as local_file: + local_file.write(contents) else: - local_file.write(contents) + with local_path.open(mode='wb') as local_file: + local_file.write(contents) @cli.command() From fd1fdd2eafa2ef4094fa5b0a7c6f5441688b7a99 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 16 Sep 2021 12:38:17 -0600 Subject: [PATCH 3/3] ampy get: allow multiple remote files for a destination directory --- ampy/cli.py | 67 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/ampy/cli.py b/ampy/cli.py index e9ee4e5..86d0cbe 100644 --- a/ampy/cli.py +++ b/ampy/cli.py @@ -101,48 +101,65 @@ def cli(port, baud, delay): @cli.command() -@click.argument("remote_file") +@click.argument("remote_files", metavar="remote_file", nargs=-1) @click.argument( "local_path", type=click.Path(writable=True, allow_dash=True, path_type=pathlib.Path), required=False ) -def get(remote_file, local_path): +def get(remote_files, local_path): """ Retrieve a file from the board. - Get will download a file from the board and print its contents or save it - locally. You must pass at least one argument which is the path to the file - to download from the board. If you don't specify a second argument then - the file contents will be printed to standard output. However if you pass - a file name or a directory as the second argument then the contents of the - downloaded file will be saved to that file or directory respectively - (overwriting anything inside it!). + Get will download one or more files from the board and print its contents or save it + locally. You must pass at least one argument which is the path to a file + to download from the board. If you specify more than one argument, the + last one is the destination. If you specify exactly one remote file and + one local path, then the local path can either be a currently existing + directory or a destination file path. If you specify more than one remote + file (i.e., three or more arguments), then the last argument must be a + local directory that exists. - For example to retrieve the boot.py and print it out run: + If only one argument is specified, or if you pass in "-" as the second + argument, then the contents of the specified remote file will be printed to + standard output. This is only available for one remote file. - ampy --port /board/serial/port get boot.py + Note: If the destination file exists, it will be overwritten! - Or to get main.py and save it as main.py locally run: + For example to retrieve the boot.py and print it out run: - ampy --port /board/serial/port get main.py ./ + ampy --port /board/serial/port get boot.py You can also specify "-" as the destination to explicitly specify to output to standard output. + + Or to get main.py and helper.py and save them in the current directory + locally, run: + + ampy --port /board/serial/port get main.py helper.py ./ """ - # Get the file contents. + # checks + if len(remote_files) == 0: + raise click.UsageError("Must specify at least one remote file") + if len(remote_files) > 1 and not local_path.is_dir(): + raise click.UsageError( + f"Invalid value for '[LOCAL_PATH]': Directory '{local_path}' does not exist.") + board_files = files.Files(_board) - contents = board_files.get(remote_file) - # Print the file out if no local file was provided, otherwise save it. - if local_path is None or str(local_path) == "-": - print(contents.decode("utf-8")) - elif local_path.is_dir(): - remote_path = pathlib.Path(remote_file) - with local_path.joinpath(remote_path.name).open(mode='wb') as local_file: - local_file.write(contents) - else: - with local_path.open(mode='wb') as local_file: - local_file.write(contents) + for remote_file in remote_files: + # Get the file contents. + contents = board_files.get(remote_file) + + # Print the file out if no local file was provided, otherwise save it. + if local_path is None or str(local_path) == "-": + print(contents.decode("utf-8")) + elif local_path.is_dir(): + remote_path = pathlib.Path(remote_file) + with local_path.joinpath(remote_path.name).open(mode='wb') as local_file: + local_file.write(contents) + else: + with local_path.open(mode='wb') as local_file: + local_file.write(contents) @cli.command()