mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-14 17:45:56 +08:00
Merge branch 'feature-backup-manager' of https://github.com/Ultimaker/Cura into feature-backup-manager
* 'feature-backup-manager' of https://github.com/Ultimaker/Cura: Do not safe data after restoring backup Rudimentary restore functionality Fix pre-installed Ultimaker PC material
This commit is contained in:
commit
c678b401e3
@ -2,6 +2,8 @@
|
|||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from zipfile import ZipFile, ZIP_DEFLATED, BadZipfile
|
from zipfile import ZipFile, ZIP_DEFLATED, BadZipfile
|
||||||
|
|
||||||
@ -17,8 +19,7 @@ class Backup:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# These files should be ignored when making a backup.
|
# These files should be ignored when making a backup.
|
||||||
# Cura.cfg might contain secret data, so we don't back it up for now.
|
IGNORED_FILES = {"cura.log"}
|
||||||
IGNORED_FILES = {"cura.log", "cura.cfg"}
|
|
||||||
|
|
||||||
def __init__(self, zip_file: bytes = None, meta_data: dict = None):
|
def __init__(self, zip_file: bytes = None, meta_data: dict = None):
|
||||||
self.zip_file = zip_file # type: Optional[bytes]
|
self.zip_file = zip_file # type: Optional[bytes]
|
||||||
@ -33,6 +34,9 @@ class Backup:
|
|||||||
|
|
||||||
Logger.log("d", "Creating backup for Cura %s, using folder %s", cura_release, version_data_dir)
|
Logger.log("d", "Creating backup for Cura %s, using folder %s", cura_release, version_data_dir)
|
||||||
|
|
||||||
|
# Ensure all current settings are saved.
|
||||||
|
CuraApplication.getInstance().saveSettings()
|
||||||
|
|
||||||
# We're using an easy to parse filename for when we're restoring edge cases:
|
# We're using an easy to parse filename for when we're restoring edge cases:
|
||||||
# TIMESTAMP.backup.VERSION.cura.zip
|
# TIMESTAMP.backup.VERSION.cura.zip
|
||||||
archive = self._makeArchive(version_data_dir)
|
archive = self._makeArchive(version_data_dir)
|
||||||
@ -76,14 +80,31 @@ class Backup:
|
|||||||
Logger.log("e", "Could not create archive from user data directory: %s", error)
|
Logger.log("e", "Could not create archive from user data directory: %s", error)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def restore(self) -> None:
|
def restore(self) -> bool:
|
||||||
"""
|
"""
|
||||||
Restore this backup.
|
Restore this backup.
|
||||||
"""
|
"""
|
||||||
if not self.zip_file or not self.meta_data or not self.meta_data.get("cura_release", None):
|
if not self.zip_file or not self.meta_data or not self.meta_data.get("cura_release", None):
|
||||||
# We can restore without the minimum required information.
|
# We can restore without the minimum required information.
|
||||||
Logger.log("w", "Tried to restore a Cura backup without having proper data or meta data.")
|
Logger.log("w", "Tried to restore a Cura backup without having proper data or meta data.")
|
||||||
return
|
return False
|
||||||
|
|
||||||
# global_data_dir = os.path.dirname(version_data_dir)
|
# global_data_dir = os.path.dirname(version_data_dir)
|
||||||
# TODO: restore logic.
|
# TODO: handle restoring older data version.
|
||||||
|
|
||||||
|
version_data_dir = Resources.getDataStoragePath()
|
||||||
|
archive = ZipFile(io.BytesIO(self.zip_file), "r")
|
||||||
|
extracted = self._extractArchive(archive, version_data_dir)
|
||||||
|
if not extracted:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _extractArchive(archive: "ZipFile", target_path: str) -> bool:
|
||||||
|
Logger.log("d", "Removing current data in location: %s", target_path)
|
||||||
|
shutil.rmtree(target_path)
|
||||||
|
|
||||||
|
Logger.log("d", "Extracting backup to location: %s", target_path)
|
||||||
|
archive.extractall(target_path)
|
||||||
|
|
||||||
|
return True
|
||||||
|
@ -4,6 +4,7 @@ from typing import Optional
|
|||||||
|
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from cura.Backups.Backup import Backup
|
from cura.Backups.Backup import Backup
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
|
|
||||||
|
|
||||||
class BackupsManager:
|
class BackupsManager:
|
||||||
@ -40,7 +41,11 @@ class BackupsManager:
|
|||||||
self._disableAutoSave()
|
self._disableAutoSave()
|
||||||
|
|
||||||
backup = Backup(zip_file = zip_file, meta_data = meta_data)
|
backup = Backup(zip_file = zip_file, meta_data = meta_data)
|
||||||
backup.restore() # At this point, Cura will need to restart for the changes to take effect
|
restored = backup.restore()
|
||||||
|
if restored:
|
||||||
|
# At this point, Cura will need to restart for the changes to take effect.
|
||||||
|
# We don't want to store the data at this point as that would override the just-restored backup.
|
||||||
|
CuraApplication.getInstance().windowClosed(safe_data=False)
|
||||||
|
|
||||||
def _disableAutoSave(self):
|
def _disableAutoSave(self):
|
||||||
"""Here we try to disable the auto-save plugin as it might interfere with restoring a backup."""
|
"""Here we try to disable the auto-save plugin as it might interfere with restoring a backup."""
|
||||||
|
@ -497,10 +497,10 @@ class CuraApplication(QtApplication):
|
|||||||
## Cura has multiple locations where instance containers need to be saved, so we need to handle this differently.
|
## Cura has multiple locations where instance containers need to be saved, so we need to handle this differently.
|
||||||
#
|
#
|
||||||
# Note that the AutoSave plugin also calls this method.
|
# Note that the AutoSave plugin also calls this method.
|
||||||
def saveSettings(self):
|
def saveSettings(self, safe_data: bool = True):
|
||||||
if not self.started: # Do not do saving during application start
|
if not self.started or not safe_data:
|
||||||
|
# Do not do saving during application start or when data should not be safed on quit.
|
||||||
return
|
return
|
||||||
|
|
||||||
ContainerRegistry.getInstance().saveDirtyContainers()
|
ContainerRegistry.getInstance().saveDirtyContainers()
|
||||||
|
|
||||||
def saveStack(self, stack):
|
def saveStack(self, stack):
|
||||||
|
@ -1025,6 +1025,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"UltimakerPC": {
|
||||||
|
"package_info": {
|
||||||
|
"package_id": "UltimakerPC",
|
||||||
|
"package_type": "material",
|
||||||
|
"display_name": "Ultimaker PC",
|
||||||
|
"description": "Example package for material and quality profiles for Ultimaker materials.",
|
||||||
|
"package_version": "1.0.0",
|
||||||
|
"cura_version": 4,
|
||||||
|
"website": "https://ultimaker.com/products/materials/pc",
|
||||||
|
"author": {
|
||||||
|
"author_id": "Ultimaker",
|
||||||
|
"display_name": "Ultimaker B.V.",
|
||||||
|
"email": "materials@ultimaker.com",
|
||||||
|
"website": "https://ultimaker.com",
|
||||||
|
"description": "Professional 3D printing made accessible.",
|
||||||
|
"support_website": "https://ultimaker.com/en/resources/troubleshooting/materials"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"UltimakerPLA": {
|
"UltimakerPLA": {
|
||||||
"package_info": {
|
"package_info": {
|
||||||
"package_id": "UltimakerPLA",
|
"package_id": "UltimakerPLA",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user