enhance: backup files when there're differences between db and disk

Previously, files are backuped to logseq/bak when logseq detects
there're differences between the db and disk. But it has two problems:

1. Only a few of users know `logseq/bak`, other users think that their
data has been lost.
2. Files in the logseq/bak folder are never truncated.

This PR backups old file in DB with timestamp suffixes instead of
logesq/bak, and only keep the latest 10 versions of any changed file.
pull/4486/head
Tienson Qin 2022-03-02 11:58:20 +08:00
parent 2e46a6bcb7
commit 8e6fb5613d
4 changed files with 38 additions and 15 deletions

View File

@ -32,6 +32,7 @@
"semver": "7.3.5",
"update-electron-app": "2.0.1",
"extract-zip": "2.0.1",
"diff-match-patch": "1.0.5",
"https-proxy-agent": "5.0.0"
},
"devDependencies": {

View File

@ -6,6 +6,7 @@
["fs-extra" :as fs-extra]
["path" :as path]
["os" :as os]
["diff-match-patch" :as google-diff]
[electron.fs-watcher :as watcher]
[electron.configs :as cfgs]
[promesa.core :as p]
@ -16,7 +17,8 @@
[electron.search :as search]
[electron.git :as git]
[electron.plugin :as plugin]
[electron.window :as win]))
[electron.window :as win]
[goog.object :as gobj]))
(defmulti handle (fn [_window args] (keyword (first args))))
@ -56,21 +58,36 @@
new-path (str recycle-dir "/" file-name)]
(fs/renameSync path new-path))))
(defonce Diff (google-diff.))
(defn string-some-deleted?
[old new]
(let [result (.diff_main Diff old new)]
(some (fn [a] (= -1 (first a))) result)))
(defn- truncate-old-versioned-files!
[file-path]
(let [dir (path/dirname file-path)
files (fs/readdirSync dir (clj->js {:withFileTypes true}))
files (map #(.-name %) files)
prefix (str (path/basename file-path) ".")
versioned-files (filter #(string/starts-with? % prefix) files)
old-versioned-files (drop 10 (reverse (sort versioned-files)))]
(doseq [file old-versioned-files]
(fs-extra/removeSync (path/join dir file)))))
(defn backup-file
[repo path content]
(let [file-name (-> (string/replace path (str repo "/") "")
(string/replace "/" "_")
(string/replace "\\" "_"))
bak-dir (str repo "/logseq/bak")
_ (fs-extra/ensureDirSync bak-dir)
new-path (str bak-dir "/" file-name "."
(string/replace (.toISOString (js/Date.)) ":" "_"))]
(let [new-path (str path "." (string/replace (.toISOString (js/Date.)) ":" "_"))]
(fs/writeFileSync new-path content)
(fs/statSync new-path)
(truncate-old-versioned-files! path)
new-path))
(defmethod handle :backupDbFile [_window [_ repo path db-content]]
(backup-file repo path db-content))
(defmethod handle :backupDbFile [_window [_ repo path db-content new-content]]
(when (and (string? db-content)
(string? new-content)
(string-some-deleted? db-content new-content))
(backup-file repo path db-content)))
(defmethod handle :readFile [_window [_ path]]
(utils/read-file path))
@ -80,7 +97,7 @@
(assert (string? path))
(try
(fs/accessSync path (aget fs "W_OK"))
(catch js/Error _e
(catch :default _e
false)))
(defmethod handle :writeFile [_window [_ repo path content]]
@ -93,10 +110,10 @@
(fs/chmodSync path "644"))
(fs/writeFileSync path content)
(fs/statSync path)
(catch js/Error e
(catch :default e
(let [backup-path (try
(backup-file repo path content)
(catch js/Error e
(catch :default e
(println "Backup file failed")
(js/console.dir e)))]
(utils/send-to-renderer "notification" {:type "error"

View File

@ -33,8 +33,8 @@
(defn- handle-add-and-change!
[repo path content db-content mtime backup?]
(p/let [
;; save the previous content in a bak file to avoid data overwritten.
_ (when backup? (ipc/ipc "backupDbFile" (config/get-local-dir repo) path db-content))
;; save the previous content in a versioned bak file to avoid data overwritten.
_ (when backup? (ipc/ipc "backupDbFile" (config/get-local-dir repo) path db-content content))
_ (file-handler/alter-file repo path content {:re-render-root? true
:from-disk? true})]
(set-missing-block-ids! content)

View File

@ -1529,6 +1529,11 @@ detect-node@^2.0.4:
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
diff-match-patch@1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37"
integrity sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==
dir-compare@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/dir-compare/-/dir-compare-2.4.0.tgz#785c41dc5f645b34343a4eafc50b79bac7f11631"