(ns db-import "Imports given file(s) to a db graph. This script is primarily for developing the import feature and for engineers who want to customize the import process" (:require ["fs" :as fs] ["fs/promises" :as fsp] ["os" :as os] ["path" :as node-path] #_:clj-kondo/ignore [babashka.cli :as cli] [cljs.pprint :as pprint] [clojure.set :as set] [clojure.string :as string] [datascript.core :as d] [logseq.common.graph :as common-graph] [logseq.graph-parser.exporter :as gp-exporter] [logseq.outliner.cli :as outliner-cli] [logseq.outliner.pipeline :as outliner-pipeline] [nbb.classpath :as cp] [nbb.core :as nbb] [promesa.core :as p])) (def tx-queue (atom cljs.core/PersistentQueue.EMPTY)) (def original-transact! d/transact!) (defn dev-transact! [conn tx-data tx-meta] (swap! tx-queue (fn [queue] (let [new-queue (conj queue {:tx-data tx-data :tx-meta tx-meta})] ;; Only care about last few so vary 10 as needed (if (> (count new-queue) 10) (pop new-queue) new-queue)))) (original-transact! conn tx-data tx-meta)) (defn- build-graph-files "Given a file graph directory, return all files including assets and adds relative paths on ::rpath since paths are absolute by default and exporter needs relative paths for some operations" [dir*] (let [dir (node-path/resolve dir*)] (->> (common-graph/get-files dir) (concat (when (fs/existsSync (node-path/join dir* "assets")) (common-graph/readdir (node-path/join dir* "assets")))) (mapv #(hash-map :path % ::rpath (node-path/relative dir* %)))))) (defn- (get-in m [:ex-data :error]) ex-data :sci.impl/callstack deref)] (println (string/join "\n" (map #(str (:file %) (when (:line %) (str ":" (:line %))) (when (:sci.impl/f-meta %) (str " calls #'" (get-in % [:sci.impl/f-meta :ns]) "/" (get-in % [:sci.impl/f-meta :name])))) (reverse stack)))) (println (some-> (get-in m [:ex-data :error]) .-stack))) (when debug (when-let [matching-tx (seq (filter #(and (get-in m [:ex-data :path]) (or (= (get-in % [:tx-meta ::gp-exporter/path]) (get-in m [:ex-data :path])) (= (get-in % [:tx-meta ::outliner-pipeline/original-tx-meta ::gp-exporter/path]) (get-in m [:ex-data :path])))) @tx-queue))] (println (str "\n" (count matching-tx)) "Tx Maps for failing path:") (pprint/pprint matching-tx)))) (when (and (= :error (:level m)) (not continue)) (js/process.exit 1))) (defn default-export-options [options] {;; common options :rpath-key ::rpath :notify-user (partial notify-user options) : (merge {:all-tags false} (dissoc options :verbose :files :help :continue)) ;; coerce option collection into strings (:tag-classes options) (update :tag-classes (partial mapv str)) true (set/rename-keys {:all-tags :convert-all-tags? :remove-inline-tags :remove-inline-tags?})) _ (when (:verbose options) (prn :options user-options)) options' (merge {:user-options user-options :graph-name db-name} (select-keys options [:files :verbose :continue :debug]))] (p/let [{:keys [import-state]} (if directory? (import-file-graph-to-db file-graph' (node-path/join dir db-name) conn options') (import-files-to-db file-graph' conn options'))] (when-let [ignored-props (seq @(:ignored-properties import-state))] (println "Ignored properties:" (pr-str ignored-props))) (when-let [ignored-files (seq @(:ignored-files import-state))] (println (count ignored-files) "ignored file(s):" (pr-str (vec ignored-files)))) (when (:verbose options') (println "Transacted" (count (d/datoms @conn :eavt)) "datoms")) (println "Created graph" (str db-name "!"))))) (when (= nbb/*file* (nbb/invoked-file)) (-main *command-line-args*))