From 32add3bfea408384d21019c745f36d96f9e081bd Mon Sep 17 00:00:00 2001 From: Tom Keffer Date: Fri, 22 Dec 2023 14:04:10 -0800 Subject: [PATCH] Seek permission before installing extensions Include the --yes option in usage strings --- docs_src/utilities/weectl-extension.md | 41 ++++++++++++++------------ src/weecfg/extension.py | 32 +++++++++----------- src/weectllib/extension_cmd.py | 8 +++-- 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/docs_src/utilities/weectl-extension.md b/docs_src/utilities/weectl-extension.md index f4b78394..ef4078ca 100644 --- a/docs_src/utilities/weectl-extension.md +++ b/docs_src/utilities/weectl-extension.md @@ -18,7 +18,7 @@ This action will list all the extensions that you have installed. weectl extension install (FILE|DIR|URL) [--config=FILENAME] - [--dry-run] [--verbosity=N] + [--dry-run] [--yes] [--verbosity=N] This action will install an extension from a zip file, tar file, directory, or URL. @@ -46,7 +46,7 @@ weectl extension install ~/Downloads/windy-0.1.zip weectl extension uninstall NAME [--config=FILENAME] - [--dry-run] [--verbosity=N] [-y] + [--dry-run] [--yes] [--verbosity=N] [-y] This action uninstalls an extension. Use the `list` action to see what to use for `NAME`. @@ -67,20 +67,22 @@ verbosity: ``` shell % weectl extension install https://github.com/matthewwall/weewx-windy/archive/master.zip --dry-run --verbosity=3 -Request to install 'https://github.com/matthewwall/weewx-windy/archive/master.zip' +weectl extension install https://github.com/matthewwall/weewx-windy/archive/master.zip --dry-run --verbosity=3 +Using configuration file /Users/joe_user/weewx-data/weewx.conf This is a dry run. Nothing will actually be done. -Extracting from zip archive /var/folders/xm/72q6zf8j71x8df2cqh0j9f6c0000gn/T/tmpuvuc_c0k - Request to install extension found in directory /var/folders/xm/72q6zf8j71x8df2cqh0j9f6c0000gn/T/tmpif_nj_0g/weewx-windy-master/ - Found extension with name 'windy' - Copying new files - Copying from '/var/folders/xm/72q6zf8j71x8df2cqh0j9f6c0000gn/T/tmpif_nj_0g/weewx-windy-master/bin/user/windy.py' to '/Users/Shared/weewx/bin/user/windy.py' - Copied 0 files - Adding services to service lists - Added new service user.windy.Windy to restful_services +Install extension 'https://github.com/matthewwall/weewx-windy/archive/master.zip'? y +Extracting from zip archive /var/folders/xm/72q6zf8j71x8df2cqh0j9f6c0000gn/T/tmpjusc3qrv + Request to install extension found in directory /var/folders/xm/72q6zf8j71x8df2cqh0j9f6c0000gn/T/tmpo0oq1u34/weewx-windy-master/. + Found extension with name 'windy'. + Copying new files... + Fake copying from '/var/folders/xm/72q6zf8j71x8df2cqh0j9f6c0000gn/T/tmpo0oq1u34/weewx-windy-master/bin/user/windy.py' to '/Users/joe_user/weewx-data/bin/user/windy.py' + Fake copied 1 files. + Adding services to service lists. + Added new service user.windy.Windy to restful_services. Adding sections to configuration file Merged extension settings into configuration file -Saving installer file to /Users/Shared/weewx/bin/user/installer/windy -Finished installing extension windy from https://github.com/matthewwall/weewx-windy/archive/master.zip +Saving installer file to /Users/joe_user/weewx-data/bin/user/installer/windy. +Finished installing extension windy from https://github.com/matthewwall/weewx-windy/archive/master.zip. This was a dry run. Nothing was actually done. ``` @@ -88,11 +90,12 @@ Do it for real, default verbosity: ``` % weectl extension install https://github.com/matthewwall/weewx-windy/archive/master.zip -Request to install 'https://github.com/matthewwall/weewx-windy/archive/master.zip' -Extracting from zip archive /var/folders/xm/72q6zf8j71x8df2cqh0j9f6c0000gn/T/tmpk8ggl4qr -Saving installer file to /Users/Shared/weewx/bin/user/installer/windy -Saved configuration dictionary. Backup copy at /Users/Shared/weewx/weewx.conf.20230110152037 -Finished installing extension windy from https://github.com/matthewwall/weewx-windy/archive/master.zip +Using configuration file /Users/joe_user/weewx-data/weewx.conf +Install extension 'https://github.com/matthewwall/weewx-windy/archive/master.zip'? y +Extracting from zip archive /var/folders/xm/72q6zf8j71x8df2cqh0j9f6c0000gn/T/tmpcc92m0oq +Saving installer file to /Users/joe_user/weewx-data/bin/user/installer/windy. +Saved configuration dictionary. Backup copy at /Users/joe_user/weewx-data/weewx.conf.20231222135954. +Finished installing extension windy from https://github.com/matthewwall/weewx-windy/archive/master.zip. ``` List the results: @@ -107,7 +110,7 @@ Uninstall the extension without asking for confirmation: ``` % weectl extension uninstall windy -y -Request to remove extension 'windy' +Using configuration file /Users/joe_user/weewx-data/weewx.conf Finished removing extension 'windy' ``` diff --git a/src/weecfg/extension.py b/src/weecfg/extension.py index 228be5d1..d88339ff 100644 --- a/src/weecfg/extension.py +++ b/src/weecfg/extension.py @@ -75,7 +75,7 @@ class ExtensionEngine(object): exts = sorted(os.listdir(ext_dir)) if exts: self.printer.out("%-18s%-10s%s" % ("Extension Name", "Version", "Description"), - level=0) + level=0) for f in exts: info = self.get_extension_info(f) msg = "%(name)-18s%(version)-10s%(description)s" % info @@ -92,15 +92,19 @@ class ExtensionEngine(object): _, installer = weecfg.get_extension_installer(ext_cache_dir) return installer - def install_extension(self, extension_path): + def install_extension(self, extension_path, no_confirm=False): """Install an extension. Args: extension_path(str): Either a file path, a directory path, or an URL. + no_confirm(bool): If False, ask for a confirmation before installing. Otherwise, + just do it. """ - self.printer.out(f"Request to install '{extension_path}'.") - if self.dry_run: - self.printer.out("This is a dry run. Nothing will actually be done.") + ans = weeutil.weeutil.y_or_n(f"Install extension '{extension_path}'? ", + noprompt=no_confirm) + if ans == 'n': + self.printer.out("Nothing done.") + return # Figure out what extension_path is if extension_path.startswith('http'): @@ -128,8 +132,6 @@ class ExtensionEngine(object): raise InstallError(f"Unrecognized type for {extension_path}") self.printer.out(f"Finished installing extension {extension_name} from {extension_path}.") - if self.dry_run: - self.printer.out("This was a dry run. Nothing was actually done.") def _install_from_file(self, filepath, filetype): """Install an extension from a file. @@ -159,7 +161,7 @@ class ExtensionEngine(object): def install_from_dir(self, extension_dir): """Install the extension whose components are in extension_dir""" self.printer.out(f"Request to install extension found in directory {extension_dir}.", - level=2) + level=2) # The "installer" is actually a dictionary containing what is to be installed and where. # The "installer_path" is the path to the file containing that dictionary. @@ -244,10 +246,10 @@ class ExtensionEngine(object): if self.dry_run: self.printer.out(f"Fake copying from '{source_path}' to '{destination_path}'", - level=3) + level=3) else: self.printer.out(f"Copying from '{source_path}' to '{destination_path}'", - level=3) + level=3) try: os.makedirs(os.path.dirname(destination_path)) except OSError: @@ -374,10 +376,7 @@ class ExtensionEngine(object): just do it. """ - if self.dry_run: - self.printer.out("This is a dry run. Nothing will actually be done.") - - ans = weeutil.weeutil.y_or_n(f"Uninstall extension '{extension_name}'? ", + ans = weeutil.weeutil.y_or_n(f"Uninstall extension '{extension_name}'? (y/n) ", noprompt=no_confirm) if ans == 'n': self.printer.out("Nothing done.") @@ -389,7 +388,7 @@ class ExtensionEngine(object): # Retrieve it _, installer = weecfg.get_extension_installer(extension_installer_dir) except weecfg.ExtensionError: - sys.exit(f"Unable to find extension '{extension_name}'." ) + sys.exit(f"Unable to find extension '{extension_name}'.") # Remove any files that were added: if 'files' in installer: @@ -420,9 +419,6 @@ class ExtensionEngine(object): self.printer.out(f"Finished removing extension '{extension_name}'") - if self.dry_run: - self.printer.out("This was a dry run. Nothing was actually done.") - def uninstall_files(self, file_list): """Delete files that were installed for this extension Args: diff --git a/src/weectllib/extension_cmd.py b/src/weectllib/extension_cmd.py index 8e0c7b3c..29245329 100644 --- a/src/weectllib/extension_cmd.py +++ b/src/weectllib/extension_cmd.py @@ -17,11 +17,11 @@ extension_list_usage = f"""{bcolors.BOLD}weectl extension list """ extension_install_usage = f""" {bcolors.BOLD}weectl extension install (FILE|DIR|URL) [--config=FILENAME] - [--dry-run] [--verbosity=N]{bcolors.ENDC} + [--dry-run] [--yes] [--verbosity=N]{bcolors.ENDC} """ extension_uninstall_usage = f""" {bcolors.BOLD}weectl extension uninstall NAME [--config=FILENAME] - [--dry-run] [--verbosity=N] [-y]{bcolors.ENDC} + [--dry-run] [--yes] [--verbosity=N] [-y]{bcolors.ENDC} """ extension_usage = '\n '.join((extension_list_usage, extension_install_usage, @@ -76,6 +76,8 @@ def add_subparser(subparsers): action='store_true', help='Print what would happen, but do not actually ' 'do it.') + install_extension_parser.add_argument('-y', '--yes', action='store_true', + help="Don't ask for confirmation. Just do it.") install_extension_parser.add_argument('--verbosity', type=int, default=1, metavar='N', help="How much information to display (0|1|2|3).") install_extension_parser.set_defaults(func=weectllib.dispatch) @@ -113,7 +115,7 @@ def list_extensions(config_dict, _): def install_extension(config_dict, namespace): ext = _get_extension_engine(config_dict, namespace.dry_run, namespace.verbosity) - ext.install_extension(namespace.source) + ext.install_extension(namespace.source, no_confirm=namespace.yes) def uninstall_extension(config_dict, namespace):