start refactor to image-service-cli namespace

This commit is contained in:
Travis Shears 2025-07-04 13:43:20 +02:00
parent ef0c96c3cf
commit ae86e83716
13 changed files with 75 additions and 169 deletions

View file

@ -1 +1 @@
["^ ","~$fetch-snippets",["^ ","~:row",10,"~:col",1,"~:fixed-arities",["~#set",[0]],"~:name","^0","~:ns","~$cli-cms.edit","~:top-ns","^7","~:type","~:fn"],"~$prompt-for-edit-type",["^ ","^1",14,"^2",1,"^3",["^4",[0]],"^5","^;","^6","^7","^8","^7","^9","^:"],"~$send-patch",["^ ","^1",24,"^2",1,"^3",["^4",[2]],"^5","^<","^6","^7","^8","^7","^9","^:"],"~$edit",["^ ","^1",30,"^2",1,"^3",["^4",[1,2]],"^5","^=","^6","^7","^8","^7","^9","^:"],"~$run",["^ ","^1",50,"^2",1,"^3",["^4",[0]],"^5","^>","^6","^7","^8","^7","^9","^:"],"~:filename","/Users/she0001t/personal_projects/image-service-cli/src/image_service_cli/edit.clj"]
["^ ","~$fetch-snippets",["^ ","~:row",10,"~:col",1,"~:fixed-arities",["~#set",[0]],"~:name","^0","~:ns","~$cli-cms.edit","~:top-ns","^7","~:type","~:fn"],"~$prompt-for-edit-type",["^ ","^1",14,"^2",1,"^3",["^4",[0]],"^5","^;","^6","^7","^8","^7","^9","^:"],"~$send-patch",["^ ","^1",24,"^2",1,"^3",["^4",[2]],"^5","^<","^6","^7","^8","^7","^9","^:"],"~$edit",["^ ","^1",30,"^2",1,"^3",["^4",[1,2]],"^5","^=","^6","^7","^8","^7","^9","^:"],"~$run",["^ ","^1",50,"^2",1,"^3",["^4",[0]],"^5","^>","^6","^7","^8","^7","^9","^:"],"~:filename","/Users/she0001t/personal_projects/image-service-cli/src/image_service_cli/list.clj"]

View file

@ -1 +1 @@
["^ ","~$fetch-snippets",["^ ","~:row",10,"~:col",1,"~:fixed-arities",["~#set",[0]],"~:name","^0","~:ns","~$cli-cms.view","~:top-ns","^7","~:type","~:fn"],"~$fetch-snippet",["^ ","^1",14,"^2",1,"^3",["^4",[1]],"^5","^;","^6","^7","^8","^7","^9","^:"],"~$view",["^ ","^1",18,"^2",1,"^3",["^4",[1]],"^5","^<","^6","^7","^8","^7","^9","^:"],"~$run",["^ ","^1",25,"^2",1,"^3",["^4",[0]],"^5","^=","^6","^7","^8","^7","^9","^:"],"~:filename","/Users/she0001t/personal_projects/image-service-cli/src/image_service_cli/view.clj"]
["^ ","~$fetch-snippets",["^ ","~:row",10,"~:col",1,"~:fixed-arities",["~#set",[0]],"~:name","^0","~:ns","~$cli-cms.view","~:top-ns","^7","~:type","~:fn"],"~$fetch-snippet",["^ ","^1",14,"^2",1,"^3",["^4",[1]],"^5","^;","^6","^7","^8","^7","^9","^:"],"~$view",["^ ","^1",18,"^2",1,"^3",["^4",[1]],"^5","^<","^6","^7","^8","^7","^9","^:"],"~$run",["^ ","^1",25,"^2",1,"^3",["^4",[0]],"^5","^=","^6","^7","^8","^7","^9","^:"],"~:filename","/Users/she0001t/personal_projects/image-service-cli/src/image_service_cli/upload.clj"]

View file

@ -1 +1 @@
["^ ","~$-main",["^ ","~:row",9,"~:col",1,"~:varargs-min-arity",0,"~:name","^0","~:ns","~$image-service-cli.main","~:top-ns","^6","~:type","~:fn"],"~:filename","/Users/she0001t/personal_projects/image-service-cli/src/image_service_cli/main.clj"]
["^ ","~$s3-list",["^ ","~:row",6,"~:col",1,"~:fixed-arities",["~#set",[1]],"~:name","^0","~:ns","~$image-service-cli.main","~:top-ns","^7","~:type","~:fn"],"~$prompt-for",["^ ","^1",9,"^2",1,"~:varargs-min-arity",1,"^5","^;","^6","^7","^8","^7","^9","^:"],"~$-main",["^ ","^1",15,"^2",1,"^<",0,"^5","^=","^6","^7","^8","^7","^9","^:"],"~:filename","/Users/she0001t/personal_projects/image-service-cli/src/image_service_cli/main.clj"]

4
bb.edn
View file

@ -1,2 +1,4 @@
{:paths ["src"]
:deps {}}
:deps {com.travisshears/gum-utils {:git/url "https://git.travisshears.com/travisshears/gum-utils"
:git/tag "39K"
:git/sha "748b21d358b62db0476bc3577cb5398acc533ba1"}}}

View file

@ -1,2 +1,2 @@
;; {:backend-host "http://localhost:8080"}
{:backend-host "http://aemos:5008"}
{:aws-profile "personal"
:s3-root "s3://travisshears.images/image-service/images/"}

View file

@ -1,49 +0,0 @@
(ns cli-cms.cli-utils
(:require
[clojure.string :as str]
[clojure.pprint :refer [pprint]]
[babashka.process :refer [shell]]))
(defn select
"Select from a list of options using gum filter.
Args:
l list of {:item any :value string}"
[l]
(let [values (map :value l)
selected-value (str/trim (:out (apply shell {:out :string} (concat '("gum" "filter") values))))
selected-item (:item (first (filter #(= (:value %) selected-value) l)))]
selected-item))
(defn color-print
([text] (color-print text "5"))
([text color]
(shell (format "gum style --foreground %s \"%s\"" color text))))
(defn print-markdown [text]
(shell (format "gum format \"%s\"" text)))
(defn prompt-for [placeholder & {:keys [prefill]}]
(let [cmd (if prefill
(format "gum input --placeholder='%s' --value='%s'" placeholder prefill)
(format "gum input --placeholder='%s'" placeholder)
)]
(str/trim (-> (shell {:out :string} cmd) :out))))
(defn prompt-for-many
([placeholder]
(let [val (prompt-for (str placeholder ", enter done to finish"))]
(println val)
(if (= val "done")
nil
(prompt-for-many placeholder `(~val)))))
([placeholder carry]
(let [val (prompt-for (str placeholder ", enter done to finish"))]
(println val)
(if (= val "done")
carry
(prompt-for-many placeholder (conj carry val))))))
(defn prompt-for-long-form [placeholder & {:keys [prefill]}]
(if prefill
(-> (shell {:out :string :extra-env {"GUM_WRITE_VALUE" prefill}} (format "gum write --placeholder='%s'" placeholder)) :out)
(-> (shell {:out :string} (format "gum write --placeholder='%s'" placeholder)) :out)))

View file

@ -1,4 +1,4 @@
(ns cli-cms.config
(ns image-service-cli.config
(:require
[babashka.fs :as fs]
[clojure.string :as str]))

View file

@ -1,25 +0,0 @@
(ns cli-cms.create
(:require
[cli-cms.cli-utils :as utils]
[clojure.string :as str]
[cli-cms.config :refer [config]]
[babashka.http-client :as http]
[cheshire.core :as json]
[babashka.process :refer [shell]]))
(defn create-snippet [{:keys [title slug markdown tags]}]
(http/post (str (:backend-host config) "/api/snippet")
{:headers {:content-type "application/json"}
:body (json/encode {:title title :slug slug :markdown markdown :tags tags})}))
(defn run []
(let [title (utils/prompt-for "title")
slug (utils/prompt-for "slug")
tags (utils/prompt-for-many "tags")
markdown (utils/prompt-for-long-form "markdown")]
;; (utils/print "Please enter a title:")
;; (println "Please enter a title:")
(println (format "TODO: create post with title: %s and slug %s" title slug))
(println tags)
(println markdown)
(create-snippet {:title title :slug slug :markdown markdown :tags tags})))

View file

@ -1,18 +0,0 @@
(ns cli-cms.delete
(:require
[cli-cms.cli-utils :as utils]
[cli-cms.config :refer [config]]
[clojure.pprint :refer [pprint]]
[babashka.http-client :as http]
[cheshire.core :as json]))
(defn fetch-snippets []
(let [res (http/get (str (:backend-host config) "/api/snippets?limit=25"))]
(json/parse-string (:body res) true)))
(defn delete-snippet [id]
(http/delete (str (:backend-host config) "/api/snippet") {:query-params {"id" id}}))
(defn run []
(let [selected-snippet (utils/select (map #(hash-map :value (:slug %) :item %) (fetch-snippets)))]
(delete-snippet (:id selected-snippet))))

View file

@ -1,54 +0,0 @@
(ns cli-cms.edit
(:require
[babashka.http-client :as http]
[clojure.pprint :refer [pprint]]
[cli-cms.config :refer [config]]
[cli-cms.view :as view]
[cheshire.core :as json]
[cli-cms.cli-utils :as utils]))
(defn fetch-snippets []
(let [res (http/get (str (:backend-host config) "/api/snippets?limit=25"))]
(json/parse-string (:body res) true)))
(defn prompt-for-edit-type []
(utils/select (map #(hash-map :value (name %) :item %)'(
:title
:markdown
:slug
:remove-tag
:add-tags
:done
))))
(defn send-patch [id patch]
(http/patch (str (:backend-host config) "/api/snippet")
{:query-params {:id id}
:headers {:content-type "application/json"}
:body (json/encode patch)}))
(defn edit
([snippet]
(edit snippet {}))
([snippet changes]
(case (prompt-for-edit-type)
:title (let [new-title (utils/prompt-for "title" :prefill (:title snippet))]
(edit (assoc snippet :title new-title) (assoc changes :title new-title)))
:slug (let [new-slug (utils/prompt-for "slug" :prefill (:slug snippet))]
(edit (assoc snippet :slug new-slug) (assoc changes :slug new-slug)))
:remove-tag (let [tag-to-remove (utils/select (map #(hash-map :value % :item %) (:tags snippet)))
tags (remove #(= % tag-to-remove) (:tags snippet))]
(edit (assoc snippet :tags tags) (assoc changes :tags tags)))
:add-tags (let [
new-tags (utils/prompt-for-many "tags")
tags (concat new-tags (:tags snippet))]
(edit (assoc snippet :tags tags) (assoc changes :tags tags)))
:markdown (let [new-markdown (utils/prompt-for-long-form "markdown" :prefill (:markdown snippet))]
(edit (assoc snippet :markdown new-markdown) (assoc changes :markdown new-markdown)))
:done changes)))
(defn run []
(let [snippet-to-edit (utils/select (map #(hash-map :value (:slug %) :item %) (fetch-snippets)))]
(send-patch (:id snippet-to-edit) (edit snippet-to-edit))
(println "Snippet updated successfully")
(view/view (view/fetch-snippet (:id snippet-to-edit)))))

View file

@ -0,0 +1,51 @@
;;; Index use-case
;;; Go through all the image files in s3 and save them to sqllite db for easier searching
(ns image-service-cli.index
(:import (java.time LocalDateTime)
(java.time.format DateTimeFormatter))
(:require
[image-service-cli.config :refer [config]]
[babashka.process :refer [shell]]
[clojure.string :as str]
[com.travisshears.gum-utils :as utils]))
(defn s3-root-dirs []
(let [filter-for-dirs (fn [lines] (filter #(re-find #"^\s*PRE" %) lines))
extract-dir-name (fn [line]
(let [match (re-find #"PRE ([^\/]+)" line)]
(when match
(second match))))
s3-output (->
(shell {:out :string :extra-env {"AWS_PROFILE" (:aws-profile config)}} "aws s3 ls" (:s3-root config))
:out)]
(->>
(str/split s3-output #"\n")
(filter-for-dirs)
(map extract-dir-name))))
(def s3-date-formatter (DateTimeFormatter/ofPattern "yyyy-MM-dd HH:mm:ss"))
(defn s3-list-dir [dir]
"List the contents of a directory in S3. Skipping nested directories"
(as->
(shell {:out :string :extra-env {"AWS_PROFILE" (:aws-profile config)}} "aws s3 ls" (str (:s3-root config) dir "/")) x
(:out x)
(str/split x #"\n") ;; split on newline
(map #(re-find #"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+\d+\s+(.+$)" %) x) ;; convert line into date and file name
(filter #(not (nil? %)) x) ;; remove lines that didn't match
(map #(list (second %) (str dir "/" (last %))) x) ;; remove full match from regex and add dir to filename
(map #(list (LocalDateTime/parse (first %) s3-date-formatter) (second %)) x)
(map #(hash-map :date (first %) :file-name (second %)) x)))
;; (defn fetch-snippets []
;; (let [res (http/get (str (:backend-host config) "/api/snippets?limit=25"))]
;; (json/parse-string (:body res) true)))
;; (defn send-patch [id patch]
;; (http/patch (str (:backend-host config) "/api/snippet")
;; {:query-params {:id id}
;; :headers {:content-type "application/json"}
;; :body (json/encode patch)}))
(defn run []
;; get file names and created dates from s3
(flatten (map image-service-cli.index/s3-list-dir (image-service-cli.index/s3-root-dirs))))

View file

@ -1,20 +1,19 @@
(ns cli-cms.main
(ns image-service-cli.main
(:require
[cli-cms.create :as create]
[cli-cms.edit :as edit]
[cli-cms.delete :as delete]
[cli-cms.cli-utils :as utils]
[cli-cms.view :as view]))
[babashka.process :refer [shell]]
[com.travisshears.gum-utils :as utils]))
(defn color-test []
(doseq [color (range 0 255)]
(utils/color-print (str "COLOR --- " color) (str color))))
(shell (format "gum format \"%s\"" text)))
(defn prompt-for [placeholder & {:keys [prefill]}]
(defn s3-list [dir]
(let [cmd (if prefill
(format "gum input --placeholder='%s' --value='%s'" placeholder prefill)
(format "gum input --placeholder='%s'" placeholder))]
(str/trim (-> (shell {:out :string} cmd) :out))))
(defn -main [& args]
(case (first args)
"create" (create/run)
"delete" (delete/run)
"edit" (edit/run)
"view" (view/run)
"color-test" (color-test)
(println "Missing command. Try create, edit, or delete.")))
"upload" (create/run)
"ls" (delete/run)
(println "Missing command. Try upload or ls.")))

View file

@ -1,4 +1,4 @@
(ns cli-cms.view
(ns image-service-cli.upload
(:require
[babashka.http-client :as http]
[clojure.pprint :refer [pprint]]