diff --git a/components/compojure/src/{$project$}/routes/router.clj b/components/compojure/src/{$project$}/routes/router.clj new file mode 100644 index 0000000..d66672b --- /dev/null +++ b/components/compojure/src/{$project$}/routes/router.clj @@ -0,0 +1,11 @@ +(ns {$project$}.routes.router + (:require [compojure.core :refer [routes GET]] + [compojure.route :as route] + [{$project$}.middleware.interface :as mw] + [{$project$}.routes.home :as home])) + +(defn create-app [] + (-> + (routes + (GET "/" request [] (home/get request))) + (mw/apply-generic))) diff --git a/components/reitit/src/{$project$}/routes/router.clj b/components/reitit/src/{$project$}/routes/router.clj new file mode 100644 index 0000000..115059f --- /dev/null +++ b/components/reitit/src/{$project$}/routes/router.clj @@ -0,0 +1,10 @@ +(ns {$project$}.routes.router + (:require [reitit.ring :as ring] + [{$project$}.middleware.interface :as mw] + [{$project$}.routes.home :as home])) + +(defn create-app [] + (ring/ring-handler + (ring/router + [["/" {:middleware [[mw/apply-generic]]} + ["" {:get home/get}]]]))) diff --git a/config.edn b/config.edn index d83ba76..be99a50 100644 --- a/config.edn +++ b/config.edn @@ -1,2 +1,10 @@ {:templates {:dir "./templates" - :list ["default" "server"]}} + :list {:default {:deps []} + :server {:deps ["http-kit/http-kit {:mvn/version \"2.8.0\"}" + "ring/ring-core {:mvn/version \"1.13.0\"}" + "ring/ring-json {:mvn/version \"0.5.1\"}"] + :component-groups {:router [:reitit + :compojure]}}}} + :components {:dir "./components" + :list {:reitit {:deps ["metosin/reitit {:mvn/version \"0.9.1\"}"]} + :compojure {:deps ["compojure/compojure {:mvn/version \"1.7.1\"}"]}}}} diff --git a/src/crapp/main.clj b/src/crapp/main.clj index 6a35715..9c78fa9 100644 --- a/src/crapp/main.clj +++ b/src/crapp/main.clj @@ -1,32 +1,66 @@ (ns crapp.main (:require [crapp.template :as template] - [crapp.utils :as utils] [crapp.config :as conf])) -(defn create-project! [project-name template] - (println (str "Creating " template " project '" project-name "'...")) - (try - (let [project-path (str "./" project-name) - template-path (str (conf/read-value :templates :dir) "/" template)] - (utils/make-directory! project-path) - (template/deploy-template-files! template-path - project-path - {:project project-name})) - (catch Exception e - (println (.getMessage e))) - (finally - (println "Done.")))) - -(defn -main [& args] - (cond - (empty? args) - (println "Please provide a project name.") - - (= (count args) 1) - (create-project! (first args) "default") - - (some #(= (last args) %) (conf/read-value :templates :list)) - (create-project! (first args) (last args)) - - (> (count args) 2) - (println "Too many arguments."))) +(defn prompt-template [] + (println "\nChoose your project template:") + (let [templates (-> (conf/read-value :templates :list) + (keys) + (vec))] + (doseq [[template index] (zipmap templates + (->> templates + (count) + (inc) + (range 1)))] + (println (str index ". " (name template)))) + + (print (str "Enter template number (1 - " (count templates) " | default 1): ")) + (flush) + + (let [n (or (parse-long (read-line)) 0) + default (first templates)] + (if (or (< n 1) (> n (count templates))) + (do (println "\nUsing default...") + default) + (nth templates (dec n)))))) + +(defn prompt-component [component-group components] + (println (str "\nChoose your " (name component-group) ":")) + + (doseq [[component index] (zipmap components + (->> components + (count) + (inc) + (range 1)))] + (println (str index ". " (name component)))) + + (print (str "Enter component number (1 - " (count components) " | default 1): ")) + (flush) + + (let [n (or (parse-long (read-line)) 0) + default (first components)] + (if (or (< n 1) (> n (count components))) + (do (println (str "\nUsing default: " (name default) "...")) + default) + (nth components (dec n))))) + +(defn -main [] + (println "Welcome to CRAPP!") + (print "Project name: ") + (flush) + (let [project (read-line) + template (prompt-template) + component-groups (conf/read-value :templates + :list + template + :component-groups) + components (reduce (fn [acc [cg cl]] + (conj acc (prompt-component cg cl))) + [] component-groups)] + (template/create-project! project template components))) + +(comment + (prompt-template) + (prompt-component :router [:reitit :compojure]) + (-main) + ()) diff --git a/src/crapp/template.clj b/src/crapp/template.clj index e1b3b87..d3a8cc6 100644 --- a/src/crapp/template.clj +++ b/src/crapp/template.clj @@ -1,13 +1,29 @@ (ns crapp.template (:require [clojure.string :as string] + [camel-snake-kebab.core :as csk] [crapp.utils :as utils] - [camel-snake-kebab.core :as csk])) + [crapp.config :as conf])) + +(defn compile-deps + "provided the template (keyword) and components (keyword vec), returns a string + of the final list of dependencies in deps.edn format. + e.g. + :deps {first/dependency {:mvn/version ###} + second/dependency {:mvn/version ###}}" + [template components] + (let [template-deps (string/join "\n" (conf/read-value :templates :list template :deps)) + components-deps (->> components + (mapv #(conf/read-value :components :list % :deps)) + (flatten) + (vec) + (string/join \newline))] + (str ":deps {" template-deps \newline components-deps "}"))) (defn parse-template [{:keys [template values]}] (string/join (map (fn [part] (or (get values (keyword part)) part)) - (string/split template #"\$")))) + (string/split template #"\{\$|\$\}")))) (defn deploy-template-files! [basepath targetpath values] (doseq [{:keys [filename is-directory]} (mapv @@ -32,13 +48,43 @@ :values values})] (spit (str targetpath "/" filename) replaced))))) +(defn create-project! [project-name template components] + (println (str "\nCreating " (name template) " project '" project-name "'...")) + (try + (let [project-path (str "./" project-name) + template-path (str (conf/read-value :templates :dir) "/" (name template))] + + (utils/make-directory! project-path) + (deploy-template-files! template-path + project-path + {:project project-name}) + + (doseq [c components] + (let [component-path (str (conf/read-value :components :dir) "/" (name c))] + (deploy-template-files! component-path + project-path + {:project project-name}))) + + (utils/append-file! (str project-path "/deps.edn") + (str (compile-deps template components) "}"))) + + (catch Exception e + (println (.getMessage e))) + (finally + (println "Done.")))) + (comment (let [dir (utils/list-files "./templates/default")] (mapv (fn [f] {:filename (utils/filename f) :is-directory (utils/is-directory f)}) dir)) - (deploy-template-files! "./templates/default" "./testing" {:project "my-app"}) + (deploy-template-files! "./templates/server" "./testing" {:project "my-server-app"}) + (deploy-template-files! "./components/reitit" "./testing" {:project "my-server-app"}) + + (utils/append-file! "testdeps.edn" (str (compile-deps :server [:reitit :compojure]) \})) + + (create-project! "my-server-app" :server [:reitit]) (->> "project" (assoc {:values {:project "my-app"}} :template) @@ -48,7 +94,7 @@ (utils/make-directory! "./testing") - (parse-template {:template "hello my name is $name$ and I am $age$ years old" + (parse-template {:template "hello my name is {$name$} and I am {$age$} years old" :values {:name "Keagan" :age 23}}) ()) diff --git a/src/crapp/utils.clj b/src/crapp/utils.clj index 7c15344..0a0b9e5 100644 --- a/src/crapp/utils.clj +++ b/src/crapp/utils.clj @@ -13,3 +13,5 @@ (defn make-directory! [path] (.mkdir (File. path))) +(defn append-file! [path content] + (spit path content :append true)) diff --git a/templates/default/deps.edn b/templates/default/deps.edn index 54621a2..2bd2c93 100644 --- a/templates/default/deps.edn +++ b/templates/default/deps.edn @@ -1,2 +1 @@ {:paths ["src"] - } diff --git a/templates/default/src/project/main.clj b/templates/default/src/{$project$}/main.clj similarity index 69% rename from templates/default/src/project/main.clj rename to templates/default/src/{$project$}/main.clj index cccce0c..dfa1ccf 100644 --- a/templates/default/src/project/main.clj +++ b/templates/default/src/{$project$}/main.clj @@ -1,4 +1,4 @@ -(ns $project$.main) +(ns {$project$}.main) (defn -main [& args] (println "Hello, world!")) diff --git a/templates/server/deps.edn b/templates/server/deps.edn index 2af7115..e6a3502 100644 --- a/templates/server/deps.edn +++ b/templates/server/deps.edn @@ -1,2 +1 @@ {:paths ["src" "dev"] - :deps {http-kit/http-kit {:mvn/version 2.8.0}}} diff --git a/templates/server/dev/dev.clj b/templates/server/dev/dev.clj index e6e3868..3865ddb 100644 --- a/templates/server/dev/dev.clj +++ b/templates/server/dev/dev.clj @@ -1,5 +1,5 @@ -(ns $project$.dev - (:require [$project$.server :as server])) +(ns {$project$}.dev + (:require [{$project$}.server :as server])) (defn after-ns-reload [] (server/restart-server)) diff --git a/templates/server/src/{$project$}/hooks.clj b/templates/server/src/{$project$}/hooks.clj new file mode 100644 index 0000000..2e99f5f --- /dev/null +++ b/templates/server/src/{$project$}/hooks.clj @@ -0,0 +1,5 @@ +(ns {$project$}.hooks) + +(defn add-shutdown-hook [f] + (let [runtime (Runtime/getRuntime)] + (.addShutdownHook runtime (Thread. #(f))))) diff --git a/templates/server/src/{$project$}/main.clj b/templates/server/src/{$project$}/main.clj new file mode 100644 index 0000000..5d8fc31 --- /dev/null +++ b/templates/server/src/{$project$}/main.clj @@ -0,0 +1,7 @@ +(ns {$project$}.main + (:require [{$project$}.server :as server] + [{$project$}.hooks :as hooks])) + +(defn -main [& _] + (server/start-server) + (hooks/add-shutdown-hook server/stop-server)) diff --git a/templates/server/src/{$project$}/middleware/core.clj b/templates/server/src/{$project$}/middleware/core.clj new file mode 100644 index 0000000..5588ea1 --- /dev/null +++ b/templates/server/src/{$project$}/middleware/core.clj @@ -0,0 +1,11 @@ +(ns {$project$}.middleware.core + (:require [ring.middleware.params :refer [wrap-params]] + [ring.middleware.json :refer [wrap-json-response wrap-json-body]] + [ring.middleware.cookies :refer [wrap-cookies]])) + +(defn apply-generic [app] + (-> app + (wrap-params) + (wrap-json-response) + (wrap-json-body {:keywords? true}) + (wrap-cookies))) diff --git a/templates/server/src/{$project$}/middleware/interface.clj b/templates/server/src/{$project$}/middleware/interface.clj new file mode 100644 index 0000000..c717414 --- /dev/null +++ b/templates/server/src/{$project$}/middleware/interface.clj @@ -0,0 +1,5 @@ +(ns {$project$}.middleware.interface + (:require [{$project$}.middleware.core :as mw])) + +(defn apply-generic [app] + (mw/apply-generic app)) diff --git a/templates/server/src/{$project$}/routes/home.clj b/templates/server/src/{$project$}/routes/home.clj new file mode 100644 index 0000000..fa71240 --- /dev/null +++ b/templates/server/src/{$project$}/routes/home.clj @@ -0,0 +1,5 @@ +(ns {$project$}.routes.home + (:require [ring.util.response :as res])) + +(defn get [request] + (res/response {:message "Hello, world!"})) diff --git a/templates/server/src/{$project$}/routes/interface.clj b/templates/server/src/{$project$}/routes/interface.clj new file mode 100644 index 0000000..54259c1 --- /dev/null +++ b/templates/server/src/{$project$}/routes/interface.clj @@ -0,0 +1,5 @@ +(ns {$project$}.routes.interface + (:require [{$project$}.routes.router :as router])) + +(defn create-app [] + (router/create-app)) diff --git a/templates/server/src/project/server.clj b/templates/server/src/{$project$}/server.clj similarity index 82% rename from templates/server/src/project/server.clj rename to templates/server/src/{$project$}/server.clj index ec834d2..9351e31 100644 --- a/templates/server/src/project/server.clj +++ b/templates/server/src/{$project$}/server.clj @@ -1,7 +1,6 @@ -(ns $project$.server - (:require - [org.httpkit.server :as http] - [$project$.routes.interface :as routes])) +(ns {$project$}.server + (:require [org.httpkit.server :as http] + [{$project$}.routes.interface :as routes])) (defonce ^:private *server (atom nil)) @@ -27,4 +26,3 @@ (defn restart-server [] (stop-server) (start-server)) -