From 581c1b4942c54f8ca6563ff5ab0fb3f4cc870111 Mon Sep 17 00:00:00 2001 From: Liang Ding Date: Sun, 21 Aug 2022 13:01:54 +0800 Subject: [PATCH] =?UTF-8?q?:art:=20=E4=BA=91=E7=AB=AF=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E5=8F=91=E7=94=9F=E5=86=B2=E7=AA=81=E6=97=B6=E7=94=9F=E6=88=90?= =?UTF-8?q?=E5=89=AF=E6=9C=AC=20https://github.com/siyuan-note/siyuan/issu?= =?UTF-8?q?es/5687?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/go.mod | 4 +-- kernel/go.sum | 8 ++--- kernel/model/file.go | 61 +++++------------------------------ kernel/model/repository.go | 36 ++++++++++++++++++++- kernel/model/tree.go | 58 +++++++++++++++++++++++++++++++++ kernel/util/working.go | 4 +-- kernel/util/working_mobile.go | 1 + 7 files changed, 110 insertions(+), 62 deletions(-) diff --git a/kernel/go.mod b/kernel/go.mod index 4733e8337..ef3d0a6e3 100644 --- a/kernel/go.mod +++ b/kernel/go.mod @@ -29,7 +29,7 @@ require ( github.com/gin-contrib/gzip v0.0.6 github.com/gin-contrib/sessions v0.0.5 github.com/gin-gonic/gin v1.8.1 - github.com/imroc/req/v3 v3.18.0 + github.com/imroc/req/v3 v3.19.0 github.com/jinzhu/copier v0.3.5 github.com/mattn/go-sqlite3 v2.0.3+incompatible github.com/mitchellh/go-ps v1.0.0 @@ -38,7 +38,7 @@ require ( github.com/patrickmn/go-cache v2.1.0+incompatible github.com/qiniu/go-sdk/v7 v7.13.0 github.com/radovskyb/watcher v1.0.7 - github.com/siyuan-note/dejavu v0.0.0-20220817100354-86e98bc81dfe + github.com/siyuan-note/dejavu v0.0.0-20220821042432-9a0649a3cf06 github.com/siyuan-note/encryption v0.0.0-20220713091850-5ecd92177b75 github.com/siyuan-note/eventbus v0.0.0-20220624162334-ca7c06dc771f github.com/siyuan-note/filelock v0.0.0-20220720144616-011221f7e128 diff --git a/kernel/go.sum b/kernel/go.sum index da3e5ecc5..b5b57c7da 100644 --- a/kernel/go.sum +++ b/kernel/go.sum @@ -200,8 +200,8 @@ github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= -github.com/imroc/req/v3 v3.18.0 h1:IKJOLXnjPG/IzC8bIuTIo77/8/j4VbVFw71D+gh4O1c= -github.com/imroc/req/v3 v3.18.0/go.mod h1:EluRnkfh8A39BmrCARYhcUrfGyR8qPw+O0BZyTy4j9k= +github.com/imroc/req/v3 v3.19.0 h1:CgUA54GlgeivADx8nodAFwlgifctXZSxf+V8XibzdDs= +github.com/imroc/req/v3 v3.19.0/go.mod h1:EluRnkfh8A39BmrCARYhcUrfGyR8qPw+O0BZyTy4j9k= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= @@ -349,8 +349,8 @@ github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1l github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= -github.com/siyuan-note/dejavu v0.0.0-20220817100354-86e98bc81dfe h1:5n6FyzATQyjrT9DZNVxqCV/CDwkvbTsa3F7icpMrchI= -github.com/siyuan-note/dejavu v0.0.0-20220817100354-86e98bc81dfe/go.mod h1:8MoQSqxsyMbvMlDgLqs60k7SewDjoYUiJT4h9jeqUJI= +github.com/siyuan-note/dejavu v0.0.0-20220821042432-9a0649a3cf06 h1:v6Sacjqh/Q3IMZvFDCYzXTBPS/fQs5A2pN2SQHXtY88= +github.com/siyuan-note/dejavu v0.0.0-20220821042432-9a0649a3cf06/go.mod h1:/7pAviNPlpJiwZkEg2eyLTEq2/8sfW/AU4eHBvyrHFk= github.com/siyuan-note/encryption v0.0.0-20220713091850-5ecd92177b75 h1:Bi7/7f29LW+Fm0cHc0J1NO1cZqyJwljSWVmfOqVZgaE= github.com/siyuan-note/encryption v0.0.0-20220713091850-5ecd92177b75/go.mod h1:H8fyqqAbp9XreANjeSbc72zEdFfKTXYN34tc1TjZwtw= github.com/siyuan-note/eventbus v0.0.0-20220624162334-ca7c06dc771f h1:JMobMNZ7AqaKKyEK+WeWFhix/2TDQXgPZDajU00IybU= diff --git a/kernel/model/file.go b/kernel/model/file.go index f1d66f11a..7e507b7b8 100644 --- a/kernel/model/file.go +++ b/kernel/model/file.go @@ -933,58 +933,15 @@ func DuplicateDoc(rootID string) (ret *parse.Tree, err error) { return } - ret.ID = ast.NewNodeID() - ret.Root.ID = ret.ID - titleSuffix := "Duplicated" - if t, parseErr := time.Parse("20060102150405", util.TimeFromID(ret.ID)); nil == parseErr { - titleSuffix = t.Format("2006-01-02 15:04:05") - } - ret.Root.SetIALAttr("id", ret.ID) - ret.Root.SetIALAttr("title", ret.Root.IALAttr("title")+" "+titleSuffix) - p := path.Join(path.Dir(ret.Path), ret.ID) + ".sy" - ret.Path = p - ret.HPath = ret.HPath + " " + titleSuffix + resetTree(ret, "Duplicated") + createTreeTx(ret) + sql.WaitForWritingDatabase() + return +} - // 收集所有引用 - refIDs := map[string]string{} - ast.Walk(ret.Root, func(n *ast.Node, entering bool) ast.WalkStatus { - if !entering || ast.NodeBlockRefID != n.Type { - return ast.WalkContinue - } - refIDs[n.TokensStr()] = "1" - return ast.WalkContinue - }) - - // 重置块 ID - ast.Walk(ret.Root, func(n *ast.Node, entering bool) ast.WalkStatus { - if !entering || ast.NodeDocument == n.Type { - return ast.WalkContinue - } - if n.IsBlock() && "" != n.ID { - newID := ast.NewNodeID() - if "1" == refIDs[n.ID] { - // 如果是文档自身的内部引用 - refIDs[n.ID] = newID - } - n.ID = newID - n.SetIALAttr("id", n.ID) - } - return ast.WalkContinue - }) - - // 重置内部引用 - ast.Walk(ret.Root, func(n *ast.Node, entering bool) ast.WalkStatus { - if !entering || ast.NodeBlockRefID != n.Type { - return ast.WalkContinue - } - if "1" != refIDs[n.TokensStr()] { - n.Tokens = []byte(refIDs[n.TokensStr()]) - } - return ast.WalkContinue - }) - - transaction := &Transaction{DoOperations: []*Operation{{Action: "create", Data: ret}}} - err = PerformTransactions(&[]*Transaction{transaction}) +func createTreeTx(tree *parse.Tree) { + transaction := &Transaction{DoOperations: []*Operation{{Action: "create", Data: tree}}} + err := PerformTransactions(&[]*Transaction{transaction}) if nil != err { tx, txErr := sql.BeginTx() if nil != txErr { @@ -996,8 +953,6 @@ func DuplicateDoc(rootID string) (ret *parse.Tree, err error) { logging.LogFatalf("transaction failed: %s", err) return } - sql.WaitForWritingDatabase() - return } func CreateDocByMd(boxID, p, title, md string, sorts []string) (err error) { diff --git a/kernel/model/repository.go b/kernel/model/repository.go index 52787a163..ea8ba7f4a 100644 --- a/kernel/model/repository.go +++ b/kernel/model/repository.go @@ -534,6 +534,40 @@ func syncRepo(boot, exit, byHand bool) (err error) { logging.LogInfof("synced data repo [ufc=%d, dfc=%d, ucc=%d, dcc=%d, ub=%s, db=%s] in [%.2fs]", trafficStat.UploadFileCount, trafficStat.DownloadFileCount, trafficStat.UploadChunkCount, trafficStat.DownloadChunkCount, humanize.Bytes(uint64(trafficStat.UploadBytes)), humanize.Bytes(uint64(trafficStat.DownloadBytes)), elapsed.Seconds()) + if 0 < len(mergeResult.Conflicts) { + // 云端同步发生冲突时生成副本 https://github.com/siyuan-note/siyuan/issues/5687 + + luteEngine := NewLute() + waitTx := false + for _, file := range mergeResult.Conflicts { + if !strings.HasSuffix(file.Path, ".sy") { + continue + } + + parts := strings.Split(file.Path[1:], "/") + if 2 > len(parts) { + continue + } + boxID := parts[0] + + absPath := filepath.Join(util.TempDir, "repo", "sync", "conflicts", file.Path) + tree, loadTreeErr := loadTree(absPath, luteEngine) + if nil != loadTreeErr { + logging.LogErrorf("loadd conflicted file [%s] failed: %s", absPath, loadTreeErr) + continue + } + tree.Box = boxID + tree.Path = strings.TrimPrefix(file.Path, "/"+boxID) + + resetTree(tree, "Conflicted") + createTreeTx(tree) + waitTx = true + } + if waitTx { + sql.WaitForWritingDatabase() + } + } + if 1 > len(mergeResult.Upserts) && 1 > len(mergeResult.Removes) { // 没有数据变更 syncSameCount++ if 10 < syncSameCount { @@ -566,7 +600,7 @@ func syncRepo(boot, exit, byHand bool) (err error) { cache.ClearDocsIAL() // 同步后文档树文档图标没有更新 https://github.com/siyuan-note/siyuan/issues/4939 fullReindex := 0.2 < float64(len(upserts))/float64(len(indexBeforeSync.Files)) - if fullReindex { + if fullReindex { // 如果更新的文件比较多则全量重建索引 RefreshFileTree() return } diff --git a/kernel/model/tree.go b/kernel/model/tree.go index 4b178c4ce..334568ccc 100644 --- a/kernel/model/tree.go +++ b/kernel/model/tree.go @@ -19,17 +19,75 @@ package model import ( "errors" "io/fs" + "path" "path/filepath" "strings" + "time" "github.com/88250/lute" + "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/filesys" "github.com/siyuan-note/siyuan/kernel/treenode" + "github.com/siyuan-note/siyuan/kernel/util" ) +func resetTree(tree *parse.Tree, titleSuffix string) { + tree.ID = ast.NewNodeID() + tree.Root.ID = tree.ID + if t, parseErr := time.Parse("20060102150405", util.TimeFromID(tree.ID)); nil == parseErr { + titleSuffix += " " + t.Format("2006-01-02 15:04:05") + } else { + titleSuffix = "Duplicated " + time.Now().Format("2006-01-02 15:04:05") + } + titleSuffix = "(" + titleSuffix + ")" + tree.Root.SetIALAttr("id", tree.ID) + tree.Root.SetIALAttr("title", tree.Root.IALAttr("title")+" "+titleSuffix) + p := path.Join(path.Dir(tree.Path), tree.ID) + ".sy" + tree.Path = p + tree.HPath = tree.HPath + " " + titleSuffix + + // 收集所有引用 + refIDs := map[string]string{} + ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus { + if !entering || ast.NodeBlockRefID != n.Type { + return ast.WalkContinue + } + refIDs[n.TokensStr()] = "1" + return ast.WalkContinue + }) + + // 重置块 ID + ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus { + if !entering || ast.NodeDocument == n.Type { + return ast.WalkContinue + } + if n.IsBlock() && "" != n.ID { + newID := ast.NewNodeID() + if "1" == refIDs[n.ID] { + // 如果是文档自身的内部引用 + refIDs[n.ID] = newID + } + n.ID = newID + n.SetIALAttr("id", n.ID) + } + return ast.WalkContinue + }) + + // 重置内部引用 + ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus { + if !entering || ast.NodeBlockRefID != n.Type { + return ast.WalkContinue + } + if "1" != refIDs[n.TokensStr()] { + n.Tokens = []byte(refIDs[n.TokensStr()]) + } + return ast.WalkContinue + }) +} + func pagedPaths(localPath string, pageSize int) (ret map[int][]string) { ret = map[int][]string{} page := 1 diff --git a/kernel/util/working.go b/kernel/util/working.go index ad3ece011..4aa5142bf 100644 --- a/kernel/util/working.go +++ b/kernel/util/working.go @@ -36,8 +36,7 @@ import ( "github.com/siyuan-note/logging" ) -//var Mode = "dev" -// +// var Mode = "dev" var Mode = "prod" const ( @@ -267,6 +266,7 @@ func initWorkspaceDir(workspaceArg string) { if err := os.MkdirAll(osTmpDir, 0755); nil != err { log.Fatalf("create os tmp dir [%s] failed: %s", osTmpDir, err) } + os.RemoveAll(filepath.Join(TempDir, "repo")) os.Setenv("TMPDIR", osTmpDir) os.Setenv("TEMP", osTmpDir) os.Setenv("TMP", osTmpDir) diff --git a/kernel/util/working_mobile.go b/kernel/util/working_mobile.go index 94cd8c8f4..caf753912 100644 --- a/kernel/util/working_mobile.go +++ b/kernel/util/working_mobile.go @@ -48,6 +48,7 @@ func BootMobile(container, appDir, workspaceDir, nativeLibDir, privateDataDir, l osTmpDir := filepath.Join(TempDir, "os") os.RemoveAll(osTmpDir) os.MkdirAll(osTmpDir, 0755) + os.RemoveAll(filepath.Join(TempDir, "repo")) os.Setenv("TMPDIR", osTmpDir) DBPath = filepath.Join(TempDir, DBName) BlockTreePath = filepath.Join(TempDir, "blocktree.msgpack")