diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index d9bae3680..8dd905ac8 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -1556,9 +1556,11 @@ func GetBlockAttributeViewKeys(nodeID string) (ret []*BlockAttributeViewKeys) { for _, avID := range avIDs { attrView := cachedAttrViews[avID] if nil == attrView { - attrView, _ = av.ParseAttributeView(avID) + var err error + attrView, err = av.ParseAttributeView(avID) if nil == attrView { - return + logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err) + continue } cachedAttrViews[avID] = attrView } diff --git a/kernel/model/export.go b/kernel/model/export.go index f95fb31a4..1b0ee31cc 100644 --- a/kernel/model/export.go +++ b/kernel/model/export.go @@ -1657,8 +1657,8 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) ( baseFolderName = path.Join(dir, name) box := Conf.Box(boxID) - exportFolder := filepath.Join(util.TempDir, "export", baseFolderName) - if err := os.MkdirAll(exportFolder, 0755); err != nil { + exportDir := filepath.Join(util.TempDir, "export", baseFolderName) + if err := os.MkdirAll(exportDir, 0755); err != nil { logging.LogErrorf("create export temp folder failed: %s", err) return } @@ -1709,7 +1709,7 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) ( } writePath := strings.TrimPrefix(tree.Path, rootDirPath) - writePath = filepath.Join(exportFolder, writePath) + writePath = filepath.Join(exportDir, writePath) writeFolder := filepath.Dir(writePath) if mkdirErr := os.MkdirAll(writeFolder, 0755); nil != mkdirErr { logging.LogErrorf("create export temp folder [%s] failed: %s", writeFolder, mkdirErr) @@ -1735,7 +1735,7 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) ( } writePath := strings.TrimPrefix(tree.Path, rootDirPath) - writePath = filepath.Join(exportFolder, treeID+".sy") + writePath = filepath.Join(exportDir, treeID+".sy") if writeErr := os.WriteFile(writePath, data, 0644); nil != writeErr { logging.LogErrorf("write export file [%s] failed: %s", writePath, writeErr) continue @@ -1785,7 +1785,7 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) ( continue } - destPath := filepath.Join(exportFolder, asset) + destPath := filepath.Join(exportDir, asset) assetErr := filelock.Copy(srcPath, destPath) if nil != assetErr { logging.LogErrorf("copy asset from [%s] to [%s] failed: %s", srcPath, destPath, assetErr) @@ -1809,7 +1809,7 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) ( emojis := emojisInTree(tree) for _, emoji := range emojis { from := filepath.Join(util.DataDir, emoji) - to := filepath.Join(exportFolder, emoji) + to := filepath.Join(exportDir, emoji) if copyErr := filelock.Copy(from, to); copyErr != nil { logging.LogErrorf("copy emojis from [%s] to [%s] failed: %s", from, to, copyErr) } @@ -1817,65 +1817,31 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) ( } // 导出数据库 Attribute View export https://github.com/siyuan-note/siyuan/issues/8710 - exportStorageAvDir := filepath.Join(exportFolder, "storage", "av") + exportStorageAvDir := filepath.Join(exportDir, "storage", "av") + var avIDs []string for _, tree := range trees { ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus { - if !entering { + if !entering || !n.IsBlock() { return ast.WalkContinue } - if ast.NodeAttributeView != n.Type { - return ast.WalkContinue + if ast.NodeAttributeView == n.Type { + avIDs = append(avIDs, n.AttributeViewID) } - - avID := n.AttributeViewID - avJSONPath := av.GetAttributeViewDataPath(avID) - if !filelock.IsExist(avJSONPath) { - return ast.WalkContinue + avs := n.IALAttr(av.NodeAttrNameAvs) + for _, avID := range strings.Split(avs, ",") { + avIDs = append(avIDs, strings.TrimSpace(avID)) } - - if copyErr := filelock.Copy(avJSONPath, filepath.Join(exportStorageAvDir, avID+".json")); nil != copyErr { - logging.LogErrorf("copy av json failed: %s", copyErr) - } - - attrView, err := av.ParseAttributeView(avID) - if err != nil { - logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err) - return ast.WalkContinue - } - - for _, keyValues := range attrView.KeyValues { - switch keyValues.Key.Type { - case av.KeyTypeMAsset: // 导出资源文件列 https://github.com/siyuan-note/siyuan/issues/9919 - for _, value := range keyValues.Values { - for _, asset := range value.MAsset { - if !util.IsAssetLinkDest([]byte(asset.Content)) { - continue - } - - destPath := filepath.Join(exportFolder, asset.Content) - srcPath := assetPathMap[asset.Content] - if "" == srcPath { - logging.LogWarnf("get asset [%s] abs path failed", asset.Content) - continue - } - - if copyErr := filelock.Copy(srcPath, destPath); nil != copyErr { - logging.LogErrorf("copy asset failed: %s", copyErr) - } - } - } - } - } - - // 级联导出关联列关联的数据库 - exportRelationAvs(avID, exportStorageAvDir) return ast.WalkContinue }) } + avIDs = gulu.Str.RemoveDuplicatedElem(avIDs) + for _, avID := range avIDs { + exportAv(avID, exportStorageAvDir, exportDir, assetPathMap) + } // 导出闪卡 Export related flashcard data when exporting .sy.zip https://github.com/siyuan-note/siyuan/issues/9372 - exportStorageRiffDir := filepath.Join(exportFolder, "storage", "riff") + exportStorageRiffDir := filepath.Join(exportDir, "storage", "riff") deck, loadErr := riff.LoadDeck(exportStorageRiffDir, builtinDeckID, Conf.Flashcard.RequestRetention, Conf.Flashcard.MaximumInterval, Conf.Flashcard.Weights) if nil != loadErr { logging.LogErrorf("load deck [%s] failed: %s", name, loadErr) @@ -1924,7 +1890,7 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) ( logging.LogErrorf("marshal sort conf failed: %s", sortErr) } if 0 < len(sortData) { - confDir := filepath.Join(exportFolder, ".siyuan") + confDir := filepath.Join(exportDir, ".siyuan") if mkdirErr := os.MkdirAll(confDir, 0755); nil != mkdirErr { logging.LogErrorf("create export conf folder [%s] failed: %s", confDir, mkdirErr) } else { @@ -1937,10 +1903,10 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) ( } } - zipPath = exportFolder + ".sy.zip" + zipPath = exportDir + ".sy.zip" zip, err := gulu.Zip.Create(zipPath) if err != nil { - logging.LogErrorf("create export .sy.zip [%s] failed: %s", exportFolder, err) + logging.LogErrorf("create export .sy.zip [%s] failed: %s", exportDir, err) return "" } @@ -1948,8 +1914,8 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) ( util.PushEndlessProgress(Conf.language(65) + " " + fmt.Sprintf(Conf.language(253), filename)) } - if err = zip.AddDirectory(baseFolderName, exportFolder, zipCallback); err != nil { - logging.LogErrorf("create export .sy.zip [%s] failed: %s", exportFolder, err) + if err = zip.AddDirectory(baseFolderName, exportDir, zipCallback); err != nil { + logging.LogErrorf("create export .sy.zip [%s] failed: %s", exportDir, err) return "" } @@ -1957,11 +1923,55 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) ( logging.LogErrorf("close export .sy.zip failed: %s", err) } - os.RemoveAll(exportFolder) + os.RemoveAll(exportDir) zipPath = "/export/" + url.PathEscape(filepath.Base(zipPath)) return } +func exportAv(avID, exportStorageAvDir, exportFolder string, assetPathMap map[string]string) { + avJSONPath := av.GetAttributeViewDataPath(avID) + if !filelock.IsExist(avJSONPath) { + return + } + + if copyErr := filelock.Copy(avJSONPath, filepath.Join(exportStorageAvDir, avID+".json")); nil != copyErr { + logging.LogErrorf("copy av json failed: %s", copyErr) + } + + attrView, err := av.ParseAttributeView(avID) + if err != nil { + logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err) + return + } + + for _, keyValues := range attrView.KeyValues { + switch keyValues.Key.Type { + case av.KeyTypeMAsset: // 导出资源文件列 https://github.com/siyuan-note/siyuan/issues/9919 + for _, value := range keyValues.Values { + for _, asset := range value.MAsset { + if !util.IsAssetLinkDest([]byte(asset.Content)) { + continue + } + + destPath := filepath.Join(exportFolder, asset.Content) + srcPath := assetPathMap[asset.Content] + if "" == srcPath { + logging.LogWarnf("get asset [%s] abs path failed", asset.Content) + continue + } + + if copyErr := filelock.Copy(srcPath, destPath); nil != copyErr { + logging.LogErrorf("copy asset failed: %s", copyErr) + } + } + } + } + } + + // 级联导出关联列关联的数据库 + exportRelationAvs(avID, exportStorageAvDir) +} + func exportRelationAvs(avID, exportStorageAvDir string) { avIDs := hashset.New() walkRelationAvs(avID, avIDs)