✨ feat(settings): write/read CfgBackup
Writing and reading of a Config Backup in the data folder of OctoKlipper
This commit is contained in:
parent
84bc7c9ddd
commit
890fe8cdcc
|
@ -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"
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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') }}">
|
||||||
|
|
Loading…
Reference in New Issue