Stop showing index rebuild dialog on upgrades (#2537)

This commit is contained in:
Veronica Berglyd Olsen
2025-10-05 17:52:40 +02:00
committed by GitHub
9 changed files with 61 additions and 26 deletions
+6
View File
@@ -560,6 +560,12 @@ def jsonEncode(data: dict | list | tuple, n: int = 0, nmax: int = 0) -> str:
return "".join(buffer)
def jsonCombine(data: dict[str, str]) -> str:
"""Combine multiple already packed JSON strings."""
payload = ",\n".join(f' "{k}": {v}' for k, v in data.items())
return f"{{\n{payload}\n}}\n"
##
# XML Helpers
##
+24 -11
View File
@@ -33,8 +33,10 @@ from pathlib import Path
from time import time
from typing import TYPE_CHECKING
from novelwriter import SHARED
from novelwriter.common import isHandle, isItemClass, isTitleTag, jsonEncode
from novelwriter import SHARED, __hexversion__
from novelwriter.common import (
formatTimeStamp, isHandle, isItemClass, isTitleTag, jsonCombine, jsonEncode
)
from novelwriter.constants import nwFiles, nwKeyWords, nwStyles
from novelwriter.core.indexdata import NOTE_TYPES, TT_NONE, IndexHeading, IndexNode, T_NoteTypes
from novelwriter.core.novelmodel import NovelModel
@@ -82,6 +84,11 @@ class Index:
a rebuild of the index data.
"""
__slots__ = (
"_indexBroken", "_indexChange", "_indexUpgrade", "_itemIndex", "_novelExtra",
"_novelModels", "_project", "_rootChange", "_tagsIndex",
)
def __init__(self, project: NWProject) -> None:
self._project = project
@@ -90,6 +97,7 @@ class Index:
self._tagsIndex = TagsIndex()
self._itemIndex = ItemIndex(project, self._tagsIndex)
self._indexBroken = False
self._indexUpgrade = False
# Models
self._novelModels: dict[str, NovelModel] = {}
@@ -110,6 +118,10 @@ class Index:
def indexBroken(self) -> bool:
return self._indexBroken
@property
def indexUpgrade(self) -> bool:
return self._indexUpgrade
##
# Getters
##
@@ -241,6 +253,8 @@ class Index:
return False
try:
meta = data.get("novelWriter.meta", {})
self._indexUpgrade = meta.get("version") != __hexversion__
self._tagsIndex.unpackData(data["novelWriter.tagsIndex"])
self._itemIndex.unpackData(data["novelWriter.itemIndex"])
except Exception:
@@ -273,23 +287,22 @@ class Index:
return False
logger.debug("Saving index file")
tStart = time()
start = time()
try:
tagsIndex = jsonEncode(self._tagsIndex.packData(), n=1, nmax=2)
itemIndex = jsonEncode(self._itemIndex.packData(), n=1, nmax=4)
meta = {"version": __hexversion__, "timestamp": formatTimeStamp(start)}
with open(indexFile, mode="w+", encoding="utf-8") as outFile:
outFile.write("{\n")
outFile.write(f' "novelWriter.tagsIndex": {tagsIndex},\n')
outFile.write(f' "novelWriter.itemIndex": {itemIndex}\n')
outFile.write("}\n")
outFile.write(jsonCombine({
"novelWriter.meta": jsonEncode(meta, n=1),
"novelWriter.tagsIndex": jsonEncode(self._tagsIndex.packData(), n=1, nmax=2),
"novelWriter.itemIndex": jsonEncode(self._itemIndex.packData(), n=1, nmax=4),
}))
except Exception:
logger.error("Failed to save index file")
logException()
return False
logger.debug("Index saved in %.3f ms", (time() - tStart)*1000)
logger.debug("Index saved in %.3f ms", (time() - start)*1000)
return True
+4 -4
View File
@@ -497,7 +497,8 @@ class GuiMain(QMainWindow):
# Check if we need to rebuild the index
if SHARED.project.index.indexBroken:
SHARED.info(self.tr("The project index is outdated or broken. Rebuilding index."))
if not SHARED.project.index.indexUpgrade:
SHARED.warn(self.tr("The project index is broken. Rebuilding index."))
self.rebuildIndex()
# Make sure the changed status is set to false on things opened
@@ -729,7 +730,7 @@ class GuiMain(QMainWindow):
return
def rebuildIndex(self, beQuiet: bool = False) -> None:
def rebuildIndex(self) -> None:
"""Rebuild the entire index."""
if SHARED.hasProject:
logger.info("Rebuilding index ...")
@@ -746,8 +747,7 @@ class GuiMain(QMainWindow):
self._updateStatusWordCount()
QApplication.restoreOverrideCursor()
if not beQuiet:
SHARED.info(self.tr("The project index has been successfully rebuilt."))
SHARED.info(self.tr("The project index has been successfully rebuilt."))
##
# Main Dialogs
@@ -1,4 +1,8 @@
{
"novelWriter.meta": {
"version": "0x020800a2",
"timestamp": "2025-10-05 17:06:58"
},
"novelWriter.tagsIndex": {
"bod": {"name": "Bod", "display": "Nobody Owens", "handle": "4c4f28287af27", "heading": "T0001", "class": "CHARACTER"},
"main": {"name": "Main", "display": "Main", "handle": "2426c6f0ca922", "heading": "T0001", "class": "PLOT"},
+15 -4
View File
@@ -36,10 +36,10 @@ from novelwriter.common import (
describeFont, elide, encodeMimeHandles, firstFloat, fontMatcher,
formatFileFilter, formatInt, formatTime, formatTimeStamp, formatVersion,
fuzzyTime, getFileSize, hexToInt, isHandle, isItemClass, isItemLayout,
isItemType, isListInstance, isTitleTag, jsonEncode, makeFileNameSafe,
minmax, numberToRoman, openExternalPath, processDialogSymbols,
readTextFile, simplified, transferCase, uniqueCompact, utf16CharMap,
xmlElement, xmlIndent, xmlSubElem, yesNo
isItemType, isListInstance, isTitleTag, jsonCombine, jsonEncode,
makeFileNameSafe, minmax, numberToRoman, openExternalPath,
processDialogSymbols, readTextFile, simplified, transferCase,
uniqueCompact, utf16CharMap, xmlElement, xmlIndent, xmlSubElem, yesNo
)
from novelwriter.enum import nwItemClass
@@ -651,6 +651,17 @@ def testBaseCommon_jsonEncode():
)
@pytest.mark.base
def testBaseCommon_jsonCombine():
"""Test the jsonCombine function."""
assert jsonCombine({"a": "[1, 2]", "b": "[3, 4]"}) == (
'{\n'
' "a": [1, 2],\n'
' "b": [3, 4]\n'
'}\n'
)
@pytest.mark.base
def testBaseCommon_xmlIndent():
"""Test the xmlIndent function."""
+1 -1
View File
@@ -157,7 +157,7 @@ def testCoreIndex_LoadSave(qtbot, monkeypatch, prjLipsum, nwGUI, tstPaths):
# Check File
copyfile(projFile, testFile)
assert cmpFiles(testFile, compFile)
assert cmpFiles(testFile, compFile, ignoreLines=[3, 4])
# Write an empty index file and load it
projFile.write_text("{}", encoding="utf-8")
+5 -4
View File
@@ -32,7 +32,8 @@ from PyQt6.QtCore import Qt
from PyQt6.QtGui import QPalette
from PyQt6.QtWidgets import QInputDialog, QMessageBox
from novelwriter import CONFIG, SHARED
from novelwriter import CONFIG, SHARED, __hexversion__
from novelwriter.common import jsonEncode
from novelwriter.config import DEF_GUI_DARK, DEF_GUI_LIGHT
from novelwriter.constants import nwFiles
from novelwriter.dialogs.editlabel import GuiEditLabel
@@ -713,7 +714,7 @@ def testGuiMain_Features(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
cHandle = SHARED.project.newFile("Jane", C.hCharRoot)
newDoc = SHARED.project.storage.getDocument(cHandle)
newDoc.writeDocument("# Jane\n\n@tag: Jane\n\n")
nwGUI.rebuildIndex(beQuiet=True)
nwGUI.rebuildIndex()
assert SHARED.focusMode is False
@@ -825,11 +826,11 @@ def testGuiMain_OpenClose(qtbot, monkeypatch, nwGUI, projPath, fncPath, mockRnd)
nwGUI.viewDocument(C.hTitlePage)
# Handle broken index on project open
idxData = jsonEncode({"novelWriter.meta": {"version": __hexversion__}})
nwGUI.closeProject()
idxPath: Path = projPath / "meta" / nwFiles.INDEX_FILE
assert idxPath.read_text(encoding="utf-8") != "{}"
idxPath.write_text("{}", encoding="utf-8")
assert idxPath.read_text(encoding="utf-8") == "{}"
idxPath.write_text(idxData, encoding="utf-8")
nwGUI.openProject(projPath)
nwGUI.saveProject()
+1 -1
View File
@@ -36,7 +36,7 @@ def testGuiStatusBar_Main(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
cHandle = SHARED.project.newFile("A Note", C.hCharRoot)
newDoc = SHARED.project.storage.getDocument(cHandle)
newDoc.writeDocument("# A Note\n\n")
nwGUI.rebuildIndex(beQuiet=True)
nwGUI.rebuildIndex()
status = nwGUI.mainStatus
+1 -1
View File
@@ -66,7 +66,7 @@ class C:
def cmpFiles(
fileOne: str | Path,
fileTwo: str | Path,
ignoreLines: list | None = None,
ignoreLines: list[int] | None = None,
ignoreStart: tuple | None = None
) -> bool:
"""Compare two files, with optional line ignore."""