Handle default printer profile like all other profiles

It now resides in a file on disk and can be deleted. If the profile
configured as default is not available (e.g. due to having been
manually deleted, or on first start), the default profile as defined
in the profile manager will be written as _default and that will be
used/set as default.

On first start after this change gets applied, OctoPrint will migrate
the old "default overlay" residing in config.yaml to a file on disk
and delete the old entries in config.yaml.

Solves core reason of #1734
This commit is contained in:
Gina Häußge 2017-03-20 17:27:50 +01:00
parent 3bc77ffe3d
commit 5535a9aeb0
3 changed files with 55 additions and 49 deletions

View file

@ -204,6 +204,37 @@ class PrinterProfileManager(object):
self._folder = settings().getBaseFolder("printerProfiles")
self._logger = logging.getLogger(__name__)
self._migrate_old_default_profile()
self._verify_default_available()
def _migrate_old_default_profile(self):
default_overrides = settings().get(["printerProfiles", "defaultProfile"])
if not default_overrides:
return
if self.exists("_default"):
return
default_overrides["id"] = "_default"
self.save(default_overrides)
settings().set(["printerProfiles", "defaultProfile"], None)
settings().save()
def _verify_default_available(self):
default_id = settings().get(["printerProfile", "default"])
if default_id is None:
default_id = "_default"
if not self.exists(default_id):
if not self.exists("_default"):
self._logger.error("Selected default profile {} and _default do not exist, creating _default again and setting it as default".format(default_id))
self.save(self.__class__.default, allow_overwrite=True, make_default=True)
else:
self._logger.error("Selected default profile {} does not exists, resetting to _default".format(default_id))
settings().set(["printerProfiles", "default"], "_default")
settings().save()
def select(self, identifier):
if identifier is None or not self.exists(identifier):
self._current = self.get_default()
@ -220,9 +251,7 @@ class PrinterProfileManager(object):
def get(self, identifier):
try:
if identifier == "_default":
return self._load_default()
elif self.exists(identifier):
if self.exists(identifier):
return self._load_from_path(self._get_profile_path(identifier))
else:
return None
@ -230,10 +259,10 @@ class PrinterProfileManager(object):
return None
def remove(self, identifier):
if identifier == "_default":
return False
if self._current is not None and self._current["id"] == identifier:
return False
elif settings().get(["printerProfiles", "default"]) == identifier:
return False
return self._remove_from_path(self._get_profile_path(identifier))
def save(self, profile, allow_overwrite=False, make_default=False):
@ -246,21 +275,16 @@ class PrinterProfileManager(object):
identifier = self._sanitize(identifier)
profile["id"] = identifier
self._migrate_profile(profile)
profile = dict_sanitize(profile, self.__class__.default)
profile = dict_merge(self.__class__.default, profile)
if identifier == self.__class__.default["id"]:
default_profile = dict_merge(self._load_default(), profile)
if not self._ensure_valid_profile(default_profile):
raise InvalidProfileError()
self._save_to_path(self._get_profile_path(identifier), profile, allow_overwrite=allow_overwrite)
settings().set(["printerProfiles", "defaultProfile"], default_profile, defaults=dict(printerProfiles=dict(defaultProfile=self.__class__.default)))
if make_default:
settings().set(["printerProfiles", "default"], identifier)
settings().save()
else:
self._save_to_path(self._get_profile_path(identifier), profile, allow_overwrite=allow_overwrite)
if make_default:
settings().set(["printerProfiles", "default"], identifier)
settings().save()
if self._current is not None and self._current["id"] == identifier:
self.select(identifier)
@ -268,8 +292,7 @@ class PrinterProfileManager(object):
def is_default_unmodified(self):
default = settings().get(["printerProfiles", "default"])
default_overrides = settings().get(["printerProfiles", "defaultProfile"])
return (default is None or default == self.__class__.default["id"]) and not default_overrides
return default is None or default == "_default" or not self.exists("_default")
@property
def profile_count(self):
@ -288,7 +311,7 @@ class PrinterProfileManager(object):
if profile is not None:
return profile
return self._load_default()
return copy.deepcopy(self.__class__.default)
def set_default(self, identifier):
all_identifiers = self._load_all_identifiers().keys()
@ -310,8 +333,6 @@ class PrinterProfileManager(object):
def exists(self, identifier):
if identifier is None:
return False
elif identifier == "_default":
return True
else:
path = self._get_profile_path(identifier)
return os.path.exists(path) and os.path.isfile(path)
@ -321,23 +342,20 @@ class PrinterProfileManager(object):
results = dict()
for identifier, path in all_identifiers.items():
try:
if identifier == "_default":
profile = self._load_default()
else:
profile = self._load_from_path(path)
profile = self._load_from_path(path)
except InvalidProfileError:
continue
if profile is None:
continue
results[identifier] = dict_merge(self._load_default(), profile)
results[identifier] = dict_merge(self.__class__.default, profile)
return results
def _load_all_identifiers(self):
results = dict(_default=None)
results = dict()
for entry in scandir(self._folder):
if is_hidden_path(entry.name) or not entry.name.endswith(".profile") or entry.name == "_default.profile":
if is_hidden_path(entry.name) or not entry.name.endswith(".profile"):
continue
if not entry.is_file():
@ -369,8 +387,6 @@ class PrinterProfileManager(object):
return profile
def _save_to_path(self, path, profile, allow_overwrite=False):
self._migrate_profile(profile)
profile = dict_merge(self.__class__.default, profile)
validated_profile = self._ensure_valid_profile(profile)
if not validated_profile:
raise InvalidProfileError()
@ -394,21 +410,6 @@ class PrinterProfileManager(object):
except:
return False
def _load_default(self):
default_overrides = settings().get(["printerProfiles", "defaultProfile"])
if self._migrate_profile(default_overrides):
try:
settings().set(["printerProfiles", "defaultProfile"], default_overrides)
settings().save()
except:
self._logger.exception("Tried to save default profile after migrating it while loading, ran into exception")
profile = self._ensure_valid_profile(dict_merge(copy.deepcopy(self.__class__.default), default_overrides))
if not profile:
self._logger.warn("Invalid default profile after applying overrides")
return copy.deepcopy(self.__class__.default)
return profile
def _get_profile_path(self, identifier):
return os.path.join(self._folder, "%s.profile" % identifier)

View file

@ -105,8 +105,14 @@ def printerProfilesGet(identifier):
@api.route("/printerprofiles/<string:identifier>", methods=["DELETE"])
@restricted_access
def printerProfilesDelete(identifier):
if printerProfileManager.get_current_or_default()["id"] == identifier:
return make_response("Cannot delete currently selected profile: %s" % identifier, 409)
current_profile = printerProfileManager.get_current()
if current_profile and current_profile["id"] == identifier:
return make_response("Cannot delete currently selected profile: {}".format(identifier), 409)
default_profile = printerProfileManager.get_default()
if default_profile and default_profile["id"] == identifier:
return make_response("Cannot delete default profile: {}".format(identifier), 409)
printerProfileManager.remove(identifier)
return NO_CONTENT

View file

@ -229,8 +229,7 @@ default_settings = {
"cutoff": 30
},
"printerProfiles": {
"default": None,
"defaultProfile": {}
"default": None
},
"printerParameters": {
"pauseTriggers": [],