| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- (ns frontend.handler.file
- "Provides util handler fns for files"
- (:refer-clojure :exclude [load-file])
- (:require [frontend.config :as config]
- [frontend.db :as db]
- [frontend.fs :as fs]
- [frontend.fs.nfs :as nfs]
- [frontend.fs.capacitor-fs :as capacitor-fs]
- [frontend.handler.common.file :as file-common-handler]
- [frontend.handler.repo-config :as repo-config-handler]
- [frontend.handler.global-config :as global-config-handler]
- [frontend.handler.ui :as ui-handler]
- [frontend.state :as state]
- [frontend.util :as util]
- [logseq.graph-parser.util :as gp-util]
- [electron.ipc :as ipc]
- [lambdaisland.glogi :as log]
- [promesa.core :as p]
- [frontend.mobile.util :as mobile-util]
- [logseq.graph-parser.config :as gp-config]
- ["path" :as path]))
- ;; TODO: extract all git ops using a channel
- (defn load-file
- [repo-url path]
- (->
- (p/let [content (fs/read-file (config/get-repo-dir repo-url) path)]
- content)
- (p/catch
- (fn [e]
- (println "Load file failed: " path)
- (js/console.error e)))))
- (defn load-multiple-files
- [repo-url paths]
- (doall
- (mapv #(load-file repo-url %) paths)))
- (defn- keep-formats
- [files formats]
- (filter
- (fn [file]
- (let [format (gp-util/get-format file)]
- (contains? formats format)))
- files))
- (defn- only-text-formats
- [files]
- (keep-formats files (gp-config/text-formats)))
- (defn- only-image-formats
- [files]
- (keep-formats files (gp-config/img-formats)))
- (defn load-files-contents!
- [repo-url files ok-handler]
- (let [images (only-image-formats files)
- files (only-text-formats files)]
- (-> (p/all (load-multiple-files repo-url files))
- (p/then (fn [contents]
- (let [file-contents (cond->
- (zipmap files contents)
- (seq images)
- (merge (zipmap images (repeat (count images) ""))))
- file-contents (for [[file content] file-contents]
- {:file/path (gp-util/path-normalize file)
- :file/content content})]
- (ok-handler file-contents))))
- (p/catch (fn [error]
- (log/error :nfs/load-files-error repo-url)
- (log/error :exception error))))))
- (defn backup-file!
- "Backup db content to bak directory"
- [repo-url path db-content content]
- (cond
- (util/electron?)
- (ipc/ipc "backupDbFile" repo-url path db-content content)
- (mobile-util/native-platform?)
- (capacitor-fs/backup-file-handle-changed! repo-url path db-content)
- :else
- nil))
- ;; TODO: Remove this function in favor of `alter-files`
- (defn alter-file
- [repo path content {:keys [reset? re-render-root? from-disk? skip-compare? new-graph? verbose
- skip-db-transact?]
- :or {reset? true
- re-render-root? false
- from-disk? false
- skip-compare? false}}]
- (let [original-content (db/get-file repo path)
- write-file! (if from-disk?
- #(p/resolved nil)
- #(let [path-dir (if (and
- (config/global-config-enabled?)
- (= (path/dirname path) (global-config-handler/global-config-dir)))
- (global-config-handler/global-config-dir)
- (config/get-repo-dir repo))]
- (fs/write-file! repo path-dir path content
- (assoc (when original-content {:old-content original-content})
- :skip-compare? skip-compare?))))
- opts {:new-graph? new-graph?
- :from-disk? from-disk?
- :skip-db-transact? skip-db-transact?}
- result (if reset?
- (do
- (when-not skip-db-transact?
- (when-let [page-id (db/get-file-page-id path)]
- (db/transact! repo
- [[:db/retract page-id :block/alias]
- [:db/retract page-id :block/tags]]
- opts)))
- (file-common-handler/reset-file! repo path content (merge opts
- (when (some? verbose) {:verbose verbose}))))
- (db/set-file-content! repo path content opts))]
- (util/p-handle (write-file!)
- (fn [_]
- (when re-render-root? (ui-handler/re-render-root!))
- (cond
- (= path (config/get-custom-css-path repo))
- (ui-handler/add-style-if-exists!)
- (= path (config/get-repo-config-path repo))
- (p/let [_ (repo-config-handler/restore-repo-config! repo content)]
- (state/pub-event! [:shortcut/refresh]))
- (and (config/global-config-enabled?) (= path (global-config-handler/global-config-path)))
- (p/let [_ (global-config-handler/restore-global-config!)]
- (state/pub-event! [:shortcut/refresh]))))
- (fn [error]
- (when (and (config/global-config-enabled?)
- (= path (global-config-handler/global-config-path)))
- (state/pub-event! [:notification/show
- {:content (str "Failed to write to file " path)
- :status :error}]))
- (println "Write file failed, path: " path ", content: " content)
- (log/error :write/failed error)))
- result))
- (defn set-file-content!
- [repo path new-content]
- (alter-file repo path new-content {:reset? false
- :re-render-root? false}))
- (defn alter-files-handler!
- [repo files {:keys [finish-handler]} file->content]
- (let [write-file-f (fn [[path content]]
- (when path
- (let [original-content (get file->content path)]
- (-> (p/let [_ (or
- (util/electron?)
- (nfs/check-directory-permission! repo))]
- (fs/write-file! repo (config/get-repo-dir repo) path content
- {:old-content original-content}))
- (p/catch (fn [error]
- (state/pub-event! [:notification/show
- {:content (str "Failed to save the file " path ". Error: "
- (str error))
- :status :error
- :clear? false}])
- (state/pub-event! [:instrument {:type :write-file/failed
- :payload {:path path
- :content-length (count content)
- :error-str (str error)
- :error error}}])
- (log/error :write-file/failed {:path path
- :content content
- :error error})))))))
- finish-handler (fn []
- (when finish-handler
- (finish-handler)))]
- (-> (p/all (map write-file-f files))
- (p/then (fn []
- (finish-handler)))
- (p/catch (fn [error]
- (println "Alter files failed:")
- (js/console.error error))))))
- (defn alter-files
- [repo files {:keys [reset? update-db?]
- :or {reset? false
- update-db? true}
- :as opts}]
- ;; old file content
- (let [file->content (let [paths (map first files)]
- (zipmap paths
- (map (fn [path] (db/get-file repo path)) paths)))]
- ;; update db
- (when update-db?
- (doseq [[path content] files]
- (if reset?
- (file-common-handler/reset-file! repo path content)
- (db/set-file-content! repo path content))))
- (alter-files-handler! repo files opts file->content)))
- (defn watch-for-current-graph-dir!
- []
- (when-let [repo (state/get-current-repo)]
- (when-let [dir (config/get-repo-dir repo)]
- ;; An unwatch shouldn't be needed on startup. However not having this
- ;; after an app refresh can cause stale page data to load
- (fs/unwatch-dir! dir)
- (fs/watch-dir! dir))))
- (defn create-metadata-file
- [repo-url encrypted?]
- (let [repo-dir (config/get-repo-dir repo-url)
- path (str config/app-name "/" config/metadata-file)
- file-path (str "/" path)
- default-content (if encrypted? "{:db/encrypted? true}" "{}")]
- (p/let [_ (fs/mkdir-if-not-exists (util/safe-path-join repo-dir config/app-name))
- file-exists? (fs/create-if-not-exists repo-url repo-dir file-path default-content)]
- (when-not file-exists?
- (file-common-handler/reset-file! repo-url path default-content)))))
- (defn create-pages-metadata-file
- [repo-url]
- (let [repo-dir (config/get-repo-dir repo-url)
- path (str config/app-name "/" config/pages-metadata-file)
- file-path (str "/" path)
- default-content "{}"]
- (p/let [_ (fs/mkdir-if-not-exists (util/safe-path-join repo-dir config/app-name))
- file-exists? (fs/create-if-not-exists repo-url repo-dir file-path default-content)]
- (when-not file-exists?
- (file-common-handler/reset-file! repo-url path default-content)))))
|