From 6f836951b5300130758f226538c7bca690168cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 24 Aug 2015 13:40:00 +0200 Subject: [PATCH 01/10] Handle Repetier resend repetitions Repetier might resend the same resend request to make sure it arrives. This commit makes OctoPrint not react to such a repeated request and instead ignore up to a configurable amount of repeated requests for the same (current) line. --- src/octoprint/settings.py | 4 +++- src/octoprint/util/comm.py | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/octoprint/settings.py b/src/octoprint/settings.py index 115932d9..969467e7 100644 --- a/src/octoprint/settings.py +++ b/src/octoprint/settings.py @@ -86,7 +86,9 @@ default_settings = { "additionalBaudrates": [], "longRunningCommands": ["G4", "G28", "G29", "G30", "G32", "M400", "M226"], "checksumRequiringCommands": ["M110"], - "helloCommand": "M110 N0" + "helloCommand": "M110 N0", + "ignoreIdenticalResends": False, + "identicalResendsCountdown": 7 }, "server": { "host": "0.0.0.0", diff --git a/src/octoprint/util/comm.py b/src/octoprint/util/comm.py index 788299f8..de819989 100644 --- a/src/octoprint/util/comm.py +++ b/src/octoprint/util/comm.py @@ -249,6 +249,8 @@ class MachineCom(object): self._lastResendNumber = None self._currentResendCount = 0 self._resendSwallowNextOk = False + self._resendSwallowRepetitions = settings().getBoolean(["serial", "ignoreIdenticalResends"]) + self._resendSwallowRepetitionsCounter = 0 self._checksum_requiring_commands = settings().get(["serial", "checksumRequiringCommands"]) self._clear_to_send = CountedEvent(max=10, name="comm.clear_to_send") @@ -1484,9 +1486,18 @@ class MachineCom(object): self._currentResendCount += 1 return + # If we ignore resend repetitions (Repetier firmware...), check if we + # need to do this now. If the same line number has been requested we + # already saw and resent, we'll ignore it up to times. + if self._resendSwallowRepetitions and lineToResend == self._lastResendNumber and self._resendSwallowRepetitionsCounter > 0: + self._logger.debug("Ignoring resend request for line %d, that is probably a repetition sent by the firmware to ensure it arrives, not a real request" % lineToResend) + self._resendSwallowRepetitionsCounter -= 1 + return + self._resendDelta = resendDelta self._lastResendNumber = lineToResend self._currentResendCount = 0 + self._resendSwallowRepetitionsCounter = settings().getInt(["serial", "identicalResendsCountdown"]) if self._resendDelta > len(self._lastLines) or len(self._lastLines) == 0 or self._resendDelta < 0: self._errorValue = "Printer requested line %d but no sufficient history is available, can't resend" % lineToResend From 6271bcfe05bd61d39ea64628332f93061ec32c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 24 Aug 2015 13:41:56 +0200 Subject: [PATCH 02/10] Virtual printer now supports resend repetitions If a new config setting is set, the virtual printer will now resend the same resend request twice to allow testing the comm layer behaviour in OctoPrint for being able to cope with these possible repetitions like they can happen with Repetier. --- src/octoprint/plugins/virtual_printer/virtual.py | 9 +++++++-- src/octoprint/settings.py | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/octoprint/plugins/virtual_printer/virtual.py b/src/octoprint/plugins/virtual_printer/virtual.py index 7044ccdf..05676ecb 100644 --- a/src/octoprint/plugins/virtual_printer/virtual.py +++ b/src/octoprint/plugins/virtual_printer/virtual.py @@ -314,8 +314,13 @@ class VirtualPrinter(object): else: self._send("Error: expected line %d got %d" % (expected, actual)) - self._send("Resend:%d" % expected) - self._send("ok") + def request_resend(): + self._send("Resend:%d" % expected) + self._send("ok") + + if settings().getBoolean(["devel", "virtualPrinter", "repetierStyleResends"]): + request_resend() + request_resend() def _debugTrigger(self, data): if data == "action_pause": diff --git a/src/octoprint/settings.py b/src/octoprint/settings.py index 969467e7..0893d6a1 100644 --- a/src/octoprint/settings.py +++ b/src/octoprint/settings.py @@ -283,6 +283,7 @@ default_settings = { }, "hasBed": True, "repetierStyleTargetTemperature": False, + "repetierStyleResends": False, "okBeforeCommandOutput": False, "smoothieTemperatureReporting": False, "extendedSdFileList": False, From 168d32eb630d0090b3a6463c0c465f928868c5a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 24 Aug 2015 13:44:09 +0200 Subject: [PATCH 03/10] Fixed regex groups for GCODE parameters --- src/octoprint/util/comm.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/octoprint/util/comm.py b/src/octoprint/util/comm.py index de819989..61546ff5 100644 --- a/src/octoprint/util/comm.py +++ b/src/octoprint/util/comm.py @@ -1751,14 +1751,14 @@ class MachineCom(object): def _gcode_T_sent(self, cmd, cmd_type=None): toolMatch = regexes_parameters["intT"].search(cmd) if toolMatch: - self._currentTool = int(toolMatch.group(1)) + self._currentTool = int(toolMatch.group("value")) def _gcode_G0_sent(self, cmd, cmd_type=None): if 'Z' in cmd: match = regexes_parameters["floatZ"].search(cmd) if match: try: - z = float(match.group(1)) + z = float(match.group("value")) if self._currentZ != z: self._currentZ = z self._callback.on_comm_z_change(z) @@ -1775,11 +1775,11 @@ class MachineCom(object): toolNum = self._currentTool toolMatch = regexes_parameters["intT"].search(cmd) if toolMatch: - toolNum = int(toolMatch.group(1)) + toolNum = int(toolMatch.group("value")) match = regexes_parameters["floatS"].search(cmd) if match: try: - target = float(match.group(1)) + target = float(match.group("value")) if toolNum in self._temp.keys() and self._temp[toolNum] is not None and isinstance(self._temp[toolNum], tuple): (actual, oldTarget) = self._temp[toolNum] self._temp[toolNum] = (actual, target) @@ -1792,7 +1792,7 @@ class MachineCom(object): match = regexes_parameters["floatS"].search(cmd) if match: try: - target = float(match.group(1)) + target = float(match.group("value")) if self._bedTemp is not None and isinstance(self._bedTemp, tuple): (actual, oldTarget) = self._bedTemp self._bedTemp = (actual, target) From d0f61e50738cf4f32916b444c13439b39b2b8508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 24 Aug 2015 14:28:42 +0200 Subject: [PATCH 04/10] Moved new resend setting into feature section That's where all other protocol specific settings are currently located. Will be migrated at a later date into the printer profile instead (that makes way more sense). --- src/octoprint/settings.py | 6 +++--- src/octoprint/util/comm.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/octoprint/settings.py b/src/octoprint/settings.py index 0893d6a1..2419b8e4 100644 --- a/src/octoprint/settings.py +++ b/src/octoprint/settings.py @@ -87,8 +87,6 @@ default_settings = { "longRunningCommands": ["G4", "G28", "G29", "G30", "G32", "M400", "M226"], "checksumRequiringCommands": ["M110"], "helloCommand": "M110 N0", - "ignoreIdenticalResends": False, - "identicalResendsCountdown": 7 }, "server": { "host": "0.0.0.0", @@ -154,7 +152,9 @@ default_settings = { "externalHeatupDetection": True, "supportWait": True, "keyboardControl": True, - "pollWatched": False + "pollWatched": False, + "ignoreIdenticalResends": False, + "identicalResendsCountdown": 7 }, "folder": { "uploads": None, diff --git a/src/octoprint/util/comm.py b/src/octoprint/util/comm.py index 61546ff5..5e03842a 100644 --- a/src/octoprint/util/comm.py +++ b/src/octoprint/util/comm.py @@ -249,7 +249,7 @@ class MachineCom(object): self._lastResendNumber = None self._currentResendCount = 0 self._resendSwallowNextOk = False - self._resendSwallowRepetitions = settings().getBoolean(["serial", "ignoreIdenticalResends"]) + self._resendSwallowRepetitions = settings().getBoolean(["feature", "ignoreIdenticalResends"]) self._resendSwallowRepetitionsCounter = 0 self._checksum_requiring_commands = settings().get(["serial", "checksumRequiringCommands"]) @@ -1497,7 +1497,7 @@ class MachineCom(object): self._resendDelta = resendDelta self._lastResendNumber = lineToResend self._currentResendCount = 0 - self._resendSwallowRepetitionsCounter = settings().getInt(["serial", "identicalResendsCountdown"]) + self._resendSwallowRepetitionsCounter = settings().getInt(["feature", "identicalResendsCountdown"]) if self._resendDelta > len(self._lastLines) or len(self._lastLines) == 0 or self._resendDelta < 0: self._errorValue = "Printer requested line %d but no sufficient history is available, can't resend" % lineToResend From 4525a3a805c72a930933bb8f183f0aaf0a528b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 24 Aug 2015 14:30:32 +0200 Subject: [PATCH 05/10] Settings dialog for new resend setting --- src/octoprint/server/api/settings.py | 4 +++- src/octoprint/static/js/app/viewmodels/settings.js | 1 + .../templates/dialogs/settings/features.jinja2 | 14 +++++++------- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/octoprint/server/api/settings.py b/src/octoprint/server/api/settings.py index 1cb3d4bf..78858407 100644 --- a/src/octoprint/server/api/settings.py +++ b/src/octoprint/server/api/settings.py @@ -69,7 +69,8 @@ def getSettings(): "repetierTargetTemp": s.getBoolean(["feature", "repetierTargetTemp"]), "externalHeatupDetection": s.getBoolean(["feature", "externalHeatupDetection"]), "keyboardControl": s.getBoolean(["feature", "keyboardControl"]), - "pollWatched": s.getBoolean(["feature", "pollWatched"]) + "pollWatched": s.getBoolean(["feature", "pollWatched"]), + "ignoreIdenticalResends": s.getBoolean(["feature", "ignoreIdenticalResends"]) }, "serial": { "port": connectionOptions["portPreference"], @@ -217,6 +218,7 @@ def _saveSettings(data): if "externalHeatupDetection" in data["feature"].keys(): s.setBoolean(["feature", "externalHeatupDetection"], data["feature"]["externalHeatupDetection"]) if "keyboardControl" in data["feature"].keys(): s.setBoolean(["feature", "keyboardControl"], data["feature"]["keyboardControl"]) if "pollWatched" in data["feature"]: s.setBoolean(["feature", "pollWatched"], data["feature"]["pollWatched"]) + if "ignoreIdenticalResends" in data["feature"]: s.setBoolean(["feature", "ignoreIdenticalResends"], data["feature"]["ignoreIdenticalResends"]) if "serial" in data.keys(): if "autoconnect" in data["serial"].keys(): s.setBoolean(["serial", "autoconnect"], data["serial"]["autoconnect"]) diff --git a/src/octoprint/static/js/app/viewmodels/settings.js b/src/octoprint/static/js/app/viewmodels/settings.js index 1900e1b1..561fbb5a 100644 --- a/src/octoprint/static/js/app/viewmodels/settings.js +++ b/src/octoprint/static/js/app/viewmodels/settings.js @@ -121,6 +121,7 @@ $(function() { self.feature_disableExternalHeatupDetection = ko.observable(undefined); self.feature_keyboardControl = ko.observable(undefined); self.feature_pollWatched = ko.observable(undefined); + self.feature_ignoreIdenticalResends = ko.observable(undefined); self.serial_port = ko.observable(); self.serial_baudrate = ko.observable(); diff --git a/src/octoprint/templates/dialogs/settings/features.jinja2 b/src/octoprint/templates/dialogs/settings/features.jinja2 index cf669653..97a5864f 100644 --- a/src/octoprint/templates/dialogs/settings/features.jinja2 +++ b/src/octoprint/templates/dialogs/settings/features.jinja2 @@ -48,6 +48,13 @@ +
+
+ +
+
-
-
- -
-
From c7fd4809fdaffe0c4c084a04f244f55342cc9022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 24 Aug 2015 16:57:08 +0200 Subject: [PATCH 06/10] Fixed bug that made browser crash when trying to log in Trying to serialize view models or browser events as username/password probably was not the best of ideas ;) --- src/octoprint/templates/navbar/login.jinja2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/octoprint/templates/navbar/login.jinja2 b/src/octoprint/templates/navbar/login.jinja2 index 229fe7f9..f712f82d 100644 --- a/src/octoprint/templates/navbar/login.jinja2 +++ b/src/octoprint/templates/navbar/login.jinja2 @@ -10,7 +10,7 @@ - +
  • {{ _('User Settings') }}
  • From cc8dcef8a1a46dc35377bb56e5504c8a682f2929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Wed, 26 Aug 2015 15:25:16 +0200 Subject: [PATCH 07/10] Also provide branch info to UI/on socket --- src/octoprint/server/util/sockjs.py | 1 + src/octoprint/server/views.py | 3 ++- src/octoprint/static/js/app/dataupdater.js | 1 + src/octoprint/templates/initscript.jinja2 | 3 ++- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/octoprint/server/util/sockjs.py b/src/octoprint/server/util/sockjs.py index 44b682f8..452a07cd 100644 --- a/src/octoprint/server/util/sockjs.py +++ b/src/octoprint/server/util/sockjs.py @@ -66,6 +66,7 @@ class PrinterStateConnection(sockjs.tornado.SockJSConnection, octoprint.printer. apikey=octoprint.server.UI_API_KEY, version=octoprint.server.VERSION, display_version=octoprint.server.DISPLAY_VERSION, + branch=octoprint.server.BRANCH, plugin_hash=plugin_hash.hexdigest(), config_hash=config_hash )) diff --git a/src/octoprint/server/views.py b/src/octoprint/server/views.py index e4661c68..8a9d0c34 100644 --- a/src/octoprint/server/views.py +++ b/src/octoprint/server/views.py @@ -13,7 +13,7 @@ from flask import request, g, url_for, make_response, render_template, send_from import octoprint.plugin from octoprint.server import app, userManager, pluginManager, gettext, \ - debug, LOCALES, VERSION, DISPLAY_VERSION, UI_API_KEY + debug, LOCALES, VERSION, DISPLAY_VERSION, UI_API_KEY, BRANCH from octoprint.settings import settings from . import util @@ -311,6 +311,7 @@ def index(): debug=debug, version=VERSION, display_version=DISPLAY_VERSION, + branch=BRANCH, gcodeMobileThreshold=settings().get(["gcodeViewer", "mobileSizeThreshold"]), gcodeThreshold=settings().get(["gcodeViewer", "sizeThreshold"]), uiApiKey=UI_API_KEY, diff --git a/src/octoprint/static/js/app/dataupdater.js b/src/octoprint/static/js/app/dataupdater.js index 52c880c0..52293417 100644 --- a/src/octoprint/static/js/app/dataupdater.js +++ b/src/octoprint/static/js/app/dataupdater.js @@ -113,6 +113,7 @@ function DataUpdater(allViewModels) { var oldVersion = VERSION; VERSION = data["version"]; DISPLAY_VERSION = data["display_version"]; + BRANCH = data["branch"]; $("span.version").text(DISPLAY_VERSION); var oldPluginHash = self._pluginHash; diff --git a/src/octoprint/templates/initscript.jinja2 b/src/octoprint/templates/initscript.jinja2 index 5d972f30..28bf8eb5 100644 --- a/src/octoprint/templates/initscript.jinja2 +++ b/src/octoprint/templates/initscript.jinja2 @@ -22,11 +22,12 @@ var SOCKJS_URI = "{{ url_for('index') }}" + "sockjs"; var SOCKJS_DEBUG = CONFIG_DEBUG; // sockjs should define CLOSE_NORMAL for us, but they don't (from ws spec) - var SOCKJS_CLOSE_NORMAL = 1000 + var SOCKJS_CLOSE_NORMAL = 1000; var UI_API_KEY = "{{ uiApiKey }}"; var VERSION = "{{ version }}"; var DISPLAY_VERSION = "{{ display_version }}"; + var BRANCH = "{{ branch }}"; var LOCALE = "{{ g.locale }}"; var AVAILABLE_LOCALES = {{ locales|tojson }}; From 8666a28f645c0d45420ca5ae2bc731bdd43003be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Wed, 26 Aug 2015 15:50:57 +0200 Subject: [PATCH 08/10] SWU: Various improvements for better usability * Allow configuration of checkout folder and version tracking type via Plugin Configuration * Display message to use if checkout folder is not configured or a non-release version is running and version tracking against releases is enabled * Clear version cache when a change in the check configuration is detected * Mark check configurations for which an update is not possible with a little exclamation mark --- .../plugins/softwareupdate/__init__.py | 100 +++++++++++++----- .../static/js/softwareupdate.js | 41 ++++++- .../templates/softwareupdate_settings.jinja2 | 34 +++++- .../softwareupdate/updaters/update_script.py | 12 ++- 4 files changed, 158 insertions(+), 29 deletions(-) diff --git a/src/octoprint/plugins/softwareupdate/__init__.py b/src/octoprint/plugins/softwareupdate/__init__.py index 32fb4ab1..6ac86bdf 100644 --- a/src/octoprint/plugins/softwareupdate/__init__.py +++ b/src/octoprint/plugins/softwareupdate/__init__.py @@ -14,6 +14,7 @@ import threading import time import logging import logging.handlers +import hashlib from . import version_checks, updaters, exceptions, util @@ -99,8 +100,12 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, self._logger.exception("Error while loading version cache from disk") else: try: - if "octoprint" in data and len(data["octoprint"]) == 4 and "local" in data["octoprint"][1] and "value" in data["octoprint"][1]["local"]: - data_version = data["octoprint"][1]["local"]["value"] + if not isinstance(data, dict): + self._logger.info("Version cache was created in a different format, not using it") + return + + if "__version" in data: + data_version = data["__version"] else: self._logger.info("Can't determine version of OctoPrint version cache was created for, not using it") return @@ -118,24 +123,18 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, self._logger.exception("Error parsing in version cache data") def _save_version_cache(self): - import tempfile import yaml - import shutil + from octoprint.util import atomic_write + from octoprint._version import get_versions - file_obj = tempfile.NamedTemporaryFile(delete=False) - try: + octoprint_version = get_versions()["version"] + self._version_cache["__version"] = octoprint_version + + with atomic_write(self._version_cache_path) as file_obj: yaml.safe_dump(self._version_cache, stream=file_obj, default_flow_style=False, indent=" ", allow_unicode=True) - file_obj.close() - shutil.move(file_obj.name, self._version_cache_path) - self._version_cache_dirty = False - self._logger.info("Saved version cache to disk") - finally: - try: - if os.path.exists(file_obj.name): - os.remove(file_obj.name) - except Exception as e: - self._logger.warn("Could not delete file {}: {}".format(file_obj.name, str(e))) + self._version_cache_dirty = False + self._logger.info("Saved version cache to disk") #~~ SettingsPlugin API @@ -159,20 +158,62 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, data = dict(octoprint.plugin.SettingsPlugin.on_settings_load(self)) if "checks" in data: del data["checks"] + + checks = self._get_configured_checks() + if "octoprint" in checks: + if "checkout_folder" in checks["octoprint"]: + data["octoprint_checkout_folder"] = checks["octoprint"]["checkout_folder"] + elif "update_folder" in checks["octoprint"]: + data["octoprint_checkout_folder"] = checks["octoprint"]["update_folder"] + else: + data["octoprint_checkout_folder"] = None + data["octoprint_type"] = checks["octoprint"].get("type", None) + else: + data["octoprint_checkout_folder"] = None + data["octoprint_type"] = None + return data def on_settings_save(self, data): for key in self.get_settings_defaults(): - if key == "checks" or key == "cache_ttl": + if key == "checks" or key == "cache_ttl" or key == "octoprint_checkout_folder" or key == "octoprint_type": continue if key in data: self._settings.set([key], data[key]) if "cache_ttl" in data: self._settings.set_int(["cache_ttl"], data["cache_ttl"]) - self._version_cache_ttl = self._settings.get_int(["cache_ttl"]) * 60 + checks = self._get_configured_checks() + if "octoprint" in checks: + check = checks["octoprint"] + update_type = check.get("type", None) + checkout_folder = check.get("checkout_folder", None) + update_folder = check.get("update_folder", None) + + defaults = dict( + plugins=dict(softwareupdate=dict( + checks=dict( + octoprint=dict( + type=update_type, + checkout_folder=checkout_folder, + update_folder=update_folder + ) + ) + )) + ) + + if "octoprint_checkout_folder" in data: + self._settings.set(["checks", "octoprint", "checkout_folder"], data["octoprint_checkout_folder"], defaults=defaults, force=True) + if update_folder and data["octoprint_checkout_folder"]: + self._settings.set(["checks", "octoprint", "update_folder"], None, defaults=defaults, force=True) + self._refresh_configured_checks = True + + if "octoprint_type" in data and data["octoprint_type"] in ("github_release", "git_commit"): + self._settings.set(["checks", "octoprint", "type"], data["octoprint_type"], defaults=defaults, force=True) + self._refresh_configured_checks = True + def get_settings_version(self): return 4 @@ -380,7 +421,7 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, try: target_information, target_update_available, target_update_possible = self._get_current_version(target, populated_check, force=force) if target_information is None: - continue + target_information = dict() except exceptions.UnknownCheckType: self._logger.warn("Unknown update check type for %s" % target) continue @@ -399,22 +440,29 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, updatePossible=target_update_possible, information=target_information, displayName=populated_check["displayName"], - displayVersion=populated_check["displayVersion"].format(octoprint_version=octoprint_version, local_name=local_name, local_value=local_value)) + displayVersion=populated_check["displayVersion"].format(octoprint_version=octoprint_version, local_name=local_name, local_value=local_value), + check=populated_check) if self._version_cache_dirty: self._save_version_cache() return information, update_available, update_possible + def _get_check_hash(self, check): + hash = hashlib.md5() + hash.update(repr(check)) + return hash.hexdigest() + def _get_current_version(self, target, check, force=False): """ Determines the current version information for one target based on its check configuration. """ + current_hash = self._get_check_hash(check) if target in self._version_cache and not force: - timestamp, information, update_available, update_possible = self._version_cache[target] - if timestamp + self._version_cache_ttl >= time.time() > timestamp: + data = self._version_cache[target] + if data["hash"] == current_hash and data["timestamp"] + self._version_cache_ttl >= time.time() > data["timestamp"]: # we also check that timestamp < now to not get confused too much by clock changes - return information, update_available, update_possible + return data["information"], data["available"], data["possible"] information = dict() update_available = False @@ -437,7 +485,11 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin, except: update_possible = False - self._version_cache[target] = (time.time(), information, update_available, update_possible) + self._version_cache[target] = dict(timestamp=time.time(), + hash=current_hash, + information=information, + available=update_available, + possible=update_possible) self._version_cache_dirty = True return information, update_available, update_possible diff --git a/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js b/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js index f9044536..a018f688 100644 --- a/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js +++ b/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js @@ -19,10 +19,20 @@ $(function() { self.workingOutput = undefined; self.loglines = ko.observableArray([]); + self.octoprintUnconfigured = ko.observable(); + self.octoprintUnreleased = ko.observable(); + self.config_cacheTtl = ko.observable(); + self.config_checkoutFolder = ko.observable(); + self.config_checkType = ko.observable(); self.configurationDialog = $("#settings_plugin_softwareupdate_configurationdialog"); + self.config_availableCheckTypes = [ + {"key": "github_release", "name": gettext("Release")}, + {"key": "git_commit", "name": gettext("Commit")} + ]; + self.versions = new ItemListHelper( "plugin.softwareupdate.versions", { @@ -82,15 +92,23 @@ $(function() { var data = { plugins: { softwareupdate: { - cache_ttl: parseInt(self.config_cacheTtl()) + cache_ttl: parseInt(self.config_cacheTtl()), + octoprint_checkout_folder: self.config_checkoutFolder(), + octoprint_type: self.config_checkType() } } }; - self.settings.saveData(data, function() { self.configurationDialog.modal("hide"); self._copyConfig(); }); + self.settings.saveData(data, function() { + self.configurationDialog.modal("hide"); + self._copyConfig(); + self.performCheck(); + }); }; self._copyConfig = function() { self.config_cacheTtl(self.settings.settings.plugins.softwareupdate.cache_ttl()); + self.config_checkoutFolder(self.settings.settings.plugins.softwareupdate.octoprint_checkout_folder()); + self.config_checkType(self.settings.settings.plugins.softwareupdate.octoprint_type()); }; self.fromCheckResponse = function(data, ignoreSeen, showIfNothingNew) { @@ -109,6 +127,25 @@ $(function() { }); self.versions.updateItems(versions); + var octoprint = data.information["octoprint"]; + if (octoprint && octoprint.hasOwnProperty("check")) { + var check = octoprint.check; + if (BRANCH != "master" && check["type"] == "github_release") { + self.octoprintUnreleased(true); + } else { + self.octoprintUnreleased(false); + } + + var checkoutFolder = (check["checkout_folder"] || "").trim(); + var updateFolder = (check["update_folder"] || "").trim(); + var checkType = check["type"] || ""; + if ((checkType == "github_release" || checkType == "git_commit") && checkoutFolder == "" && updateFolder == "") { + self.octoprintUnconfigured(true); + } else { + self.octoprintUnconfigured(false); + } + } + if (data.status == "updateAvailable" || data.status == "updatePossible") { var text = gettext("There are updates available for the following components:"); diff --git a/src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2 b/src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2 index d649099d..5f56ba6f 100644 --- a/src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2 +++ b/src/octoprint/plugins/softwareupdate/templates/softwareupdate_settings.jinja2 @@ -1,3 +1,21 @@ +
    {% trans %} + Please configure the checkout folder of OctoPrint, otherwise + this plugin won't be able to update it. Click on the button + to do this. Also refer to the Documentation. +{% endtrans %}
    +
    {% trans %} +

    + You are running a non-release version of OctoPrint but are tracking OctoPrint + releases. +

    + You probably want OctoPrint to track the matching development version instead. + If you have a local OctoPrint checkout folder switched to another branch, + simply switching over to "Commit" tracking will already + take care of that. Otherwise please take a look at the + Documentation. +

    +{% endtrans %}
    +
    @@ -11,7 +29,7 @@ - :
    + :
    {{ _('Installed:') }}
    {{ _('Available:') }} @@ -44,7 +62,7 @@
    - +
    @@ -55,6 +73,18 @@