🎨 The old version of the application no longer supports opening the new version of the document https://github.com/siyuan-note/siyuan/issues/16505

Signed-off-by: Daniel <845765@qq.com>
This commit is contained in:
Daniel 2025-12-03 22:03:13 +08:00
parent 9e075581ff
commit b5c84f2354
No known key found for this signature in database
GPG key ID: 86211BA83DF03017
21 changed files with 114 additions and 41 deletions

View file

@ -1704,6 +1704,7 @@
"271": "اكتملت عملية تحسين فهرس البيانات، تم تحرير [%s] من مساحة القرص",
"272": "حقل غير مسمى",
"273": "لا تقم بإنشاء مساحة العمل في مسار جذر القسم، يرجى إنشاء مجلد جديد كمساحة عمل",
"274": "يحتوي هذا المجلد على ملفات أخرى، يرجى إنشاء مجلد جديد كمساحة عمل"
"274": "يحتوي هذا المجلد على ملفات أخرى، يرجى إنشاء مجلد جديد كمساحة عمل",
"275": "يتعذر فتح المستند الذي تم إنشاؤه بواسطة إصدار أحدث. يرجى الترقية إلى أحدث إصدار ثم المحاولة مرة أخرى"
}
}

View file

@ -1704,6 +1704,7 @@
"271": "Datenindex-Optimierung abgeschlossen, [%s] Speicherplatz freigegeben",
"272": "Unbenanntes Feld",
"273": "Erstellen Sie den Arbeitsbereich nicht im Stammverzeichnis der Partition, erstellen Sie bitte einen neuen Ordner als Arbeitsbereich",
"274": "Dieser Ordner enthält andere Dateien, erstellen Sie bitte einen neuen Ordner als Arbeitsbereich"
"274": "Dieser Ordner enthält andere Dateien, erstellen Sie bitte einen neuen Ordner als Arbeitsbereich",
"275": "Dokumente, die mit einer neueren Version erstellt wurden, können nicht geöffnet werden. Bitte aktualisieren Sie auf die neueste Version und versuchen Sie es erneut"
}
}

View file

@ -1704,6 +1704,7 @@
"271": "Data index optimization completed, [%s] disk space freed",
"272": "Unnamed field",
"273": "Do not create the workspace in the partition root path, please create a new folder as the workspace",
"274": "This folder contains other files, please create a new folder as the workspace"
"274": "This folder contains other files, please create a new folder as the workspace",
"275": "Cannot open documents created by a newer version. Please upgrade to the latest version and try again"
}
}

View file

@ -1704,6 +1704,7 @@
"271": "Optimización del índice de datos completada, se liberaron [%s] de espacio en disco",
"272": "Campo sin nombre",
"273": "No cree el espacio de trabajo en la ruta raíz de la partición, cree una nueva carpeta como espacio de trabajo",
"274": "Esta carpeta contiene otros archivos, cree una nueva carpeta como espacio de trabajo"
"274": "Esta carpeta contiene otros archivos, cree una nueva carpeta como espacio de trabajo",
"275": "No se puede abrir el documento creado con una versión más reciente. Actualiza a la última versión e inténtalo de nuevo"
}
}

View file

@ -1704,6 +1704,7 @@
"271": "Optimisation de l'index des données terminée, [%s] d'espace disque libéré",
"272": "Champ sans nom",
"273": "Ne créez pas lespace de travail à la racine de la partition, créez un nouveau dossier comme espace de travail",
"274": "Ce dossier contient dautres fichiers, créez un nouveau dossier comme espace de travail"
"274": "Ce dossier contient dautres fichiers, créez un nouveau dossier comme espace de travail",
"275": "Impossible d'ouvrir le document créé par une version plus récente. Veuillez mettre à jour vers la dernière version et réessayer"
}
}

View file

@ -1704,6 +1704,7 @@
"271": "אופטימיזציית אינדקס הנתונים הושלמה, שוחררו [%s] שטח דיסק",
"272": "שדה ללא שם",
"273": "אל תיצור סביבת עבודה בנתיב השורש של המחיצה, צור תיקיה חדשה כסביבת עבודה",
"274": "התיקיה הזו מכילה קבצים נוספים, צור תיקיה חדשה כסביבת עבודה"
"274": "התיקיה הזו מכילה קבצים נוספים, צור תיקיה חדשה כסביבת עבודה",
"275": "לא ניתן לפתוח את המסמך שנוצר בגרסה חדשה יותר. יש לעדכן לגרסה העדכנית ביותר ולנסות שוב"
}
}

View file

@ -1704,6 +1704,7 @@
"271": "Ottimizzazione dell'indice dei dati completata, liberati [%s] di spazio su disco",
"272": "Campo senza nome",
"273": "Non creare lo spazio di lavoro nella directory radice della partizione, crea una nuova cartella come spazio di lavoro",
"274": "Questa cartella contiene altri file, crea una nuova cartella come spazio di lavoro"
"274": "Questa cartella contiene altri file, crea una nuova cartella come spazio di lavoro",
"275": "Impossibile aprire il documento creato con una versione più recente. Aggiorna all'ultima versione e riprova"
}
}

View file

@ -1704,6 +1704,7 @@
"271": "データインデックスの最適化が完了しました。合計 [%s] のディスク容量が解放されました",
"272": "未命名フィールド",
"273": "パーティションのルートパスにワークスペースを作成しないでください。新しいフォルダーをワークスペースとして作成してください",
"274": "このフォルダーには他のファイルが含まれています。新しいフォルダーをワークスペースとして作成してください"
"274": "このフォルダーには他のファイルが含まれています。新しいフォルダーをワークスペースとして作成してください",
"275": "新しいバージョンで作成された文書を開くことができません。最新バージョンにアップデートしてから再試行してください"
}
}

View file

@ -1704,6 +1704,7 @@
"271": "Optymalizacja indeksu danych zakończona, zwolniono [%s] miejsca na dysku",
"272": "Nienazwane pole",
"273": "Nie twórz przestrzeni roboczej w katalogu głównym partycji, utwórz nowy folder jako przestrzeń roboczą",
"274": "Ten folder zawiera inne pliki, utwórz nowy folder jako przestrzeń roboczą"
"274": "Ten folder zawiera inne pliki, utwórz nowy folder jako przestrzeń roboczą",
"275": "Nie można otworzyć dokumentu utworzonego w nowszej wersji. Zaktualizuj program do najnowszej wersji i spróbuj ponownie"
}
}

View file

@ -1704,6 +1704,7 @@
"271": "Otimização do índice de dados concluída, [%s] de espaço liberado",
"272": "Campo sem nome",
"273": "Não crie o espaço de trabalho na raiz da partição, crie uma nova pasta para o espaço de trabalho",
"274": "Esta pasta contém outros arquivos, crie uma nova pasta para o espaço de trabalho"
"274": "Esta pasta contém outros arquivos, crie uma nova pasta para o espaço de trabalho",
"275": "Não é possível abrir o documento criado por uma versão mais recente. Atualize para a versão mais recente e tente novamente"
}
}

View file

@ -1704,6 +1704,7 @@
"271": "Оптимизация индекса данных завершена, освобождено [%s] дискового пространства",
"272": "Неименованное поле",
"273": "Не создавайте рабочее пространство в корневом каталоге раздела, создайте отдельную папку для рабочего пространства",
"274": "Эта папка содержит другие файлы, создайте отдельную папку для рабочего пространства"
"274": "Эта папка содержит другие файлы, создайте отдельную папку для рабочего пространства",
"275": "Невозможно открыть документ, созданный в более новой версии. Пожалуйста, обновите приложение до последней версии и попробуйте снова"
}
}

View file

@ -1704,6 +1704,7 @@
"271": "資料索引優化完畢,共釋放 [%s] 磁碟空間",
"272": "未命名欄位",
"273": "請勿在分區根路徑上建立工作空間,請新建一個資料夾作為工作空間",
"274": "該資料夾包含其他檔案,請新建一個資料夾作為工作空間"
"274": "該資料夾包含其他檔案,請新建一個資料夾作為工作空間",
"275": "無法打開由新版本建立的檔案,請升級到最新版本後再試"
}
}

View file

@ -1704,6 +1704,7 @@
"271": "数据索引优化完毕,共释放 [%s] 磁盘空间",
"272": "未命名字段",
"273": "请勿在分区根路径上创建工作空间,请新建一个文件夹作为工作空间",
"274": "该文件夹包含了其他文件,请新建一个文件夹作为工作空间"
"274": "该文件夹包含了其他文件,请新建一个文件夹作为工作空间",
"275": "无法打开新版本创建的文档,请升级到最新版本后再试"
}
}

View file

@ -28,6 +28,7 @@ import (
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/filesys"
"github.com/siyuan-note/siyuan/kernel/model"
"github.com/siyuan-note/siyuan/kernel/treenode"
"github.com/siyuan-note/siyuan/kernel/util"
)
@ -660,6 +661,10 @@ func getBlockInfo(c *gin.Context) {
ret.Code = 3
ret.Msg = model.Conf.Language(56)
return
} else if errors.Is(err, treenode.ErrSpecTooNew) {
ret.Code = -1
ret.Msg = model.Conf.Language(275)
return
}
block, _ := model.GetBlock(id, tree)

View file

@ -125,10 +125,9 @@ func LoadTree(boxID, p string, luteEngine *lute.Lute) (ret *parse.Tree, err erro
}
func LoadTreeByData(data []byte, boxID, p string, luteEngine *lute.Lute) (ret *parse.Tree, err error) {
ret = parseJSON2Tree(boxID, p, data, luteEngine)
if nil == ret {
logging.LogErrorf("parse tree [%s] failed", p)
err = errors.New("parse tree failed")
ret, err = parseJSON2Tree(boxID, p, data, luteEngine)
if nil != err {
logging.LogErrorf("parse tree [%s] failed: %s", p, err)
return
}
ret.Path = p
@ -245,12 +244,9 @@ func prepareWriteTree(tree *parse.Tree) (data []byte, filePath string, err error
treenode.UpsertBlockTree(tree)
}
treenode.UpgradeSpec(tree)
filePath = filepath.Join(util.DataDir, tree.Box, tree.Path)
if oldSpec := tree.Root.Spec; "" == oldSpec {
parse.NestedInlines2FlattedSpans(tree, false)
tree.Root.Spec = "1"
logging.LogInfof("migrated tree [%s] from spec [%s] to [%s]", filePath, oldSpec, tree.Root.Spec)
}
tree.Root.SetIALAttr("type", "doc")
renderer := render.NewJSONRenderer(tree, luteEngine.RenderOptions)
data = renderer.Render()
@ -277,8 +273,7 @@ func afterWriteTree(tree *parse.Tree) {
cache.PutDocIAL(tree.Path, docIAL)
}
func parseJSON2Tree(boxID, p string, jsonData []byte, luteEngine *lute.Lute) (ret *parse.Tree) {
var err error
func parseJSON2Tree(boxID, p string, jsonData []byte, luteEngine *lute.Lute) (ret *parse.Tree, err error) {
var needFix bool
ret, needFix, err = dataparser.ParseJSON(jsonData, luteEngine.ParseOptions)
if err != nil {
@ -289,12 +284,12 @@ func parseJSON2Tree(boxID, p string, jsonData []byte, luteEngine *lute.Lute) (re
ret.Box = boxID
ret.Path = p
filePath := filepath.Join(util.DataDir, ret.Box, ret.Path)
if oldSpec := ret.Root.Spec; "" == oldSpec {
parse.NestedInlines2FlattedSpans(ret, false)
ret.Root.Spec = "1"
if err = treenode.CheckSpec(ret); errors.Is(err, treenode.ErrSpecTooNew) {
return
}
if treenode.UpgradeSpec(ret) {
needFix = true
logging.LogInfof("migrated tree [%s] from spec [%s] to [%s]", filePath, oldSpec, ret.Root.Spec)
}
if pathID := util.GetTreeID(p); pathID != ret.Root.ID {
@ -318,6 +313,7 @@ func parseJSON2Tree(boxID, p string, jsonData []byte, luteEngine *lute.Lute) (re
data = buf.Bytes()
}
filePath := filepath.Join(util.DataDir, ret.Box, ret.Path)
if err = os.MkdirAll(filepath.Dir(filePath), 0755); err != nil {
return
}

View file

@ -1748,7 +1748,7 @@ func createDoc(boxID, p, title, dom string) (tree *parse.Tree, err error) {
tree.HPath = hPath
tree.ID = id
tree.Root.ID = id
tree.Root.Spec = "1"
tree.Root.Spec = treenode.CurrentSpec
updated := util.TimeFromID(id)
tree.Root.KramdownIAL = [][]string{{"id", id}, {"title", html.EscapeAttrVal(title)}, {"updated", updated}}
if nil == tree.Root.FirstChild {

View file

@ -23,6 +23,7 @@ import (
"github.com/88250/lute/editor"
"github.com/88250/lute/render"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/treenode"
"github.com/siyuan-note/siyuan/kernel/util"
)
@ -63,13 +64,13 @@ func AutoSpace(rootID string) (err error) {
formatRenderer := render.NewFormatRenderer(tree, luteEngine.RenderOptions)
md := formatRenderer.Render()
newTree := parseKTree(md)
newTree.Root.Spec = "1"
newTree.Root.Spec = treenode.CurrentSpec
// 第二次格式化启用自动空格
luteEngine.SetAutoSpace(true)
formatRenderer = render.NewFormatRenderer(newTree, luteEngine.RenderOptions)
md = formatRenderer.Render()
newTree = parseKTree(md)
newTree.Root.Spec = "1"
newTree.Root.Spec = treenode.CurrentSpec
newTree.Root.ID = tree.ID
newTree.Root.KramdownIAL = rootIAL
newTree.ID = tree.ID

View file

@ -427,7 +427,7 @@ func Heading2Doc(srcHeadingID, targetBoxID, targetPath, previousPath string) (sr
newTree.Box, newTree.Path = targetBoxID, newTargetPath
newTree.Root.SetIALAttr("updated", util.CurrentTimeSecondsStr())
newTree.Root.Spec = "1"
newTree.Root.Spec = treenode.CurrentSpec
if "" != previousPath {
box.addSort(previousPath, newTree.ID)
} else {

View file

@ -418,10 +418,7 @@ func ImportSY(zipPath, boxID, toPath string) (err error) {
for _, tree := range trees {
util.PushEndlessProgress(Conf.language(73) + " " + fmt.Sprintf(Conf.language(70), tree.Root.IALAttr("title")))
syPath := filepath.Join(unzipRootPath, tree.Path)
if "" == tree.Root.Spec {
parse.NestedInlines2FlattedSpans(tree, false)
tree.Root.Spec = "1"
}
treenode.UpgradeSpec(tree)
renderer := render.NewJSONRenderer(tree, luteEngine.RenderOptions)
data := renderer.Render()
@ -943,7 +940,7 @@ func ImportFromLocalPath(boxID, localPath string, toPath string) (err error) {
tree.Path = targetPath
targetPaths[curRelPath] = targetPath
tree.HPath = hPath
tree.Root.Spec = "1"
tree.Root.Spec = treenode.CurrentSpec
docDirLocalPath := filepath.Dir(filepath.Join(boxLocalPath, targetPath))
assetDirPath := getAssetsDir(boxLocalPath, docDirLocalPath)
@ -1075,7 +1072,7 @@ func ImportFromLocalPath(boxID, localPath string, toPath string) (err error) {
tree.Box = boxID
tree.Path = targetPath
tree.HPath = path.Join(baseHPath, title)
tree.Root.Spec = "1"
tree.Root.Spec = treenode.CurrentSpec
docDirLocalPath := filepath.Dir(filepath.Join(boxLocalPath, targetPath))
assetDirPath := getAssetsDir(boxLocalPath, docDirLocalPath)

View file

@ -128,7 +128,7 @@ func ListItem2Doc(srcListItemID, targetBoxID, targetPath, previousPath string) (
newTree.Box, newTree.Path = targetBoxID, newTargetPath
newTree.Root.SetIALAttr("updated", util.CurrentTimeSecondsStr())
newTree.Root.Spec = "1"
newTree.Root.Spec = treenode.CurrentSpec
if "" != previousPath {
box.addSort(previousPath, newTree.ID)
} else {

View file

@ -22,6 +22,7 @@ import (
"io/fs"
"path/filepath"
"sort"
"strconv"
"strings"
"github.com/88250/gulu"
@ -29,6 +30,7 @@ import (
"github.com/88250/lute/ast"
"github.com/88250/lute/parse"
"github.com/siyuan-note/filelock"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/util"
)
@ -71,7 +73,7 @@ func NewTree(boxID, p, hp, title string) *parse.Tree {
root.SetIALAttr("id", id)
root.SetIALAttr("updated", util.TimeFromID(id))
ret := &parse.Tree{Root: root, ID: id, Box: boxID, Path: p, HPath: hp}
ret.Root.Spec = "1"
ret.Root.Spec = CurrentSpec
newPara := &ast.Node{Type: ast.NodeParagraph, ID: ast.NewNodeID(), Box: boxID, Path: p}
newPara.SetIALAttr("id", newPara.ID)
newPara.SetIALAttr("updated", util.TimeFromID(newPara.ID))
@ -129,3 +131,62 @@ func NewSpanAnchor(id string) (ret *ast.Node) {
func ContainOnlyDefaultIAL(tree *parse.Tree) bool {
return 5 > len(tree.Root.KramdownIAL)
}
var CurrentSpec = "2"
var ErrSpecTooNew = fmt.Errorf("the document spec is too new")
func CheckSpec(tree *parse.Tree) (err error) {
if CurrentSpec == tree.Root.Spec || "" == tree.Root.Spec {
return
}
spec, err := strconv.Atoi(tree.Root.Spec)
if nil != err {
logging.LogErrorf("parse spec [%s] failed: %s", tree.Root.Spec, err)
return
}
currentSpec, _ := strconv.Atoi(CurrentSpec)
if spec > currentSpec {
logging.LogErrorf("tree spec [%s] is newer than current spec [%s]", tree.Root.Spec, CurrentSpec)
return ErrSpecTooNew
}
return
}
func UpgradeSpec(tree *parse.Tree) (upgraded bool) {
if CurrentSpec == tree.Root.Spec {
return
}
upgradeSpec1(tree)
upgradeSpec2(tree)
return true
}
func upgradeSpec2(tree *parse.Tree) {
oldSpec, err := strconv.Atoi(tree.Root.Spec)
if nil != err {
logging.LogErrorf("parse spec [%s] failed: %s", tree.Root.Spec, err)
return
}
if 2 <= oldSpec {
return
}
// 增加了 Callout
tree.Root.Spec = "2"
}
func upgradeSpec1(tree *parse.Tree) {
if "" != tree.Root.Spec {
return
}
parse.NestedInlines2FlattedSpans(tree, false)
tree.Root.Spec = "1"
return
}