enhance: export command can save to file option

Also update export-edn command to have same default behavior as
export command. Printing to stdout was ok for dev but is surprising and
possibly overwhelming for most graphs
This commit is contained in:
Gabriel Horner
2025-08-25 09:31:53 -04:00
parent 13d7709b34
commit ffaccbb33e
8 changed files with 45 additions and 28 deletions

View File

@@ -1,6 +1,10 @@
## 0.2.0
* Add export command to export graph as markdown
* Like export command, export-edn command defaults to exporting to file
## 0.1.0
* Initial release!
* Provides commands: list, show, search, query, export-edn and help
* All commands except search work offline. search and query have options for calling HTTP Server of
* All commands work offline. search and query have options for calling HTTP API Server of
open desktop Logseq app

6
deps/cli/README.md vendored
View File

@@ -110,7 +110,11 @@ $ logseq query '(task DOING)' -a my-token
:uuid "68795144-e5f6-48e8-849d-79cd6473b952"}
...
# Export your DB graph as EDN
# Export DB graph as markdown
$ logseq export yep
Exported 41 pages to yep_markdown_1756128259.zip
# Export DB graph as EDN
$ logseq export-edn woot -f woot.edn
Exported 16 properties, 16 classes and 36 pages
```

View File

@@ -1,6 +1,6 @@
{
"name": "@logseq/cli",
"version": "0.1.0",
"version": "0.2.0",
"description": "Logseq CLI",
"bin": {
"logseq": "cli.mjs"

View File

@@ -78,7 +78,8 @@
:spec cli-spec/query}
{:cmds ["export"] :desc "Export DB graph as MD"
:fn (lazy-load-fn 'logseq.cli.commands.export/export)
:args->opts [:graph] :require [:graph]}
:args->opts [:graph] :require [:graph]
:spec cli-spec/export}
{:cmds ["export-edn"] :desc "Export DB graph as EDN"
:fn (lazy-load-fn 'logseq.cli.commands.export-edn/export)
:args->opts [:graph] :require [:graph]

View File

@@ -1,5 +1,5 @@
(ns logseq.cli.commands.export
"Export command"
"Export MD command"
(:require ["fs" :as fs]
[cljs.pprint]
[clojure.string :as string]
@@ -53,7 +53,7 @@
(defn- export-repo-as-markdown!
"Modified version of handler.export.text/export-repo-as-markdown for the CLI"
[repo db]
[repo db {:keys [file]}]
(let [content-config (get-content-config db)
files* (get-file-contents repo db content-config "md")]
(when (seq files*)
@@ -62,14 +62,19 @@
cli-export-common/*content-config* content-config]
(export-files-as-markdown repo files* nil))
repo' (string/replace repo common-config/db-version-prefix "")
zip-file-name (str repo' "_markdown_" (quot (common-util/time-ms) 1000))
zip (cli-common-util/make-export-zip zip-file-name files)]
zip-file-name (if file
(string/replace-first file #"(?i)\.zip$" "")
(str repo' "_markdown_" (quot (common-util/time-ms) 1000)))
file-name (or file (str zip-file-name ".zip"))
zip (cli-common-util/make-export-zip zip-file-name files)
;; matches behavior in make-export-zip
exported-files (remove #(string/blank? (second %)) files)]
(-> (.generateNodeStream zip #js {:streamFiles true :type "nodebuffer"})
(.pipe (fs/createWriteStream (str zip-file-name ".zip"))))
(println "Exported graph to" (str zip-file-name ".zip"))))))
(.pipe (fs/createWriteStream file-name)))
(println "Exported" (count exported-files) "pages to" file-name)))))
(defn export [{{:keys [graph]} :opts}]
(defn export [{{:keys [graph] :as opts} :opts}]
(if (fs/existsSync (cli-util/get-graph-dir graph))
(let [conn (apply sqlite-cli/open-db! (cli-util/->open-db-args graph))]
(export-repo-as-markdown! (str common-config/db-version-prefix graph) @conn))
(export-repo-as-markdown! (str common-config/db-version-prefix graph) @conn opts))
(cli-util/error "Graph" (pr-str graph) "does not exist")))

View File

@@ -4,21 +4,20 @@
[clojure.pprint :as pprint]
[logseq.db.common.sqlite-cli :as sqlite-cli]
[logseq.db.sqlite.export :as sqlite-export]
[logseq.common.util :as common-util]
[logseq.cli.util :as cli-util]))
(defn export [{{:keys [graph] :as options} :opts}]
(if (fs/existsSync (cli-util/get-graph-dir graph))
(let [conn (apply sqlite-cli/open-db! (cli-util/->open-db-args graph))
export-map (sqlite-export/build-export @conn
(cond-> {:export-type (:export-type options)}
(= :graph (:export-type options))
(assoc :graph-options (dissoc options :file :export-type :graph))))]
(if (:file options)
(do
(println "Exported" (count (:properties export-map)) "properties,"
(count (:properties export-map)) "classes and"
(count (:pages-and-blocks export-map)) "pages")
(fs/writeFileSync (:file options)
(with-out-str (pprint/pprint export-map))))
(pprint/pprint export-map)))
(let [conn (apply sqlite-cli/open-db! (cli-util/->open-db-args graph))
export-map (sqlite-export/build-export @conn
(cond-> {:export-type (:export-type options)}
(= :graph (:export-type options))
(assoc :graph-options (dissoc options :file :export-type :graph))))
file (or (:file options) (str graph "_" (quot (common-util/time-ms) 1000) ".edn"))]
(println "Exported" (count (:properties export-map)) "properties,"
(count (:properties export-map)) "classes and"
(count (:pages-and-blocks export-map)) "pages to" file)
(fs/writeFileSync file
(with-out-str (pprint/pprint export-map))))
(cli-util/error "Graph" (pr-str graph) "does not exist")))

View File

@@ -2,11 +2,15 @@
"Babashka.cli specs for commands. Normally these would live alongside their
commands but are separate because command namespaces are lazy loaded")
(def export
{:file {:alias :f
:desc "File to save export"}})
(def export-edn
{:include-timestamps? {:alias :T
:desc "Include timestamps in export"}
:file {:alias :f
:desc "Saves edn to file"}
:desc "File to save export"}
:catch-validation-errors? {:alias :c
:desc "Catch validation errors for dev"}
:exclude-namespaces {:alias :e
@@ -29,7 +33,7 @@
:coerce :boolean
:desc "Make properties on entity queries show property values instead of ids"}
:title-query {:alias :t
:desc "Invokes local query on :block/title"}
:desc "Invoke local query on :block/title"}
:api-query-token {:alias :a
:desc "Query current graph with api server token"}})

View File

@@ -1,5 +1,5 @@
(ns ^:node-only logseq.cli.util
"Util fns"
"CLI only util fns"
(:require ["path" :as node-path]
[clojure.string :as string]
[logseq.cli.common.graph :as cli-common-graph]