Move zipping of project to storage class
This commit is contained in:
+21
-56
@@ -27,7 +27,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import shutil
|
|
||||||
import logging
|
import logging
|
||||||
import novelwriter
|
import novelwriter
|
||||||
|
|
||||||
@@ -299,7 +298,6 @@ class NWProject(QObject):
|
|||||||
xmlParsed = xmlReader.read(self._data, projContent)
|
xmlParsed = xmlReader.read(self._data, projContent)
|
||||||
|
|
||||||
appVersion = xmlReader.appVersion or self.tr("Unknown")
|
appVersion = xmlReader.appVersion or self.tr("Unknown")
|
||||||
hexVersion = xmlReader.hexVersion or "0x0"
|
|
||||||
|
|
||||||
if not xmlParsed:
|
if not xmlParsed:
|
||||||
if xmlReader.state == XMLReadState.NOT_NWX_FILE:
|
if xmlReader.state == XMLReadState.NOT_NWX_FILE:
|
||||||
@@ -339,7 +337,7 @@ class NWProject(QObject):
|
|||||||
# Check novelWriter Version
|
# Check novelWriter Version
|
||||||
# =========================
|
# =========================
|
||||||
|
|
||||||
if hexToInt(hexVersion) > hexToInt(novelwriter.__hexversion__):
|
if xmlReader.hexVersion > hexToInt(novelwriter.__hexversion__):
|
||||||
msgYes = self.mainGui.askQuestion(
|
msgYes = self.mainGui.askQuestion(
|
||||||
self.tr("Version Conflict"),
|
self.tr("Version Conflict"),
|
||||||
self.tr(
|
self.tr(
|
||||||
@@ -359,7 +357,7 @@ class NWProject(QObject):
|
|||||||
|
|
||||||
self._tree.unpack(projContent)
|
self._tree.unpack(projContent)
|
||||||
self._options.loadSettings()
|
self._options.loadSettings()
|
||||||
self._index.loadIndex()
|
self._loadProjectLocalisation()
|
||||||
|
|
||||||
# Update recent projects
|
# Update recent projects
|
||||||
self.mainConf.updateRecentCache(
|
self.mainConf.updateRecentCache(
|
||||||
@@ -376,7 +374,7 @@ class NWProject(QObject):
|
|||||||
del self._tree[tHandle] # The file will be re-added as orphaned
|
del self._tree[tHandle] # The file will be re-added as orphaned
|
||||||
|
|
||||||
self._scanProjectFolder()
|
self._scanProjectFolder()
|
||||||
self._loadProjectLocalisation()
|
self._index.loadIndex()
|
||||||
self.updateWordCounts()
|
self.updateWordCounts()
|
||||||
|
|
||||||
self._projOpened = time()
|
self._projOpened = time()
|
||||||
@@ -466,21 +464,17 @@ class NWProject(QObject):
|
|||||||
self._data.itemImport.write(None, self.tr("Main"), (50, 200, 0))
|
self._data.itemImport.write(None, self.tr("Main"), (50, 200, 0))
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
def backupProject(self, doNotify):
|
||||||
# Zip/Unzip Project
|
|
||||||
##
|
|
||||||
|
|
||||||
def zipIt(self, doNotify):
|
|
||||||
"""Create a zip file of the entire project.
|
"""Create a zip file of the entire project.
|
||||||
"""
|
"""
|
||||||
if not self.mainGui.hasProject:
|
if not self._storage.isOpen():
|
||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
logger.info("Backing up project")
|
logger.info("Backing up project")
|
||||||
self.mainGui.setStatus(self.tr("Backing up project ..."))
|
self.mainGui.setStatus(self.tr("Backing up project ..."))
|
||||||
|
|
||||||
if not (self.mainConf.backupPath and os.path.isdir(self.mainConf.backupPath)):
|
if not self.mainConf.backupPath:
|
||||||
self.mainGui.makeAlert(self.tr(
|
self.mainGui.makeAlert(self.tr(
|
||||||
"Cannot backup project because no valid backup path is set. "
|
"Cannot backup project because no valid backup path is set. "
|
||||||
"Please set a valid backup location in Preferences."
|
"Please set a valid backup location in Preferences."
|
||||||
@@ -490,52 +484,37 @@ class NWProject(QObject):
|
|||||||
if not self._data.name:
|
if not self._data.name:
|
||||||
self.mainGui.makeAlert(self.tr(
|
self.mainGui.makeAlert(self.tr(
|
||||||
"Cannot backup project because no project name is set. "
|
"Cannot backup project because no project name is set. "
|
||||||
"Please set a Working Title in Project Settings."
|
"Please set a Project Name in Project Settings."
|
||||||
), nwAlert.ERROR)
|
), nwAlert.ERROR)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
cleanName = makeFileNameSafe(self._data.name)
|
cleanName = makeFileNameSafe(self._data.name)
|
||||||
baseDir = os.path.abspath(os.path.join(self.mainConf.backupPath, cleanName))
|
baseDir = Path(self.mainConf.backupPath) / cleanName
|
||||||
if not os.path.isdir(baseDir):
|
try:
|
||||||
try:
|
baseDir.mkdir(exist_ok=True)
|
||||||
os.mkdir(baseDir)
|
except Exception as exc:
|
||||||
logger.debug("Created folder: %s", baseDir)
|
|
||||||
except Exception as exc:
|
|
||||||
self.mainGui.makeAlert(self.tr(
|
|
||||||
"Could not create backup folder."
|
|
||||||
), nwAlert.ERROR, exception=exc)
|
|
||||||
return False
|
|
||||||
|
|
||||||
if baseDir and baseDir.startswith(str(self._storage.runtimePath)):
|
|
||||||
self.mainGui.makeAlert(self.tr(
|
self.mainGui.makeAlert(self.tr(
|
||||||
"Cannot backup project because the backup path is within the "
|
"Could not create backup folder."
|
||||||
"project folder to be backed up. Please choose a different "
|
), nwAlert.ERROR, exception=exc)
|
||||||
"backup path in Preferences."
|
|
||||||
), nwAlert.ERROR)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
archName = self.tr("Backup from {0}").format(formatTimeStamp(time(), fileSafe=True))
|
archName = baseDir / self.tr(
|
||||||
baseName = os.path.join(baseDir, archName)
|
"Backup from {0}.zip"
|
||||||
|
).format(formatTimeStamp(time(), fileSafe=True))
|
||||||
try:
|
if self._storage.zipIt(archName, compression=2):
|
||||||
self._storage.clearLockFile()
|
|
||||||
shutil.make_archive(baseName, "zip", self._storage.runtimePath, ".")
|
|
||||||
self._storage.writeLockFile()
|
|
||||||
logger.info("Backup written to: %s", archName)
|
|
||||||
if doNotify:
|
if doNotify:
|
||||||
self.mainGui.makeAlert(self.tr(
|
self.mainGui.makeAlert(self.tr(
|
||||||
"Backup archive file written to: {0}"
|
"Backup archive file written to: {0}"
|
||||||
).format(f"{os.path.join(cleanName, archName)}.zip"), nwAlert.INFO)
|
).format(str(archName), nwAlert.INFO))
|
||||||
|
else:
|
||||||
except Exception as exc:
|
|
||||||
self.mainGui.makeAlert(self.tr(
|
self.mainGui.makeAlert(self.tr(
|
||||||
"Could not write backup archive."
|
"Could not write backup archive."
|
||||||
), nwAlert.ERROR, exception=exc)
|
), nwAlert.ERROR)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.mainGui.setStatus(self.tr(
|
self.mainGui.setStatus(self.tr(
|
||||||
"Project backed up to '{0}'"
|
"Project backed up to '{0}'"
|
||||||
).format(f"{baseName}.zip"))
|
).format(str(archName)))
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -737,20 +716,6 @@ class NWProject(QObject):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _checkFolder(self, thePath):
|
|
||||||
"""Check if a folder exists, and if it doesn't, create it.
|
|
||||||
"""
|
|
||||||
if not os.path.isdir(thePath):
|
|
||||||
try:
|
|
||||||
os.mkdir(thePath)
|
|
||||||
logger.debug("Created folder: %s", thePath)
|
|
||||||
except Exception as exc:
|
|
||||||
self.mainGui.makeAlert(self.tr(
|
|
||||||
"Could not create folder."
|
|
||||||
), nwAlert.ERROR, exception=exc)
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _scanProjectFolder(self):
|
def _scanProjectFolder(self):
|
||||||
"""Scan the project folder and check that the files in it are
|
"""Scan the project folder and check that the files in it are
|
||||||
also in the project XML file. If they aren't, import them as
|
also in the project XML file. If they aren't, import them as
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
from novelwriter.common import (
|
from novelwriter.common import (
|
||||||
checkBool, checkInt, checkString, checkStringNone, formatTimeStamp,
|
checkBool, checkInt, checkString, checkStringNone, formatTimeStamp,
|
||||||
simplified, yesNo
|
hexToInt, simplified, yesNo
|
||||||
)
|
)
|
||||||
from novelwriter.constants import nwFiles
|
from novelwriter.constants import nwFiles
|
||||||
|
|
||||||
@@ -104,9 +104,9 @@ class ProjectXMLReader:
|
|||||||
self._state = XMLReadState.NO_ACTION
|
self._state = XMLReadState.NO_ACTION
|
||||||
|
|
||||||
self._root = ""
|
self._root = ""
|
||||||
self._version = 0x0000
|
self._version = 0x0
|
||||||
self._appVersion = ""
|
self._appVersion = ""
|
||||||
self._hexVersion = ""
|
self._hexVersion = 0x0
|
||||||
self._timeStamp = ""
|
self._timeStamp = ""
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -200,7 +200,7 @@ class ProjectXMLReader:
|
|||||||
logger.debug("XML is '%s' version '%s'", self._root, fileVersion)
|
logger.debug("XML is '%s' version '%s'", self._root, fileVersion)
|
||||||
|
|
||||||
self._appVersion = str(xRoot.attrib.get("appVersion", ""))
|
self._appVersion = str(xRoot.attrib.get("appVersion", ""))
|
||||||
self._hexVersion = str(xRoot.attrib.get("hexVersion", ""))
|
self._hexVersion = hexToInt(xRoot.attrib.get("hexVersion", ""))
|
||||||
self._timeStamp = str(xRoot.attrib.get("timeStamp", ""))
|
self._timeStamp = str(xRoot.attrib.get("timeStamp", ""))
|
||||||
|
|
||||||
for xSection in xRoot:
|
for xSection in xRoot:
|
||||||
|
|||||||
+50
-11
@@ -28,7 +28,9 @@ import novelwriter
|
|||||||
|
|
||||||
from time import time
|
from time import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from zipfile import ZIP_DEFLATED, ZIP_STORED, ZipFile
|
||||||
|
|
||||||
|
from novelwriter.common import minmax
|
||||||
from novelwriter.constants import nwFiles
|
from novelwriter.constants import nwFiles
|
||||||
from novelwriter.core.document import NWDocument
|
from novelwriter.core.document import NWDocument
|
||||||
from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter
|
from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter
|
||||||
@@ -232,18 +234,55 @@ class NWStorage:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def zipIt(self, target, compression=None):
|
||||||
|
"""Zip the content of the project at its runtime location into a
|
||||||
|
zip file. This process will only grab files that are supposed to
|
||||||
|
be in the project. All non-project files will be left out.
|
||||||
|
"""
|
||||||
|
basePath = self._runtimePath
|
||||||
|
if not isinstance(basePath, Path):
|
||||||
|
logger.error("No path set")
|
||||||
|
return False
|
||||||
|
|
||||||
|
baseMeta = basePath / "meta"
|
||||||
|
baseCont = basePath / "content"
|
||||||
|
files = [
|
||||||
|
(basePath / nwFiles.PROJ_FILE, nwFiles.PROJ_FILE),
|
||||||
|
(baseMeta / nwFiles.OPTS_FILE, f"meta/{nwFiles.OPTS_FILE}"),
|
||||||
|
(baseMeta / nwFiles.SESS_STATS, f"meta/{nwFiles.SESS_STATS}"),
|
||||||
|
(baseMeta / nwFiles.INDEX_FILE, f"meta/{nwFiles.INDEX_FILE}"),
|
||||||
|
(baseMeta / nwFiles.PROJ_DICT, f"meta/{nwFiles.PROJ_DICT}"),
|
||||||
|
]
|
||||||
|
for contItem in baseCont.iterdir():
|
||||||
|
name = contItem.name
|
||||||
|
if contItem.is_file() and len(name) == 17 and name.endswith(".nwd"):
|
||||||
|
files.append((contItem, f"content/{name}"))
|
||||||
|
|
||||||
|
comp = ZIP_STORED if compression is None else ZIP_DEFLATED
|
||||||
|
level = minmax(compression, 0, 9) if isinstance(compression, int) else None
|
||||||
|
try:
|
||||||
|
with ZipFile(target, mode="w", compression=comp, compresslevel=level) as zipObj:
|
||||||
|
logger.info("Creating archive: %s", target)
|
||||||
|
for srcPath, zipPath in files:
|
||||||
|
if srcPath.is_file():
|
||||||
|
zipObj.write(srcPath, zipPath)
|
||||||
|
logger.debug("Added: %s", zipPath)
|
||||||
|
except Exception:
|
||||||
|
logger.error("Failed to create acrhive")
|
||||||
|
logException()
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
##
|
##
|
||||||
# Internal Functions
|
# Internal Functions
|
||||||
##
|
##
|
||||||
|
|
||||||
def _zipIt(self, target):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _prepareStorage(self, checkLegacy=True, newProject=False):
|
def _prepareStorage(self, checkLegacy=True, newProject=False):
|
||||||
"""Prepare the storage area for the project.
|
"""Prepare the storage area for the project.
|
||||||
"""
|
"""
|
||||||
path = self._runtimePath
|
path = self._runtimePath
|
||||||
if path is None:
|
if not isinstance(path, Path):
|
||||||
logger.error("No path set")
|
logger.error("No path set")
|
||||||
self.clear()
|
self.clear()
|
||||||
return False
|
return False
|
||||||
@@ -336,13 +375,13 @@ class NWStorage:
|
|||||||
"""Delete files that are no longer used by novelWriter.
|
"""Delete files that are no longer used by novelWriter.
|
||||||
"""
|
"""
|
||||||
remove = [
|
remove = [
|
||||||
path / "meta" / "mainOptions.json",
|
path / "meta" / "mainOptions.json", # Replaced in 0.5
|
||||||
path / "meta" / "exportOptions.json",
|
path / "meta" / "exportOptions.json", # Replaced in 0.5
|
||||||
path / "meta" / "outlineOptions.json",
|
path / "meta" / "outlineOptions.json", # Replaced in 0.5
|
||||||
path / "meta" / "timelineOptions.json",
|
path / "meta" / "timelineOptions.json", # Replaced in 0.5
|
||||||
path / "meta" / "docMergeOptions.json",
|
path / "meta" / "docMergeOptions.json", # Replaced in 0.5
|
||||||
path / "meta" / "sessionLogOptions.json",
|
path / "meta" / "sessionLogOptions.json", # Replaced in 0.5
|
||||||
path / "ToC.json",
|
path / "ToC.json", # Dropped in 1.0 RC 1
|
||||||
]
|
]
|
||||||
for item in remove:
|
for item in remove:
|
||||||
if item.is_file():
|
if item.is_file():
|
||||||
|
|||||||
@@ -824,7 +824,7 @@ class GuiMainMenu(QMenuBar):
|
|||||||
|
|
||||||
# Tools > Backup
|
# Tools > Backup
|
||||||
self.aBackupProject = QAction(self.tr("Backup Project"), self)
|
self.aBackupProject = QAction(self.tr("Backup Project"), self)
|
||||||
self.aBackupProject.triggered.connect(lambda: self.theProject.zipIt(True))
|
self.aBackupProject.triggered.connect(lambda: self.theProject.backupProject(doNoify=True))
|
||||||
self.toolsMenu.addAction(self.aBackupProject)
|
self.toolsMenu.addAction(self.aBackupProject)
|
||||||
|
|
||||||
# Tools > Export Project
|
# Tools > Export Project
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ class GuiMain(QMainWindow):
|
|||||||
if not msgYes:
|
if not msgYes:
|
||||||
doBackup = False
|
doBackup = False
|
||||||
if doBackup:
|
if doBackup:
|
||||||
self.theProject.zipIt(False)
|
self.theProject.backupProject(doNotify=False)
|
||||||
else:
|
else:
|
||||||
saveOK = True
|
saveOK = True
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ from mock import causeException
|
|||||||
from tools import C, buildTestProject, cmpFiles, writeFile
|
from tools import C, buildTestProject, cmpFiles, writeFile
|
||||||
|
|
||||||
from novelwriter.enum import nwItemClass, nwItemLayout
|
from novelwriter.enum import nwItemClass, nwItemLayout
|
||||||
|
from novelwriter.constants import nwFiles
|
||||||
from novelwriter.core.index import NWIndex, countWords, TagsIndex
|
from novelwriter.core.index import NWIndex, countWords, TagsIndex
|
||||||
from novelwriter.core.project import NWProject
|
from novelwriter.core.project import NWProject
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ def testCoreIndex_LoadSave(monkeypatch, nwLipsum, mockGUI, outDir, refDir):
|
|||||||
"""Test core functionality of scaning, saving, loading and checking
|
"""Test core functionality of scaning, saving, loading and checking
|
||||||
the index cache file.
|
the index cache file.
|
||||||
"""
|
"""
|
||||||
projFile = os.path.join(nwLipsum, "meta", "tagsIndex.json")
|
projFile = os.path.join(nwLipsum, "meta", nwFiles.INDEX_FILE)
|
||||||
testFile = os.path.join(outDir, "coreIndex_LoadSave_tagsIndex.json")
|
testFile = os.path.join(outDir, "coreIndex_LoadSave_tagsIndex.json")
|
||||||
compFile = os.path.join(refDir, "coreIndex_LoadSave_tagsIndex.json")
|
compFile = os.path.join(refDir, "coreIndex_LoadSave_tagsIndex.json")
|
||||||
|
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncDir, mockRnd):
|
|||||||
|
|
||||||
# Won't convert legacy file
|
# Won't convert legacy file
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(ProjectXMLReader, "hexVersion", property(lambda *a: "0x99999999"))
|
mp.setattr(ProjectXMLReader, "hexVersion", property(lambda *a: 0x99999999))
|
||||||
mockGUI.askResponse = False
|
mockGUI.askResponse = False
|
||||||
assert theProject.openProject(fncDir) is False
|
assert theProject.openProject(fncDir) is False
|
||||||
assert "This project was saved by a newer version" in mockGUI.lastQuestion[1]
|
assert "This project was saved by a newer version" in mockGUI.lastQuestion[1]
|
||||||
@@ -699,46 +699,42 @@ def testCoreProject_Backup(monkeypatch, mockGUI, fncDir, tmpDir):
|
|||||||
|
|
||||||
# No project
|
# No project
|
||||||
mockGUI.hasProject = False
|
mockGUI.hasProject = False
|
||||||
assert theProject.zipIt(doNotify=False) is False
|
assert theProject.backupProject(doNotify=False) is False
|
||||||
mockGUI.hasProject = True
|
mockGUI.hasProject = True
|
||||||
|
|
||||||
# Invalid path
|
# Invalid path
|
||||||
theProject.mainConf.backupPath = None
|
theProject.mainConf.backupPath = None
|
||||||
assert theProject.zipIt(doNotify=False) is False
|
assert theProject.backupProject(doNotify=False) is False
|
||||||
|
|
||||||
# Missing project name
|
# Missing project name
|
||||||
theProject.mainConf.backupPath = tmpDir
|
theProject.mainConf.backupPath = tmpDir
|
||||||
theProject.data.setName("")
|
theProject.data.setName("")
|
||||||
assert theProject.zipIt(doNotify=False) is False
|
assert theProject.backupProject(doNotify=False) is False
|
||||||
|
|
||||||
# Non-existent folder
|
# Non-existent folder
|
||||||
theProject.mainConf.backupPath = os.path.join(tmpDir, "nonexistent")
|
theProject.mainConf.backupPath = os.path.join(tmpDir, "nonexistent")
|
||||||
theProject.data.setName("Test Minimal")
|
theProject.data.setName("Test Minimal")
|
||||||
assert theProject.zipIt(doNotify=False) is False
|
assert theProject.backupProject(doNotify=False) is False
|
||||||
|
|
||||||
# Same folder as project (causes infinite loop in zipping)
|
|
||||||
theProject.mainConf.backupPath = fncDir
|
|
||||||
assert theProject.zipIt(doNotify=False) is False
|
|
||||||
|
|
||||||
# Subfolder of project (causes infinite loop in zipping)
|
# Subfolder of project (causes infinite loop in zipping)
|
||||||
theProject.mainConf.backupPath = os.path.join(fncDir, "subdir")
|
theProject.mainConf.backupPath = os.path.join(fncDir, "subdir")
|
||||||
assert theProject.zipIt(doNotify=False) is False
|
assert theProject.backupProject(doNotify=False) is False
|
||||||
|
|
||||||
# Set a valid folder
|
# Set a valid folder
|
||||||
theProject.mainConf.backupPath = tmpDir
|
theProject.mainConf.backupPath = tmpDir
|
||||||
|
|
||||||
# Can't make folder
|
# Can't make folder
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr("os.mkdir", causeOSError)
|
mp.setattr("pathlib.Path.mkdir", causeOSError)
|
||||||
assert theProject.zipIt(doNotify=False) is False
|
assert theProject.backupProject(doNotify=False) is False
|
||||||
|
|
||||||
# Can't write archive
|
# Can't write archive
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr("shutil.make_archive", causeOSError)
|
mp.setattr("zipfile.ZipFile.write", causeOSError)
|
||||||
assert theProject.zipIt(doNotify=False) is False
|
assert theProject.backupProject(doNotify=False) is False
|
||||||
|
|
||||||
# Test correct settings
|
# Test correct settings
|
||||||
assert theProject.zipIt(doNotify=True) is True
|
assert theProject.backupProject(doNotify=True) is True
|
||||||
|
|
||||||
theFiles = os.listdir(os.path.join(tmpDir, "Test Minimal"))
|
theFiles = os.listdir(os.path.join(tmpDir, "Test Minimal"))
|
||||||
assert len(theFiles) == 1
|
assert len(theFiles) == 1
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ def testCoreProjectXML_ReadCurrent(monkeypatch, tstPaths, fncPath):
|
|||||||
assert xmlReader.xmlRoot == "novelWriterXML"
|
assert xmlReader.xmlRoot == "novelWriterXML"
|
||||||
assert xmlReader.xmlVersion == 0x0105
|
assert xmlReader.xmlVersion == 0x0105
|
||||||
assert xmlReader.appVersion == "2.0-rc1"
|
assert xmlReader.appVersion == "2.0-rc1"
|
||||||
assert xmlReader.hexVersion == "0x020000c1"
|
assert xmlReader.hexVersion == 0x020000c1
|
||||||
|
|
||||||
# Check loaded data
|
# Check loaded data
|
||||||
assert data.name == "Sample Project"
|
assert data.name == "Sample Project"
|
||||||
@@ -257,7 +257,7 @@ def testCoreProjectXML_ReadLegacy10(tstPaths, fncPath, mockRnd):
|
|||||||
assert xmlReader.xmlRoot == "novelWriterXML"
|
assert xmlReader.xmlRoot == "novelWriterXML"
|
||||||
assert xmlReader.xmlVersion == 0x0100
|
assert xmlReader.xmlVersion == 0x0100
|
||||||
assert xmlReader.appVersion == "0.6.1"
|
assert xmlReader.appVersion == "0.6.1"
|
||||||
assert xmlReader.hexVersion == "0x000601f0"
|
assert xmlReader.hexVersion == 0x000601f0
|
||||||
|
|
||||||
# Check loaded data
|
# Check loaded data
|
||||||
assert data.name == "Sample Project"
|
assert data.name == "Sample Project"
|
||||||
@@ -399,7 +399,7 @@ def testCoreProjectXML_ReadLegacy11(tstPaths, fncPath, mockRnd):
|
|||||||
assert xmlReader.xmlRoot == "novelWriterXML"
|
assert xmlReader.xmlRoot == "novelWriterXML"
|
||||||
assert xmlReader.xmlVersion == 0x0101
|
assert xmlReader.xmlVersion == 0x0101
|
||||||
assert xmlReader.appVersion == "0.9.2"
|
assert xmlReader.appVersion == "0.9.2"
|
||||||
assert xmlReader.hexVersion == "0x000902f0"
|
assert xmlReader.hexVersion == 0x000902f0
|
||||||
|
|
||||||
# Check loaded data
|
# Check loaded data
|
||||||
assert data.name == "Sample Project"
|
assert data.name == "Sample Project"
|
||||||
@@ -541,7 +541,7 @@ def testCoreProjectXML_ReadLegacy12(tstPaths, fncPath, mockRnd):
|
|||||||
assert xmlReader.xmlRoot == "novelWriterXML"
|
assert xmlReader.xmlRoot == "novelWriterXML"
|
||||||
assert xmlReader.xmlVersion == 0x0102
|
assert xmlReader.xmlVersion == 0x0102
|
||||||
assert xmlReader.appVersion == "1.4.2"
|
assert xmlReader.appVersion == "1.4.2"
|
||||||
assert xmlReader.hexVersion == "0x010402f0"
|
assert xmlReader.hexVersion == 0x010402f0
|
||||||
|
|
||||||
# Check loaded data
|
# Check loaded data
|
||||||
assert data.name == "Sample Project"
|
assert data.name == "Sample Project"
|
||||||
@@ -686,7 +686,7 @@ def testCoreProjectXML_ReadLegacy13(tstPaths, fncPath, mockRnd):
|
|||||||
assert xmlReader.xmlRoot == "novelWriterXML"
|
assert xmlReader.xmlRoot == "novelWriterXML"
|
||||||
assert xmlReader.xmlVersion == 0x0103
|
assert xmlReader.xmlVersion == 0x0103
|
||||||
assert xmlReader.appVersion == "1.6.6"
|
assert xmlReader.appVersion == "1.6.6"
|
||||||
assert xmlReader.hexVersion == "0x010606f0"
|
assert xmlReader.hexVersion == 0x010606f0
|
||||||
|
|
||||||
# Check loaded data
|
# Check loaded data
|
||||||
assert data.name == "Sample Project"
|
assert data.name == "Sample Project"
|
||||||
@@ -831,7 +831,7 @@ def testCoreProjectXML_ReadLegacy14(tstPaths, fncPath, mockRnd):
|
|||||||
assert xmlReader.xmlRoot == "novelWriterXML"
|
assert xmlReader.xmlRoot == "novelWriterXML"
|
||||||
assert xmlReader.xmlVersion == 0x0104
|
assert xmlReader.xmlVersion == 0x0104
|
||||||
assert xmlReader.appVersion == "2.0-rc1"
|
assert xmlReader.appVersion == "2.0-rc1"
|
||||||
assert xmlReader.hexVersion == "0x020000c1"
|
assert xmlReader.hexVersion == 0x020000c1
|
||||||
|
|
||||||
# Check loaded data
|
# Check loaded data
|
||||||
assert data.name == "Sample Project"
|
assert data.name == "Sample Project"
|
||||||
|
|||||||
Reference in New Issue
Block a user