Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Vanessa 2025-09-26 18:52:36 +08:00
commit 52eaa5519b
2 changed files with 73 additions and 61 deletions

View file

@ -1556,9 +1556,11 @@ func GetBlockAttributeViewKeys(nodeID string) (ret []*BlockAttributeViewKeys) {
for _, avID := range avIDs { for _, avID := range avIDs {
attrView := cachedAttrViews[avID] attrView := cachedAttrViews[avID]
if nil == attrView { if nil == attrView {
attrView, _ = av.ParseAttributeView(avID) var err error
attrView, err = av.ParseAttributeView(avID)
if nil == attrView { if nil == attrView {
return logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err)
continue
} }
cachedAttrViews[avID] = attrView cachedAttrViews[avID] = attrView
} }

View file

@ -1657,8 +1657,8 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) (
baseFolderName = path.Join(dir, name) baseFolderName = path.Join(dir, name)
box := Conf.Box(boxID) box := Conf.Box(boxID)
exportFolder := filepath.Join(util.TempDir, "export", baseFolderName) exportDir := filepath.Join(util.TempDir, "export", baseFolderName)
if err := os.MkdirAll(exportFolder, 0755); err != nil { if err := os.MkdirAll(exportDir, 0755); err != nil {
logging.LogErrorf("create export temp folder failed: %s", err) logging.LogErrorf("create export temp folder failed: %s", err)
return return
} }
@ -1709,7 +1709,7 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) (
} }
writePath := strings.TrimPrefix(tree.Path, rootDirPath) writePath := strings.TrimPrefix(tree.Path, rootDirPath)
writePath = filepath.Join(exportFolder, writePath) writePath = filepath.Join(exportDir, writePath)
writeFolder := filepath.Dir(writePath) writeFolder := filepath.Dir(writePath)
if mkdirErr := os.MkdirAll(writeFolder, 0755); nil != mkdirErr { if mkdirErr := os.MkdirAll(writeFolder, 0755); nil != mkdirErr {
logging.LogErrorf("create export temp folder [%s] failed: %s", writeFolder, 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 := 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 { if writeErr := os.WriteFile(writePath, data, 0644); nil != writeErr {
logging.LogErrorf("write export file [%s] failed: %s", writePath, writeErr) logging.LogErrorf("write export file [%s] failed: %s", writePath, writeErr)
continue continue
@ -1785,7 +1785,7 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) (
continue continue
} }
destPath := filepath.Join(exportFolder, asset) destPath := filepath.Join(exportDir, asset)
assetErr := filelock.Copy(srcPath, destPath) assetErr := filelock.Copy(srcPath, destPath)
if nil != assetErr { if nil != assetErr {
logging.LogErrorf("copy asset from [%s] to [%s] failed: %s", srcPath, destPath, 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) emojis := emojisInTree(tree)
for _, emoji := range emojis { for _, emoji := range emojis {
from := filepath.Join(util.DataDir, emoji) from := filepath.Join(util.DataDir, emoji)
to := filepath.Join(exportFolder, emoji) to := filepath.Join(exportDir, emoji)
if copyErr := filelock.Copy(from, to); copyErr != nil { if copyErr := filelock.Copy(from, to); copyErr != nil {
logging.LogErrorf("copy emojis from [%s] to [%s] failed: %s", from, to, copyErr) 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 // 导出数据库 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 { for _, tree := range trees {
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus { ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
if !entering { if !entering || !n.IsBlock() {
return ast.WalkContinue return ast.WalkContinue
} }
if ast.NodeAttributeView != n.Type { if ast.NodeAttributeView == n.Type {
return ast.WalkContinue avIDs = append(avIDs, n.AttributeViewID)
} }
avs := n.IALAttr(av.NodeAttrNameAvs)
avID := n.AttributeViewID for _, avID := range strings.Split(avs, ",") {
avJSONPath := av.GetAttributeViewDataPath(avID) avIDs = append(avIDs, strings.TrimSpace(avID))
if !filelock.IsExist(avJSONPath) {
return ast.WalkContinue
} }
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 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 // 导出闪卡 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) deck, loadErr := riff.LoadDeck(exportStorageRiffDir, builtinDeckID, Conf.Flashcard.RequestRetention, Conf.Flashcard.MaximumInterval, Conf.Flashcard.Weights)
if nil != loadErr { if nil != loadErr {
logging.LogErrorf("load deck [%s] failed: %s", name, 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) logging.LogErrorf("marshal sort conf failed: %s", sortErr)
} }
if 0 < len(sortData) { if 0 < len(sortData) {
confDir := filepath.Join(exportFolder, ".siyuan") confDir := filepath.Join(exportDir, ".siyuan")
if mkdirErr := os.MkdirAll(confDir, 0755); nil != mkdirErr { if mkdirErr := os.MkdirAll(confDir, 0755); nil != mkdirErr {
logging.LogErrorf("create export conf folder [%s] failed: %s", confDir, mkdirErr) logging.LogErrorf("create export conf folder [%s] failed: %s", confDir, mkdirErr)
} else { } 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) zip, err := gulu.Zip.Create(zipPath)
if err != nil { 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 "" return ""
} }
@ -1948,8 +1914,8 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) (
util.PushEndlessProgress(Conf.language(65) + " " + fmt.Sprintf(Conf.language(253), filename)) util.PushEndlessProgress(Conf.language(65) + " " + fmt.Sprintf(Conf.language(253), filename))
} }
if err = zip.AddDirectory(baseFolderName, exportFolder, zipCallback); err != nil { if err = zip.AddDirectory(baseFolderName, exportDir, zipCallback); 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 "" return ""
} }
@ -1957,11 +1923,55 @@ func exportSYZip(boxID, rootDirPath, baseFolderName string, docPaths []string) (
logging.LogErrorf("close export .sy.zip failed: %s", err) logging.LogErrorf("close export .sy.zip failed: %s", err)
} }
os.RemoveAll(exportFolder) os.RemoveAll(exportDir)
zipPath = "/export/" + url.PathEscape(filepath.Base(zipPath)) zipPath = "/export/" + url.PathEscape(filepath.Base(zipPath))
return 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) { func exportRelationAvs(avID, exportStorageAvDir string) {
avIDs := hashset.New() avIDs := hashset.New()
walkRelationAvs(avID, avIDs) walkRelationAvs(avID, avIDs)