Bläddra i källkod

refactor(fs): refactor bfs to memory-fs, add memory:// support

Andelf 2 år sedan
förälder
incheckning
e95d73059b

+ 0 - 1
deps/graph-parser/src/logseq/graph_parser/extract.cljc

@@ -186,7 +186,6 @@
 (defn extract
 (defn extract
   "Extracts pages, blocks and ast from given file"
   "Extracts pages, blocks and ast from given file"
   [file-path content {:keys [user-config verbose] :or {verbose true} :as options}]
   [file-path content {:keys [user-config verbose] :or {verbose true} :as options}]
-  (prn ::extract file-path)
   (if (string/blank? content)
   (if (string/blank? content)
     []
     []
     (let [format (gp-util/get-format file-path)
     (let [format (gp-util/get-format file-path)

+ 30 - 19
src/main/frontend/config.cljs

@@ -8,7 +8,8 @@
             [frontend.util :as util]
             [frontend.util :as util]
             [logseq.graph-parser.config :as gp-config]
             [logseq.graph-parser.config :as gp-config]
             [logseq.graph-parser.util :as gp-util]
             [logseq.graph-parser.util :as gp-util]
-            [shadow.resource :as rc]))
+            [shadow.resource :as rc]
+            [frontend.fs2.path :as path]))
 
 
 (goog-define DEV-RELEASE false)
 (goog-define DEV-RELEASE false)
 (defonce dev-release? DEV-RELEASE)
 (defonce dev-release? DEV-RELEASE)
@@ -329,8 +330,8 @@
   "Demo graph or nil graph?"
   "Demo graph or nil graph?"
   ([]
   ([]
    (demo-graph? (state/get-current-repo)))
    (demo-graph? (state/get-current-repo)))
-  ([graph]
-   (or (nil? graph) (= graph local-repo))))
+  ([repo-url]
+   (or (nil? repo-url) (= repo-url local-repo))))
 
 
 (defonce recycle-dir ".recycle")
 (defonce recycle-dir ".recycle")
 (def config-file "config.edn")
 (def config-file "config.edn")
@@ -369,14 +370,21 @@
 
 
     (and (mobile-util/native-platform?) (local-db? repo-url))
     (and (mobile-util/native-platform?) (local-db? repo-url))
     (let [dir (get-local-dir repo-url)]
     (let [dir (get-local-dir repo-url)]
-      (if (string/starts-with? dir "file:")
+      (if (string/starts-with? dir "file://")
         dir
         dir
+        ;; FIXME(andelf): should not use str to concat file:// url
         (str "file:///" (string/replace dir #"^/+" ""))))
         (str "file:///" (string/replace dir #"^/+" ""))))
 
 
+    ;; Special handling for demo graph
+    (= repo-url "local")
+    "memory:///local"
+
     :else
     :else
-    (str "/"
-         (->> (take-last 2 (string/split repo-url #"/"))
-              (string/join "_")))))
+    (do
+      (js/console.error "BUG: get-repo-dir" repo-url)
+      (str "/"
+           (->> (take-last 2 (string/split repo-url #"/"))
+                (string/join "_"))))))
 
 
 (defn get-string-repo-dir
 (defn get-string-repo-dir
   [repo-dir]
   [repo-dir]
@@ -406,23 +414,26 @@
 
 
 (defn get-file-path
 (defn get-file-path
   "Normalization happens here"
   "Normalization happens here"
-  [repo-url relative-path]
-  (js/console.error "::SHOULD-NOT-USE-BUGGY-FN" repo-url relative-path)
-  (when (and repo-url relative-path)
+  [repo-url rpath]
+  (js/console.error "BUG SHOULD-NOT-USE-BUGGY-FN" repo-url rpath)
+  (when (and repo-url rpath)
     (let [path (cond
     (let [path (cond
                  (demo-graph?)
                  (demo-graph?)
-                 nil
+                 (let [dir (get-repo-dir repo-url)
+                       r (fs2-path/path-join dir rpath)]
+                   (js/console.error "get-file-path" r)
+                   r)
 
 
                  (and (util/electron?) (local-db? repo-url))
                  (and (util/electron?) (local-db? repo-url))
                  (let [dir (get-repo-dir repo-url)]
                  (let [dir (get-repo-dir repo-url)]
-                   (if (string/starts-with? relative-path dir)
-                     relative-path
+                   (if (string/starts-with? rpath dir)
+                     rpath
                      (str dir "/"
                      (str dir "/"
-                          (string/replace relative-path #"^/" ""))))
+                          (string/replace rpath #"^/" ""))))
 
 
                  (and (mobile-util/native-ios?) (local-db? repo-url))
                  (and (mobile-util/native-ios?) (local-db? repo-url))
                  (let [dir (get-repo-dir repo-url)]
                  (let [dir (get-repo-dir repo-url)]
-                   (util/safe-path-join dir relative-path))
+                   (fs2-path/path-join dir rpath))
 
 
                  (and (mobile-util/native-android?) (local-db? repo-url))
                  (and (mobile-util/native-android?) (local-db? repo-url))
                  (let [dir (get-repo-dir repo-url)
                  (let [dir (get-repo-dir repo-url)
@@ -430,13 +441,13 @@
                                    (string/starts-with? dir "content:"))
                                    (string/starts-with? dir "content:"))
                              dir
                              dir
                              (str "file:///" (string/replace dir #"^/+" "")))]
                              (str "file:///" (string/replace dir #"^/+" "")))]
-                   (util/safe-path-join dir relative-path))
+                   (util/safe-path-join dir rpath))
 
 
-                 (= "/" (first relative-path))
-                 (subs relative-path 1)
+                 (= "/" (first rpath))
+                 (subs rpath 1)
 
 
                  :else
                  :else
-                 relative-path)]
+                 rpath)]
       (and (not-empty path) (gp-util/path-normalize path)))))
       (and (not-empty path) (gp-util/path-normalize path)))))
 
 
 ;; NOTE: js/encodeURIComponent cannot be used here
 ;; NOTE: js/encodeURIComponent cannot be used here

+ 3 - 1
src/main/frontend/db/model.cljs

@@ -262,6 +262,8 @@
   ([path]
   ([path]
    (get-file (state/get-current-repo) path))
    (get-file (state/get-current-repo) path))
   ([repo path]
   ([repo path]
+   (when (string/starts-with? path "/")
+     (js/console.error "BUG: Using absolute path while querying DB"))
    (when (and repo path)
    (when (and repo path)
      (when-let [db (conn/get-db repo)]
      (when-let [db (conn/get-db repo)]
        (:file/content (db-utils/entity db [:file/path path]))))))
        (:file/content (db-utils/entity db [:file/path path]))))))
@@ -269,7 +271,7 @@
 (defn get-custom-css
 (defn get-custom-css
   []
   []
   (when-let [repo (state/get-current-repo)]
   (when-let [repo (state/get-current-repo)]
-    (get-file (config/get-file-path repo "logseq/custom.css"))))
+    (get-file repo "logseq/custom.css")))
 
 
 (defn get-block-by-uuid
 (defn get-block-by-uuid
   [id]
   [id]

+ 34 - 31
src/main/frontend/fs.cljs

@@ -6,7 +6,7 @@
             [frontend.fs.nfs :as nfs]
             [frontend.fs.nfs :as nfs]
             [frontend.fs.node :as node]
             [frontend.fs.node :as node]
             [frontend.fs.capacitor-fs :as capacitor-fs]
             [frontend.fs.capacitor-fs :as capacitor-fs]
-            [frontend.fs.bfs :as bfs]
+            [frontend.fs.memory-fs :as bfs]
             [frontend.mobile.util :as mobile-util]
             [frontend.mobile.util :as mobile-util]
             [frontend.fs.protocol :as protocol]
             [frontend.fs.protocol :as protocol]
             [frontend.util :as util]
             [frontend.util :as util]
@@ -19,10 +19,10 @@
             [logseq.graph-parser.util :as gp-util]
             [logseq.graph-parser.util :as gp-util]
             [electron.ipc :as ipc]))
             [electron.ipc :as ipc]))
 
 
-(defonce nfs-record (nfs/->Nfs))
-(defonce bfs-record (bfs/->Bfs))
-(defonce node-record (node/->Node))
-(defonce mobile-record (capacitor-fs/->Capacitorfs))
+(defonce nfs-backend (nfs/->Nfs))
+(defonce memory-backend (bfs/->Bfs))
+(defonce node-backend (node/->Node))
+(defonce mobile-backend (capacitor-fs/->Capacitorfs))
 
 
 (defn local-db?
 (defn local-db?
   [dir]
   [dir]
@@ -34,17 +34,22 @@
   (let [bfs-local? (or (string/starts-with? dir "/local")
   (let [bfs-local? (or (string/starts-with? dir "/local")
                        (string/starts-with? dir "local"))]
                        (string/starts-with? dir "local"))]
     (cond
     (cond
+      (string/starts-with? dir "memory://")
+      (do
+        ; (prn ::debug-using-memory-backend)
+        memory-backend)
+
       (and (util/electron?) (not bfs-local?))
       (and (util/electron?) (not bfs-local?))
-      node-record
+      node-backend
 
 
       (mobile-util/native-platform?)
       (mobile-util/native-platform?)
-      mobile-record
+      mobile-backend
 
 
       (local-db? dir)
       (local-db? dir)
-      nfs-record
+      nfs-backend
 
 
       :else
       :else
-      bfs-record)))
+      memory-backend)))
 
 
 (defn mkdir!
 (defn mkdir!
   [dir]
   [dir]
@@ -73,14 +78,14 @@
    Warning: only run it for browser cache."
    Warning: only run it for browser cache."
   [dir]
   [dir]
   (when-let [fs (get-fs dir)]
   (when-let [fs (get-fs dir)]
-    (when (= fs bfs-record)
+    (when (= fs memory-backend)
       (protocol/rmdir! fs dir))))
       (protocol/rmdir! fs dir))))
 
 
 ;; TODO(andelf): distingush from graph file writing and global file write
 ;; TODO(andelf): distingush from graph file writing and global file write
 (defn write-file!
 (defn write-file!
-  [repo dir path content opts]
+  [repo dir rpath content opts]
   (when content
   (when content
-    (let [path (gp-util/path-normalize path)
+    (let [path (gp-util/path-normalize rpath)
           fs-record (get-fs dir)]
           fs-record (get-fs dir)]
       (->
       (->
        (p/let [opts (assoc opts
        (p/let [opts (assoc opts
@@ -91,9 +96,7 @@
                                                                           :fs (type fs-record)
                                                                           :fs (type fs-record)
                                                                           :user-agent (when js/navigator js/navigator.userAgent)
                                                                           :user-agent (when js/navigator js/navigator.userAgent)
                                                                           :content-length (count content)}}])))
                                                                           :content-length (count content)}}])))
-               _ (protocol/write-file! (get-fs dir) repo dir path content opts)]
-         (when (= bfs-record fs-record)
-           (db/set-file-last-modified-at! repo (config/get-file-path repo path) (js/Date.))))
+               _ (protocol/write-file! (get-fs dir) repo dir path content opts)])
        (p/catch (fn [error]
        (p/catch (fn [error]
                   (log/error :file/write-failed {:dir dir
                   (log/error :file/write-failed {:dir dir
                                                  :path path
                                                  :path path
@@ -105,7 +108,7 @@
 (defn read-file
 (defn read-file
   ([dir path]
   ([dir path]
    (let [fs (get-fs dir)
    (let [fs (get-fs dir)
-         options (if (= fs bfs-record)
+         options (if (= fs memory-backend)
                    {:encoding "utf8"}
                    {:encoding "utf8"}
                    {})]
                    {})]
      (read-file dir path options)))
      (read-file dir path options)))
@@ -146,21 +149,22 @@
   [dir path]
   [dir path]
   (protocol/stat (get-fs dir) dir path))
   (protocol/stat (get-fs dir) dir path))
 
 
-(defn- get-record
+(defn- get-native-backend
+  "Native FS backend of current platform"
   []
   []
   (cond
   (cond
     (util/electron?)
     (util/electron?)
-    node-record
+    node-backend
 
 
     (mobile-util/native-platform?)
     (mobile-util/native-platform?)
-    mobile-record
+    mobile-backend
 
 
     :else
     :else
-    nfs-record))
+    nfs-backend))
 
 
 (defn open-dir
 (defn open-dir
   [dir ok-handler]
   [dir ok-handler]
-  (let [record (get-record)]
+  (let [record (get-native-backend)]
     (p/let [result (protocol/open-dir record dir ok-handler)]
     (p/let [result (protocol/open-dir record dir ok-handler)]
       (if (or (util/electron?)
       (if (or (util/electron?)
               (mobile-util/native-platform?))
               (mobile-util/native-platform?))
@@ -178,7 +182,7 @@
   "List all files in the directory, recursively.
   "List all files in the directory, recursively.
    {:path :files []}"
    {:path :files []}"
   [path-or-handle ok-handler]
   [path-or-handle ok-handler]
-  (let [fs-record (get-record)]
+  (let [fs-record (get-native-backend)]
     (when ok-handler
     (when ok-handler
       (js/console.warn "ok-handler not nil"))
       (js/console.warn "ok-handler not nil"))
     (p/let [result (protocol/list-files fs-record path-or-handle ok-handler)]
     (p/let [result (protocol/list-files fs-record path-or-handle ok-handler)]
@@ -198,11 +202,11 @@
 
 
 (defn watch-dir!
 (defn watch-dir!
   ([dir] (watch-dir! dir {}))
   ([dir] (watch-dir! dir {}))
-  ([dir options] (protocol/watch-dir! (get-record) dir options)))
+  ([dir options] (protocol/watch-dir! (get-fs dir) dir options)))
 
 
 (defn unwatch-dir!
 (defn unwatch-dir!
   [dir]
   [dir]
-  (protocol/unwatch-dir! (get-record) dir))
+  (protocol/unwatch-dir! (get-fs dir) dir))
 
 
 (defn mkdir-if-not-exists
 (defn mkdir-if-not-exists
   [dir]
   [dir]
@@ -219,13 +223,12 @@
   ([repo dir path]
   ([repo dir path]
    (create-if-not-exists repo dir path ""))
    (create-if-not-exists repo dir path ""))
   ([repo dir path initial-content]
   ([repo dir path initial-content]
-   (let []
-     (-> (p/let [_stat (stat dir path)]
-           true)
-         (p/catch
-          (fn [_error]
-            (p/let [_ (write-file! repo dir path initial-content nil)]
-              false)))))))
+   (-> (p/let [_stat (stat dir path)]
+         true)
+       (p/catch
+        (fn [_error]
+          (p/let [_ (write-file! repo dir path initial-content nil)]
+            false))))))
 
 
 (defn file-exists?
 (defn file-exists?
   [dir path]
   [dir path]

+ 0 - 40
src/main/frontend/fs/bfs.cljs

@@ -1,40 +0,0 @@
-(ns ^:no-doc frontend.fs.bfs
-  (:require [frontend.fs.protocol :as protocol]
-            [frontend.util :as util]
-            [promesa.core :as p]))
-
-(defrecord Bfs []
-  protocol/Fs
-  (mkdir! [_this dir]
-    (when (and js/window.pfs (not (util/electron?)))
-      (->
-       (js/window.pfs.mkdir dir)
-       (p/catch (fn [error] (println "Mkdir error: " error))))))
-  (readdir [_this dir]
-    (when js/window.pfs
-      (js/window.pfs.readdir dir)))
-  (unlink! [_this _repo path opts]
-    (when js/window.pfs
-      (p/let [stat (js/window.pfs.stat path)]
-        (if (= (.-type stat) "file")
-          (js/window.pfs.unlink path opts)
-          (p/rejected "Unlinking a directory is not allowed")))))
-  (rmdir! [_this dir]
-    (js/window.workerThread.rimraf dir))
-  (read-file [_this dir path options]
-    (js/window.pfs.readFile (str dir "/" path) (clj->js options)))
-  (write-file! [_this _repo dir path content _opts]
-    (when-not (util/electron?)
-      (js/window.pfs.writeFile (str dir "/" path) content)))
-  (rename! [_this _repo old-path new-path]
-    (js/window.pfs.rename old-path new-path))
-  (stat [_this dir path]
-    (js/window.pfs.stat (str dir path)))
-  (open-dir [_this _dir _ok-handler]
-    nil)
-  (list-files [_this _path-or-handle _ok-handler]
-    nil)
-  (watch-dir! [_this _dir _options]
-    nil)
-  (unwatch-dir! [_this _dir]
-    nil))

+ 104 - 0
src/main/frontend/fs/memory_fs.cljs

@@ -0,0 +1,104 @@
+(ns ^:no-doc frontend.fs.memory-fs
+  "Memory FS backed by lightning-fs
+   
+   denoted by `memory://`"
+  (:require [cljs-bean.core :as bean]
+            [frontend.db :as db]
+            [frontend.fs.protocol :as protocol]
+            [frontend.fs2.path :as fs2-path]
+            [promesa.core :as p]))
+
+(defn- <readdir
+  "Read dir recursively, return all paths
+   
+   accept dir as path, without memory:// prefix for simplicity"
+  [dir]
+  (p/let [result (p/loop [result []
+                          dirs [dir]]
+                   (if (empty? dirs)
+                     result
+                     (p/let [dir (first dirs)
+                             stat (js/window.pfs.stat dir)
+                             is-file? (= (.-type stat) "file")
+                             result (if is-file?
+                                      (conj result dir)
+                                      result)
+                             dir-content (when-not is-file?
+                                           (-> (js/window.pfs.readdir dir)
+                                               (p/then bean/->clj)
+                                               (p/then (fn [rpaths]
+                                                         (mapv #(fs2-path/path-join dir %) rpaths)))))]
+                       (p/recur result (concat (rest dirs) dir-content)))))]
+    result))
+
+
+(defn- <ensure-dir!
+  "dir is path, without memory:// prefix for simplicity"
+  [dir]
+  (-> (p/let [stat (js/window.pfs.stat dir)]
+        (cond
+          (= (.-type stat) "file")
+          (p/rejected "Path is a file")
+
+          :else
+          (p/resolved nil)))
+      (p/catch (fn [_error]
+                 (js/window.pfs.mkdir dir)))))
+  
+
+(defrecord Bfs []
+  protocol/Fs
+  (mkdir! [_this dir]
+    (js/console.trace)
+    (when js/window.pfs
+      (let [fpath (fs2-path/url-to-path dir)]
+        (-> (js/window.pfs.mkdir fpath)
+            (p/catch (fn [error] (println "Mkdir error: " error)))))))
+  (readdir [_this dir]
+    (when js/window.pfs
+      (let [fpath (fs2-path/url-to-path dir)]
+        (-> (<readdir fpath)
+            ;; (p/then bean/->clj)
+            (p/then (fn [rpaths]
+                      (prn ::debug rpaths)
+                      (mapv #(fs2-path/path-join "memory://" %) rpaths)))))))
+
+  (unlink! [_this _repo path opts]
+    (when js/window.pfs
+      (p/let [fpath (fs2-path/url-to-path path)
+              stat (js/window.pfs.stat fpath)]
+        (if (= (.-type stat) "file")
+          (js/window.pfs.unlink fpath opts)
+          (p/rejected "Unlinking a directory is not allowed, use rmdir! instead")))))
+  (rmdir! [_this dir]
+    (let [fpath (fs2-path/url-to-path dir)]
+      (js/window.workerThread.rimraf fpath)))
+  (read-file [_this dir path options]
+    (let [fpath (fs2-path/url-to-path (fs2-path/path-join dir path))]
+      (js/window.pfs.readFile fpath (clj->js options))))
+  (write-file! [_this repo dir rpath content _opts]
+    (p/let [fpath (fs2-path/url-to-path (fs2-path/path-join dir rpath))
+            containing-dir (fs2-path/parent fpath)
+            _ (<ensure-dir! containing-dir)
+            _ (js/window.pfs.writeFile fpath content)]
+      (db/set-file-content! repo rpath content)
+      (db/set-file-last-modified-at! repo rpath (js/Date.))))
+  (rename! [_this _repo old-path new-path]
+    (let [old-path (fs2-path/url-to-path old-path)
+          new-path (fs2-path/url-to-path new-path)]
+      (js/window.pfs.rename old-path new-path)))
+  ;; FIXME(andelf): API sign for dir-only state
+  (stat [_this dir path]
+    (if path
+      (let [fpath (fs2-path/url-to-path (fs2-path/path-join dir path))]
+        (js/window.pfs.stat fpath))
+      (let [fpath (fs2-path/url-to-path dir)]
+        (js/window.pfs.stat fpath))))
+  (open-dir [_this _dir _ok-handler]
+    nil)
+  (list-files [_this _path-or-handle _ok-handler]
+    nil)
+  (watch-dir! [_this _dir _options]
+    nil)
+  (unwatch-dir! [_this _dir]
+    nil))

+ 8 - 2
src/main/frontend/fs2/path.cljs

@@ -12,6 +12,7 @@
            (string/starts-with? s "content://") ;; android only
            (string/starts-with? s "content://") ;; android only
            (string/starts-with? s "assets://") ;; FIXME: Electron asset, not urlencoded
            (string/starts-with? s "assets://") ;; FIXME: Electron asset, not urlencoded
            (string/starts-with? s "logseq://") ;; reserved for future fs protocl
            (string/starts-with? s "logseq://") ;; reserved for future fs protocl
+           (string/starts-with? s "memory://") ;; special memory fs
            (string/starts-with? s "s3://"))))
            (string/starts-with? s "s3://"))))
 
 
 
 
@@ -201,13 +202,18 @@
         sub-path))))
         sub-path))))
 
 
 (defn url-to-path
 (defn url-to-path
-  "Extract path part of a URL. decoded"
+  "Extract path part of a URL, decoded.
+   
+   The reverse operation is (path-join protocl:// path)"
   [original-url]
   [original-url]
   (if (is-file-url original-url)
   (if (is-file-url original-url)
     ;; NOTE: URL type is not consistent across all protocols
     ;; NOTE: URL type is not consistent across all protocols
     ;; Check file:// and assets://, pathname behavior is different
     ;; Check file:// and assets://, pathname behavior is different
     (let [^js url (js/URL. (string/replace original-url "assets://" "file://"))
     (let [^js url (js/URL. (string/replace original-url "assets://" "file://"))
-          path (gp-util/safe-decode-uri-component (.-pathname url))]
+          path (gp-util/safe-decode-uri-component (.-pathname url))
+          path (if (string/starts-with? path "///")
+                 (subs path 2)
+                 path)]
       path)
       path)
     original-url))
     original-url))
 
 

+ 2 - 3
src/main/frontend/handler/file.cljs

@@ -21,7 +21,6 @@
             [promesa.core :as p]
             [promesa.core :as p]
             [frontend.mobile.util :as mobile-util]
             [frontend.mobile.util :as mobile-util]
             [logseq.graph-parser.config :as gp-config]
             [logseq.graph-parser.config :as gp-config]
-            [clojure.string :as string]
             ["path" :as path]))
             ["path" :as path]))
 
 
 ;; TODO: extract all git ops using a channel
 ;; TODO: extract all git ops using a channel
@@ -163,10 +162,10 @@
               (when re-render-root? (ui-handler/re-render-root!))
               (when re-render-root? (ui-handler/re-render-root!))
 
 
               (cond
               (cond
-                (= path "logseq/custom.css") ; (= path (config/get-custom-css-path repo))
+                (= path "logseq/custom.css")
                 (ui-handler/add-style-if-exists!)
                 (ui-handler/add-style-if-exists!)
 
 
-                (= path "logseq/config.edn") ; (= path (config/get-repo-config-path repo))
+                (= path "logseq/config.edn")
                 (p/let [_ (repo-config-handler/restore-repo-config! repo content)]
                 (p/let [_ (repo-config-handler/restore-repo-config! repo content)]
                   (state/pub-event! [:shortcut/refresh]))
                   (state/pub-event! [:shortcut/refresh]))
 
 

+ 4 - 4
src/main/frontend/handler/page.cljs

@@ -838,13 +838,13 @@
               today-page (util/page-name-sanity-lc title)
               today-page (util/page-name-sanity-lc title)
               format (state/get-preferred-format repo)
               format (state/get-preferred-format repo)
               file-name (date/journal-title->default title)
               file-name (date/journal-title->default title)
-              file-path (str (config/get-journals-directory) "/" file-name "."
-                        (config/get-file-extension format))
+              file-rpath (str (config/get-journals-directory) "/" file-name "."
+                              (config/get-file-extension format))
               repo-dir (config/get-repo-dir repo)
               repo-dir (config/get-repo-dir repo)
               template (state/get-default-journal-template)]
               template (state/get-default-journal-template)]
-          (p/let [file-exists? (fs/file-exists? repo-dir file-path)
+          (p/let [file-exists? (fs/file-exists? repo-dir file-rpath)
                   file-content (when file-exists?
                   file-content (when file-exists?
-                                 (fs/read-file repo-dir file-path))]
+                                 (fs/read-file repo-dir file-rpath))]
             (when (and (db/page-empty? repo today-page)
             (when (and (db/page-empty? repo today-page)
                        (or (not file-exists?)
                        (or (not file-exists?)
                            (and file-exists? (string/blank? file-content))))
                            (and file-exists? (string/blank? file-content))))

+ 18 - 17
src/main/frontend/handler/repo.cljs

@@ -30,7 +30,8 @@
             [cljs-bean.core :as bean]
             [cljs-bean.core :as bean]
             [clojure.core.async :as async]
             [clojure.core.async :as async]
             [frontend.mobile.util :as mobile-util]
             [frontend.mobile.util :as mobile-util]
-            [medley.core :as medley]))
+            [medley.core :as medley]
+            [frontend.fs2.path :as fs2-path]))
 
 
 ;; Project settings should be checked in two situations:
 ;; Project settings should be checked in two situations:
 ;; 1. User changes the config.edn directly in logseq.com (fn: alter-file)
 ;; 1. User changes the config.edn directly in logseq.com (fn: alter-file)
@@ -41,7 +42,7 @@
   (spec/validate :repos/url repo-url)
   (spec/validate :repos/url repo-url)
   (p/let [repo-dir (config/get-repo-dir repo-url)
   (p/let [repo-dir (config/get-repo-dir repo-url)
           pages-dir (state/get-pages-directory)
           pages-dir (state/get-pages-directory)
-          [org-path md-path] (map #(str "/" pages-dir "/contents." %) ["org" "md"])
+          [org-path md-path] (map #(str pages-dir "/contents." %) ["org" "md"])
           contents-file-exist? (some #(fs/file-exists? repo-dir %) [org-path md-path])]
           contents-file-exist? (some #(fs/file-exists? repo-dir %) [org-path md-path])]
     (when-not contents-file-exist?
     (when-not contents-file-exist?
       (let [format (state/get-preferred-format)
       (let [format (state/get-preferred-format)
@@ -64,7 +65,7 @@
         path (str config/app-name "/" config/custom-css-file)
         path (str config/app-name "/" config/custom-css-file)
         file-rpath path
         file-rpath path
         default-content ""]
         default-content ""]
-    (p/let [_ (fs/mkdir-if-not-exists (util/safe-path-join repo-dir config/app-name))
+    (p/let [_ (fs/mkdir-if-not-exists (fs2-path/path-join repo-dir config/app-name))
             file-exists? (fs/create-if-not-exists repo-url repo-dir file-rpath default-content)]
             file-exists? (fs/create-if-not-exists repo-url repo-dir file-rpath default-content)]
       (when-not file-exists?
       (when-not file-exists?
         (file-common-handler/reset-file! repo-url path default-content)))))
         (file-common-handler/reset-file! repo-url path default-content)))))
@@ -73,11 +74,10 @@
   [repo-url content]
   [repo-url content]
   (spec/validate :repos/url repo-url)
   (spec/validate :repos/url repo-url)
   (let [repo-dir (config/get-repo-dir repo-url)
   (let [repo-dir (config/get-repo-dir repo-url)
-        path (str (config/get-pages-directory) "/how_to_make_dummy_notes.md")
-        file-path (str "/" path)]
-    (p/let [_ (fs/mkdir-if-not-exists (util/safe-path-join repo-dir (config/get-pages-directory)))
-            _file-exists? (fs/create-if-not-exists repo-url repo-dir file-path content)]
-      (file-common-handler/reset-file! repo-url path content))))
+        file-rpath (str (config/get-pages-directory) "/how_to_make_dummy_notes.md")]
+    (p/let [_ (fs/mkdir-if-not-exists (fs2-path/path-join repo-dir (config/get-pages-directory)))
+            _file-exists? (fs/create-if-not-exists repo-url repo-dir file-rpath content)]
+      (file-common-handler/reset-file! repo-url file-rpath content))))
 
 
 (defn- create-today-journal-if-not-exists
 (defn- create-today-journal-if-not-exists
   [repo-url {:keys [content]}]
   [repo-url {:keys [content]}]
@@ -101,18 +101,17 @@
 
 
                     :else
                     :else
                     default-content)
                     default-content)
-          path (util/safe-path-join (config/get-journals-directory) (str file-name "."
-                                                                         (config/get-file-extension format)))
-          file-path (str "/" path)
+          file-rpath (fs2-path/path-join (config/get-journals-directory) (str file-name "."
+                                                                              (config/get-file-extension format)))
           page-exists? (db/entity repo-url [:block/name (util/page-name-sanity-lc title)])
           page-exists? (db/entity repo-url [:block/name (util/page-name-sanity-lc title)])
           empty-blocks? (db/page-empty? repo-url (util/page-name-sanity-lc title))]
           empty-blocks? (db/page-empty? repo-url (util/page-name-sanity-lc title))]
       (when (or empty-blocks? (not page-exists?))
       (when (or empty-blocks? (not page-exists?))
         (p/let [_ (nfs/check-directory-permission! repo-url)
         (p/let [_ (nfs/check-directory-permission! repo-url)
-                _ (fs/mkdir-if-not-exists (util/safe-path-join repo-dir (config/get-journals-directory)))
-                file-exists? (fs/file-exists? repo-dir file-path)]
+                _ (fs/mkdir-if-not-exists (fs2-path/path-join repo-dir (config/get-journals-directory)))
+                file-exists? (fs/file-exists? repo-dir file-rpath)]
           (when-not file-exists?
           (when-not file-exists?
-            (p/let [_ (file-common-handler/reset-file! repo-url path content)]
-              (p/let [_ (fs/create-if-not-exists repo-url repo-dir file-path content)]
+            (p/let [_ (file-common-handler/reset-file! repo-url file-rpath content)]
+              (p/let [_ (fs/create-if-not-exists repo-url repo-dir file-rpath content)]
                 (when-not (state/editing?)
                 (when-not (state/editing?)
                   (ui-handler/re-render-root!)))))
                   (ui-handler/re-render-root!)))))
           (when-not (state/editing?)
           (when-not (state/editing?)
@@ -374,8 +373,9 @@
   []
   []
   ;; loop query if js/window.pfs is ready, interval 100ms
   ;; loop query if js/window.pfs is ready, interval 100ms
   (if js/window.pfs
   (if js/window.pfs
-    (let [repo config/local-repo]
-      (p/do! (fs/mkdir-if-not-exists (str "/" repo))
+    (let [repo config/local-repo
+          repo-dir (config/get-repo-dir repo)]
+      (p/do! (fs/mkdir-if-not-exists repo-dir) ;; create memory://local
              (state/set-current-repo! repo)
              (state/set-current-repo! repo)
              (db/start-db-conn! repo)
              (db/start-db-conn! repo)
              (when-not config/publishing?
              (when-not config/publishing?
@@ -394,6 +394,7 @@
             setup-local-repo-if-not-exists-impl!)))
             setup-local-repo-if-not-exists-impl!)))
 
 
 (defn setup-local-repo-if-not-exists!
 (defn setup-local-repo-if-not-exists!
+  "Setup demo repo, i.e. `local-repo`"
   []
   []
   ;; ensure `(state/set-db-restoring! false)` at exit
   ;; ensure `(state/set-db-restoring! false)` at exit
   (-> (setup-local-repo-if-not-exists-impl!)
   (-> (setup-local-repo-if-not-exists-impl!)

+ 15 - 14
src/main/frontend/handler/repo_config.cljs

@@ -3,19 +3,20 @@
   This component only concerns itself with one user-facing repo config file,
   This component only concerns itself with one user-facing repo config file,
   logseq/config.edn. In the future it may manage more files. This component
   logseq/config.edn. In the future it may manage more files. This component
   depends on a repo."
   depends on a repo."
-  (:require [frontend.db :as db]
+  (:require [clojure.edn :as edn]
             [frontend.config :as config]
             [frontend.config :as config]
-            [frontend.state :as state]
+            [frontend.db :as db]
+            [frontend.fs :as fs]
+            [frontend.fs2.path :as fs2-path]
             [frontend.handler.common.file :as file-common-handler]
             [frontend.handler.common.file :as file-common-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.notification :as notification]
-            [frontend.fs :as fs]
-            [promesa.core :as p]
-            [clojure.edn :as edn]
-            [frontend.spec :as spec]))
+            [frontend.spec :as spec]
+            [frontend.state :as state]
+            [promesa.core :as p]))
 
 
 (defn- get-repo-config-content
 (defn- get-repo-config-content
   [repo-url]
   [repo-url]
-  (db/get-file repo-url (config/get-repo-config-path)))
+  (db/get-file repo-url "logseq/config.edn"))
 
 
 (defn read-repo-config
 (defn read-repo-config
   "Converts file content to edn"
   "Converts file content to edn"
@@ -40,14 +41,14 @@
   (spec/validate :repos/url repo-url)
   (spec/validate :repos/url repo-url)
   (let [repo-dir (config/get-repo-dir repo-url)
   (let [repo-dir (config/get-repo-dir repo-url)
         app-dir config/app-name
         app-dir config/app-name
-        dir (str repo-dir "/" app-dir)]
+        dir (fs2-path/path-join repo-dir app-dir)]
     (p/let [_ (fs/mkdir-if-not-exists dir)]
     (p/let [_ (fs/mkdir-if-not-exists dir)]
-           (let [default-content config/config-default-content
-                  path (str app-dir "/" config/config-file)]
-             (p/let [file-exists? (fs/create-if-not-exists repo-url repo-dir "logseq/config.edn" default-content)]
-                    (when-not file-exists?
-                      (file-common-handler/reset-file! repo-url path default-content)
-                      (set-repo-config-state! repo-url default-content)))))))
+      (let [default-content config/config-default-content
+            path (str app-dir "/" config/config-file)]
+        (p/let [file-exists? (fs/create-if-not-exists repo-url repo-dir "logseq/config.edn" default-content)]
+          (when-not file-exists?
+            (file-common-handler/reset-file! repo-url path default-content)
+            (set-repo-config-state! repo-url default-content)))))))
 
 
 (defn restore-repo-config!
 (defn restore-repo-config!
   "Sets repo config state from db"
   "Sets repo config state from db"

+ 1 - 3
src/main/frontend/handler/web/nfs.cljs

@@ -2,7 +2,6 @@
   "The File System Access API, https://web.dev/file-system-access/."
   "The File System Access API, https://web.dev/file-system-access/."
   (:require ["/frontend/utils" :as utils]
   (:require ["/frontend/utils" :as utils]
             [cljs-bean.core :as bean]
             [cljs-bean.core :as bean]
-            [clojure.core.async :as async]
             [clojure.set :as set]
             [clojure.set :as set]
             [clojure.string :as string]
             [clojure.string :as string]
             [frontend.config :as config]
             [frontend.config :as config]
@@ -23,8 +22,7 @@
             [lambdaisland.glogi :as log]
             [lambdaisland.glogi :as log]
             [logseq.graph-parser.config :as gp-config]
             [logseq.graph-parser.config :as gp-config]
             [logseq.graph-parser.util :as gp-util]
             [logseq.graph-parser.util :as gp-util]
-            [promesa.core :as p]
-            [frontend.fs.capacitor-fs :as capacitor-fs]))
+            [promesa.core :as p]))
 
 
 (defn remove-ignore-files
 (defn remove-ignore-files
   [files dir-name nfs?]
   [files dir-name nfs?]