mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-04-21 05:09:37 +08:00

The one actual change was this: To give a KeyError when stuff can't be found in a dictionary, rather than returning None there and then getting a TypeError later. Contributes to issue CURA-5936.
145 lines
7.8 KiB
Python
145 lines
7.8 KiB
Python
# Copyright (c) 2018 Ultimaker B.V.
|
|
# Cura is released under the terms of the LGPLv3 or higher.
|
|
|
|
import configparser #To read config files.
|
|
import io #To write config files to strings as if they were files.
|
|
import os.path #To get the path to write new user profiles to.
|
|
from typing import Dict, List, Optional, Set, Tuple
|
|
import urllib #To serialise the user container file name properly.
|
|
|
|
import UM.VersionUpgrade #To indicate that a file is of incorrect format.
|
|
import UM.VersionUpgradeManager #To schedule more files to be upgraded.
|
|
from UM.Resources import Resources #To get the config storage path.
|
|
|
|
## Creates a new machine instance instance by parsing a serialised machine
|
|
# instance in version 1 of the file format.
|
|
#
|
|
# \param serialised The serialised form of a machine instance in version 1.
|
|
# \param filename The supposed file name of this machine instance, without
|
|
# extension.
|
|
# \return A machine instance instance, or None if the file format is
|
|
# incorrect.
|
|
def importFrom(serialised: str, filename: str) -> Optional["MachineInstance"]:
|
|
try:
|
|
return MachineInstance(serialised, filename)
|
|
except (configparser.Error, UM.VersionUpgrade.FormatException, UM.VersionUpgrade.InvalidVersionException):
|
|
return None
|
|
|
|
## A representation of a machine instance used as intermediary form for
|
|
# conversion from one format to the other.
|
|
class MachineInstance:
|
|
## Reads version 1 of the file format, storing it in memory.
|
|
#
|
|
# \param serialised A string with the contents of a machine instance file,
|
|
# without extension.
|
|
# \param filename The supposed file name of this machine instance.
|
|
def __init__(self, serialised: str, filename: str) -> None:
|
|
self._filename = filename
|
|
|
|
config = configparser.ConfigParser(interpolation = None)
|
|
config.read_string(serialised) # Read the input string as config file.
|
|
|
|
# Checking file correctness.
|
|
if not config.has_section("general"):
|
|
raise UM.VersionUpgrade.FormatException("No \"general\" section.")
|
|
if not config.has_option("general", "version"):
|
|
raise UM.VersionUpgrade.FormatException("No \"version\" in \"general\" section.")
|
|
if not config.has_option("general", "name"):
|
|
raise UM.VersionUpgrade.FormatException("No \"name\" in \"general\" section.")
|
|
if not config.has_option("general", "type"):
|
|
raise UM.VersionUpgrade.FormatException("No \"type\" in \"general\" section.")
|
|
if int(config.get("general", "version")) != 1: # Explicitly hard-code version 1, since if this number changes the programmer MUST change this entire function.
|
|
raise UM.VersionUpgrade.InvalidVersionException("The version of this machine instance is wrong. It must be 1.")
|
|
|
|
self._type_name = config.get("general", "type")
|
|
self._variant_name = config.get("general", "variant", fallback = "empty_variant")
|
|
self._name = config.get("general", "name", fallback = "")
|
|
self._key = config.get("general", "key", fallback = "")
|
|
self._active_profile_name = config.get("general", "active_profile", fallback = "empty_quality")
|
|
self._active_material_name = config.get("general", "material", fallback = "empty_material")
|
|
|
|
self._machine_setting_overrides = {} # type: Dict[str, str]
|
|
for key, value in config["machine_settings"].items():
|
|
self._machine_setting_overrides[key] = value
|
|
|
|
## Serialises this machine instance as file format version 2.
|
|
#
|
|
# This is where the actual translation happens in this case.
|
|
#
|
|
# \return A tuple containing the new filename and a serialised form of
|
|
# this machine instance, serialised in version 2 of the file format.
|
|
def export(self) -> Tuple[List[str], List[str]]:
|
|
config = configparser.ConfigParser(interpolation = None) # Build a config file in the form of version 2.
|
|
|
|
config.add_section("general")
|
|
config.set("general", "name", self._name)
|
|
config.set("general", "id", self._name)
|
|
config.set("general", "version", "2") # Hard-code version 2, since if this number changes the programmer MUST change this entire function.
|
|
|
|
import VersionUpgrade21to22 # Import here to prevent circular dependencies.
|
|
has_machine_qualities = self._type_name in VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.machinesWithMachineQuality()
|
|
type_name = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translatePrinter(self._type_name)
|
|
active_material = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateMaterial(self._active_material_name)
|
|
variant = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateVariant(self._variant_name, type_name)
|
|
variant_materials = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateVariantForMaterials(self._variant_name, type_name)
|
|
|
|
#Convert to quality profile if we have one of the built-in profiles, otherwise convert to a quality-changes profile.
|
|
if self._active_profile_name in VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.builtInProfiles():
|
|
active_quality = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateProfile(self._active_profile_name)
|
|
active_quality_changes = "empty_quality_changes"
|
|
else:
|
|
active_quality = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.getQualityFallback(type_name, variant, active_material)
|
|
active_quality_changes = self._active_profile_name
|
|
|
|
if has_machine_qualities: #This machine now has machine-quality profiles.
|
|
active_material += "_" + variant_materials
|
|
|
|
#Create a new user profile and schedule it to be upgraded.
|
|
user_profile = configparser.ConfigParser(interpolation = None)
|
|
user_profile["general"] = {
|
|
"version": "2",
|
|
"name": "Current settings",
|
|
"definition": type_name
|
|
}
|
|
user_profile["metadata"] = {
|
|
"type": "user",
|
|
"machine": self._name
|
|
}
|
|
user_profile["values"] = {}
|
|
|
|
version_upgrade_manager = UM.VersionUpgradeManager.VersionUpgradeManager.getInstance()
|
|
user_version_to_paths_dict = version_upgrade_manager.getStoragePaths("user")
|
|
paths_set = set() # type: Set[str]
|
|
for paths in user_version_to_paths_dict.values():
|
|
paths_set |= paths
|
|
|
|
user_storage = os.path.join(Resources.getDataStoragePath(), next(iter(paths_set)))
|
|
user_profile_file = os.path.join(user_storage, urllib.parse.quote_plus(self._name) + "_current_settings.inst.cfg")
|
|
if not os.path.exists(user_storage):
|
|
os.makedirs(user_storage)
|
|
with open(user_profile_file, "w", encoding = "utf-8") as file_handle:
|
|
user_profile.write(file_handle)
|
|
version_upgrade_manager.upgradeExtraFile(user_storage, urllib.parse.quote_plus(self._name), "user")
|
|
|
|
containers = [
|
|
self._name + "_current_settings", #The current profile doesn't know the definition ID when it was upgraded, only the instance ID, so it will be invalid. Sorry, your current settings are lost now.
|
|
active_quality_changes,
|
|
active_quality,
|
|
active_material,
|
|
variant,
|
|
type_name
|
|
]
|
|
config.set("general", "containers", ",".join(containers))
|
|
|
|
config.add_section("metadata")
|
|
config.set("metadata", "type", "machine")
|
|
|
|
VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateSettings(self._machine_setting_overrides)
|
|
config.add_section("values")
|
|
for key, value in self._machine_setting_overrides.items():
|
|
config.set("values", key, str(value))
|
|
|
|
output = io.StringIO()
|
|
config.write(output)
|
|
return [self._filename], [output.getvalue()]
|