feat(settings): write/read CfgBackup

Writing and reading of a Config Backup in the data folder of OctoKlipper
This commit is contained in:
thelastWallE 2021-05-30 15:01:40 +02:00
parent 84bc7c9ddd
commit 890fe8cdcc
3 changed files with 168 additions and 83 deletions

View File

@ -163,10 +163,8 @@ class KlipperPlugin(
) )
if "config" in data: if "config" in data:
if self.key_exist(data, "configuration", "parse_check"): check_parse = self._settings.get(["configuration", "parse_check"])
check_parse = data["configuration"]["parse_check"] self.log_debug("check_parse: {}".format(check_parse))
else:
check_parse = self._settings.get(["configuration", "parse_check"])
if sys.version_info[0] < 3: if sys.version_info[0] < 3:
data["config"] = data["config"].encode('utf-8') data["config"] = data["config"].encode('utf-8')
@ -187,7 +185,6 @@ class KlipperPlugin(
f.write(data["config"]) f.write(data["config"])
f.close() f.close()
self.log_debug("Writing Klipper config to {}".format(configpath)) self.log_debug("Writing Klipper config to {}".format(configpath))
except IOError: except IOError:
self.log_error("Error: Couldn't write Klipper config file: {}".format(configpath)) self.log_error("Error: Couldn't write Klipper config file: {}".format(configpath))
@ -284,7 +281,7 @@ class KlipperPlugin(
settings.set(["config_path"], settings.get(["configPath"])) settings.set(["config_path"], settings.get(["configPath"]))
settings.remove(["configPath"]) settings.remove(["configPath"])
if target is 3 and current is 2: if current is not None and current < 3:
settings = self._settings settings = self._settings
if settings.has(["configuration", "navbar"]): if settings.has(["configuration", "navbar"]):
self.log_info("migrate setting for: configuration/navbar") self.log_info("migrate setting for: configuration/navbar")
@ -441,32 +438,19 @@ class KlipperPlugin(
data["logFile"]) data["logFile"])
return flask.jsonify(log_analyzer.analyze()) return flask.jsonify(log_analyzer.analyze())
elif command == "reloadConfig": elif command == "reloadConfig":
data = octoprint.plugin.SettingsPlugin.on_settings_load(self) self.log_debug("reloadConfig")
return self.reload_cfg()
configpath = os.path.expanduser( elif command == "reloadCfgBackup":
self._settings.get(["configuration", "configpath"]) self.log_debug("reloadCfgBackup")
) return self.read_cfg_backup()
try:
f = open(configpath, "r")
data["config"] = f.read()
f.close()
except IOError:
self.log_error(
"Error: Klipper config file not found at: {}".format(
configpath)
)
else:
self._settings.set(["config"], data["config"])
# self.send_message("reload", "config", "", data["config"])
# send the configdata to frontend to update ace editor
if sys.version_info[0] < 3:
data["config"] = data["config"].decode('utf-8')
return flask.jsonify(data=data["config"])
elif command == "checkConfig": elif command == "checkConfig":
if "config" in data: if "config" in data:
if not self.validate_configfile(data["config"]): self.write_cfg_backup(data["config"])
if self.key_exist(data, "configuration", "parse_check"):
check_parse = data["configuration"]["parse_check"]
else:
check_parse = self._settings.get(["configuration", "parse_check"])
if check_parse and not self.validate_configfile(data["config"]):
self.log_debug("validateConfig not ok") self.log_debug("validateConfig not ok")
self._settings.set(["configuration", "old_config"], data["config"]) self._settings.set(["configuration", "old_config"], data["config"])
return flask.jsonify(checkConfig="not OK") return flask.jsonify(checkConfig="not OK")
@ -501,6 +485,9 @@ class KlipperPlugin(
#-- Helpers #-- Helpers
def send_message(self, type, subtype, title, payload): def send_message(self, type, subtype, title, payload):
"""
Send Message over API to FrontEnd
"""
self._plugin_manager.send_plugin_message( self._plugin_manager.send_plugin_message(
self._identifier, self._identifier,
dict( dict(
@ -554,63 +541,138 @@ class KlipperPlugin(
""" """
--->SyntaxCheck for a given data<---- --->SyntaxCheck for a given data<----
""" """
check_parse = self._settings.get(["configuration", "parse_check"])
try: if check_parse:
dataToValidated = configparser.RawConfigParser(strict=False)
#
if sys.version_info[0] < 3:
buf = StringIO.StringIO(dataToBeValidated)
dataToValidated.readfp(buf)
else:
dataToValidated.read_string(dataToBeValidated)
sections_search_list = ["bltouch",
"probe"]
value_search_list = [ "x_offset",
"y_offset",
"z_offset"]
try: try:
# cycle through sections and then values dataToValidated = configparser.RawConfigParser(strict=False)
for y in sections_search_list: #
for x in value_search_list: if sys.version_info[0] < 3:
if dataToValidated.has_option(y, x): buf = StringIO.StringIO(dataToBeValidated)
a_float = dataToValidated.getfloat(y, x) dataToValidated.readfp(buf)
except ValueError as error: else:
dataToValidated.read_string(dataToBeValidated)
sections_search_list = ["bltouch",
"probe"]
value_search_list = [ "x_offset",
"y_offset",
"z_offset"]
try:
# cycle through sections and then values
for y in sections_search_list:
for x in value_search_list:
if dataToValidated.has_option(y, x):
a_float = dataToValidated.getfloat(y, x)
except ValueError as error:
self.log_error(
"Error: Invalid Value for <b>"+x+"</b> in Section: <b>"+y+"</b>\n" +
"{}".format(str(error))
)
self.send_message("PopUp", "warning", "OctoKlipper: Invalid Config\n",
"Config got not saved!\n" +
"You can reload your last changes\n" +
"on the 'Klipper Configuration' tab.\n\n" +
"Invalid Value for <b>"+x+"</b> in Section: <b>"+y+"</b>\n" + "{}".format(str(error)))
self._parsing_check_response = False
return False
except configparser.Error as error:
if sys.version_info[0] < 3:
error.message = error.message.replace("\\n","")
error.message = error.message.replace("file: u","Klipper Configuration", 1)
error.message = error.message.replace("'","", 2)
error.message = error.message.replace("u'","'", 1)
else:
error.message = error.message.replace("\\n","")
error.message = error.message.replace("file:","Klipper Configuration", 1)
error.message = error.message.replace("'","", 2)
self.log_error( self.log_error(
"Error: Invalid Value for <b>"+x+"</b> in Section: <b>"+y+"</b>\n" + "Error: Invalid Klipper config file:\n" +
"{}".format(str(error)) "{}".format(str(error))
) )
self.send_message("PopUp", "warning", "OctoKlipper: Invalid Config\n", self.send_message("PopUp", "warning", "OctoKlipper: Invalid Config data\n",
"Config got not saved!\n" + "Config got not saved!\n" +
"You can reload your last changes\n" + "You can reload your last changes\n" +
"on the 'Klipper Configuration' tab.\n\n" + "on the 'Klipper Configuration' tab.\n\n" + str(error))
"Invalid Value for <b>"+x+"</b> in Section: <b>"+y+"</b>\n" + "{}".format(str(error)))
self._parsing_check_response = False self._parsing_check_response = False
return False return False
except configparser.Error as error:
if sys.version_info[0] < 3:
error.message = error.message.replace("\\n","")
error.message = error.message.replace("file: u","Klipper Configuration", 1)
error.message = error.message.replace("'","", 2)
error.message = error.message.replace("u'","'", 1)
else: else:
error.message = error.message.replace("\\n","") self._parsing_check_response = True
error.message = error.message.replace("file:","Klipper Configuration", 1) return True
error.message = error.message.replace("'","", 2)
def reload_cfg(self):
data = octoprint.plugin.SettingsPlugin.on_settings_load(self)
configpath = os.path.expanduser(
self._settings.get(["configuration", "configpath"])
)
try:
f = open(configpath, "r")
data["config"] = f.read()
f.close()
except IOError:
self.log_error( self.log_error(
"Error: Invalid Klipper config file:\n" + "Error: Klipper config file not found at: {}".format(
"{}".format(str(error)) configpath)
) )
self.send_message("PopUp", "warning", "OctoKlipper: Invalid Config data\n",
"Config got not saved!\n" +
"You can reload your last changes\n" +
"on the 'Klipper Configuration' tab.\n\n" + str(error))
self._parsing_check_response = False
return False
else: else:
self._parsing_check_response = True
return True self._settings.set(["config"], data["config"])
# self.send_message("reload", "config", "", data["config"])
# send the configdata to frontend to update ace editor
if sys.version_info[0] < 3:
data["config"] = data["config"].decode('utf-8')
return flask.jsonify(data=data["config"])
def read_cfg_backup(self):
"""
Read the backuped printer.cfg in the data folder of OctoKlipper
:return:
The last version of the configfile printer_bak.cfg in the data folder as json
"""
data = octoprint.plugin.SettingsPlugin.on_settings_load(self)
self.oldconfig_path = os.path.join(self.get_plugin_data_folder(), "printer_bak.cfg")
self.log_debug("reloadCfgBackupPath:" + self.oldconfig_path)
if os.path.exists(self.oldconfig_path):
try:
f = open(self.oldconfig_path, "r")
data["config"] = f.read()
f.close()
except IOError:
self.log_error(
"Error: Klipper config file not found at: {}".format(
self.oldconfig_path)
)
else:
self._settings.set(["config"], data["config"])
# self.send_message("reload", "config", "", data["config"])
# send the configdata to frontend to update ace editor
if sys.version_info[0] < 3:
data["config"] = data["config"].decode('utf-8')
self.log_debug("return CfgBackup now")
return flask.jsonify(data=data["config"])
def write_cfg_backup(self, data):
"""
Write the backuped printer.cfg into the data folder of OctoKlipper as printer_bak.cfg
"""
data = octoprint.plugin.SettingsPlugin.on_settings_load(self)
self.oldconfig_path = os.path.join(self.get_plugin_data_folder(), "printer_bak.cfg")
self.log_debug("WriteCfgBackupPath:" + self.oldconfig_path)
try:
f = open(self.oldconfig_path, "w")
f.write(data["config"])
f.close()
except IOError:
self.log_error(
"Error: Couldn't write Klipper config file to {}".format(
self.oldconfig_path)
)
else:
self.log_debug("CfgBackup writen")
__plugin_name__ = "OctoKlipper" __plugin_name__ = "OctoKlipper"
__plugin_pythoncompat__ = ">=2.7,<4" __plugin_pythoncompat__ = ">=2.7,<4"

View File

@ -31,7 +31,7 @@ $(function() {
self.apiUrl = OctoPrint.getSimpleApiUrl("klipper"); self.apiUrl = OctoPrint.getSimpleApiUrl("klipper");
self.onSettingsBeforeSave = function () { self.onSettingsBeforeSave = function () {
if (editor.session && self.settings.settings.plugins.klipper.configuration.parse_check() === true) { if (editor.session) {
self.klipperViewModel.consoleMessage("debug", "onSettingsBeforeSave:") self.klipperViewModel.consoleMessage("debug", "onSettingsBeforeSave:")
var settings = { var settings = {
"crossDomain": true, "crossDomain": true,
@ -152,8 +152,31 @@ $(function() {
} }
$.ajax(settings).done(function (response) { $.ajax(settings).done(function (response) {
editor.session.setValue(response["data"]); if (editor.session) {
editor.clearSelection(); editor.session.setValue(response["data"]);
editor.clearSelection();
}
});
}
}
self.loadCfgBackup = function () {
if (editor.session) {
var settings = {
"crossDomain": true,
"url": self.apiUrl,
"method": "POST",
"headers": self.header,
"processData": false,
"dataType": "json",
"data": JSON.stringify({command: "reloadCfgBackup"})
}
$.ajax(settings).done(function (response) {
if (editor.session) {
editor.session.setValue(response["data"]);
editor.clearSelection();
}
}); });
} }
} }

View File

@ -208,9 +208,9 @@
<script src="plugin/klipper/static/js/lib/ace/theme-monokai.min.js" type="text/javascript" charset="utf-8"></script> <script src="plugin/klipper/static/js/lib/ace/theme-monokai.min.js" type="text/javascript" charset="utf-8"></script>
<script src="plugin/klipper/static/js/lib/ace/mode-klipper_config.js" type="text/javascript"></script> <script src="plugin/klipper/static/js/lib/ace/mode-klipper_config.js" type="text/javascript"></script>
<div class="editor-controls"> <div class="editor-controls">
<button class="btn btn-small" data-bind="click: loadLastSession" <button class="btn btn-small" data-bind="click: loadCfgBackup"
title="{{ _('Reload last changes') }}"> title="{{ _('Reload last version') }}">
<i class="fas fa-redo"></i> {{ _('Reload last changes') }} <i class="fas fa-redo"></i> {{ _('Reload last version') }}
</button> </button>
<button class="btn btn-small" data-bind='click: reloadFromFile' <button class="btn btn-small" data-bind='click: reloadFromFile'
title="{{ _('Reload from file') }}"> title="{{ _('Reload from file') }}">