SoftwareUpdate: Don't persist more check data than necessary in config

The SoftwareUpdate Plugin had a bug that caused way too much check data to be stored in the configuration, leading to plugins potentially being stuck in an "update available" loop although the update had already been applied. Now only the current version of github_commit update types is persisted, not the full check configuration.

Also introduced a configuration version and made the migration function migrate old configs to remove anything that was same as the default supplied for the "octoprint" and all plugin hook checks. That should clean things up in existing installations.
This commit is contained in:
Gina Häußge 2015-06-19 11:12:24 +02:00
parent d5af7b9b48
commit f1be116190

View file

@ -91,6 +91,69 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin,
super(SoftwareUpdatePlugin, self).on_settings_save(data)
self._version_cache_ttl = self._settings.get_int(["cache_ttl"]) * 60
def get_settings_version(self):
return 1
def on_settings_migrate(self, target, current=None):
if current is None:
# there might be some left over data from the time we still persisted everything to settings,
# even the stuff that shouldn't be persisted but always provided by the hook - let's
# clean up
# take care of the octoprint entry
configured_checks = self._settings.get(["checks"], merged=True)
octoprint_check = dict(configured_checks["octoprint"])
if "type" in octoprint_check and not octoprint_check["type"] == "github_commit":
deletables=["current"]
else:
deletables=[]
octoprint_check = self._clean_settings_check("octoprint", octoprint_check, self.get_settings_defaults()["checks"]["octoprint"], delete=deletables, save=False)
configured_checks["octoprint"] = octoprint_check
# and the hooks
update_check_hooks = self._plugin_manager.get_hooks("octoprint.plugin.softwareupdate.check_config")
for name, hook in update_check_hooks.items():
try:
hook_checks = hook()
except:
self._logger.exception("Error while retrieving update information from plugin {name}".format(**locals()))
else:
for key, data in hook_checks.items():
if key in configured_checks:
settings_check = dict(configured_checks[key])
merged = dict_merge(data, settings_check)
if "type" in merged and not merged["type"] == "github_commit":
deletables = ["current", "displayVersion"]
else:
deletables = []
self._clean_settings_check(key, settings_check, data, delete=deletables, save=False)
def _clean_settings_check(self, key, data, defaults, delete=None, save=True):
if delete is None:
delete = []
for k, v in data.items():
if k in defaults and defaults[k] == data[k]:
del data[k]
for k in delete:
if k in data:
del data[k]
dummy_defaults = dict(plugins=dict())
dummy_defaults["plugins"][self._identifier] = dict(checks=dict())
dummy_defaults["plugins"][self._identifier]["checks"][key] = defaults
if len(data):
self._settings.set(["checks", key], data, defaults=dummy_defaults)
else:
self._settings.set(["checks", key], None, defaults=dummy_defaults)
if save:
self._settings.save()
return data
#~~ BluePrint API
@octoprint.plugin.BlueprintPlugin.route("/check", methods=["GET"])
@ -380,15 +443,14 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin,
# persist the new version if necessary for check type
if check["type"] == "github_commit":
checks = self._settings.get(["checks"], merged=True)
if target in checks:
# TODO make this cleaner, right now it saves too much to disk
checks[target]["current"] = target_version
self._settings.set(["checks"], checks)
dummy_default = dict(plugins=dict())
dummy_default["plugins"][self._identifier] = dict(checks=dict())
dummy_default["plugins"][self._identifier]["checks"][target] = dict(current=None)
self._settings.set(["checks", target, "current"], target_version, defaults=dummy_default)
# we have to save here (even though that makes us save quite often) since otherwise the next
# load will overwrite our changes we just made
self._settings.save()
# we have to save here (even though that makes us save quite often) since otherwise the next
# load will overwrite our changes we just made
self._settings.save()
return target_error, target_result