From 169aff4f8fcf2ba99e1cd442dfb15b8319005e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Thu, 5 Nov 2015 16:54:47 +0100 Subject: [PATCH] CLI for the software update plugin --- .../plugins/softwareupdate/__init__.py | 141 +++++++++++++++++- 1 file changed, 139 insertions(+), 2 deletions(-) diff --git a/src/octoprint/plugins/softwareupdate/__init__.py b/src/octoprint/plugins/softwareupdate/__init__.py index 33451e57..a1904963 100644 --- a/src/octoprint/plugins/softwareupdate/__init__.py +++ b/src/octoprint/plugins/softwareupdate/__init__.py @@ -351,7 +351,7 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, @restricted_access def check_for_update(self): if "check" in flask.request.values: - check_targets = map(str.strip, flask.request.values["check"].split(",")) + check_targets = map(lambda x: x.strip(), flask.request.values["check"].split(",")) else: check_targets = None @@ -528,7 +528,8 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, updater_thread.daemon = False updater_thread.start() - return to_be_updated, dict((key, check["displayName"] if "displayName" in check else key) for key, check in checks.items() if key in to_be_updated) + check_data = dict((key, self._populated_check(key, check)["displayName"]) for key, check in checks.items() if key in to_be_updated) + return to_be_updated, check_data def _update_worker(self, checks, check_targets, force): @@ -761,6 +762,137 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, else: raise exceptions.UnknownUpdateType() +def cli_commands(cli_group, pass_octoprint_ctx, *args, **kwargs): + import click + import sys + import requests.exceptions + import octoprint_client as client + + @click.command("check") + @click.option("--force", is_flag=True, help="Ignore the cache for the update check") + @click.argument("targets", nargs=-1) + def check_command(force, targets): + """Check for updates.""" + params = dict(force=force) + if targets: + params["check"] = ",".join(targets) + + client.init_client(cli_group.settings) + r = client.get("plugin/softwareupdate/check", params=params) + try: + r.raise_for_status() + except requests.exceptions.HTTPError as e: + click.echo("Could not get update information from server, got {}".format(e)) + sys.exit(1) + + data = r.json() + status = data["status"] + information = data["information"] + + lines = [] + octoprint_line = None + for key, info in information.items(): + status_text = "Up to date" + if info["updateAvailable"]: + if info["updatePossible"]: + status_text = "Update available" + else: + status_text = "Update available (manual)" + line = "{}\n\tInstalled: {}\n\tAvailable: {}\n\t=> {}".format(info["displayName"], + info["information"]["local"]["name"], + info["information"]["remote"]["name"], + status_text) + if key == "octoprint": + octoprint_line = line + else: + lines.append(line) + + lines.sort() + if octoprint_line: + lines = [octoprint_line] + lines + + for line in lines: + click.echo(line) + + click.echo() + if status == "current": + click.echo("Everything is up to date") + else: + click.echo("There are updates available!") + + + @click.command("update") + @click.option("--force", is_flag=True, help="Update even if already up to date") + @click.argument("targets", nargs=-1) + def update_command(force, targets): + """Apply updates.""" + client.init_client(cli_group.settings) + + data = dict(force=force) + if targets: + data["check"] = ",".join(targets) + + client.init_client(cli_group.settings) + + def on_message(ws, msg_type, msg): + if msg_type != "plugin" or msg["plugin"] != "softwareupdate": + return + + plugin_message = msg["data"] + if not "type" in plugin_message: + return + + plugin_message_type = plugin_message["type"] + plugin_message_data = plugin_message["data"] + + if plugin_message_type == "updating": + click.echo("Updating {} to {}...".format(plugin_message_data["name"], plugin_message_data["target"])) + + elif plugin_message_type == "update_failed": + click.echo("\t... failed: {}".format(plugin_message_data["reason"])) + + elif plugin_message_type == "loglines" and "loglines" in plugin_message_data: + for entry in plugin_message_data["loglines"]: + prefix = ">>> " if entry["stream"] == "call" else "" + error = entry["stream"] == "stderr" + click.echo("\t{}{}".format(prefix, entry["line"].replace("\n", "\n\t")), err=error) + + elif plugin_message_type == "success" or plugin_message_type == "restart_manually": + results = plugin_message_data["results"] if "results" in plugin_message_data else dict() + if results: + click.echo("The update finished successfully.") + if plugin_message_type == "restart_manually": + click.echo("Please restart the OctoPrint server.") + else: + click.echo("No update necessary") + ws.close() + + elif plugin_message_type == "failure": + click.echo("Error") + ws.close() + + thread = client.connect_socket(on_message=on_message) + + r = client.post_json("plugin/softwareupdate/update", data=data) + try: + r.raise_for_status() + except requests.exceptions.HTTPError as e: + click.echo("Could not get update information from server, got {}".format(e)) + sys.exit(1) + + data = r.json() + to_be_updated = data["order"] + checks = data["checks"] + click.echo("Update in progress, updating:") + for name in to_be_updated: + click.echo("\t{}".format(name if not name in checks else checks[name])) + + thread.join() + + + return [check_command, update_command] + + __plugin_name__ = "Software Update" __plugin_author__ = "Gina Häußge" __plugin_url__ = "https://github.com/foosel/OctoPrint/wiki/Plugin:-Software-Update" @@ -778,4 +910,9 @@ def __plugin_load__(): util=util ) + global __plugin_hooks__ + __plugin_hooks__ = { + "octoprint.cli.commands": cli_commands + } +