├── libs ├── kit-generator │ ├── test │ │ ├── resources │ │ │ ├── modules │ │ │ │ └── kit │ │ │ │ │ ├── html │ │ │ │ │ ├── assets │ │ │ │ │ │ ├── home.html │ │ │ │ │ │ ├── pages.clj │ │ │ │ │ │ └── img │ │ │ │ │ │ │ └── luminus.png │ │ │ │ │ └── config.edn │ │ │ │ │ ├── cljs │ │ │ │ │ ├── assets │ │ │ │ │ │ ├── src │ │ │ │ │ │ │ ├── app.cljs │ │ │ │ │ │ │ └── core.cljs │ │ │ │ │ │ ├── package.json │ │ │ │ │ │ ├── shadow-cljs.edn │ │ │ │ │ │ └── build.clj │ │ │ │ │ └── config.edn │ │ │ │ │ └── modules.edn │ │ │ ├── snippets │ │ │ │ └── kit │ │ │ │ │ ├── SomeOdd-FileNameFor_Snippet.md │ │ │ │ │ └── routing.md │ │ │ ├── sample-system.edn │ │ │ ├── kit.edn │ │ │ └── core.clj │ │ ├── kit_generator │ │ │ ├── core_test.clj │ │ │ ├── io.clj │ │ │ ├── snippets.clj │ │ │ ├── injections.clj │ │ │ └── generator_test.clj │ │ └── kit │ │ │ └── generator │ │ │ ├── io_test.clj │ │ │ └── modules │ │ │ └── dependencies_test.clj │ ├── src │ │ └── kit │ │ │ ├── generator │ │ │ ├── io.clj │ │ │ ├── modules │ │ │ │ ├── dependencies.clj │ │ │ │ ├── generator.clj │ │ │ │ └── injections.clj │ │ │ ├── renderer.clj │ │ │ ├── git.clj │ │ │ ├── modules.clj │ │ │ └── snippets.clj │ │ │ └── api.clj │ └── deps.edn ├── kit-mysql │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── db │ │ └── mysql.clj ├── deps-template │ ├── resources │ │ └── io │ │ │ └── github │ │ │ └── kit_clj │ │ │ └── kit │ │ │ ├── resources │ │ │ ├── migrations │ │ │ │ └── placeholder.txt │ │ │ ├── queries.sql │ │ │ └── system.edn │ │ │ ├── env │ │ │ ├── dev │ │ │ │ ├── clj │ │ │ │ │ ├── dev_middleware.clj │ │ │ │ │ ├── env.clj │ │ │ │ │ └── user.clj │ │ │ │ └── resources │ │ │ │ │ └── logback.xml │ │ │ ├── prod │ │ │ │ ├── clj │ │ │ │ │ └── env.clj │ │ │ │ └── resources │ │ │ │ │ └── logback.xml │ │ │ └── test │ │ │ │ └── resources │ │ │ │ └── logback.xml │ │ │ ├── .dir-locals.el │ │ │ ├── Makefile │ │ │ ├── kit.git-config.edn │ │ │ ├── template.edn │ │ │ ├── test │ │ │ └── clj │ │ │ │ ├── core_test.clj │ │ │ │ ├── web │ │ │ │ └── request_test.clj │ │ │ │ └── test_utils.clj │ │ │ ├── src │ │ │ └── clj │ │ │ │ ├── config.clj │ │ │ │ ├── web │ │ │ │ ├── routes │ │ │ │ │ ├── utils.clj │ │ │ │ │ └── api.clj │ │ │ │ ├── controllers │ │ │ │ │ └── health.clj │ │ │ │ ├── middleware │ │ │ │ │ ├── formats.clj │ │ │ │ │ ├── core.clj │ │ │ │ │ └── exception.clj │ │ │ │ └── handler.clj │ │ │ │ └── core.clj │ │ │ ├── gitignore │ │ │ ├── kit.edn │ │ │ ├── Dockerfile │ │ │ ├── versions.edn │ │ │ ├── bb.edn │ │ │ ├── build.clj │ │ │ ├── README.md │ │ │ └── deps.edn │ ├── deps.edn │ └── src │ │ └── io │ │ └── github │ │ └── kit_clj │ │ ├── deps_template │ │ └── helpers.clj │ │ └── deps_template.clj ├── kit-hato │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── http │ │ └── hato.clj ├── kit-http-kit │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── server │ │ └── http_kit.clj ├── kit-jetty │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── server │ │ └── jetty.clj ├── kit-repl │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── utils │ │ └── repl.clj ├── kit-xtdb │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── db │ │ └── xtdb.clj ├── kit-selmer │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── templating │ │ └── selmer.clj ├── kit-sql-migratus │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── db │ │ └── sql │ │ └── migratus.clj ├── kit-jdk-http │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── server │ │ └── jdk.clj ├── kit-postgres │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── db │ │ └── postgres.clj ├── kit-sql │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── db │ │ └── sql.clj ├── kit-sql-conman │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── db │ │ └── sql │ │ └── conman.clj ├── kit-undertow │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── server │ │ └── undertow.clj ├── kit-core │ ├── deps.edn │ └── src │ │ └── kit │ │ ├── config.clj │ │ └── ig_utils.clj ├── lein-template │ ├── deps.edn │ └── src │ │ └── leiningen │ │ └── new │ │ └── io │ │ └── github │ │ ├── kit_clj │ │ └── options │ │ │ ├── sql.clj │ │ │ ├── helpers.clj │ │ │ └── base.clj │ │ └── kit_clj.clj ├── kit-nrepl │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── utils │ │ └── nrepl.clj ├── kit-quartz │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── scheduling │ │ └── quartz.clj ├── kit-redis │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── cache │ │ └── redis.clj ├── kit-sql-hikari │ ├── deps.edn │ └── src │ │ └── kit │ │ └── edge │ │ └── db │ │ └── sql │ │ └── hikari.clj └── kit-metrics │ ├── deps.edn │ └── src │ └── kit │ └── edge │ └── utils │ └── metrics.clj ├── .gitignore ├── .github └── workflows │ └── ci.yml ├── LICENSE ├── deps.edn ├── bb.edn ├── test └── kit │ └── template_test.clj ├── README.md └── CHANGELOG.md /libs/kit-generator/test/resources/modules/kit/html/assets/home.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/modules/kit/html/assets/pages.clj: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /libs/kit-mysql/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {com.mysql/mysql-connector-j {:mvn/version "8.1.0"}}} 3 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/resources/migrations/placeholder.txt: -------------------------------------------------------------------------------- 1 | See https://github.com/yogthos/migratus -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/resources/queries.sql: -------------------------------------------------------------------------------- 1 | -- place your sql queries here 2 | -- see https://www.hugsql.org/ for documentation -------------------------------------------------------------------------------- /libs/kit-hato/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {integrant/integrant {:mvn/version "1.0.0"} 3 | hato/hato {:mvn/version "1.0.0"}}} 4 | -------------------------------------------------------------------------------- /libs/kit-http-kit/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {integrant/integrant {:mvn/version "1.0.0"} 3 | http-kit/http-kit {:mvn/version "2.7.0"}}} 4 | -------------------------------------------------------------------------------- /libs/kit-jetty/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {integrant/integrant {:mvn/version "1.0.0"} 3 | ring/ring-jetty-adapter {:mvn/version "1.12.2"}}} 4 | -------------------------------------------------------------------------------- /libs/kit-repl/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {org.clojure/tools.logging {:mvn/version "1.2.4"} 3 | integrant/integrant {:mvn/version "1.0.0"}}} 4 | -------------------------------------------------------------------------------- /libs/kit-xtdb/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {integrant/integrant {:mvn/version "1.0.0"} 3 | com.xtdb/xtdb-core {:mvn/version "1.23.0"}}} 4 | -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/modules/kit/cljs/assets/src/app.cljs: -------------------------------------------------------------------------------- 1 | (ns ^:dev/once <>.app 2 | (:require [<>.core :as core])) 3 | 4 | (core/init!) -------------------------------------------------------------------------------- /libs/kit-selmer/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {integrant/integrant {:mvn/version "1.0.0"} 3 | selmer/selmer {:mvn/version "1.12.59"}}} 4 | -------------------------------------------------------------------------------- /libs/kit-sql-migratus/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {integrant/integrant {:mvn/version "1.0.0"} 3 | migratus/migratus {:mvn/version "1.5.1"}}} 4 | -------------------------------------------------------------------------------- /libs/kit-generator/test/kit_generator/core_test.clj: -------------------------------------------------------------------------------- 1 | (ns kit-generator.core-test 2 | (:require 3 | [kit-generator.generator-test] 4 | [kit-generator.injections])) 5 | -------------------------------------------------------------------------------- /libs/kit-jdk-http/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {integrant/integrant {:mvn/version "1.0.0"} 3 | com.github.igrishaev/ring-jdk-adapter {:mvn/version "0.1.1"}}} 4 | -------------------------------------------------------------------------------- /libs/kit-postgres/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {org.postgresql/postgresql {:mvn/version "42.6.0"} 3 | cheshire/cheshire {:mvn/version "5.11.0"}}} 4 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/env/dev/clj/dev_middleware.clj: -------------------------------------------------------------------------------- 1 | (ns <>.dev-middleware) 2 | 3 | (defn wrap-dev [handler _opts] 4 | (-> handler 5 | )) 6 | -------------------------------------------------------------------------------- /libs/kit-sql/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {io.github.kit-clj/kit-sql-conman {:mvn/version "1.10.5"} 3 | io.github.kit-clj/kit-sql-migratus {:mvn/version "1.0.5"}}} 4 | -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/modules/kit/html/assets/img/luminus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kit-clj/kit/HEAD/libs/kit-generator/test/resources/modules/kit/html/assets/img/luminus.png -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((clojure-mode . ((cider-clojure-cli-aliases . ":dev:cider") 2 | (cider-preferred-build-tool . clojure-cli)))) 3 | -------------------------------------------------------------------------------- /libs/kit-sql-conman/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {integrant/integrant {:mvn/version "1.0.0"} 3 | conman/conman {:mvn/version "0.9.6"} 4 | io.github.kit-clj/kit-core {:mvn/version "1.0.8"}}} 5 | -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/snippets/kit/SomeOdd-FileNameFor_Snippet.md: -------------------------------------------------------------------------------- 1 | ## tags 2 | odd file 3 | 4 | ## description 5 | a snippet with an odd file name 6 | 7 | ### code 8 | 9 | ```clojure 10 | (fn [] "hi") 11 | ``` 12 | -------------------------------------------------------------------------------- /libs/kit-undertow/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {org.clojure/tools.logging {:mvn/version "1.3.0"} 3 | integrant/integrant {:mvn/version "1.0.1"} 4 | luminus/ring-undertow-adapter {:mvn/version "1.4.3"}}} 5 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/Makefile: -------------------------------------------------------------------------------- 1 | clean: 2 | rm -rf target 3 | 4 | run: 5 | clj -M:dev 6 | 7 | repl: 8 | clj -M:dev:nrepl 9 | 10 | test: 11 | clj -M:test 12 | 13 | uberjar: 14 | clj -T:build all 15 | -------------------------------------------------------------------------------- /libs/deps-template/deps.edn: -------------------------------------------------------------------------------- 1 | {:deps {babashka/fs {:mvn/version "0.5.27"} 2 | selmer/selmer {:mvn/version "1.12.67"} 3 | io.github.seancorfield/deps-new {:git/tag "v0.10.1" :git/sha "a90029c"}} 4 | :paths ["src" "resources"]} 5 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/kit.git-config.edn: -------------------------------------------------------------------------------- 1 | {:name "~/.ssh/id_rsa" 2 | :passphrase "" 3 | :options {"StrictHostKeyChecking" "no" 4 | "UserKnownHostsFile" "/dev/null"} 5 | :exclusive true} 6 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/template.edn: -------------------------------------------------------------------------------- 1 | {:description "FIXME: my new kit project" 2 | :root "_" 3 | :data-fn io.github.kit-clj.deps-template/data-fn 4 | :template-fn io.github.kit-clj.deps-template/template-fn} 5 | -------------------------------------------------------------------------------- /libs/kit-core/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {aero/aero {:mvn/version "1.1.6"} 3 | integrant/integrant {:mvn/version "1.0.0"} 4 | org.clojure/tools.logging {:mvn/version "1.2.4"}}} 5 | -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/modules/kit/cljs/assets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "shadow-cljs": "^2.16.5" 4 | }, 5 | "dependencies": { 6 | "react": "^17.0.2", 7 | "react-dom": "^17.0.2" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/test/clj/core_test.clj: -------------------------------------------------------------------------------- 1 | (ns <>.core-test 2 | (:require 3 | [<>.test-utils :as utils] 4 | [clojure.test :refer :all])) 5 | 6 | (deftest example-test 7 | (is (= 1 2))) 8 | 9 | -------------------------------------------------------------------------------- /libs/lein-template/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {selmer/selmer {:mvn/version "1.12.67"} 3 | com.github.seancorfield/clj-new {:mvn/version "1.2.381"} 4 | io.github.kit-clj/deps-template {:mvn/version "0.1.85"}}} 5 | -------------------------------------------------------------------------------- /libs/kit-sql/src/kit/edge/db/sql.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.db.sql 2 | "This library simply in kit-sql-conman and kit-sql-migratus for compatibility purposes. 3 | It serves no other purpose" 4 | (:require 5 | [kit.edge.db.sql.conman] 6 | [kit.edge.db.sql.migratus])) 7 | -------------------------------------------------------------------------------- /libs/kit-nrepl/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {org.clojure/tools.logging {:mvn/version "1.2.4"} 3 | integrant/integrant {:mvn/version "1.0.0"} 4 | nrepl/nrepl {:mvn/version "1.1.1"} 5 | io.github.kit-clj/kit-core {:mvn/version "1.0.8"}}} 6 | -------------------------------------------------------------------------------- /libs/kit-quartz/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {aero/aero {:mvn/version "1.1.6"} 3 | integrant/integrant {:mvn/version "1.0.0"} 4 | com.troy-west/cronut {:mvn/version "0.2.6"} 5 | io.github.kit-clj/kit-core {:mvn/version "1.0.8"}}} 6 | -------------------------------------------------------------------------------- /libs/kit-redis/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {integrant/integrant {:mvn/version "1.0.0"} 3 | org.clojure/core.cache {:mvn/version "1.0.225"} 4 | com.taoensso/carmine {:mvn/version "3.2.0"} 5 | io.github.kit-clj/kit-core {:mvn/version "1.0.8"}}} 6 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/src/clj/config.clj: -------------------------------------------------------------------------------- 1 | (ns <>.config 2 | (:require 3 | [kit.config :as config])) 4 | 5 | (def ^:const system-filename "system.edn") 6 | 7 | (defn system-config 8 | [options] 9 | (config/read-config system-filename options)) 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | classes/ 3 | checkouts/ 4 | profiles.clj 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | *.bak 9 | .lein-*/ 10 | .nrepl-port/ 11 | .prepl-port/ 12 | .hgignore 13 | .hg/ 14 | *.iml 15 | .idea/ 16 | .cpcache/ 17 | .DS_Store 18 | .nrepl-port 19 | .lsp 20 | .clj-kondo/.cache/ 21 | .aider* 22 | -------------------------------------------------------------------------------- /libs/kit-xtdb/src/kit/edge/db/xtdb.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.db.xtdb 2 | (:require 3 | [xtdb.api :as xtdb] 4 | [integrant.core :as ig])) 5 | 6 | (defmethod ig/init-key :db.xtdb/node 7 | [_ config] 8 | (xtdb/start-node config)) 9 | 10 | (defmethod ig/halt-key! :db.xtdb/node 11 | [_ xtdb-node] 12 | (.close xtdb-node)) -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/src/clj/web/routes/utils.clj: -------------------------------------------------------------------------------- 1 | (ns <>.web.routes.utils) 2 | 3 | (def route-data-path [:reitit.core/match :data]) 4 | 5 | (defn route-data 6 | [req] 7 | (get-in req route-data-path)) 8 | 9 | (defn route-data-key 10 | [req k] 11 | (get-in req (conj route-data-path k))) 12 | -------------------------------------------------------------------------------- /libs/kit-sql-hikari/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {integrant/integrant {:mvn/version "1.0.0"} 3 | com.github.seancorfield/next.jdbc {:mvn/version "1.3.883"} ;; TODO: is this required here? 4 | hikari-cp/hikari-cp {:mvn/version "3.0.1"} 5 | io.github.kit-clj/kit-core {:mvn/version "1.0.8"}}} 6 | -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/modules/kit/modules.edn: -------------------------------------------------------------------------------- 1 | {:module-root "kit" 2 | :modules 3 | {:html 4 | {:path "html" 5 | :doc "adds support for HTML templating using Selmer"} 6 | :kit/cljs 7 | {:path "cljs" 8 | :doc "adds support for cljs using shadow-cljs"}}} 9 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/gitignore: -------------------------------------------------------------------------------- 1 | kit.git-config.edn 2 | .DS_Store 3 | .nrepl-port 4 | hs_err_pid*.log 5 | .cpcache/ 6 | target 7 | log/ 8 | .shadow-cljs/ 9 | node_modules/ 10 | modules/ 11 | 12 | # IntelliJ 13 | *.iml 14 | .idea/ 15 | *.bak 16 | 17 | # clj-kondo 18 | .clj-kondo/.cache/ 19 | .calva/output-window/ 20 | .lsp/.cache/ 21 | -------------------------------------------------------------------------------- /libs/kit-hato/src/kit/edge/http/hato.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.http.hato 2 | (:require 3 | [hato.client :as client] 4 | [integrant.core :as ig])) 5 | 6 | (derive :http.client/hato :http/client) 7 | 8 | (defmethod ig/init-key :http.client/hato 9 | [_ config] 10 | (client/build-http-client config)) 11 | 12 | (defmethod ig/halt-key! :http.client/hato [_ _] nil) -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/kit.edn: -------------------------------------------------------------------------------- 1 | {:full-name "<>" 2 | :ns-name "<>" 3 | :sanitized "<>" 4 | :name "<>" 5 | :modules {:root "modules" 6 | :repositories [{:url "https://github.com/kit-clj/modules.git" 7 | :tag "master" 8 | :name "kit-modules"}]}} 9 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | jobs: 4 | bb-run-test: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Check out repository code 8 | uses: actions/checkout@v5 9 | - name: Install clojure tools 10 | uses: DeLaGuardo/setup-clojure@13.4 11 | with: 12 | cli: latest 13 | bb: latest 14 | - run: bb ci 15 | -------------------------------------------------------------------------------- /libs/kit-generator/test/kit_generator/io.clj: -------------------------------------------------------------------------------- 1 | (ns kit-generator.io 2 | (:require [clojure.java.io :as io])) 3 | 4 | (defn delete-folder [file-name] 5 | (letfn [(func [f] 6 | (when (.exists f) 7 | (when (.isDirectory f) 8 | (doseq [f2 (.listFiles f)] 9 | (func f2))) 10 | (io/delete-file f)))] 11 | (func (io/file file-name)))) 12 | -------------------------------------------------------------------------------- /libs/kit-sql-migratus/src/kit/edge/db/sql/migratus.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.db.sql.migratus 2 | (:require 3 | [integrant.core :as ig] 4 | [migratus.core :as migratus])) 5 | 6 | (defmethod ig/init-key :db.sql/migrations 7 | [_ {:keys [migrate-on-init?] 8 | :or {migrate-on-init? true} 9 | :as component}] 10 | (when migrate-on-init? 11 | (migratus/migrate component)) 12 | component) 13 | 14 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax = docker/dockerfile:1.2 2 | FROM clojure:openjdk-17 AS build 3 | 4 | WORKDIR / 5 | COPY . / 6 | 7 | RUN clj -Sforce -T:build all 8 | 9 | FROM azul/zulu-openjdk-alpine:17 10 | 11 | COPY --from=build /target/<>-standalone.jar /<>/<>-standalone.jar 12 | 13 | EXPOSE $PORT 14 | 15 | ENTRYPOINT exec java $JAVA_OPTS -jar /<>/<>-standalone.jar 16 | -------------------------------------------------------------------------------- /libs/kit-generator/src/kit/generator/io.clj: -------------------------------------------------------------------------------- 1 | (ns kit.generator.io 2 | (:require 3 | [clojure.edn :as edn])) 4 | 5 | (defn str->edn [config] 6 | (edn/read-string {:default tagged-literal} config)) 7 | 8 | (defn edn->str [edn] 9 | (binding [*print-namespace-maps* false] 10 | (with-out-str (prn edn)))) 11 | 12 | (defn update-edn-file [path f] 13 | (spit 14 | path 15 | (-> (slurp path) 16 | (str->edn) 17 | (f) 18 | (edn->str)))) 19 | 20 | -------------------------------------------------------------------------------- /libs/lein-template/src/leiningen/new/io/github/kit_clj/options/sql.clj: -------------------------------------------------------------------------------- 1 | (ns leiningen.new.io.github.kit-clj.options.sql 2 | (:require 3 | [leiningen.new.io.github.kit-clj.options.helpers :as helpers])) 4 | 5 | (defn queries-files 6 | [data] 7 | [["resources/queries.sql" (helpers/render "resources/queries.sql" data)]]) 8 | 9 | (defn migrations-files 10 | [data] 11 | [["resources/migrations/placeholder.txt" (helpers/render "resources/migrations/placeholder.txt" data)]]) -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/env/prod/clj/env.clj: -------------------------------------------------------------------------------- 1 | (ns <>.env 2 | (:require [clojure.tools.logging :as log])) 3 | 4 | (def defaults 5 | {:init (fn [] 6 | (log/info "\n-=[<> starting]=-")) 7 | :start (fn [] 8 | (log/info "\n-=[<> started successfully]=-")) 9 | :stop (fn [] 10 | (log/info "\n-=[<> has shut down successfully]=-")) 11 | :middleware (fn [handler _] handler) 12 | :opts {:profile :prod}}) 13 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/src/clj/web/controllers/health.clj: -------------------------------------------------------------------------------- 1 | (ns <>.web.controllers.health 2 | (:require 3 | [ring.util.http-response :as http-response]) 4 | (:import 5 | [java.util Date])) 6 | 7 | (defn healthcheck! 8 | [req] 9 | (http-response/ok 10 | {:time (str (Date. (System/currentTimeMillis))) 11 | :up-since (str (Date. (.getStartTime (java.lang.management.ManagementFactory/getRuntimeMXBean)))) 12 | :app {:status "up" 13 | :message ""}})) 14 | -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/modules/kit/cljs/assets/src/core.cljs: -------------------------------------------------------------------------------- 1 | (ns <>.core 2 | (:require 3 | [reagent.core :as r] 4 | [reagent.dom :as d])) 5 | 6 | ;; ------------------------- 7 | ;; Views 8 | 9 | (defn home-page [] 10 | [:div [:h2 "Welcome to Reagent!"]]) 11 | 12 | ;; ------------------------- 13 | ;; Initialize app 14 | 15 | (defn ^:dev/after-load mount-root [] 16 | (d/render [home-page] (.getElementById js/document "app"))) 17 | 18 | (defn ^:export ^:dev/once init! [] 19 | (mount-root)) 20 | -------------------------------------------------------------------------------- /libs/deps-template/src/io/github/kit_clj/deps_template/helpers.clj: -------------------------------------------------------------------------------- 1 | (ns io.github.kit-clj.deps-template.helpers 2 | (:require [selmer.parser :as selmer])) 3 | 4 | (defn render-selmer 5 | [text options] 6 | (selmer/render 7 | (str "<% safe %>" text "<% endsafe %>") 8 | options 9 | {:tag-open \< :tag-close \> :filter-open \< :filter-close \>})) 10 | 11 | (defn generate-cookie-secret 12 | ([] (generate-cookie-secret 16)) 13 | ([n] 14 | (->> (repeatedly #(char (+ (rand 26) 65))) 15 | (take n) 16 | (apply str)))) 17 | -------------------------------------------------------------------------------- /libs/kit-generator/test/kit_generator/snippets.clj: -------------------------------------------------------------------------------- 1 | (ns kit-generator.snippets 2 | (:require 3 | [kit.generator.snippets :refer :all] 4 | [clojure.java.io :as io] 5 | [clojure.test :refer :all])) 6 | 7 | (deftest parse-snippets 8 | (let [snippets (load-snippets "test/resources/snippets")] 9 | (is (= #{:kit/routing :kit/some-odd-file-name-for-snippet} (set (keys snippets)))))) 10 | 11 | (deftest find-snippet 12 | (let [snippets (load-snippets "test/resources/snippets")] 13 | (is (= [:kit/routing] (find-snippets snippets "rei"))))) 14 | -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/snippets/kit/routing.md: -------------------------------------------------------------------------------- 1 | ## tags 2 | reitit routing routes 3 | 4 | ## description 5 | 6 | generates a route definition 7 | takes path and method as arguments 8 | 9 | arguments are path string and method keyword 10 | 11 | generates a route, e.g: 12 | ["/foo" {:get ...}] 13 | 14 | ## code 15 | 16 | ```clojure 17 | ["<>" 18 | {<> 19 | {:summary "TODO" 20 | :parameters {} 21 | :responses {200 {:body map?}} 22 | :handler 23 | (fn [request] 24 | {:body "<>"})}}] 25 | ``` 26 | -------------------------------------------------------------------------------- /libs/kit-core/src/kit/config.clj: -------------------------------------------------------------------------------- 1 | (ns kit.config 2 | (:require 3 | [aero.core :as aero] 4 | [clojure.java.io :as io] 5 | [clojure.tools.logging :as log] 6 | [integrant.core :as ig])) 7 | 8 | (defmethod aero/reader 'ig/ref 9 | [_ _ value] 10 | (ig/ref value)) 11 | 12 | (defmethod aero/reader 'ig/refset 13 | [_ _ value] 14 | (ig/refset value)) 15 | 16 | (defn read-config 17 | [filename options] 18 | (log/info "Reading config" filename) 19 | (aero/read-config (io/resource filename) options)) 20 | 21 | (defmethod ig/init-key :system/env [_ env] env) -------------------------------------------------------------------------------- /libs/kit-metrics/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {org.clojure/tools.logging {:mvn/version "1.2.4"} 3 | clj-commons/iapetos {:mvn/version "0.1.13"} 4 | io.prometheus/simpleclient {:mvn/version "0.16.0"} 5 | io.prometheus/simpleclient_common {:mvn/version "0.16.0"} 6 | io.prometheus/simpleclient_hotspot {:mvn/version "0.16.0"} 7 | io.prometheus/simpleclient_httpserver {:mvn/version "0.16.0"} 8 | io.prometheus/simpleclient_pushgateway {:mvn/version "0.16.0"}}} 9 | -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/sample-system.edn: -------------------------------------------------------------------------------- 1 | {:system/env 2 | #profile {:dev :dev 3 | :test :test 4 | :prod :prod} 5 | 6 | :server/undertow 7 | {:port #long #or [#env PORT 3000] 8 | :handler #ig/ref :handler/ring} 9 | 10 | :handler/ring 11 | {:router #ig/ref :router/core 12 | :api-path "/api" 13 | } 14 | 15 | :reitit.routes/api 16 | {:base-path "/api" 17 | :env #ig/ref :system/env 18 | } 19 | 20 | :router/routes 21 | {:routes #ig/refset :reitit/routes} 22 | 23 | :router/core 24 | {:routes #ig/ref :router/routes}} 25 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/src/clj/web/middleware/formats.clj: -------------------------------------------------------------------------------- 1 | (ns <>.web.middleware.formats 2 | (:require 3 | [luminus-transit.time :as time] 4 | [muuntaja.core :as m])) 5 | 6 | (def instance 7 | (m/create 8 | (-> m/default-options 9 | (update-in 10 | [:formats "application/transit+json" :decoder-opts] 11 | (partial merge time/time-deserialization-handlers)) 12 | (update-in 13 | [:formats "application/transit+json" :encoder-opts] 14 | (partial merge time/time-serialization-handlers))))) 15 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/test/clj/web/request_test.clj: -------------------------------------------------------------------------------- 1 | (ns <>.web.request-test 2 | (:require [clojure.test :refer [deftest testing is use-fixtures]] 3 | [<>.test-utils :refer [system-state system-fixture GET]])) 4 | 5 | (use-fixtures :once (system-fixture)) 6 | 7 | (deftest health-request-test [] 8 | (testing "happy path" 9 | (let [handler (:handler/ring (system-state)) 10 | params {} 11 | headers {} 12 | response (GET handler "/api/health" params headers)] 13 | (is (= 200 (:status response)))))) 14 | -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/modules/kit/cljs/assets/shadow-cljs.edn: -------------------------------------------------------------------------------- 1 | {:nrepl {:port 7002} 2 | :source-paths ["src/cljs"] 3 | :dependencies [[binaryage/devtools "1.0.3"] 4 | [nrepl "0.8.3"] 5 | [reagent "1.1.0"] 6 | [cljs-ajax "0.8.4"]] 7 | :builds {:app {:target :browser 8 | :output-dir "target/classes/cljsbuild/public/js" 9 | :asset-path "/js" 10 | :modules {:app {:entries [<>.core]}} 11 | :devtools {:after-load <>.core/mount-root}}}} 12 | -------------------------------------------------------------------------------- /libs/kit-generator/src/kit/generator/modules/dependencies.clj: -------------------------------------------------------------------------------- 1 | (ns kit.generator.modules.dependencies) 2 | 3 | (defn resolve-dependencies 4 | ([module-config feature-flag] 5 | (resolve-dependencies module-config feature-flag #{})) 6 | ([module-config feature-flag reqs] 7 | (let [requires (get-in module-config [feature-flag :requires] []) 8 | feature-requires (get-in module-config [feature-flag :feature-requires])] 9 | (if feature-requires 10 | (into #{} (mapcat #(resolve-dependencies (dissoc module-config feature-flag) % requires) feature-requires)) 11 | (into reqs requires))))) 12 | -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/kit.edn: -------------------------------------------------------------------------------- 1 | {:ns-name "myapp" 2 | :sanitized "myapp" 3 | :name "myapp" 4 | :project-root "test/resources/generated" 5 | :modules {:root "test/resources/modules" 6 | :repositories [{:url "git@github.com:kit-clj/modules.git" 7 | :tag "master" 8 | :name "kit"}]} 9 | :snippets {:root "test/resources/snippets" 10 | :repositories [{:url "git@github.com:kit-clj/snippets.git" 11 | :tag "master" 12 | :name "kit"}]}} 13 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/env/dev/clj/env.clj: -------------------------------------------------------------------------------- 1 | (ns <>.env 2 | (:require 3 | [clojure.tools.logging :as log] 4 | [<>.dev-middleware :refer [wrap-dev]])) 5 | 6 | (def defaults 7 | {:init (fn [] 8 | (log/info "\n-=[<> starting using the development or test profile]=-")) 9 | :start (fn [] 10 | (log/info "\n-=[<> started successfully using the development or test profile]=-")) 11 | :stop (fn [] 12 | (log/info "\n-=[<> has shut down successfully]=-")) 13 | :middleware wrap-dev 14 | :opts {:profile :dev}}) 15 | -------------------------------------------------------------------------------- /libs/kit-generator/src/kit/generator/renderer.clj: -------------------------------------------------------------------------------- 1 | (ns kit.generator.renderer 2 | (:require 3 | [clojure.string :as string] 4 | [selmer.parser :as selmer])) 5 | 6 | (defn render-template [ctx template] 7 | (selmer/render 8 | (str "<% safe %>" template "<% endsafe %>") 9 | ctx 10 | {:tag-open \< :tag-close \> :filter-open \< :filter-close \>})) 11 | 12 | (selmer/add-tag! 13 | :include 14 | (fn [args context-map] 15 | (-> (render-template context-map (slurp (first args))) 16 | (string/replace #"^\n+" "") 17 | (string/replace #"\n+$" "")))) 18 | 19 | (defn render-asset [ctx asset] 20 | (if (string? asset) 21 | (render-template ctx asset) 22 | asset)) 23 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/env/prod/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %-5relative %-5level %logger{35} - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/env/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %-5relative %-5level %logger{35} - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/versions.edn: -------------------------------------------------------------------------------- 1 | {"kit-core" "1.0.9" 2 | "kit-http-kit" "1.0.5" 3 | "kit-jdk-http" "1.0.0" 4 | "kit-jetty" "1.0.0" 5 | "kit-xtdb" "1.0.4" 6 | "kit-generator" "0.2.5" 7 | "kit-hato" "1.0.4" 8 | "kit-nrepl" "1.0.5" 9 | "kit-metrics" "1.0.3" 10 | "kit-mysql" "1.0.5" 11 | "kit-postgres" "1.0.7" 12 | "kit-quartz" "1.0.4" 13 | "kit-redis" "1.0.6" 14 | "kit-repl" "1.0.3" 15 | "kit-selmer" "1.0.4" 16 | "kit-sql-migratus" "1.0.5" 17 | "kit-sql-conman" "1.10.5" 18 | "kit-sql-hikari" "1.0.6" 19 | "kit-sql" "1.1.4" 20 | "kit-undertow" "1.0.10" 21 | "lein-template" "0.1.85" 22 | "deps-template" "0.1.85"} 23 | -------------------------------------------------------------------------------- /libs/kit-selmer/src/kit/edge/templating/selmer.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.templating.selmer 2 | (:require 3 | [integrant.core :as ig] 4 | [selmer.parser :as selmer])) 5 | 6 | (defmethod ig/init-key :templating/selmer 7 | [_ {:keys [resource-path cache? custom-markers] 8 | :or {cache? true}}] 9 | ;; To use default path, resource-path must be nil 10 | (selmer/set-resource-path! resource-path) 11 | 12 | ;; Clear cache (for reloadable workflow) 13 | (reset! selmer/templates {}) 14 | (if cache? (selmer/cache-on!) (selmer/cache-off!)) 15 | 16 | {:render (fn [template & [opts]] 17 | (selmer/render template opts custom-markers)) 18 | :render-file (fn [file & [opts]] 19 | (selmer/render-file file opts custom-markers))}) 20 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/src/clj/web/middleware/core.clj: -------------------------------------------------------------------------------- 1 | (ns <>.web.middleware.core 2 | (:require 3 | [<>.env :as env] 4 | [ring.middleware.defaults :as defaults] 5 | [ring.middleware.session.cookie :as cookie]<% if metrics? %> 6 | [iapetos.collector.ring :as prometheus-ring]<% endif %>)) 7 | 8 | (defn wrap-base 9 | [{:keys [metrics site-defaults-config cookie-secret] :as opts}] 10 | (let [cookie-store (cookie/cookie-store {:key (.getBytes ^String cookie-secret)})] 11 | (fn [handler] 12 | (cond-> ((:middleware env/defaults) handler opts) 13 | true (defaults/wrap-defaults 14 | (assoc-in site-defaults-config [:session :store] cookie-store)) 15 | <% if metrics? %> (some? metrics) (prometheus-ring/wrap-metrics metrics) <% endif %>)))) 16 | -------------------------------------------------------------------------------- /libs/kit-generator/test/kit/generator/io_test.clj: -------------------------------------------------------------------------------- 1 | (ns kit.generator.io-test 2 | (:require 3 | [clojure.test :refer :all] 4 | [kit.generator.io :as io])) 5 | 6 | (deftest edn-read-write-test 7 | (testing "round trip test" 8 | (is (= "{:db.sql/connection #profile {:prod {:jdbc-url #env JDBC_URL}}}\n" 9 | (io/edn->str (io/str->edn "{:db.sql/connection #profile\n {:prod {:jdbc-url #env JDBC_URL}}}")))) 10 | (is (= "{:base-path \"/\", :env #ig/ref :system/env}\n" 11 | (io/edn->str (io/str->edn "{:base-path \"/\" :env #ig/ref :system/env}")))) 12 | 13 | (is (= "{:port #long #or [#env PORT 3000], :handler #ig/ref :handler/ring}\n" 14 | (io/edn->str (io/str->edn "{:port #long #or [#env PORT 3000]\n :handler #ig/ref :handler/ring}")))) 15 | 16 | (is (= "{'foo :bar}\n" 17 | (io/edn->str (io/str->edn "{'foo :bar}")))))) 18 | -------------------------------------------------------------------------------- /libs/kit-generator/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {org.clojure/clojure {:mvn/version "1.11.1"} 3 | hato/hato {:mvn/version "1.0.0"} 4 | selmer/selmer {:mvn/version "1.12.59"} 5 | clj-jgit/clj-jgit {:mvn/version "1.0.2"} 6 | org.clojure/tools.logging {:mvn/version "1.2.4"} 7 | borkdude/rewrite-edn {:mvn/version "0.4.6"} 8 | enlive/enlive {:mvn/version "1.1.6"} 9 | rewrite-clj/rewrite-clj {:mvn/version "1.1.46"} 10 | mvxcvi/cljstyle {:mvn/version "0.15.0"} 11 | cljfmt/cljfmt {:mvn/version "0.9.2"} 12 | clj-fuzzy/clj-fuzzy {:mvn/version "0.4.1"} 13 | clojure-deep-merge/clojure-deep-merge {:mvn/version "0.1.2"}}} 14 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/test/clj/test_utils.clj: -------------------------------------------------------------------------------- 1 | (ns <>.test-utils 2 | (:require 3 | [<>.core :as core] 4 | [peridot.core :as p] 5 | [byte-streams :as bs] 6 | [integrant.repl.state :as state])) 7 | 8 | (defn system-state 9 | [] 10 | (or @core/system state/system)) 11 | 12 | (defn system-fixture 13 | [] 14 | (fn [f] 15 | (when (nil? (system-state)) 16 | (core/start-app {:opts {:profile :test}})) 17 | (f) 18 | (core/stop-app))) 19 | 20 | (defn get-response [ctx] 21 | (-> ctx 22 | :response 23 | (update :body (fnil bs/to-string "")))) 24 | 25 | (defn GET [app path params headers] 26 | (-> (p/session app) 27 | (p/request path 28 | :request-method :get 29 | :content-type "application/edn" 30 | :headers headers 31 | :params params) 32 | (get-response))) 33 | -------------------------------------------------------------------------------- /libs/kit-repl/src/kit/edge/utils/repl.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.utils.repl 2 | (:require 3 | [clojure.core.server :as socket] 4 | [clojure.tools.logging :as log] 5 | [integrant.core :as ig])) 6 | 7 | (defmethod ig/expand-key :repl/server 8 | [k config] 9 | {k (merge {:name "main"} config)}) 10 | 11 | (defmethod ig/init-key :repl/server 12 | [_ {:keys [port host name] :as config}] 13 | (try 14 | (socket/start-server {:address host 15 | :port port 16 | :name name 17 | :accept 'clojure.core.server/repl}) 18 | (log/info "REPL server started on host:" host "port:" port) 19 | (catch Exception e 20 | (log/error "failed to start the REPL server on host:" host "port:" port) 21 | (throw e))) 22 | config) 23 | 24 | (defmethod ig/halt-key! :repl/server 25 | [_ config] 26 | (socket/stop-server (:name config)) 27 | (log/info "REPL server stopped")) 28 | -------------------------------------------------------------------------------- /libs/kit-mysql/src/kit/edge/db/mysql.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.db.mysql 2 | (:require 3 | [next.jdbc] 4 | [next.jdbc.prepare :as prepare] 5 | [next.jdbc.result-set :as result-set]) 6 | (:import 7 | [java.sql Array PreparedStatement Timestamp] 8 | [java.time Instant LocalDate LocalDateTime])) 9 | 10 | (extend-protocol result-set/ReadableColumn 11 | Array 12 | (read-column-by-label [^Array v _] (vec (.getArray v))) 13 | (read-column-by-index [^Array v _2 _3] (vec (.getArray v)))) 14 | 15 | (extend-protocol prepare/SettableParameter 16 | Instant 17 | (set-parameter [^Instant v ^PreparedStatement ps ^long i] 18 | (.setTimestamp ps i (Timestamp/from v))) 19 | 20 | LocalDate 21 | (set-parameter [^LocalDate v ^PreparedStatement ps ^long i] 22 | (.setTimestamp ps i (Timestamp/valueOf (.atStartOfDay v)))) 23 | 24 | LocalDateTime 25 | (set-parameter [^LocalDateTime v ^PreparedStatement ps ^long i] 26 | (.setTimestamp ps i (Timestamp/valueOf v)))) 27 | -------------------------------------------------------------------------------- /libs/kit-core/src/kit/ig_utils.clj: -------------------------------------------------------------------------------- 1 | (ns kit.ig-utils 2 | "Integrant utilities" 3 | (:require 4 | [clojure.java.io :as io] 5 | [clojure.tools.logging :as log] 6 | [integrant.core :as ig]) 7 | (:import (java.nio.file Files LinkOption Paths))) 8 | 9 | (defn resume-handler 10 | "Useful where you don't want to reset an integrant component in development" 11 | [k opts old-opts old-impl] 12 | (log/info k "resume check. Same?" (= opts old-opts)) 13 | (if (= opts old-opts) 14 | old-impl 15 | (do (ig/halt-key! k old-impl) 16 | (ig/init-key k opts)))) 17 | 18 | (defn last-modified [filename] 19 | (let [url (io/resource filename)] 20 | (if url 21 | (case (.getProtocol url) 22 | "file" (-> (.toURI url) 23 | (Paths/get) 24 | (Files/getLastModifiedTime (into-array LinkOption [])) 25 | (.toMillis)) 26 | "jar" 0 27 | (throw (ex-info "Unsupported URL protocol" {:protocol (.getProtocol url)}))) 28 | (throw (ex-info "Resource not found" {:filename filename}))))) 29 | 30 | -------------------------------------------------------------------------------- /libs/kit-quartz/src/kit/edge/scheduling/quartz.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.scheduling.quartz 2 | (:require 3 | [aero.core :as aero] 4 | [integrant.core :as ig] 5 | [kit.ig-utils :as ig-utils] 6 | [troy-west.cronut :as cronut])) 7 | 8 | (defmethod aero/reader 'cronut/trigger 9 | [_ _ value] 10 | (cronut/trigger-builder value)) 11 | 12 | (defmethod aero/reader 'cronut/cron 13 | [_ _ value] 14 | (cronut/shortcut-cron value)) 15 | 16 | (defmethod aero/reader 'cronut/interval 17 | [_ _ value] 18 | (cronut/shortcut-interval value)) 19 | 20 | (defmethod ig/suspend-key! :cronut/scheduler [_ _]) 21 | 22 | (defmethod ig/resume-key :cronut/scheduler 23 | [key opts old-opts old-impl] 24 | (ig-utils/resume-handler key opts old-opts old-impl)) 25 | 26 | ;; Means of setting environment properties during runtime 27 | ;; Handy in case there's a scenario where you can't (for whatever reason) set 28 | ;; secrets in your JVM properties 29 | (defmethod ig/init-key :scheduling.quartz/env-properties 30 | [_ properties] 31 | (doseq [[k v] properties] 32 | (when (some? v) 33 | (System/setProperty (name k) v)))) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Kit framework team 2021 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /libs/kit-nrepl/src/kit/edge/utils/nrepl.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.utils.nrepl 2 | (:require 3 | [clojure.tools.logging :as log] 4 | [integrant.core :as ig] 5 | [kit.ig-utils :as ig-utils] 6 | [nrepl.cmdline] 7 | [nrepl.server :as nrepl])) 8 | 9 | (defmethod ig/init-key :nrepl/server 10 | [_ {:keys [port bind ack-port create-nrepl-port-file?] :as config}] 11 | (try 12 | (let [server (nrepl/start-server :port port 13 | :bind bind 14 | :ack-port ack-port)] 15 | (when create-nrepl-port-file? 16 | (nrepl.cmdline/save-port-file server {})) 17 | (log/info "nREPL server started on port:" port) 18 | (assoc config ::server server)) 19 | (catch Exception e 20 | (log/error "failed to start the nREPL server on port:" port) 21 | (throw e)))) 22 | 23 | (defmethod ig/suspend-key! :nrepl/server [_ _]) 24 | 25 | (defmethod ig/halt-key! :nrepl/server 26 | [_ {::keys [server]}] 27 | (nrepl/stop-server server) 28 | (log/info "nREPL server stopped")) 29 | 30 | (defmethod ig/resume-key :nrepl/server 31 | [key opts old-opts old-impl] 32 | (ig-utils/resume-handler key opts old-opts old-impl)) 33 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/bb.edn: -------------------------------------------------------------------------------- 1 | {:min-bb-version "0.8.156" 2 | :deps {failjure/failjure {:mvn/version "2.3.0"}} 3 | :tasks {:requires ([babashka.fs :as fs] 4 | [babashka.tasks :refer [shell]]) 5 | 6 | run {:doc "starts the app" 7 | :task (if (fs/windows?) 8 | (clojure {:dir "."} "-M:dev") 9 | (shell {:dir "."} "clj -M:dev"))} 10 | 11 | nrepl {:doc "starts the nREPL" 12 | :task (clojure {:dir "."} "-M:dev:nrepl")} 13 | 14 | cider {:doc "starts the cider" 15 | :task (clojure {:dir "."} "-M:dev:cider")} 16 | 17 | test {:doc "runs tests" 18 | :task (clojure {:dir "."} "-M:test")} 19 | 20 | uberjar {:doc "builds the uberjar" 21 | :task (clojure {:dir "."} "-T:build all")} 22 | 23 | format {:doc "Formats codebase" 24 | :task (try 25 | (shell {:dir "src"} "cljstyle fix") 26 | (catch Exception _ 27 | (clojure {:dir "src"} "-M:dev -m cljstyle.main fix")))}}} 28 | -------------------------------------------------------------------------------- /libs/kit-metrics/src/kit/edge/utils/metrics.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.utils.metrics 2 | (:require 3 | [clojure.tools.logging :as log] 4 | [iapetos.core :as prometheus] 5 | [iapetos.collector.fn :as fn] 6 | [iapetos.collector.jvm :as jvm] 7 | [iapetos.collector.ring :as ring] 8 | [integrant.core :as ig])) 9 | 10 | (defn register-definition 11 | [{:keys [type metric opts] 12 | :or {opts {}}}] 13 | ((case type 14 | :histogram prometheus/histogram 15 | :gauge prometheus/gauge 16 | :counter prometheus/counter 17 | :summary prometheus/summary 18 | (throw (ex-info "Metric not defined" {:type ::not-defined 19 | :metric-type type 20 | :metric metric}))) 21 | metric 22 | opts)) 23 | 24 | (defmethod ig/init-key :metrics/prometheus 25 | [_ {:keys [definitions jvm? fn? ring?] 26 | :or {jvm? true 27 | fn? true 28 | ring? true}}] 29 | (log/info :action "Initializing metrics") 30 | (cond-> (apply prometheus/register (prometheus/collector-registry) (map register-definition definitions)) 31 | jvm? (jvm/initialize) 32 | fn? (fn/initialize) 33 | ring? (ring/initialize))) -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/core.clj: -------------------------------------------------------------------------------- 1 | (ns myapp.core 2 | (:require 3 | [clojure.tools.logging :as log] 4 | [integrant.core :as ig] 5 | [wake.guestbook.config :as config] 6 | [wake.guestbook.env :refer [defaults]] 7 | 8 | ;; Edges 9 | [kit.edge.utils.repl] 10 | [kit.edge.server.undertow] 11 | [wake.guestbook.web.handler] 12 | 13 | ;; Routes 14 | [wake.guestbook.web.routes.api] 15 | [wake.guestbook.web.routes.pages] 16 | ) 17 | (:gen-class)) 18 | 19 | ;; log uncaught exceptions in threads 20 | (Thread/setDefaultUncaughtExceptionHandler 21 | (reify Thread$UncaughtExceptionHandler 22 | (uncaughtException [_ thread ex] 23 | (log/error {:what :uncaught-exception 24 | :exception ex 25 | :where (str "Uncaught exception on" (.getName thread))})))) 26 | 27 | (defonce system (atom nil)) 28 | 29 | (defn stop-app [] 30 | ((or (:stop defaults) (fn []))) 31 | (some-> (deref system) (ig/halt!))) 32 | 33 | (defn start-app [& [params]] 34 | ((or (:start params) (:start defaults) (fn []))) 35 | (->> (config/system-config (or (:opts params) (:opts defaults) {})) 36 | (ig/expand) 37 | (ig/init) 38 | (reset! system)) 39 | (.addShutdownHook (Runtime/getRuntime) (Thread. (fn [] (stop-app) (shutdown-agents))))) 40 | 41 | (defn -main [& _] 42 | (start-app)) 43 | -------------------------------------------------------------------------------- /deps.edn: -------------------------------------------------------------------------------- 1 | {:deps {io.github.kit-clj/deps-template {:local/root "libs/deps-template"}} 2 | :aliases {:new {:extra-deps {com.github.seancorfield/clj-new {:mvn/version "1.3.415"}} 3 | :exec-fn clj-new/create 4 | :exec-args {:template kit-clj}} 5 | :deps-new {:extra-deps {io.github.seancorfield/deps-new {:git/tag "v0.10.1" :git/sha "a90029c"}} 6 | :exec-fn org.corfield.new/create} 7 | :build {:deps {io.github.clojure/tools.build {:mvn/version "0.10.11"} 8 | slipset/deps-deploy {:mvn/version "0.2.2"} 9 | weavejester/dependency {:mvn/version "1.0.0"} 10 | rewrite-clj/rewrite-clj {:mvn/version "1.2.50"} 11 | babashka/fs {:mvn/version "0.5.27"}} 12 | :extra-paths ["build"] 13 | :ns-default build} 14 | 15 | :test ;; added by neil 16 | {:extra-paths ["test"] 17 | :extra-deps {io.github.cognitect-labs/test-runner 18 | {:git/tag "v0.5.1" :git/sha "dfb30dd"} 19 | babashka/fs {:mvn/version "0.5.27"} 20 | babashka/process {:mvn/version "0.6.23"}} 21 | :main-opts ["-m" "cognitect.test-runner"] 22 | :exec-fn cognitect.test-runner.api/test}}} 23 | -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/modules/kit/html/config.edn: -------------------------------------------------------------------------------- 1 | {:default 2 | {:require-restart? true 3 | :success-message "HTML module installed successfully!" 4 | :actions {:assets [["assets/home.html" "test/resources/generated/resources/public/home.html"] 5 | ["assets/img/luminus.png" "test/resources/generated/resources/public/img/luminus.png"] 6 | ["assets/pages.clj" "test/resources/generated/src/clj/<>/web/routes/pages.clj"]] 7 | :injections 8 | [{:type :edn 9 | :path "test/resources/generated/resources/system.edn" 10 | :target [] 11 | :action :merge 12 | :value {:reitit.routes/pages 13 | {:base-path "/" 14 | :env #ig/ref :system/env} 15 | :templating/selmer 16 | {}}} 17 | {:type :clj 18 | :path "test/resources/generated/src/<>/core.clj" 19 | :action :append-requires 20 | :value ["[<>.web.routes.pages]"]}]}}} 21 | -------------------------------------------------------------------------------- /libs/lein-template/src/leiningen/new/io/github/kit_clj/options/helpers.clj: -------------------------------------------------------------------------------- 1 | (ns leiningen.new.io.github.kit-clj.options.helpers 2 | (:require 3 | [leiningen.new.templates :as templates] 4 | [clojure.java.io :as io] 5 | [io.github.kit-clj.deps-template.helpers :refer [render-selmer]])) 6 | 7 | (def template-name "kit") 8 | 9 | (defn resource-path->template-path [resource-path] 10 | (str "io/github/kit_clj/" (templates/sanitize template-name) "/" resource-path)) 11 | 12 | (defn render-text [template & [data]] 13 | (let [path (resource-path->template-path template)] 14 | (if-let [resource (io/resource path)] 15 | (if data 16 | (render-selmer (templates/slurp-resource resource) data) 17 | (io/reader resource)) 18 | (throw (ex-info (format "Template resource '%s' not found." path) 19 | {}))))) 20 | 21 | (defn resource-input 22 | "Get resource input stream. Useful for binary resources like images." 23 | [resource-path] 24 | (-> (resource-path->template-path resource-path) 25 | io/resource 26 | io/input-stream)) 27 | 28 | (defn render 29 | "Render the content of a resource" 30 | ([resource-path] 31 | (resource-input resource-path)) 32 | ([resource-path data] 33 | (render-text resource-path data))) 34 | 35 | (defn option? [option-name options] 36 | (boolean 37 | (some #{option-name} options))) 38 | -------------------------------------------------------------------------------- /libs/kit-sql-hikari/src/kit/edge/db/sql/hikari.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.db.sql.hikari 2 | (:require 3 | [hikari-cp.core :as cp] 4 | [integrant.core :as ig] 5 | [kit.ig-utils :as ig-utils] 6 | )) 7 | 8 | (defmethod ig/init-key :db.sql/hikari-connection 9 | [_ pool-spec] 10 | (cp/make-datasource pool-spec)) 11 | 12 | (defmethod ig/suspend-key! :db.sql/hikari-connection [_ _]) 13 | 14 | (defmethod ig/halt-key! :db.sql/hikari-connection 15 | [_ conn] 16 | (cp/close-datasource conn)) 17 | 18 | (defmethod ig/resume-key :db.sql/hikari-connection 19 | [key opts old-opts old-impl] 20 | (ig-utils/resume-handler key opts old-opts old-impl)) 21 | 22 | 23 | (comment 24 | ;; pool-spec-example 25 | {:auto-commit true 26 | :read-only false 27 | :connection-timeout 30000 28 | :validation-timeout 5000 29 | :idle-timeout 600000 30 | :max-lifetime 1800000 31 | :minimum-idle 10 32 | :maximum-pool-size 10 33 | :pool-name "ds-pool" 34 | :username "root" 35 | :password "123456" 36 | :jdbc-url "jdbc:mysql://1270.0.01:3306/test_db?characterEncoding=utf8" 37 | :driver-class-name "com.mysql.jdbc.Driver" 38 | ;; :adapter "mysql" 39 | ;; :database-name "test_db" 40 | ;; :server-name "192.210.170.12" 41 | ;; :port-number 3306 42 | :register-mbeans false} 43 | 44 | ) 45 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/src/clj/web/middleware/exception.clj: -------------------------------------------------------------------------------- 1 | (ns <>.web.middleware.exception 2 | (:require 3 | [clojure.tools.logging :as log] 4 | [reitit.ring.middleware.exception :as exception])) 5 | 6 | (defn handler [message status exception request] 7 | (when (>= status 500) 8 | ;; You can optionally use this to report error to an external service 9 | (log/error exception)) 10 | {:status status 11 | :body {:message message 12 | :exception (.getClass exception) 13 | :data (ex-data exception) 14 | :uri (:uri request)}}) 15 | 16 | (def wrap-exception 17 | (exception/create-exception-middleware 18 | (merge 19 | exception/default-handlers 20 | {:system.exception/internal (partial handler "internal exception" 500) 21 | :system.exception/business (partial handler "bad request" 400) 22 | :system.exception/not-found (partial handler "not found" 404) 23 | :system.exception/unauthorized (partial handler "unauthorized" 401) 24 | :system.exception/forbidden (partial handler "forbidden" 403) 25 | 26 | ;; override the default handler 27 | ::exception/default (partial handler "default" 500) 28 | 29 | ;; print stack-traces for all exceptions 30 | ::exception/wrap (fn [handler e request] 31 | (handler e request))}))) 32 | -------------------------------------------------------------------------------- /libs/kit-jdk-http/src/kit/edge/server/jdk.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.server.jdk 2 | (:require 3 | [integrant.core :as ig] 4 | [clojure.tools.logging :as log] 5 | [ring.adapter.jdk :as jdk])) 6 | 7 | (defn start [handler {:keys [host port] :as opts}] 8 | (try 9 | (log/info "starting HTTP server on port" port) 10 | (jdk/server handler (dissoc opts :handler :init)) 11 | (catch Throwable t 12 | (log/error t (str "server failed to start on" host "port" port)) 13 | (throw t)))) 14 | 15 | (defn stop [http-server] 16 | (jdk/stop http-server) 17 | (log/info "HTTP server stopped")) 18 | 19 | (defmethod ig/expand-key :server/http 20 | [k config] 21 | {k (merge {:port 3000 22 | :host "0.0.0.0"} 23 | config)}) 24 | 25 | (defmethod ig/init-key :server/http 26 | [_ opts] 27 | (let [handler (atom (delay (:handler opts)))] 28 | {:handler handler 29 | :server (start (fn [req] (@@handler req)) (dissoc opts :handler))})) 30 | 31 | (defmethod ig/halt-key! :server/http 32 | [_ {:keys [server]}] 33 | (stop server)) 34 | 35 | (defmethod ig/suspend-key! :server/http 36 | [_ {:keys [handler]}] 37 | (reset! handler (promise))) 38 | 39 | (defmethod ig/resume-key :server/http 40 | [k opts old-opts old-impl] 41 | (if (= (dissoc opts :handler) (dissoc old-opts :handler)) 42 | (do (deliver @(:handler old-impl) (:handler opts)) 43 | old-impl) 44 | (do (ig/halt-key! k old-impl) 45 | (ig/init-key k opts)))) 46 | -------------------------------------------------------------------------------- /libs/kit-undertow/src/kit/edge/server/undertow.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.server.undertow 2 | (:require 3 | [clojure.tools.logging :as log] 4 | [integrant.core :as ig] 5 | [ring.adapter.undertow :refer [run-undertow]])) 6 | 7 | (defn start [handler {:keys [port] :as opts}] 8 | (try 9 | (let [server (run-undertow handler (dissoc opts :handler))] 10 | (log/info "server started on port" port) 11 | server) 12 | (catch Throwable t 13 | (log/error t (str "server failed to start on port: " port))))) 14 | 15 | (defn stop [server] 16 | (.stop server) 17 | (log/info "HTTP server stopped")) 18 | 19 | (defmethod ig/expand-key :server/http 20 | [k config] 21 | {k (merge {:port 3000 22 | :host "0.0.0.0"} 23 | config)}) 24 | 25 | (defmethod ig/init-key :server/http 26 | [_ opts] 27 | (let [handler (atom (delay (:handler opts)))] 28 | {:handler handler 29 | :server (start (fn [req] (@@handler req)) (dissoc opts :handler))})) 30 | 31 | (defmethod ig/halt-key! :server/http 32 | [_ {:keys [server]}] 33 | (stop server)) 34 | 35 | (defmethod ig/suspend-key! :server/http 36 | [_ {:keys [handler]}] 37 | (reset! handler (promise))) 38 | 39 | (defmethod ig/resume-key :server/http 40 | [k opts old-opts old-impl] 41 | (if (= (dissoc opts :handler) (dissoc old-opts :handler)) 42 | (do (deliver @(:handler old-impl) (:handler opts)) 43 | old-impl) 44 | (do (ig/halt-key! k old-impl) 45 | (ig/init-key k opts)))) 46 | -------------------------------------------------------------------------------- /bb.edn: -------------------------------------------------------------------------------- 1 | {:paths ["build"] 2 | :deps {io.aviso/pretty {:mvn/version "1.4.4"}} 3 | :tasks {:requires ([clojure.string :as str] 4 | [io.aviso.ansi :as ansi]) 5 | :init (do 6 | (def lib (first *command-line-args*)) 7 | (defn clj [& args] 8 | (println (str 9 | ansi/bold-font "+ clojure " (str/join " " args) 10 | ansi/reset-font)) 11 | (apply clojure args))) 12 | publish-local (clj "-T:build install-lib" :artifact-id lib) 13 | publish (clj "-T:build install-lib" :artifact-id lib :publish true) 14 | publish-all-local (clj "-T:build all" :publish false) 15 | antq (clj 16 | "-Sdeps '{:deps {com.github.liquidz/antq {:mvn/version \"RELEASE\"}}}'" 17 | "-M" "-m" "antq.core" "-d" "build") 18 | sync-deps ((requiring-resolve 'kit.sync-lib-deps/-main)) 19 | ci {:doc "Run all CI tasks locally" 20 | :requires ([taoensso.timbre :as log]) 21 | :task (do 22 | (log/info "bb run publish-local deps-template") 23 | (clj "-T:build install-lib" :artifact-id "deps-template") 24 | (log/info "bb run publish-local lein-template") 25 | (clj "-T:build install-lib" :artifact-id "lein-template") 26 | (log/info "bb run test") 27 | (run 'test))} 28 | test (clj "-M:test")}} 29 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/build.clj: -------------------------------------------------------------------------------- 1 | (ns build 2 | (:require [clojure.string :as string] 3 | [clojure.tools.build.api :as b])) 4 | 5 | (def lib '<>) 6 | (def main-cls (string/join "." (filter some? [(namespace lib) (name lib) "core"]))) 7 | (def version (format "0.0.1-SNAPSHOT")) 8 | (def target-dir "target") 9 | (def class-dir (str target-dir "/" "classes")) 10 | (def uber-file (format "%s/%s-standalone.jar" target-dir (name lib))) 11 | (def basis (b/create-basis {:project "deps.edn"})) 12 | 13 | (defn clean 14 | "Delete the build target directory" 15 | [_] 16 | (println (str "Cleaning " target-dir)) 17 | (b/delete {:path target-dir})) 18 | 19 | (defn prep [_] 20 | (println "Writing Pom...") 21 | (b/write-pom {:class-dir class-dir 22 | :lib lib 23 | :version version 24 | :basis basis 25 | :src-dirs ["src/clj"]}) 26 | (b/copy-dir {:src-dirs ["src/clj" "resources" "env/prod/resources" "env/prod/clj"] 27 | :target-dir class-dir})) 28 | 29 | (defn uber [_] 30 | (println "Compiling Clojure...") 31 | (b/compile-clj {:basis basis 32 | :src-dirs ["src/clj" "resources" "env/prod/resources" "env/prod/clj"] 33 | :class-dir class-dir}) 34 | (println "Making uberjar...") 35 | (b/uber {:class-dir class-dir 36 | :uber-file uber-file 37 | :main main-cls 38 | :basis basis})) 39 | 40 | (defn all [_] 41 | (do (clean nil) (prep nil) (uber nil))) 42 | -------------------------------------------------------------------------------- /libs/kit-jetty/src/kit/edge/server/jetty.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.server.jetty 2 | (:require 3 | [integrant.core :as ig] 4 | [clojure.tools.logging :as log] 5 | [ring.adapter.jetty :as jetty])) 6 | 7 | (defn start [handler {:keys [host port] :as opts}] 8 | (try 9 | (log/info "starting HTTP server on port" port) 10 | (jetty/run-jetty 11 | handler 12 | (-> opts 13 | (assoc :join? false) 14 | (dissoc :handler :init))) 15 | (catch Throwable t 16 | (log/error t (str "server failed to start on" host "port" port)) 17 | (throw t)))) 18 | 19 | (defn stop [http-server] 20 | (let [result @(future (.stop http-server))] 21 | (log/info "HTTP server stopped") 22 | result)) 23 | 24 | (defmethod ig/expand-key :server/http 25 | [k config] 26 | {k (merge {:port 3000 27 | :host "0.0.0.0"} 28 | config)}) 29 | 30 | (defmethod ig/init-key :server/http 31 | [_ opts] 32 | (let [handler (atom (delay (:handler opts)))] 33 | {:handler handler 34 | :server (start (fn [req] (@@handler req)) (dissoc opts :handler))})) 35 | 36 | (defmethod ig/halt-key! :server/http 37 | [_ {:keys [server]}] 38 | (stop server)) 39 | 40 | (defmethod ig/suspend-key! :server/http 41 | [_ {:keys [handler]}] 42 | (reset! handler (promise))) 43 | 44 | (defmethod ig/resume-key :server/http 45 | [k opts old-opts old-impl] 46 | (if (= (dissoc opts :handler) (dissoc old-opts :handler)) 47 | (do (deliver @(:handler old-impl) (:handler opts)) 48 | old-impl) 49 | (do (ig/halt-key! k old-impl) 50 | (ig/init-key k opts)))) 51 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/README.md: -------------------------------------------------------------------------------- 1 | # <> 2 | 3 | Start a [REPL](#repls) in your editor or terminal of choice. 4 | 5 | Start the server with: 6 | 7 | ```clojure 8 | (go) 9 | ``` 10 | 11 | The default API is available under http://localhost:3000/api 12 | 13 | System configuration is available under `resources/system.edn`. 14 | 15 | To reload changes: 16 | 17 | ```clojure 18 | (reset) 19 | ``` 20 | 21 | ## REPLs 22 | 23 | ### Cursive 24 | 25 | Configure a [REPL following the Cursive documentation](https://cursive-ide.com/userguide/repl.html). Using the default "Run with IntelliJ project classpath" option will let you select an alias from the ["Clojure deps" aliases selection](https://cursive-ide.com/userguide/deps.html#refreshing-deps-dependencies). 26 | 27 | ### CIDER 28 | 29 | Use the `cider` alias for CIDER nREPL support (run `clj -M:dev:cider`). See the [CIDER docs](https://docs.cider.mx/cider/basics/up_and_running.html) for more help. 30 | 31 | Note that this alias runs nREPL during development. To run nREPL in production (typically when the system starts), use the kit-nrepl library through the +nrepl profile as described in [the documentation](https://kit-clj.github.io/docs/profiles.html#profiles). 32 | 33 | ### Command Line 34 | 35 | Run `clj -M:dev:nrepl` or `make repl`. 36 | 37 | Note that, just like with [CIDER](#cider), this alias runs nREPL during development. To run nREPL in production (typically when the system starts), use the kit-nrepl library through the +nrepl profile as described in [the documentation](https://kit-clj.github.io/docs/profiles.html#profiles). 38 | -------------------------------------------------------------------------------- /libs/kit-generator/test/kit/generator/modules/dependencies_test.clj: -------------------------------------------------------------------------------- 1 | (ns kit.generator.modules.dependencies-test 2 | (:require [kit.generator.modules.dependencies :as deps] 3 | [clojure.test :refer :all])) 4 | 5 | (deftest resolve-requires 6 | (testing "empty requires" 7 | (is (= #{} (deps/resolve-dependencies {:default {}} :default)))) 8 | (testing "simple default requires" 9 | (is (= #{:a} (deps/resolve-dependencies {:default {:requires [:a]}} :default))))) 10 | 11 | (deftest resolve-feature-requires 12 | (testing "simple feature requires" 13 | (is (= #{:b} (deps/resolve-dependencies {:default {:feature-requires [:base]} 14 | :base {:requires [:b]}} :default)))) 15 | (testing "double feature require" 16 | (is (= #{:a :b} (deps/resolve-dependencies {:default {:feature-requires [:base :tool]} 17 | :base {:requires [:a]} 18 | :tool {:requires [:b]}} :default)))) 19 | (testing "feature requires another feature" 20 | (is (= #{:a :b} (deps/resolve-dependencies {:default {:feature-requires [:base :tool]} 21 | :base {:requires [:a]} 22 | :tool {:requires [:b] :feature-requires [:base]}} :default)))) 23 | (testing "ciclic feature require" 24 | (is (= #{:a :b} (deps/resolve-dependencies {:default {:feature-requires [:base :tool]} 25 | :base {:requires [:a] :feature-requires [:tool]} 26 | :tool {:requires [:b] :feature-requires [:base]}} :default))))) 27 | -------------------------------------------------------------------------------- /libs/kit-http-kit/src/kit/edge/server/http_kit.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.server.http-kit 2 | (:require 3 | [integrant.core :as ig] 4 | [clojure.tools.logging :as log] 5 | [org.httpkit.server :as http-kit])) 6 | 7 | (defn start [handler {:keys [host port] :as opts}] 8 | (try 9 | (log/info "starting HTTP server on port" port) 10 | (http-kit/run-server 11 | handler 12 | (-> opts 13 | (assoc :legacy-return-value? false) 14 | (dissoc :handler :init))) 15 | (catch Throwable t 16 | (log/error t (str "server failed to start on" host "port" port)) 17 | (throw t)))) 18 | 19 | (defn stop [http-server timeout] 20 | (let [result @(future (http-kit/server-stop! http-server {:timeout (or timeout 100)}))] 21 | (log/info "HTTP server stopped") 22 | result)) 23 | 24 | (defmethod ig/expand-key :server/http 25 | [k config] 26 | {k (merge {:port 3000 27 | :host "0.0.0.0"} 28 | config)}) 29 | 30 | (defmethod ig/init-key :server/http 31 | [_ opts] 32 | (let [handler (atom (delay (:handler opts)))] 33 | {:handler handler 34 | :server (start (fn [req] (@@handler req)) (dissoc opts :handler))})) 35 | 36 | (defmethod ig/halt-key! :server/http 37 | [{:keys [timeout]} {:keys [server]}] 38 | (stop server timeout)) 39 | 40 | (defmethod ig/suspend-key! :server/http 41 | [_ {:keys [handler]}] 42 | (reset! handler (promise))) 43 | 44 | (defmethod ig/resume-key :server/http 45 | [k opts old-opts old-impl] 46 | (if (= (dissoc opts :handler) (dissoc old-opts :handler)) 47 | (do (deliver @(:handler old-impl) (:handler opts)) 48 | old-impl) 49 | (do (ig/halt-key! k old-impl) 50 | (ig/init-key k opts)))) 51 | -------------------------------------------------------------------------------- /libs/kit-generator/test/kit_generator/injections.clj: -------------------------------------------------------------------------------- 1 | (ns kit-generator.injections 2 | (:require 3 | [clojure.java.io :as jio] 4 | [clojure.test :refer :all] 5 | [rewrite-clj.zip :as z] 6 | [kit-generator.io :refer [delete-folder]] 7 | [kit.generator.io :as io] 8 | [kit.generator.modules.injections :refer :all])) 9 | 10 | (def config-template "test/resources/sample-system.edn") 11 | (def test-config "test/resources/generated/system.edn") 12 | 13 | (deftest inject-clj-test 14 | (let [zloc (z/of-string "(ns foo.core\n (:require\n [clojure.tools.logging :as log]\n [integrant.core :as ig]))") 15 | requires [['foo :as 'bar] 16 | ['bar :as 'baz]]] 17 | (= "(ns foo.core\n (:require\n [clojure.tools.logging :as log]\n [integrant.core :as ig] \n [foo :as bar] \n [bar :as baz]))" 18 | (z/root-string (append-requires zloc requires))))) 19 | 20 | (deftest injection-test 21 | (when (.exists (jio/file test-config)) 22 | (jio/delete-file test-config)) 23 | (spit test-config (slurp config-template)) 24 | (is 25 | (= 26 | "{:system/env #profile {:dev :dev, :test :test, :prod :prod}, :server/http {:port #long #or [#env PORT 3000], :handler #ig/ref :handler/ring}, :handler/ring {:router #ig/ref :router/core, :api-path \"/api\"}, :reitit.routes/api {:base-path \"/api\", :env #ig/ref :system/env}, :router/routes {:routes #ig/refset :reitit/routes}, :router/core {:routes #ig/ref :router/routes}, :foo :bar} 27 | " 28 | (io/edn->str 29 | (inject {:type :edn 30 | :target (io/str->edn (slurp "test/resources/generated/system.edn")) 31 | :query [] 32 | :action :merge 33 | :value {:foo :bar}}))))) 34 | -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/modules/kit/cljs/assets/build.clj: -------------------------------------------------------------------------------- 1 | (ns build 2 | (:require [clojure.tools.build.api :as b] 3 | [clojure.string :as string] 4 | [clojure.java.shell :refer [sh]] 5 | [deps-deploy.deps-deploy :as deploy])) 6 | 7 | (def lib 'com.example/test) 8 | (def main-cls (string/join "." (filter some? [(namespace lib) (name lib) "core"]))) 9 | (def version (format "0.0.1-SNAPSHOT")) 10 | (def target-dir "target") 11 | (def class-dir (str target-dir "/" "classes")) 12 | (def uber-file (format "%s/%s-standalone.jar" target-dir (name lib))) 13 | (def basis (b/create-basis {:project "deps.edn"})) 14 | 15 | (defn clean 16 | "Delete the build target directory" 17 | [_] 18 | (println (str "Cleaning " target-dir)) 19 | (b/delete {:path target-dir})) 20 | 21 | (defn prep [_] 22 | (b/write-pom {:class-dir class-dir 23 | :lib lib 24 | :version version 25 | :basis basis 26 | :src-dirs ["src/clj"]}) 27 | (b/copy-dir {:src-dirs ["src" "resources" "env/prod"] 28 | :target-dir class-dir})) 29 | 30 | (defn build-cljs [_] 31 | (println "npx shadow-cljs release app...") 32 | (let [{:keys [exit] :as s} (sh "npx" "shadow-cljs" "release" "app")] 33 | (when-not (zero? exit) 34 | (throw (ex-info "could not compile cljs" s))))) 35 | 36 | (defn uber [_] 37 | (b/compile-clj {:basis basis 38 | :src-dirs ["src/clj" "env/prod/clj"] 39 | :class-dir class-dir}) 40 | (build-cljs nil) 41 | (println "Making uberjar...") 42 | (b/uber {:class-dir class-dir 43 | :uber-file uber-file 44 | :main main-cls 45 | :basis basis})) 46 | 47 | (defn all [_] 48 | (do (clean nil) (prep nil) (uber nil))) 49 | -------------------------------------------------------------------------------- /libs/kit-generator/src/kit/generator/git.clj: -------------------------------------------------------------------------------- 1 | (ns kit.generator.git 2 | (:require 3 | [clojure.string :as string] 4 | [clj-jgit.porcelain :as git]) 5 | (:import 6 | [java.io File FileNotFoundException])) 7 | 8 | (defn repo-root [name git-url] 9 | (or name 10 | (-> git-url 11 | (string/split #"/") 12 | (last) 13 | (string/split #"\.") 14 | (first)))) 15 | 16 | (defn repo-path [root name git-url] 17 | (str root File/separator (repo-root name git-url))) 18 | 19 | (defn git-config [] 20 | (if (.exists (clojure.java.io/file "kit.git-config.edn")) 21 | (read-string (slurp "kit.git-config.edn")) 22 | {:name "~/.ssh/id_rsa"})) 23 | 24 | (defn sync-repository! [root {:keys [name url tag]} & [callback]] 25 | (try 26 | ;;docs https://github.com/clj-jgit/clj-jgit (version 0.8.10) 27 | (git/with-identity 28 | (git-config) 29 | (let [path (repo-path root name url)] 30 | (try 31 | (let [repo (git/load-repo path)] 32 | (git/git-pull repo)) 33 | (catch FileNotFoundException _e 34 | (git/git-clone url :dir path 35 | :remote "origin" 36 | :branch (or tag "master") 37 | :bare? false 38 | :clone-all? false))) 39 | (when callback (callback path)))) 40 | (catch org.eclipse.jgit.api.errors.TransportException e 41 | (println (.getMessage e) 42 | "\nif you do not have a key file, set the :name key in kit.git-config.edn to an empty string")) 43 | (catch Exception e 44 | (println "failed to clone module:" url "\ncause:" (.getMessage e)) 45 | (.printStackTrace e)))) 46 | -------------------------------------------------------------------------------- /libs/kit-generator/test/resources/modules/kit/cljs/config.edn: -------------------------------------------------------------------------------- 1 | {:default 2 | {:require-restart? true 3 | :requires [:kit/html] 4 | :actions 5 | {:assets [["assets/shadow-cljs.edn" "shadow-cljs.edn"] 6 | ["assets/package.json" "package.json"] 7 | ["assets/src/core.cljs" "src/cljs/<>/core.cljs"]] 8 | :injections [{:type :html 9 | :path "resources/html/home.html" 10 | :action :append 11 | :target [:body] 12 | :value [:div {:id "app"}]} 13 | {:type :html 14 | :path "resources/html/home.html" 15 | :action :append 16 | :target [:body] 17 | :value [:script {:src "/js/app.js"}]} 18 | {:type :edn 19 | :path "deps.edn" 20 | :target [:paths] 21 | :action :append 22 | :value "target/classes/cljsbuild"} 23 | {:type :clj 24 | :path "build.clj" 25 | :action :append-requires 26 | :value ["[clojure.java.shell :refer [sh]]"]} 27 | {:type :clj 28 | :path "build.clj" 29 | :action :append-build-task 30 | :value (defn build-cljs [] 31 | (println "npx shadow-cljs release app...") 32 | (let [{:keys [exit] 33 | :as s} (sh "npx" "shadow-cljs" "release" "app")] 34 | (when-not (zero? exit) 35 | (throw (ex-info "could not compile cljs" s)))))} 36 | {:type :clj 37 | :path "build.clj" 38 | :action :append-build-task-call 39 | :value (build-cljs)}]}}} 40 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/src/clj/web/handler.clj: -------------------------------------------------------------------------------- 1 | (ns <>.web.handler 2 | (:require 3 | [<>.web.middleware.core :as middleware] 4 | [integrant.core :as ig] 5 | [ring.util.http-response :as http-response] 6 | [reitit.ring :as ring] 7 | [reitit.swagger-ui :as swagger-ui])) 8 | 9 | (defmethod ig/init-key :handler/ring 10 | [_ {:keys [router api-path] :as opts}] 11 | (ring/ring-handler 12 | (router) 13 | (ring/routes 14 | ;; Handle trailing slash in routes - add it + redirect to it 15 | ;; https://github.com/metosin/reitit/blob/master/doc/ring/slash_handler.md 16 | (ring/redirect-trailing-slash-handler) 17 | (ring/create-resource-handler {:path "/"}) 18 | (when (some? api-path) 19 | (swagger-ui/create-swagger-ui-handler {:path api-path 20 | :url (str api-path "/swagger.json")})) 21 | (ring/create-default-handler 22 | {:not-found 23 | (constantly (-> {:status 404, :body "Page not found"} 24 | (http-response/content-type "text/plain"))) 25 | :method-not-allowed 26 | (constantly (-> {:status 405, :body "Not allowed"} 27 | (http-response/content-type "text/plain"))) 28 | :not-acceptable 29 | (constantly (-> {:status 406, :body "Not acceptable"} 30 | (http-response/content-type "text/plain")))})) 31 | {:middleware [(middleware/wrap-base opts)]})) 32 | 33 | (defmethod ig/init-key :router/routes 34 | [_ {:keys [routes]}] 35 | (mapv (fn [route] 36 | (if (fn? route) 37 | (route) 38 | route)) 39 | routes)) 40 | 41 | (defmethod ig/init-key :router/core 42 | [_ {:keys [routes env] :as opts}] 43 | (if (= env :dev) 44 | #(ring/router ["" opts routes]) 45 | (constantly (ring/router ["" opts routes])))) 46 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/src/clj/core.clj: -------------------------------------------------------------------------------- 1 | (ns <>.core 2 | (:require 3 | [clojure.tools.logging :as log] 4 | [integrant.core :as ig] 5 | [<>.config :as config] 6 | [<>.env :refer [defaults]] 7 | 8 | ;; Edges<% if redis? %> 9 | [kit.edge.cache.redis] <% endif %><% if xtdb? %> 10 | [kit.edge.db.xtdb] <% endif %><% if hikari? %> 11 | [kit.edge.db.sql.hikari] <% endif %><% if conman? %> 12 | [kit.edge.db.sql.conman] <% endif %><% if migratus? %> 13 | [kit.edge.db.sql.migratus] <% endif %><% if postgres? %> 14 | [kit.edge.db.postgres] <% endif %><% if mysql? %> 15 | [kit.edge.db.mysql] <% endif %><% if hato? %> 16 | [kit.edge.http.hato] <% endif %><% if quartz? %> 17 | [kit.edge.scheduling.quartz] <% endif %><% if selmer? %> 18 | [kit.edge.templating.selmer] <% endif %><% if metrics? %> 19 | [kit.edge.utils.metrics] <% endif %><% if repl? %> 20 | [kit.edge.utils.repl] <% endif %><% if nrepl? %> 21 | [kit.edge.utils.nrepl] <% endif %> 22 | [kit.edge.server.undertow] 23 | [<>.web.handler] 24 | 25 | ;; Routes 26 | [<>.web.routes.api]) 27 | (:gen-class)) 28 | 29 | ;; log uncaught exceptions in threads 30 | (Thread/setDefaultUncaughtExceptionHandler 31 | (fn [thread ex] 32 | (log/error {:what :uncaught-exception 33 | :exception ex 34 | :where (str "Uncaught exception on" (.getName thread))}))) 35 | 36 | (defonce system (atom nil)) 37 | 38 | (defn stop-app [] 39 | ((or (:stop defaults) (fn []))) 40 | (some-> (deref system) (ig/halt!))) 41 | 42 | (defn start-app [& [params]] 43 | ((or (:start params) (:start defaults) (fn []))) 44 | (->> (config/system-config (or (:opts params) (:opts defaults) {})) 45 | (ig/expand) 46 | (ig/init) 47 | (reset! system))) 48 | 49 | (defn -main [& _] 50 | (start-app) 51 | (.addShutdownHook (Runtime/getRuntime) (Thread. (fn [] (stop-app) (shutdown-agents))))) -------------------------------------------------------------------------------- /libs/kit-generator/test/kit_generator/generator_test.clj: -------------------------------------------------------------------------------- 1 | (ns kit-generator.generator-test 2 | (:require 3 | [clojure.java.io :as io] 4 | [clojure.test :refer :all] 5 | [kit-generator.io :refer [delete-folder]] 6 | [kit.generator.modules.generator :as g] 7 | [kit.generator.modules :as m] 8 | [kit.generator.modules.injections :as ij])) 9 | 10 | 11 | 12 | (def source-folder "test/resources") 13 | (def target-folder "test/resources/generated") 14 | (def ctx (read-string (slurp "test/resources/kit.edn"))) 15 | 16 | (defn write-file [source target] 17 | (io/make-parents target) 18 | (->> (slurp source) 19 | (spit target))) 20 | 21 | (use-fixtures :once 22 | (fn [f] 23 | (let [files ["/sample-system.edn" "/resources/system.edn" 24 | "/core.clj" "/src/myapp/core.clj"] 25 | install-log (io/file "test/resources/modules/install-log.edn")] 26 | (when (.exists install-log) 27 | (.delete install-log)) 28 | (delete-folder target-folder) 29 | (doseq [[source target] (partition 2 files)] 30 | (write-file (str source-folder source) (str target-folder target))) 31 | (f)))) 32 | 33 | (deftest test-edn-injection 34 | (testing "testing EDN injection" 35 | (let [ctx (m/load-modules ctx)] 36 | (g/generate ctx :html :default)) 37 | ;;todo add some validation 38 | #_(is (= 0 1)))) 39 | 40 | (comment 41 | 42 | (let [files ["/sample-system.edn" "/resources/system.edn" 43 | "/core.clj" "/src/myapp/core.clj"] 44 | install-log (io/file "test/resources/modules/install-log.edn")] 45 | (when (.exists install-log) 46 | (.delete install-log)) 47 | (delete-folder target-folder) 48 | (doseq [[source target] (partition 2 files)] 49 | (write-file (str source-folder source) (str target-folder target)))) 50 | ) 51 | 52 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/env/dev/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | UTF-8 9 | %date{ISO8601} [%thread] %-5level %logger{36} - %msg %n 10 | 11 | 12 | 13 | log/<>.log 14 | 15 | log/<>.%d{yyyy-MM-dd}.%i.log 16 | 17 | 100MB 18 | 19 | 20 | 30 21 | 22 | 23 | UTF-8 24 | %date{ISO8601} [%thread] %-5level %logger{36} - %msg %n 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /libs/kit-generator/src/kit/generator/modules.clj: -------------------------------------------------------------------------------- 1 | (ns kit.generator.modules 2 | (:require 3 | [clojure.java.io :as jio] 4 | [kit.generator.git :as git] 5 | [kit.generator.io :as io]) 6 | (:import java.io.File)) 7 | 8 | (defn sync-modules! 9 | "Clones or pulls modules from git repositories. 10 | 11 | If on local disk git repository for module is present, it will `git pull` 12 | Otherwise it will create a new repository by `git clone` 13 | 14 | Each module is defined as a map with keys 15 | :name - the name which will be used as the path locally 16 | :url - the git repository URL 17 | :tag - the branch to pull from" 18 | [{:keys [modules]}] 19 | (doseq [{:keys [name url] :as repository} (-> modules :repositories)] 20 | (git/sync-repository! 21 | (:root modules) 22 | repository))) 23 | 24 | (defn set-module-path [module-config base-path] 25 | (update module-config :path #(str base-path File/separator %))) 26 | 27 | (defn set-module-paths [root {:keys [module-root modules]}] 28 | (reduce 29 | (fn [modules [id config]] 30 | (assoc modules id (set-module-path config (str root File/separator module-root)))) 31 | {} 32 | modules)) 33 | 34 | (defn load-modules [{:keys [modules] :as ctx}] 35 | (let [root (:root modules)] 36 | (->> root 37 | (jio/file) 38 | (file-seq) 39 | (keep #(when (= "modules.edn" (.getName %)) 40 | (set-module-paths root (assoc 41 | (read-string (slurp %)) 42 | :module-root (-> % .getParentFile .getName))))) 43 | (apply merge) 44 | (assoc-in ctx [:modules :modules])))) 45 | 46 | (defn list-modules [ctx] 47 | (let [modules (-> ctx :modules :modules)] 48 | (if (empty? modules) 49 | (println "No modules installed, maybe run `(kit/sync-modules)`") 50 | (doseq [[id {:keys [doc]}] modules] 51 | (println id "-" doc))))) 52 | 53 | (defn module-exists? [ctx module-key] 54 | (contains? (-> ctx :modules :modules) module-key)) 55 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/env/dev/clj/user.clj: -------------------------------------------------------------------------------- 1 | (ns user 2 | "Userspace functions you can run by default in your local REPL." 3 | (:require 4 | [clojure.pprint] 5 | [clojure.spec.alpha :as s] 6 | [clojure.tools.namespace.repl :as repl] 7 | [criterium.core :as c] ;; benchmarking 8 | [expound.alpha :as expound] 9 | [integrant.core :as ig] 10 | [integrant.repl :refer [clear go halt prep init reset reset-all]] 11 | [integrant.repl.state :as state] 12 | [kit.api :as kit] 13 | [lambdaisland.classpath.watch-deps :as watch-deps] ;; hot loading for deps 14 | [<>.core :refer [start-app]])) 15 | 16 | ;; uncomment to enable hot loading for deps 17 | (watch-deps/start! {:aliases [:dev :test]}) 18 | 19 | (alter-var-root #'s/*explain-out* (constantly expound/printer)) 20 | 21 | (add-tap (bound-fn* clojure.pprint/pprint)) 22 | 23 | (defn dev-prep! 24 | [] 25 | (integrant.repl/set-prep! (fn [] 26 | (-> (<>.config/system-config {:profile :dev}) 27 | (ig/expand))))) 28 | 29 | (defn test-prep! 30 | [] 31 | (integrant.repl/set-prep! (fn [] 32 | (-> (<>.config/system-config {:profile :test}) 33 | (ig/expand))))) 34 | 35 | ;; Can change this to test-prep! if want to run tests as the test profile in your repl 36 | ;; You can run tests in the dev profile, too, but there are some differences between 37 | ;; the two profiles. 38 | (dev-prep!) 39 | 40 | (repl/set-refresh-dirs "src/clj") 41 | 42 | (def refresh repl/refresh) 43 | 44 | <% if sql? %> 45 | (defn reset-db [] 46 | (migratus.core/reset (:db.sql/migrations state/system))) 47 | 48 | (defn rollback [] 49 | (migratus.core/rollback (:db.sql/migrations state/system))) 50 | 51 | (defn migrate [] 52 | (migratus.core/migrate (:db.sql/migrations state/system))) 53 | 54 | (def query-fn (:db.sql/query-fn state/system)) 55 | <% endif %> 56 | 57 | (comment 58 | (go) 59 | (reset)) 60 | -------------------------------------------------------------------------------- /libs/kit-sql-conman/src/kit/edge/db/sql/conman.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.db.sql.conman 2 | (:require 3 | [clojure.tools.logging :as log] 4 | [conman.core :as conman] 5 | [integrant.core :as ig] 6 | [kit.ig-utils :as ig-utils])) 7 | 8 | (defmethod ig/init-key :db.sql/connection 9 | [_ pool-spec] 10 | (conman/connect! pool-spec)) 11 | 12 | (defmethod ig/suspend-key! :db.sql/connection [_ _]) 13 | 14 | (defmethod ig/halt-key! :db.sql/connection 15 | [_ conn] 16 | (conman/disconnect! conn)) 17 | 18 | (defmethod ig/resume-key :db.sql/connection 19 | [key opts old-opts old-impl] 20 | (ig-utils/resume-handler key opts old-opts old-impl)) 21 | 22 | (defn queries-dev [load-queries] 23 | (fn 24 | ([query params] 25 | (conman/query (load-queries) query params)) 26 | ([conn query params & opts] 27 | (conman/query conn (load-queries) query params opts)))) 28 | 29 | (defn queries-prod [load-queries] 30 | (let [queries (load-queries)] 31 | (fn 32 | ([query params] 33 | (conman/query queries query params)) 34 | ([conn query params & opts] 35 | (conman/query conn queries query params opts))))) 36 | 37 | (defmethod ig/init-key :db.sql/query-fn 38 | [_ {:keys [conn options filename filenames env] 39 | :or {options {}}}] 40 | (let [filenames (or filenames [filename]) 41 | load-queries #(apply conman/bind-connection-map conn options filenames)] 42 | (with-meta 43 | (if (= env :dev) 44 | (queries-dev load-queries) 45 | (queries-prod load-queries)) 46 | {:mtimes (mapv ig-utils/last-modified filenames)}))) 47 | 48 | (defmethod ig/suspend-key! :db.sql/query-fn [_ _]) 49 | 50 | (defmethod ig/resume-key :db.sql/query-fn 51 | [k {:keys [filename filenames] :as opts} old-opts old-impl] 52 | (let [check-res (and (= opts old-opts) 53 | (= (mapv ig-utils/last-modified (or filenames [filename])) 54 | (:mtimes (meta old-impl))))] 55 | (log/info k "resume check. Same?" check-res) 56 | (if check-res 57 | old-impl 58 | (do (ig/halt-key! k old-impl) 59 | (ig/init-key k opts))))) 60 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/src/clj/web/routes/api.clj: -------------------------------------------------------------------------------- 1 | (ns <>.web.routes.api 2 | (:require 3 | [<>.web.controllers.health :as health] 4 | [<>.web.middleware.exception :as exception] 5 | [<>.web.middleware.formats :as formats] 6 | [integrant.core :as ig] 7 | [reitit.coercion.malli :as malli] 8 | [reitit.ring.coercion :as coercion] 9 | [reitit.ring.middleware.muuntaja :as muuntaja] 10 | [reitit.ring.middleware.parameters :as parameters] 11 | [reitit.swagger :as swagger])) 12 | 13 | (def route-data 14 | {:coercion malli/coercion 15 | :muuntaja formats/instance 16 | :swagger {:id ::api} 17 | :middleware [;; query-params & form-params 18 | parameters/parameters-middleware 19 | ;; content-negotiation 20 | muuntaja/format-negotiate-middleware 21 | ;; encoding response body 22 | muuntaja/format-response-middleware 23 | ;; exception handling 24 | coercion/coerce-exceptions-middleware 25 | ;; decoding request body 26 | muuntaja/format-request-middleware 27 | ;; coercing response bodys 28 | coercion/coerce-response-middleware 29 | ;; coercing request parameters 30 | coercion/coerce-request-middleware 31 | ;; exception handling 32 | exception/wrap-exception]}) 33 | 34 | ;; Routes 35 | (defn api-routes [_opts] 36 | [["/swagger.json" 37 | {:get {:no-doc true 38 | :swagger {:info {:title "<> API"}} 39 | :handler (swagger/create-swagger-handler)}}] 40 | ["/health" 41 | ;; note that use of the var is necessary 42 | ;; for reitit to reload routes without 43 | ;; restarting the system 44 | {:get #'health/healthcheck!}]]) 45 | 46 | (derive :reitit.routes/api :reitit/routes) 47 | 48 | (defmethod ig/init-key :reitit.routes/api 49 | [_ {:keys [base-path] 50 | :or {base-path ""} 51 | :as opts}] 52 | (fn [] [base-path route-data (api-routes opts)])) 53 | -------------------------------------------------------------------------------- /libs/kit-redis/src/kit/edge/cache/redis.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.cache.redis 2 | (:require 3 | [clojure.core.cache :as cache] 4 | [integrant.core :as ig] 5 | [kit.ig-utils :as ig-utils] 6 | [taoensso.carmine :as carmine])) 7 | 8 | (def ^:const default-ttl 3600) ;; in seconds, 60 hours 9 | 10 | (declare inner-config) 11 | 12 | (defmacro wcar* 13 | [config & body] 14 | `(carmine/wcar (inner-config ~config) 15 | ~@body)) 16 | 17 | (defprotocol CacheConfig 18 | (get-config [this])) 19 | 20 | (defprotocol CacheKey 21 | (cache-key [this])) 22 | 23 | (extend-protocol CacheKey 24 | nil 25 | (cache-key [this] "") 26 | Integer 27 | (cache-key [this] (str this)) 28 | Double 29 | (cache-key [this] (str this)) 30 | Float 31 | (cache-key [this] (str this)) 32 | Character 33 | (cache-key [this] (str this)) 34 | String 35 | (cache-key [this] this) 36 | Object 37 | (cache-key [this] (hash this))) 38 | 39 | (defn key-for [config item] 40 | (let [k (cache-key item)] 41 | (if-some [prefix (:key-prefix config)] 42 | (str prefix ":" k) 43 | k))) 44 | 45 | (cache/defcache RedisCache [config] 46 | cache/CacheProtocol 47 | (lookup [this item] 48 | (wcar* config (carmine/get (key-for config item)))) 49 | 50 | (lookup [this item not-found] 51 | (or (wcar* config (carmine/get (key-for config item))) not-found)) 52 | 53 | (has? [this item] 54 | (= 1 (wcar* (carmine/exists (key-for config item))))) 55 | 56 | (hit [this item] 57 | (RedisCache. config)) 58 | 59 | (miss [this item {:keys [val ttl]}] 60 | (let [ttl (or ttl (:ttl config) default-ttl) 61 | key (key-for config item)] 62 | (wcar* config 63 | (carmine/set key val) 64 | (carmine/expire key ttl))) 65 | (RedisCache. config)) 66 | 67 | (evict [this item] 68 | (wcar* config (carmine/del (key-for config item))) 69 | (RedisCache. config)) 70 | 71 | (seed [this base] 72 | (RedisCache. base)) 73 | 74 | CacheConfig 75 | (get-config [this] config)) 76 | 77 | (defn inner-config 78 | [config] 79 | (if (instance? RedisCache config) 80 | (:conn (get-config config)) 81 | (:conn config))) 82 | 83 | (defmethod ig/init-key :cache/redis 84 | [_ config] 85 | (cache/seed (RedisCache. {}) config)) 86 | 87 | (defmethod ig/suspend-key! :cache/redis [_ _]) 88 | 89 | (defmethod ig/resume-key :cache/redis 90 | [key opts old-opts old-impl] 91 | (ig-utils/resume-handler key opts old-opts old-impl)) -------------------------------------------------------------------------------- /test/kit/template_test.clj: -------------------------------------------------------------------------------- 1 | (ns kit.template-test 2 | (:require [clojure.test :refer [deftest is]] 3 | [clojure.string :as str] 4 | [babashka.fs :as fs] 5 | [babashka.process :as p])) 6 | 7 | 8 | (defn powershell-diff-folders [folder1 folder2] 9 | (let [cmd ["powershell.exe" 10 | "-Command" 11 | (str "Compare-Object (Get-ChildItem -Recurse " folder1 ") (Get-ChildItem -Recurse " folder2 ")")] 12 | {:keys [out err exit]} @(p/process cmd {:out :string :err :string})] 13 | (if (zero? exit) 14 | out 15 | (str "Error: " err)))) 16 | 17 | (defn shell-diff-folders [folder1 folder2] 18 | (let [{:keys [out]} (p/check (p/sh ["diff" "--recursive" "--brief" 19 | folder1 folder2])) 20 | diff (some-> out str/trim not-empty str/split-lines)] 21 | diff)) 22 | 23 | 24 | (deftest deps-new-and-clj-new-parity-test 25 | (let [clj-new-path (doto (fs/create-temp-dir {:prefix "clj-new-app"}) 26 | (fs/delete-on-exit)) 27 | deps-new-path (doto (fs/create-temp-dir {:prefix "deps-new-path"}) 28 | (fs/delete-on-exit)) 29 | clj-new-command ["clojure" 30 | "-Sdeps" "{:deps {io.github.kit-clj/kit {:local/root \".\"}}}" 31 | "-T:new" 32 | ":template" "io.github.kit-clj" 33 | ":output" (pr-str (str clj-new-path)) 34 | ":name" "yourname/app" 35 | ":force" "true" 36 | ":args" "[+override-default-cookie-secret]"] 37 | deps-new-command ["clojure" 38 | "-Sdeps" "{:deps {io.github.kit-clj/kit {:local/root \".\"}}}" 39 | "-T:deps-new" 40 | ":template" "io.github.kit-clj/kit" 41 | ":target-dir" (pr-str (str deps-new-path)) 42 | ":name" "yourname/app" 43 | ":default-cookie-secret" "test-secret" 44 | ":overwrite" "delete"] 45 | pre-start-fn #(apply println "+" (:cmd %))] 46 | (p/check (p/sh clj-new-command {:pre-start-fn pre-start-fn})) 47 | (p/check (p/sh deps-new-command {:pre-start-fn pre-start-fn})) 48 | (let [ res (if (fs/windows?) 49 | (powershell-diff-folders (str clj-new-path) (str deps-new-path)) 50 | (shell-diff-folders (str clj-new-path) (str deps-new-path)))] 51 | (is (empty? res))))) 52 | -------------------------------------------------------------------------------- /libs/kit-postgres/src/kit/edge/db/postgres.clj: -------------------------------------------------------------------------------- 1 | (ns kit.edge.db.postgres 2 | (:require 3 | [cheshire.core :as cheshire] 4 | [next.jdbc] 5 | [next.jdbc.prepare :as prepare] 6 | [next.jdbc.result-set :as result-set]) 7 | (:import 8 | [clojure.lang IPersistentMap IPersistentVector] 9 | [java.sql Array PreparedStatement Timestamp] 10 | [java.time Instant LocalDate LocalDateTime] 11 | [org.postgresql.util PGobject])) 12 | 13 | (def ->json cheshire/generate-string) 14 | (def <-json #(cheshire/parse-string % true)) 15 | 16 | (defn ->pgobject 17 | "Transforms Clojure data to a PGobject that contains the data as 18 | JSON. PGObject type defaults to `jsonb` but can be changed via 19 | metadata key `:pgtype`" 20 | [x] 21 | (let [pgtype (:pgtype (meta x) "jsonb")] 22 | (doto (PGobject.) 23 | (.setType pgtype) 24 | (.setValue (->json x))))) 25 | 26 | (defn <-pgobject 27 | "Transform PGobject containing `json` or `jsonb` value to Clojure data" 28 | [^PGobject v] 29 | (let [type (.getType v) 30 | value (.getValue v)] 31 | (if (#{"jsonb" "json"} type) 32 | (when value 33 | (with-meta (<-json value) {:pgtype type})) 34 | value))) 35 | 36 | (extend-protocol result-set/ReadableColumn 37 | Array 38 | (read-column-by-label [^Array v _] (vec (.getArray v))) 39 | (read-column-by-index [^Array v _2 _3] (vec (.getArray v))) 40 | 41 | PGobject 42 | (read-column-by-label [^PGobject v _] (<-pgobject v)) 43 | (read-column-by-index [^PGobject v _2 _3] (<-pgobject v))) 44 | 45 | (extend-protocol prepare/SettableParameter 46 | Instant 47 | (set-parameter [^Instant v ^PreparedStatement ps ^long i] 48 | (.setTimestamp ps i (Timestamp/from v))) 49 | 50 | LocalDate 51 | (set-parameter [^LocalDate v ^PreparedStatement ps ^long i] 52 | (.setTimestamp ps i (Timestamp/valueOf (.atStartOfDay v)))) 53 | 54 | LocalDateTime 55 | (set-parameter [^LocalDateTime v ^PreparedStatement ps ^long i] 56 | (.setTimestamp ps i (Timestamp/valueOf v))) 57 | 58 | IPersistentMap 59 | (set-parameter [m ^PreparedStatement s i] 60 | (.setObject s i (->pgobject m))) 61 | 62 | IPersistentVector 63 | (set-parameter [^clojure.lang.IPersistentVector v ^java.sql.PreparedStatement stmt ^long idx] 64 | (let [conn (.getConnection stmt) 65 | meta (.getParameterMetaData stmt) 66 | type-name (.getParameterTypeName meta idx)] 67 | (if-let [elem-type (when (= (first type-name) \_) 68 | (apply str (rest type-name)))] 69 | (.setObject stmt idx (.createArrayOf conn elem-type (to-array v))) 70 | (.setObject stmt idx (->pgobject v)))))) 71 | -------------------------------------------------------------------------------- /libs/lein-template/src/leiningen/new/io/github/kit_clj/options/base.clj: -------------------------------------------------------------------------------- 1 | (ns leiningen.new.io.github.kit-clj.options.base 2 | (:require 3 | [leiningen.new.io.github.kit-clj.options.helpers :as helpers])) 4 | 5 | (defn files 6 | [data] 7 | [[".gitignore" (helpers/render "gitignore" data)] 8 | ["README.md" (helpers/render "README.md" data)] 9 | ["Dockerfile" (helpers/render "Dockerfile" data)] 10 | ["Makefile" (helpers/render "Makefile" data)] 11 | ["bb.edn" (helpers/render "bb.edn" data)] 12 | ["deps.edn" (helpers/render "deps.edn" data)] 13 | ["build.clj" (helpers/render "build.clj" data)] 14 | ["kit.edn" (helpers/render "kit.edn" data)] 15 | ["kit.git-config.edn" (helpers/render "kit.git-config.edn" data)] 16 | 17 | ["env/dev/clj/{{sanitized}}/dev_middleware.clj" (helpers/render "env/dev/clj/dev_middleware.clj" data)] 18 | ["env/dev/clj/{{sanitized}}/env.clj" (helpers/render "env/dev/clj/env.clj" data)] 19 | ["env/dev/clj/user.clj" (helpers/render "env/dev/clj/user.clj" data)] 20 | ["env/dev/resources/logback.xml" (helpers/render "env/dev/resources/logback.xml" data)] 21 | 22 | ["env/test/resources/logback.xml" (helpers/render "env/test/resources/logback.xml" data)] 23 | 24 | ["env/prod/clj/{{sanitized}}/env.clj" (helpers/render "env/prod/clj/env.clj" data)] 25 | ["env/prod/resources/logback.xml" (helpers/render "env/prod/resources/logback.xml" data)] 26 | 27 | ["resources/system.edn" (helpers/render "resources/system.edn" data)] 28 | 29 | ["src/clj/{{sanitized}}/config.clj" (helpers/render "src/clj/config.clj" data)] 30 | ["src/clj/{{sanitized}}/core.clj" (helpers/render "src/clj/core.clj" data)] 31 | ["src/clj/{{sanitized}}/web/handler.clj" (helpers/render "src/clj/web/handler.clj" data)] 32 | ["src/clj/{{sanitized}}/web/controllers/health.clj" (helpers/render "src/clj/web/controllers/health.clj" data)] 33 | ["src/clj/{{sanitized}}/web/middleware/core.clj" (helpers/render "src/clj/web/middleware/core.clj" data)] 34 | ["src/clj/{{sanitized}}/web/middleware/exception.clj" (helpers/render "src/clj/web/middleware/exception.clj" data)] 35 | ["src/clj/{{sanitized}}/web/middleware/formats.clj" (helpers/render "src/clj/web/middleware/formats.clj" data)] 36 | ["src/clj/{{sanitized}}/web/routes/api.clj" (helpers/render "src/clj/web/routes/api.clj" data)] 37 | ["src/clj/{{sanitized}}/web/routes/utils.clj" (helpers/render "src/clj/web/routes/utils.clj" data)] 38 | 39 | ["test/clj/{{sanitized}}/test_utils.clj" (helpers/render "test/clj/test_utils.clj" data)] 40 | ["test/clj/{{sanitized}}/core_test.clj" (helpers/render "test/clj/core_test.clj" data)] 41 | ["test/clj/{{sanitized}}/web/request_test.clj" (helpers/render "test/clj/web/request_test.clj" data)]]) 42 | 43 | -------------------------------------------------------------------------------- /libs/kit-generator/src/kit/api.clj: -------------------------------------------------------------------------------- 1 | (ns kit.api 2 | (:require 3 | [clojure.string :as string] 4 | [kit.generator.modules.generator :as generator] 5 | [kit.generator.modules.dependencies :as deps] 6 | [kit.generator.modules :as modules] 7 | [kit.generator.snippets :as snippets] 8 | [kit.generator.io :as io])) 9 | 10 | ;; TODO: Add docstrings 11 | 12 | (defn read-ctx 13 | ([] (read-ctx nil)) 14 | ([path] 15 | (-> (or path "kit.edn") 16 | (slurp) 17 | (io/str->edn)))) 18 | 19 | (defn sync-modules [] 20 | (modules/sync-modules! (read-ctx)) 21 | :done) 22 | 23 | (defn list-modules [] 24 | (let [ctx (modules/load-modules (read-ctx))] 25 | (modules/list-modules ctx)) 26 | :done) 27 | 28 | (declare install-module) 29 | (defn install-dependency [module-key] 30 | (if (vector? module-key) 31 | (apply install-module module-key) 32 | (install-module module-key))) 33 | 34 | (defn install-module 35 | ([module-key] 36 | (install-module module-key {:feature-flag :default})) 37 | ([module-key {:keys [feature-flag] :as opts}] 38 | (let [{:keys [modules] :as ctx} (modules/load-modules (read-ctx))] 39 | (if (modules/module-exists? ctx module-key) 40 | (let [module-config (generator/read-module-config ctx modules module-key) 41 | deps (deps/resolve-dependencies module-config feature-flag)] 42 | (println module-key "requires following modules:" deps) 43 | (doseq [module-key deps] 44 | (install-dependency module-key)) 45 | (generator/generate ctx module-key opts)) 46 | (println "no module found with name:" module-key)) 47 | :done))) 48 | 49 | (defn list-installed-modules [] 50 | (doseq [[id status] (-> (read-ctx) 51 | :modules 52 | :root 53 | (generator/read-modules-log))] 54 | (println id (if (= status :success) 55 | "installed successfully" 56 | "failed to install"))) 57 | :done) 58 | 59 | (def snippets-db 60 | (let [db (atom nil)] 61 | (fn [ctx & [reload?]] 62 | (if (or (empty? @db) reload?) 63 | (reset! db (-> ctx :snippets :root (snippets/load-snippets))) 64 | @db)))) 65 | 66 | (defn sync-snippets [] 67 | (let [ctx (read-ctx)] 68 | (snippets/sync-snippets! ctx) 69 | (snippets-db ctx true) 70 | :done)) 71 | 72 | (defn find-snippets [query] 73 | (snippets/print-snippets (snippets-db (read-ctx)) query) 74 | :done) 75 | 76 | (defn find-snippet-ids [query] 77 | (println (string/join ", " (map :id (snippets/match-snippets (snippets-db (read-ctx)) query)))) 78 | :done) 79 | 80 | (defn list-snippets [] 81 | (println (string/join "\n" (keys (snippets-db (read-ctx))))) 82 | :done) 83 | 84 | (defn snippet [id & args] 85 | (snippets/gen-snippet (snippets-db (read-ctx)) id args)) 86 | 87 | -------------------------------------------------------------------------------- /libs/kit-generator/src/kit/generator/snippets.clj: -------------------------------------------------------------------------------- 1 | (ns kit.generator.snippets 2 | (:require 3 | [clojure.edn :as edn] 4 | [clojure.pprint :refer [pprint]] 5 | [kit.generator.renderer :as renderer] 6 | [clojure.string :as string] 7 | [clojure.java.io :as io] 8 | [kit.generator.git :as git] 9 | [clj-fuzzy.metrics :as fm])) 10 | 11 | (defn sync-snippets! [{:keys [snippets]}] 12 | (doseq [repository (-> snippets :repositories)] 13 | (git/sync-repository! (:root snippets) repository))) 14 | 15 | (defn parse-keys [code] 16 | (loop [val nil 17 | in-val? false 18 | keys [] 19 | [c & chars] code] 20 | (cond 21 | (nil? c) 22 | keys 23 | (and (= c \<) (= (first chars) \<)) 24 | (recur val true keys (rest chars)) 25 | (and (= c \>) (= (first chars) \>)) 26 | (recur nil false (cond-> keys (not-empty val) (conj (keyword val))) (rest chars)) 27 | :else 28 | (recur 29 | (if in-val? (str val c)) 30 | in-val? 31 | keys 32 | chars)))) 33 | 34 | (defn parse-code [code] 35 | {:keys (parse-keys code) 36 | :code 37 | (cond 38 | (string/starts-with? code "```clojure") 39 | (string/trim (subs code 10 (- (count code) 3))) 40 | :else 41 | (throw (Exception. (str "unrecognize code format: " code))))}) 42 | 43 | (defn matches? [line id] 44 | (boolean (re-matches (re-pattern (str "^#+\\s*?" id)) (string/trim line)))) 45 | 46 | (defn parse-snippet [text] 47 | (loop [m {:tags [] :description "" :code nil} 48 | section nil 49 | [line & lines] (string/split-lines text)] 50 | (cond 51 | (nil? line) 52 | (-> m 53 | (update :description string/trim) 54 | (update :code parse-code)) 55 | (matches? line "tags") 56 | (recur m :tags lines) 57 | (matches? line "description") 58 | (recur m :description lines) 59 | (matches? line "code") 60 | (recur m :code lines) 61 | :else 62 | (recur 63 | (case section 64 | :tags 65 | (cond-> m (not-empty line) 66 | (update :tags into (string/split (string/trim line) #"\s+"))) 67 | :description 68 | (update m :description str "\n" line) 69 | :code 70 | (update m :code str line) 71 | :else 72 | (throw (Exception. (str "unrecognized section in snippet: " section)))) 73 | section 74 | lines)))) 75 | 76 | (defn gen-snippet [snippets-db snippet-id args] 77 | (if-let [{:keys [keys code]} (get-in snippets-db [snippet-id :code])] 78 | (if (or (empty? keys) (= (count args) (count keys))) 79 | (edn/read-string (renderer/render-asset (merge {:*ns* *ns*} (zipmap keys args)) code)) 80 | (println "wrong number of arguments:\nplease provide following values:" keys)))) 81 | 82 | (defn query-matches? [tag query] 83 | (> (fm/jaro-winkler 84 | (name tag) 85 | (-> query 86 | (string/replace #"[^A-Za-z\s]+" "") 87 | (string/lower-case))) 88 | 0.8)) 89 | 90 | (defn match-snippets [snippets query] 91 | (keep 92 | (fn [[id {:keys [tags] :as snippet}]] 93 | (when (or (query-matches? (name id) query) 94 | (some #(query-matches? % query) tags)) 95 | (assoc snippet :id id))) 96 | snippets)) 97 | 98 | (defn print-snippets [snippets query] 99 | (doseq [item (interpose "\n----" (match-snippets snippets query))] 100 | (if (string? item) 101 | (println item) 102 | (let [{:keys [id description]} item] 103 | (println "\nsnippet:" id "\n" (string/trim description)))))) 104 | 105 | (defn format-name [s] 106 | (loop [sb (StringBuilder.) 107 | [c & chars] s] 108 | (if (nil? c) 109 | (.toString sb) 110 | (recur 111 | (.append sb 112 | (cond 113 | (zero? (.length sb)) 114 | (Character/toLowerCase ^Character c) 115 | (and (= \- (.charAt sb (dec (.length sb)))) 116 | (or (= \_ c) (= \- c))) 117 | "" 118 | (= \_ c) 119 | \- 120 | (Character/isUpperCase ^Character c) 121 | (if (= \- (.charAt sb (dec (.length sb)))) 122 | (Character/toLowerCase ^Character c) 123 | (str "-" (Character/toLowerCase ^Character c))) 124 | :else 125 | c)) 126 | chars)))) 127 | 128 | (defn file->keyword [file] 129 | (keyword 130 | (format-name (.getName (.getParentFile file))) 131 | (format-name (string/replace (.getName file) #".md" "")))) 132 | 133 | (defn load-snippets [path] 134 | (->> (io/file path) 135 | (file-seq) 136 | (rest) 137 | (filter #(.endsWith (.getName %) ".md")) 138 | (map (fn [file] {(file->keyword file) (parse-snippet (slurp file))})) 139 | (apply merge))) 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /libs/lein-template/src/leiningen/new/io/github/kit_clj.clj: -------------------------------------------------------------------------------- 1 | (ns leiningen.new.io.github.kit-clj 2 | (:require 3 | [leiningen.new.templates 4 | :refer [name-to-path sanitize-ns project-name ->files]] 5 | [leiningen.new.io.github.kit-clj.options.base :as base] 6 | [leiningen.new.io.github.kit-clj.options.helpers :as helpers] 7 | [leiningen.new.io.github.kit-clj.options.sql :as sql] 8 | [io.github.kit-clj.deps-template.helpers :refer [generate-cookie-secret]] 9 | [clojure.java.io :as io] 10 | [clojure.set :as set] 11 | [clojure.walk :as walk])) 12 | 13 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 14 | ;; Files & Data for Template 15 | 16 | (defn app-files [data] 17 | (concat 18 | (base/files data) 19 | (when (:conman? data) 20 | (sql/queries-files data)) 21 | (when (:migratus? data) 22 | (sql/migrations-files data)))) 23 | 24 | (def versions (-> (io/resource "io/github/kit_clj/kit/versions.edn") 25 | (slurp) 26 | (read-string) 27 | (walk/keywordize-keys))) 28 | 29 | (defn template-data [name options] 30 | (let [full? (helpers/option? "+full" options)] 31 | {:full-name name 32 | :name (project-name name) 33 | :ns-name (sanitize-ns name) 34 | :sanitized (name-to-path name) 35 | :default-cookie-secret (if (helpers/option? "+override-default-cookie-secret" options) 36 | "test-secret" 37 | (generate-cookie-secret)) 38 | :xtdb? (or full? (helpers/option? "+xtdb" options) (helpers/option? "+xtdb" options)) 39 | ;; SQL data coercion 40 | :sql? (or full? 41 | (helpers/option? "+sql" options)) 42 | :postgres? (or full? 43 | (helpers/option? "+sql" options) 44 | (helpers/option? "+postgres" options)) 45 | :mysql? (or full? 46 | (helpers/option? "+sql" options) 47 | (helpers/option? "+mysql" options)) 48 | ;; SQL libs 49 | :conman? (or full? 50 | (helpers/option? "+sql" options) 51 | (helpers/option? "+mysql" options) 52 | (helpers/option? "+postgres" options) 53 | (helpers/option? "+conman" options)) 54 | :migratus? (or full? 55 | (helpers/option? "+sql" options) 56 | (helpers/option? "+mysql" options) 57 | (helpers/option? "+postgres" options) 58 | (helpers/option? "+migratus" options)) 59 | :hikari? (helpers/option? "+hikari" options) 60 | 61 | :hato? (or full? (helpers/option? "+hato" options)) 62 | :metrics? (or full? (helpers/option? "+metrics" options)) 63 | :quartz? (or full? (helpers/option? "+quartz" options)) 64 | :redis? (or full? (helpers/option? "+redis" options)) 65 | :selmer? (or full? (helpers/option? "+selmer" options)) 66 | 67 | :repl? (or full? (helpers/option? "+socket-repl" options)) 68 | :nrepl? (helpers/option? "+nrepl" options) 69 | 70 | :versions versions})) 71 | 72 | 73 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 74 | ;; Check Options 75 | 76 | (def available-set 77 | #{"+full" 78 | "+xtdb" 79 | "+hato" 80 | "+metrics" 81 | "+quartz" 82 | "+redis" 83 | "+selmer" 84 | 85 | ;; sql variants 86 | "+sql" ;; default sql config 87 | "+conman" 88 | "+hikari" 89 | "+migratus" 90 | ;; sql data coercion 91 | "+mysql" 92 | "+postgres" 93 | 94 | "+nrepl" 95 | "+socket-repl" 96 | 97 | "+override-default-cookie-secret"}) 98 | 99 | (defn check-available 100 | [options] 101 | (let [options-set (into #{} options) 102 | abort? (not (set/superset? available-set 103 | options-set))] 104 | (when abort? 105 | (throw (ex-info "Error: invalid profile(s)" {}))))) 106 | 107 | (defn check-conflicts 108 | [options] 109 | #_(when (> (count (filter #{"+full" "+bare"} options)) 110 | 1) 111 | (throw (ex-info "Cannot have both +full and +bare profile present" {})))) 112 | 113 | (defn check-options 114 | "Check the user-provided options" 115 | [options] 116 | (doto options 117 | (check-available) 118 | (check-conflicts))) 119 | 120 | 121 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 122 | ;; Main 123 | 124 | (defn kit-clj [name & options] 125 | (check-options options) 126 | (let [data (template-data name options)] 127 | (println "Generating kit project.") 128 | (apply ->files data (app-files data)))) 129 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/resources/system.edn: -------------------------------------------------------------------------------- 1 | {:system/env 2 | #profile {:dev :dev 3 | :test :test 4 | :prod :prod} 5 | <% if metrics? %> 6 | :metrics/prometheus 7 | {} <% endif %> 8 | <% if repl? %> 9 | :repl/server 10 | {:port #long #or [#env REPL_PORT 7200] 11 | :host #or [#env REPL_HOST "127.0.0.1"]} <% endif %> 12 | <% if nrepl? %> 13 | :nrepl/server 14 | {:port #long #or [#env NREPL_PORT 7000] 15 | :bind #or [#env NREPL_HOST "127.0.0.1"]} <% endif %> 16 | <% if redis? %> 17 | :cache/redis 18 | {:ttl 3600 19 | :conn {:pool {} 20 | :spec {:uri #env REDIS_URI}}} <% endif %> 21 | 22 | :server/http 23 | {:port #long #or [#env PORT 3000] 24 | :host #or [#env HTTP_HOST "0.0.0.0"] 25 | :handler #ig/ref :handler/ring} 26 | 27 | :handler/ring 28 | {:router #ig/ref :router/core<% if metrics? %> 29 | :metrics #ig/ref :metrics/prometheus<% endif %> 30 | :api-path "/api" 31 | :cookie-secret #or [#env COOKIE_SECRET "<>"] 32 | ;; from ring.middleware.defaults. anti-forgery `false` by default because services may not require it 33 | :site-defaults-config {:params {:urlencoded true 34 | :multipart true 35 | :nested true 36 | :keywordize true} 37 | :cookies true 38 | :session {:flash true 39 | :cookie-name "<>" 40 | :cookie-attrs {:max-age 86400 41 | :http-only true 42 | :same-site :strict}} 43 | :security {:anti-forgery false 44 | :xss-protection {:enable? true, :mode :block} 45 | :frame-options :sameorigin 46 | :content-type-options :nosniff} 47 | :static {:resources "public"} 48 | :responses {:not-modified-responses true 49 | :absolute-redirects true 50 | :content-types true 51 | :default-charset "utf-8"}}} 52 | 53 | :reitit.routes/api 54 | {:base-path "/api" 55 | :env #ig/ref :system/env<% if metrics? %> 56 | :metrics #ig/ref :metrics/prometheus<% endif %><% if conman? %> 57 | :query-fn #ig/ref :db.sql/query-fn<% endif %>} 58 | 59 | :router/routes 60 | {:routes #ig/refset :reitit/routes} 61 | 62 | :router/core 63 | {:routes #ig/ref :router/routes 64 | :env #ig/ref :system/env} <% if quartz? %> 65 | 66 | :cronut/scheduler 67 | {:schedule []} <% endif %><% if selmer? %> 68 | 69 | :templating/selmer 70 | {} <% endif %><% if xtdb? %> 71 | 72 | ;; https://docs.xtdb.com/administration/configuring/ 73 | :db.xtdb/node 74 | #profile {:dev {:xtdb.http-server/server {:port 3100} 75 | :xtdb/tx-log {:kv-store {:xtdb/module xtdb.rocksdb/->kv-store 76 | :db-dir "data/dev/tx-log" 77 | :sync? true}} 78 | :xtdb/document-store {:kv-store {:xtdb/module xtdb.rocksdb/->kv-store 79 | :db-dir "data/dev/doc-store" 80 | :sync? true}} 81 | :xtdb/index-store {:kv-store {:xtdb/module xtdb.rocksdb/->kv-store 82 | :db-dir "data/dev/index-store" 83 | :sync? true}}} 84 | :test {} 85 | :prod {}} <% endif %><% if hikari? %> 86 | 87 | :db.sql/hikari-connection 88 | #profile {:dev {:jdbc-url "jdbc:mysql://127.0.0.1:3306/<>?characterEncoding=utf8"} 89 | :test {} 90 | :prod {:auto-commit true 91 | :read-only false 92 | :connection-timeout 30000 93 | :validation-timeout 5000 94 | :idle-timeout 600000 95 | :max-lifetime 1800000 96 | :minimum-idle 10 97 | :maximum-pool-size 10 98 | :pool-name "ds-pool" 99 | :username "root" 100 | :password "123456" 101 | :jdbc-url #env JDBC_URL 102 | :driver-class-name "com.mysql.jdbc.Driver" 103 | :register-mbeans false}} <% endif %><% if conman? %> 104 | 105 | :db.sql/connection 106 | #profile {:dev {:jdbc-url "jdbc:postgresql://localhost/<>?user=<>&password=<>"} 107 | :test {} 108 | :prod {:jdbc-url #env JDBC_URL 109 | :init-size 1 110 | :min-idle 1 111 | :max-idle 8 112 | :max-active 32}} 113 | 114 | :db.sql/query-fn 115 | {:conn #ig/ref :db.sql/connection 116 | :options {} 117 | :filename "queries.sql" 118 | :env #ig/ref :system/env} <% endif %><% if migratus? %> 119 | 120 | :db.sql/migrations 121 | {:store :database 122 | :db {:datasource #ig/ref :db.sql/connection} 123 | :migrate-on-init? true} <% endif %>} -------------------------------------------------------------------------------- /libs/deps-template/src/io/github/kit_clj/deps_template.clj: -------------------------------------------------------------------------------- 1 | (ns io.github.kit-clj.deps-template 2 | (:require 3 | [clojure.string :as str] 4 | [babashka.fs :as fs] 5 | [clojure.edn :as edn] 6 | [io.github.kit-clj.deps-template.helpers :as helpers] 7 | [selmer.parser :as selmer]) 8 | (:import java.io.File)) 9 | 10 | (defn- excluded-template-files 11 | "Returns a sequence of files that will be excluded from the output." 12 | [{:keys [migratus conman] :as _data}] 13 | (->> ["versions.edn" 14 | "template.edn" 15 | ".dir-locals.el" 16 | (when-not migratus "resources/migrations/placeholder.txt") 17 | (when-not conman "resources/queries.sql")] 18 | (remove nil?))) 19 | 20 | (defn- ->ns 21 | "Copied from org.corfield.new.impl/->ns." 22 | [f] 23 | (-> f (str) (str/replace "/" ".") (str/replace "_" "-"))) 24 | 25 | (defn- ->file 26 | "Copied from org.corfield.new.impl/->file." 27 | [n] 28 | (-> n (str) (str/replace "." "/") (str/replace "-" "_"))) 29 | 30 | (defn- selmer-opts 31 | "Returns the data to be passed into the Selmer templates." 32 | [{:keys [template-dir default-cookie-secret] :as data}] 33 | (let [full-name (:name data) 34 | parts (str/split full-name #"/") 35 | name (last parts) 36 | versions (edn/read-string (slurp (fs/file template-dir "versions.edn"))) 37 | default-cookie-secret' (or default-cookie-secret 38 | (helpers/generate-cookie-secret))] 39 | (as-> data $ 40 | (merge $ {:versions versions 41 | :full-name full-name 42 | :app name 43 | :ns-name (str (->ns full-name)) 44 | :name name 45 | :sanitized (->file full-name) 46 | :default-cookie-secret default-cookie-secret'}) 47 | (merge $ (update-keys $ #(edn/read-string (str % "?"))))))) 48 | 49 | 50 | (defn adapt-separator [pattern] 51 | (let [separator File/separator 52 | escaped-separator (if (= "\\" separator) "\\\\" separator)] 53 | (clojure.string/replace pattern "/" escaped-separator))) 54 | 55 | (defn windows-to-unix-slash [s] 56 | (clojure.string/replace s "\\" "/")) 57 | 58 | 59 | 60 | (defn- match-namespaced-file 61 | "If a file needs to include the namespace in its path, return a map with the 62 | prefix and suffix." 63 | [file-path] 64 | (let [pattern1 (adapt-separator #"^((?:src|test)/clj)/(.+)$") 65 | pattern2 (adapt-separator #"^(env/(?:dev|prod)/clj)/((?:dev_middleware|env)\.clj)$")] 66 | (or (let [[[_ prefix suffix]] (re-seq (re-pattern pattern1) file-path)] 67 | (when (and prefix suffix) 68 | {:prefix prefix :suffix suffix})) 69 | (let [[[_ prefix suffix]] (re-seq (re-pattern pattern2) file-path)] 70 | (when (and prefix suffix) 71 | {:prefix prefix :suffix suffix}))))) 72 | 73 | (defn dest-path 74 | "Returns the destination path of a file in the output template. 75 | 76 | This can be used to rename files when they don't map directly to the template 77 | files in the resource path." 78 | [file-path] 79 | (let [separator File/separator] 80 | (or (when-let [{:keys [prefix suffix]} (match-namespaced-file file-path)] 81 | (str prefix separator "{{sanitized}}" separator suffix)) 82 | (let [[m] (re-seq #"^gitignore$" file-path)] 83 | (when m ".gitignore")) 84 | file-path))) 85 | 86 | (defn- render-templates 87 | "Returns a sequence containing a map for each rendered Selmer template file." 88 | [{:keys [template-dir] :as data}] 89 | (let [opts (selmer-opts data) 90 | render-path (fn [path-template] 91 | (selmer/render path-template opts))] 92 | (->> (file-seq (fs/file template-dir)) 93 | (filter #(and (.isFile %) (not (.isHidden %)))) 94 | (map #(fs/relativize template-dir %)) 95 | (filter #(not (contains? (set (excluded-template-files data)) (windows-to-unix-slash (str %))))) 96 | (map (fn [f] 97 | {:src-path (str f) 98 | :dest-path (render-path (dest-path (str f))) 99 | :output (helpers/render-selmer (slurp (fs/file template-dir f)) 100 | opts) 101 | :temp-name (str (random-uuid))}))))) 102 | 103 | (defn data-fn 104 | "Returns template data with template files added. 105 | 106 | This is the first step in the deps-new pipeline." 107 | [data] 108 | (assoc data ::template-files (render-templates data))) 109 | 110 | (defn- write-temporary-files 111 | "Writes template files to the temp-dir." 112 | [temp-dir template-files] 113 | (doseq [{:keys [temp-name output]} template-files] 114 | (let [output-with-newline (if (.endsWith output "\n") 115 | output 116 | (str output "\n"))] 117 | (spit (fs/file temp-dir temp-name) output-with-newline)))) 118 | 119 | (defn transform-temporary-files 120 | "A deps-new transform to copy the temporary files to the output directory." 121 | [temp-dir {:keys [template-dir ::template-files]}] 122 | (let [extra-dir (str (fs/relativize template-dir (str temp-dir))) 123 | rename-map (->> template-files 124 | (map (fn [{:keys [temp-name dest-path]}] 125 | [temp-name dest-path])) 126 | (into {}))] 127 | [[extra-dir rename-map :only]])) 128 | 129 | (defn template-fn 130 | "Writes Selmer output to temporary files and adds transforms to copy the 131 | temporary files to the template output directory. 132 | 133 | This is the second step in the deps-new pipeline." 134 | [template {:keys [::template-files] :as data}] 135 | (let [temp-dir (-> (fs/create-temp-dir) fs/delete-on-exit)] 136 | (write-temporary-files temp-dir template-files) 137 | (assoc template :transform (transform-temporary-files temp-dir data)))) 138 | -------------------------------------------------------------------------------- /libs/deps-template/resources/io/github/kit_clj/kit/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src/clj" 2 | "resources"] 3 | 4 | :deps {org.clojure/clojure {:mvn/version "1.12.3"} 5 | 6 | ;; Routing 7 | metosin/reitit {:mvn/version "0.9.2"} 8 | 9 | ;; Ring 10 | metosin/ring-http-response {:mvn/version "0.9.5"} 11 | ring/ring-core {:mvn/version "1.15.3"} 12 | ring/ring-defaults {:mvn/version "0.7.0"} 13 | 14 | ;; Logging 15 | ch.qos.logback/logback-classic {:mvn/version "1.5.20"} 16 | 17 | ;; Data coercion 18 | luminus-transit/luminus-transit {:mvn/version "0.1.6" 19 | :exclusions [com.cognitect/transit-clj]} 20 | metosin/muuntaja {:mvn/version "0.6.11"} 21 | 22 | ;; kit Libs 23 | io.github.kit-clj/kit-core {:mvn/version "<>"} 24 | io.github.kit-clj/kit-undertow {:mvn/version "<>"}<% if xtdb? %> 25 | io.github.kit-clj/kit-xtdb {:mvn/version "<>"}<% endif %><% if mysql? %> 26 | io.github.kit-clj/kit-mysql {:mvn/version "<>"}<% endif %><% if postgres? %> 27 | io.github.kit-clj/kit-postgres {:mvn/version "<>"}<% endif %><% if conman? %> 28 | io.github.kit-clj/kit-sql-conman {:mvn/version "<>"}<% endif %><% if migratus? %> 29 | io.github.kit-clj/kit-sql-migratus {:mvn/version "<>"}<% endif %><% if hikari? %> 30 | io.github.kit-clj/kit-sql-hikari {:mvn/version "<>"}<% endif %><% if hato? %> 31 | io.github.kit-clj/kit-hato {:mvn/version "<>"}<% endif %><% if quartz? %> 32 | io.github.kit-clj/kit-quartz {:mvn/version "<>"}<% endif %><% if redis? %> 33 | io.github.kit-clj/kit-redis {:mvn/version "<>"}<% endif %><% if selmer? %> 34 | io.github.kit-clj/kit-selmer {:mvn/version "<>"}<% endif %><% if metrics? %> 35 | io.github.kit-clj/kit-metrics {:mvn/version "<>"}<% endif %><% if repl? %> 36 | io.github.kit-clj/kit-repl {:mvn/version "<>"}<% endif %><% if nrepl? %> 37 | io.github.kit-clj/kit-nrepl {:mvn/version "<>"}<% endif %> 38 | } 39 | :aliases {:build {:deps {io.github.clojure/tools.build {:mvn/version "0.10.11"}} 40 | :ns-default build} 41 | 42 | 43 | :dev {:extra-deps {com.lambdaisland/classpath {:mvn/version "0.6.58"} 44 | criterium/criterium {:mvn/version "0.4.6"} 45 | expound/expound {:mvn/version "0.9.0"} 46 | integrant/repl {:mvn/version "0.5.0"} 47 | mvxcvi/cljstyle {:mvn/version "0.17.642"} 48 | pjstadig/humane-test-output {:mvn/version "0.11.0"} 49 | ring/ring-devel {:mvn/version "1.15.3"} 50 | ring/ring-mock {:mvn/version "0.6.2"} 51 | io.github.kit-clj/kit-generator {:mvn/version "<>"} 52 | org.clojure/tools.namespace {:mvn/version "1.5.0"}<% if xtdb? %> 53 | com.xtdb/xtdb-rocksdb {:mvn/version "1.21.0-beta3"} 54 | com.xtdb/xtdb-http-server {:mvn/version "1.21.0-beta3"}<%endif%> 55 | } 56 | :extra-paths ["env/dev/clj" "env/dev/resources" "test/clj"]} 57 | :nrepl {:extra-deps {nrepl/nrepl {:mvn/version "1.5.1"}} 58 | :main-opts ["-m" "nrepl.cmdline" "-i"]} 59 | :cider {:extra-deps {nrepl/nrepl {:mvn/version "1.5.1"} 60 | cider/cider-nrepl {:mvn/version "0.58.0"}} 61 | :main-opts ["-m" "nrepl.cmdline" "--middleware" "[cider.nrepl/cider-middleware]" "-i"]} 62 | 63 | :test {:extra-deps {criterium/criterium {:mvn/version "0.4.6"} 64 | expound/expound {:mvn/version "0.9.0"} 65 | integrant/repl {:mvn/version "0.5.0"} 66 | io.github.cognitect-labs/test-runner {:git/url "https://github.com/cognitect-labs/test-runner.git" 67 | :git/tag "v0.5.1" 68 | :git/sha "dfb30dd"} 69 | pjstadig/humane-test-output {:mvn/version "0.11.0"} 70 | ring/ring-devel {:mvn/version "1.15.3"} 71 | ring/ring-mock {:mvn/version "0.6.2"} 72 | io.github.kit-clj/kit-generator {:mvn/version "<>"} 73 | org.clojure/tools.namespace {:mvn/version "1.5.0"} 74 | peridot/peridot {:mvn/version "0.5.4"} 75 | org.clj-commons/byte-streams {:mvn/version "0.3.4"} 76 | com.lambdaisland/classpath {:mvn/version "0.6.58"}} 77 | :exec-fn cognitect.test-runner.api/test 78 | :extra-paths ["env/dev/clj" "env/dev/resources" "env/test/resources" "test/clj"] 79 | :main-opts ["-e" "(require 'pjstadig.humane-test-output) (pjstadig.humane-test-output/activate!)" 80 | "-m" "cognitect.test-runner"]}} 81 | } 82 | -------------------------------------------------------------------------------- /libs/kit-generator/src/kit/generator/modules/generator.clj: -------------------------------------------------------------------------------- 1 | (ns kit.generator.modules.generator 2 | (:require 3 | [kit.generator.io :as io] 4 | [kit.generator.modules :as modules] 5 | [kit.generator.modules.injections :as ij] 6 | [kit.generator.renderer :as renderer] 7 | [clojure.java.io :as jio] 8 | [clojure.pprint :refer [pprint]] 9 | [deep.merge :as deep-merge] 10 | [rewrite-clj.zip :as z]) 11 | (:import java.io.File 12 | java.nio.file.Files)) 13 | 14 | (defn concat-path [base-path asset-path] 15 | (str base-path File/separator (if (.startsWith asset-path "/") 16 | (subs asset-path 1) 17 | asset-path))) 18 | 19 | (defn template? [asset-path] 20 | (->> [".txt" ".md" "Dockerfile" "gitignore" ".html" ".edn" ".clj" ".cljs"] 21 | (map #(.endsWith asset-path %)) 22 | (some true?))) 23 | 24 | (defn read-asset [asset-path] 25 | (try 26 | (if (template? asset-path) 27 | (slurp asset-path) 28 | (Files/readAllBytes (.toPath (jio/file asset-path)))) 29 | (catch Exception e 30 | (println "failed to read asset:" asset-path (.getMessage e))))) 31 | 32 | (defn write-string [template-string target-path] 33 | (spit target-path template-string)) 34 | 35 | (defn write-binary [bytes target-path] 36 | (jio/copy bytes (jio/file target-path))) 37 | 38 | (defn write-asset [asset path force?] 39 | (jio/make-parents path) 40 | (if (and (.exists (jio/file path)) (not force?)) 41 | (println "asset already exists:" path) 42 | ((if (string? asset) write-string write-binary) asset path))) 43 | 44 | (defmulti handle-action (fn [_ [id]] id)) 45 | 46 | (comment 47 | (ns-unmap 'kit.generator.modules.generator 'handle-action)) 48 | 49 | (defmethod handle-action :assets [{:keys [module-path] :as ctx} [_ assets]] 50 | (doseq [asset assets] 51 | (cond 52 | ;; if asset is a string assume it's a directory to be created 53 | (string? asset) 54 | (.mkdir (jio/file (renderer/render-template ctx asset))) 55 | ;; otherwise asset should be a tuple of [source target] path strings 56 | (and (sequential? asset) (contains? #{2 3} (count asset))) 57 | (let [[asset-path target-path force?] asset] 58 | (write-asset 59 | (->> (read-asset (concat-path module-path asset-path)) 60 | (renderer/render-asset ctx)) 61 | (renderer/render-template ctx target-path) 62 | force?)) 63 | :else 64 | (println "unrecognized asset type:" asset)))) 65 | 66 | (defmethod handle-action :injections [ctx [_ injections]] 67 | (ij/inject-data ctx injections)) 68 | 69 | (defmethod handle-action :default [_ [id]] 70 | (println "undefined action:" id)) 71 | 72 | (defn read-config [ctx module-path] 73 | (some->> (str module-path File/separator "config.edn") 74 | (slurp) 75 | (renderer/render-template ctx))) 76 | 77 | (defn modules-log-path [modules-root] 78 | (str modules-root File/separator "install-log.edn")) 79 | 80 | (defn read-modules-log [modules-root] 81 | (let [log-path (modules-log-path modules-root)] 82 | (if (.exists (jio/file log-path)) 83 | (io/str->edn (slurp log-path)) 84 | {}))) 85 | 86 | (defn write-modules-log [modules-root log] 87 | (spit (modules-log-path modules-root) log)) 88 | 89 | (defn read-module-config [ctx modules module-key] 90 | (let [module-path (get-in modules [:modules module-key :path]) 91 | ctx (assoc ctx :module-path module-path) 92 | config-str (read-config ctx module-path)] 93 | (io/str->edn config-str))) 94 | 95 | (defn get-throw-on-not-found 96 | [m k] 97 | (or (get m k) 98 | (throw (ex-info "Key not found or nil" {:key k 99 | :available-keys (keys m)})))) 100 | 101 | (defn apply-features 102 | [edn-config {:keys [feature-requires] :as config}] 103 | (if (some? feature-requires) 104 | (do 105 | (println "applying features to config:" feature-requires) 106 | (apply deep-merge/concat-merge 107 | (conj (mapv #(get-throw-on-not-found edn-config %) feature-requires) 108 | config))) 109 | config)) 110 | 111 | (defn generate [{:keys [modules] :as ctx} module-key {:keys [feature-flag] 112 | :or {feature-flag :default}}] 113 | (let [modules-root (:root modules) 114 | module-log (read-modules-log modules-root)] 115 | (if (= :success (module-log module-key)) 116 | (println "module" module-key "is already installed!") 117 | (try 118 | (let [module-path (get-in modules [:modules module-key :path]) 119 | ctx (assoc ctx :module-path module-path) 120 | config-str (read-config ctx module-path) 121 | edn-config (io/str->edn config-str) 122 | zip-config (z/of-string config-str) 123 | config (get edn-config feature-flag)] 124 | (cond 125 | (nil? edn-config) 126 | (do 127 | (println "module" module-key "not found, available modules:") 128 | (pprint (modules/list-modules ctx))) 129 | 130 | (nil? config) 131 | (do 132 | (println "feature" feature-flag "not found for module" module-key ", available features:") 133 | (pprint (keys edn-config))) 134 | 135 | :else 136 | (let [{:keys [actions success-message require-restart?]} (apply-features edn-config config) 137 | ctx (assoc ctx :zip-config zip-config)] 138 | (doseq [action actions] 139 | (handle-action ctx action)) 140 | (write-modules-log modules-root (assoc module-log module-key :success)) 141 | (println (or success-message 142 | (str module-key " installed successfully!"))) 143 | (when require-restart? 144 | (println "restart required!"))))) 145 | (catch Exception e 146 | (println "failed to install module" module-key) 147 | (write-modules-log modules-root (assoc module-log module-key :error)) 148 | (.printStackTrace e)))))) 149 | 150 | (comment 151 | (let [ctx {:ns-name "myapp" 152 | :sanitized "myapp" 153 | :name "myapp" 154 | :modules {:root "test/resources/modules" 155 | :repositories [{:url "git@github.com:nikolap/kit.git" 156 | :tag "master" 157 | :name "kit"}] 158 | :modules {:html {:path "html"}}}}] 159 | (generate ctx :html {:feature-flag :default}))) 160 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kit 2 | 3 | Lightweight, modular framework for scalable production 4 | systems. 5 | 6 | ## Goal 7 | 8 | The goal of Kit is to provide a template for a robust, 9 | scalable Clojure web application. It hides common plumbing 10 | that is standard across projects via its libs system, while 11 | exposing code that tends to be customized in the clj-new 12 | template. 13 | 14 | Thanks to `integrant`, and `aero`, the libs are simple 15 | skeletons with the bulk of the customization being done in 16 | the system configuration EDN file. 17 | 18 | ## Quick start 19 | 20 | Kit 21 | requires [clj-new](https://github.com/seancorfield/clj-new), 22 | installed preferably as a tool: 23 | 24 | `clojure -Ttools install com.github.seancorfield/clj-new '{:git/tag "v1.2.381"}' :as clj-new` 25 | 26 | To create a new Kit application: 27 | 28 | `clojure -Tclj-new create :template io.github.kit-clj :name yourname/app` 29 | 30 | ## Latest versions 31 | 32 | | Library | Latest Version | 33 | |------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| 34 | | io.github.kit-clj/kit-core | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-core.svg)](https://clojars.org/io.github.kit-clj/kit-core) | 35 | | io.github.kit-clj/kit-hato | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-hato.svg)](https://clojars.org/io.github.kit-clj/kit-hato) | 36 | | io.github.kit-clj/kit-http-kit | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-http-kit.svg)](https://clojars.org/io.github.kit-clj/kit-http-kit) | 37 | | io.github.kit-clj/kit-jetty | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-jetty.svg)](https://clojars.org/io.github.kit-clj/kit-jetty) | 38 | | io.github.kit-clj/kit-metrics | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-metrics.svg)](https://clojars.org/io.github.kit-clj/kit-metrics) | 39 | | io.github.kit-clj/kit-nrepl | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-nrepl.svg)](https://clojars.org/io.github.kit-clj/kit-nrepl) | 40 | | io.github.kit-clj/kit-quartz | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-quartz.svg)](https://clojars.org/io.github.kit-clj/kit-quartz) | 41 | | io.github.kit-clj/kit-redis | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-redis.svg)](https://clojars.org/io.github.kit-clj/kit-redis) | 42 | | io.github.kit-clj/kit-repl | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-repl.svg)](https://clojars.org/io.github.kit-clj/kit-repl) | 43 | | io.github.kit-clj/kit-selmer | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-selmer.svg)](https://clojars.org/io.github.kit-clj/kit-selmer) | 44 | | io.github.kit-clj/kit-sql | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-sql.svg)](https://clojars.org/io.github.kit-clj/kit-sql) | 45 | | io.github.kit-clj/kit-sql-conman | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-sql-conman.svg)](https://clojars.org/io.github.kit-clj/kit-sql-conman) | 46 | | io.github.kit-clj/kit-sql-hikari | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-sql-hikari.svg)](https://clojars.org/io.github.kit-clj/kit-sql-hikari) | 47 | | io.github.kit-clj/kit-sql-migratus | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-sql-migratus.svg)](https://clojars.org/io.github.kit-clj/kit-sql-migratus) | 48 | | io.github.kit-clj/kit-postgres | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-postgres.svg)](https://clojars.org/io.github.kit-clj/kit-postgres) | 49 | | io.github.kit-clj/kit-mysql | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-mysql.svg)](https://clojars.org/io.github.kit-clj/kit-mysql) | 50 | | io.github.kit-clj/kit-xtdb | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-xtdb.svg)](https://clojars.org/io.github.kit-clj/kit-xtdb) | 51 | | io.github.kit-clj/kit-generator | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/kit-generator.svg)](https://clojars.org/io.github.kit-clj/kit-generator) | 52 | | io.github.kit-clj/lein-template | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/lein-template.svg)](https://clojars.org/io.github.kit-clj/lein-template) | 53 | | io.github.kit-clj/deps-template | [![Clojars Project](https://img.shields.io/clojars/v/io.github.kit-clj/lein-template.svg)](https://clojars.org/io.github.kit-clj/deps-template) | 54 | 55 | ### Profiles 56 | 57 | Default libs included with no profile specified: 58 | 59 | - `kit-core` 60 | - `kit-undertow` 61 | 62 | Additional profiles: 63 | 64 | - `+xtdb` - Adds the `kit-xtdb` lib 65 | - `+hato` - Adds the `kit-hato` lib 66 | - `+metrics` - Adds the `kit-metrics` lib 67 | - `+quartz` - Adds the `kit-quartz` lib 68 | - `+redis` - Adds the `kit-redis` lib 69 | - `+selmer` - Adds the `kit-selmer` lib 70 | - `+nrepl` - Adds the `kit-nrepl` lib 71 | - `+socket-repl` - Adds the `kit-repl` lib 72 | - `+sql` - Adds the default SQL libraries: `kit-sql-conman` 73 | , `kit-sql-migratus`, and `kit-postgres` libs 74 | - `+conman` - Adds the `kit-sql-conman` lib 75 | - `+hikari` - Adds the `kit-sql-hikari` lib 76 | - `+migratus` - Adds the `kit-sql-migratus` lib 77 | - `+mysql` - Adds the `kit-sql-general` and `kit-mysql` libs 78 | - `+full` - Adds the libs `kit-xtdb`, `kit-hato` 79 | , `kit-metrics`, `kit-quartz`, `kit-redis`, `kit-selmer` 80 | , `kit-repl`, `kit-sql-conman`, `kit-postgres`, 81 | and `kit-sql-migratus` 82 | 83 | ## Libs 84 | 85 | - `kit-core` - basic utility functions used by some other 86 | libs 87 | - `kit-xtdb` - Simple binding to connect to 88 | a [XTDB](https://xtdb.com/) database node 89 | - `kit-hato` - HTTP client 90 | using [hato](https://github.com/gnarroway/hato) 91 | - `kit-nrepl` - [nREPL](https://github.com/nrepl/nrepl) 92 | component for use in a running system. e.g. to connect to 93 | a production REPL 94 | - `kit-metrics` - Configurable metrics 95 | using [iapetos](https://github.com/clj-commons/iapetos) 96 | - `kit-quartz` - Scheduler 97 | using [cronut](https://github.com/troy-west/cronut) as an 98 | integrant binding 99 | for [quartz](http://www.quartz-scheduler.org/). Exposes 100 | the `cronut` API, simply some extensions for `aero` and 101 | utilities 102 | - `kit-redis` - An extension 103 | of [core.cache](https://github.com/clojure/core.cache) for 104 | Redis 105 | via [carmine](https://github.com/ptaoussanis/carmine) 106 | - `kit-repl` - Socket REPL integrant binding for use in a 107 | running system. e.g. to connect to a production REPL 108 | - `kit-selmer` - Templating configuration 109 | with [selmer](https://github.com/yogthos/Selmer) 110 | - `kit-sql` - Deprecated. Use `kit-sql-conman` 111 | and `kit-sql-migratus`. Pulls in both of these as generic 112 | SQL integrant binding. 113 | Uses [conman](https://github.com/luminus-framework/conman) 114 | , [next.jdbc](https://github.com/seancorfield/next-jdbc) 115 | , [hugsql](https://www.hugsql.org/), 116 | and [migratus](https://github.com/yogthos/migratus) 117 | directly, or implicitly 118 | - `kit-sql-conman` - 119 | Uses [conman](https://github.com/luminus-framework/conman) 120 | , [next.jdbc](https://github.com/seancorfield/next-jdbc) 121 | , [hugsql](https://www.hugsql.org/), 122 | - `kit-sql-hikari` - General sql layer, just contains 123 | connection pooling ( 124 | via [hikari-cp](https://github.com/tomekw/hikari-cp)) and 125 | jdbc wrapper ( 126 | via [next.jdbc](https://github.com/seancorfield/next-jdbc)) 127 | . 128 | - `kit-sql-migratus` - 129 | uses [migratus](https://github.com/yogthos/migratus) for 130 | SQL migrations 131 | - `kit-postgres` - lib with data bindings and utilities for 132 | working with Postgres 133 | - `kit-mysql` - lib with data bindings and utilities for 134 | working with MySQL8+ 135 | - `kit-undertow` - Server binding 136 | via [ring-undertow-adapter](https://github.com/luminus-framework/ring-undertow-adapter) 137 | 138 | ## Build Tool Support 139 | 140 | Presently only Clojure deps is supported, however there are 141 | plans to add Leiningen support. 142 | 143 | ## Documentation 144 | 145 | [Documentation can be found here](https://kit-clj.github.io) 146 | 147 | ## Emacs Integration 148 | 149 | An [emacs package](https://github.com/jpe90/emacs-clj-deps-new) is available which provides a Magit-style interface to `clj-new` and `deps-new` and provides a command to create Kit web applications. 150 | 151 | ## Inspiration and thanks to 152 | 153 | - [integrant](https://github.com/weavejester/integrant) as 154 | the basis of the project 155 | - [aero](https://github.com/juxt/aero) for powerful 156 | configuration used throughout 157 | - [re-frame template](https://github.com/day8/re-frame-template) 158 | for code used directly in `kit-template` 159 | - [Luminus framework](https://luminusweb.com/) from which 160 | the initial project that Kit's predecessor was built upon 161 | 162 | ## License 163 | 164 | Copyright © 2021 165 | 166 | Released under the MIT license. 167 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ### `io.github.kit-clj/deps-template {:mvn/version "1.0.4"}` 4 |
5 | version bumps 6 | 7 | * `*failjure/failjure` 2.2.0 -> 2.3.0 8 | * `ch.qos.logback/logback-classic` 1.4.4 -> 1.4.11 9 | * `cider/cider-nrepl` 0.28.3 -> 0.35.0 10 | * `com.lambdaisland/classpath` 0.0.27 -> 0.4.44 11 | * `integrant/repl` 0.3.2 -> 0.3.3 12 | * `io.github.clojure/tools.build` v0.8.0 -> v0.9.5 13 | * `io.github.cognitect-labs/test-runner` v0.5.0 -> v0.5.1 14 | * `luminus-transit/luminus-transit` 0.1.5 -> 0.1.6 15 | * `nrepl/nrepl` 0.9.0 -> 1.0.0 16 | * `org.clojure/tools.namespace` 1.2.0 -> 1.4.4 17 | * `ring/ring-defaults` 0.3.3 -> 0.3.4 18 | * `ring/ring-devel` 1.9.5 -> 1.10.0 19 | 20 | * `integrant/integrant` 0.8.0 -> 0.8.1 21 | 22 |
23 | kit-core 24 | 25 | ### `io.github.kit-clj/kit-core {:mvn/version "1.0.3"}` 26 | 27 | - Change: Bump dependencies 28 | 29 | ### `io.github.kit-clj/kit-core {:mvn/version "1.0.1"}` 30 | 31 | - Change: Bump dependencies 32 | 33 | ### `io.github.kit-clj/kit-core {:mvn/version "1.0.0"}` 34 | 35 | - Initial release 36 |
37 | 38 | 39 | 40 |
41 | kit-hato 42 | 43 | ### `io.github.kit-clj/kit-hato {:mvn/version "1.0.1"}` 44 | 45 | - Change: Bump dependencies 46 | 47 | ### `io.github.kit-clj/kit-hato {:mvn/version "1.0.0"}` 48 | 49 | - Initial release 50 |
51 | 52 | 53 | 54 |
55 | kit-metrics 56 | 57 | ### `io.github.kit-clj/kit-metrics {:mvn/version "1.0.3"}` 58 | 59 | - Change: Bump dependencies 60 | 61 | ### `io.github.kit-clj/kit-metrics {:mvn/version "1.0.2"}` 62 | 63 | - Change: Bump dependencies 64 | 65 | ### `io.github.kit-clj/kit-metrics {:mvn/version "1.0.1"}` 66 | 67 | - Breaking fix: metric definitions API is broken 68 | 69 | ### `io.github.kit-clj/kit-metrics {:mvn/version "1.0.0"}` 70 | 71 | - Initial release 72 |
73 | 74 | 75 | 76 |
77 | kit-quartz 78 | 79 | ### `io.github.kit-clj/kit-quartz {:mvn/version "1.0.2"}` 80 | 81 | - Change: Bump dependencies 82 | 83 | ### `io.github.kit-clj/kit-quartz {:mvn/version "1.0.1"}` 84 | 85 | - bump dependencies 86 | 87 | ### `io.github.kit-clj/kit-quartz {:mvn/version "1.0.0"}` 88 | 89 | - Initial release 90 |
91 | 92 | 93 | 94 |
95 | kit-redis 96 | 97 | ### `io.github.kit-clj/kit-redis {:mvn/version "1.0.4"}` 98 | 99 | - Change: Bump dependencies 100 | 101 | ### `io.github.kit-clj/kit-redis {:mvn/version "1.0.3"}` 102 | 103 | - Change: Bump dependencies 104 | 105 | ### `io.github.kit-clj/kit-redis {:mvn/version "1.0.2"}` 106 | 107 | - bump dependencies 108 | 109 | ### `io.github.kit-clj/kit-redis {:mvn/version "1.0.1"}` 110 | 111 | - Change: `key-for` uses CacheKey protocol to convert based on type, defaulting to hashing Objects instead of `pr-str` 112 | - Change: `key-for` ignores prefixing keys when there is no default `key-prefix` in the component config 113 | 114 | ### `io.github.kit-clj/kit-redis {:mvn/version "1.0.0"}` 115 | 116 | - Initial release 117 |
118 | 119 | 120 | 121 |
122 | kit-repl 123 | 124 | ### `io.github.kit-clj/kit-repl {:mvn/version "1.0.1"}` 125 | 126 | - Fix: ensure org.clojure/tools.logging is included in deps in case used as standalone 127 | 128 | ### `io.github.kit-clj/kit-repl {:mvn/version "1.0.0"}` 129 | 130 | - Initial release 131 |
132 | 133 | 134 | 135 |
136 | kit-nrepl 137 | 138 | ### `io.github.kit-clj/kit-nrepl {:mvn/version "1.0.0"}` 139 | 140 | - Initial release 141 |
142 | 143 | 144 | 145 |
146 | kit-sql 147 | 148 | ### `io.github.kit-clj/kit-sql {:mvn/version "1.1.3"}` 149 | 150 | - Change: Bump dependencies 151 | 152 | ### `io.github.kit-clj/kit-sql {:mvn/version "1.1.2"}` 153 | 154 | - Change: Bump dependencies 155 | 156 | ### `io.github.kit-clj/kit-sql {:mvn/version "1.1.1"}` 157 | 158 | - bump dependencies 159 | 160 | ### `io.github.kit-clj/kit-sql {:mvn/version "1.1.0"}` 161 | 162 | - Change: Now just a bare bones wrapper that imports kit-sql-conman and kit-sql-migratus for compatibility purposes 163 | 164 | ### `io.github.kit-clj/kit-sql {:mvn/version "1.0.0"}` 165 | 166 | - Initial release 167 |
168 | 169 | 170 | 171 |
172 | kit-sql-conman 173 | 174 | ### `io.github.kit-clj/kit-sql-conman {:mvn/version "1.0.6"}` 175 | 176 | - Change: Bump dependencies 177 | 178 | ### `io.github.kit-clj/kit-sql-conman {:mvn/version "1.0.4"}` 179 | 180 | - Change: Bump dependencies 181 | 182 | ### `io.github.kit-clj/kit-sql-conman {:mvn/version "1.0.2"}` 183 | 184 | - bump dependencies 185 | 186 | ### `io.github.kit-clj/kit-sql-conman {:mvn/version "1.0.1"}` 187 | 188 | - Fix: Remove unused reference to conman in require 189 | 190 | ### `io.github.kit-clj/kit-sql-conman {:mvn/version "1.0.0"}` 191 | 192 | - Initial release 193 |
194 | 195 | 196 | 197 |
198 | kit-sql-hikari 199 | 200 | ### `io.github.kit-clj/kit-sql-hikari {:mvn/version "1.0.3"}` 201 | 202 | - Change: Bump dependencies 203 | 204 | ### `io.github.kit-clj/kit-sql-hikari {:mvn/version "1.0.1"}` 205 | 206 | - Change: Bump dependencies 207 | 208 | ### `io.github.kit-clj/kit-sql-hikari {:mvn/version "1.0.1"}` 209 | 210 | - Initial release 211 | 212 |
213 | 214 | 215 | 216 |
217 | kit-sql-migratus 218 | 219 | ### `io.github.kit-clj/kit-sql-migratus {:mvn/version "1.0.3"}` 220 | 221 | - Change: Bump dependencies 222 | 223 | ### `io.github.kit-clj/kit-sql-migratus {:mvn/version "1.0.2"}` 224 | 225 | - Change: Bump dependencies 226 | 227 | ### `io.github.kit-clj/kit-sql-migratus {:mvn/version "1.0.1"}` 228 | 229 | - Change: Bump dependencies 230 | 231 | ### `io.github.kit-clj/kit-sql-migratus {:mvn/version "1.0.0"}` 232 | 233 | - Initial release 234 |
235 | 236 | 237 | 238 |
239 | kit-postgres 240 | 241 | ### `io.github.kit-clj/kit-postgres {:mvn/version "1.0.3"}` 242 | 243 | - Change: Bump dependencies 244 | 245 | ### `io.github.kit-clj/kit-postgres {:mvn/version "1.0.2"}` 246 | 247 | - Change: Bump dependencies 248 | 249 | ### `io.github.kit-clj/kit-postgres {:mvn/version "1.0.1"}` 250 | 251 | - bump dependencies 252 | 253 | ### `io.github.kit-clj/kit-postgres {:mvn/version "1.0.0"}` 254 | 255 | - Initial release 256 |
257 | 258 | 259 | 260 |
261 | kit-mysql 262 | 263 | ### `io.github.kit-clj/kit-mysql {:mvn/version "1.0.3"}` 264 | 265 | - Change: Bump dependencies 266 | 267 | ### `io.github.kit-clj/kit-mysql {:mvn/version "1.0.2"}` 268 | 269 | - Change: Bump dependencies 270 | 271 | ### `io.github.kit-clj/kit-mysql {:mvn/version "1.0.1"}` 272 | 273 | - bump dependencies 274 | 275 | ### `io.github.kit-clj/kit-mysql {:mvn/version "1.0.0"}` 276 | 277 | - Initial release [PR #18](https://github.com/kit-clj/kit/pull/18) 278 |
279 | 280 | 281 | 282 |
283 | kit-undertow 284 | 285 | ### `io.github.kit-clj/kit-undertow {:mvn/version "1.0.4"}` 286 | 287 | - Change: Bump dependencies 288 | 289 | ### `io.github.kit-clj/kit-undertow {:mvn/version "1.0.2"}` 290 | 291 | - Bump version 292 | 293 | ### `io.github.kit-clj/kit-undertow {:mvn/version "1.0.1"}` 294 | 295 | - Fix: ensure org.clojure/tools.logging is included in deps in case used as standalone 296 | 297 | ### `io.github.kit-clj/kit-undertow {:mvn/version "1.0.0"}` 298 | 299 | - Initial release 300 |
301 | 302 | 303 | 304 |
305 | kit-http-kit 306 | 307 | ### `io.github.kit-clj/kit-http-kit {:mvn/version "1.0.2"}` 308 | 309 | - Change: Bump dependencies 310 | 311 | ### `io.github.kit-clj/kit-http-kit {:mvn/version "1.0.1"}` 312 | 313 | - Change: Bump dependencies 314 | 315 | ### `io.github.kit-clj/kit-http-kit {:mvn/version "1.0.0"}` 316 | 317 | - Initial release 318 |
319 | 320 | 321 | 322 |
323 | kit-xtdb 324 | 325 | ### `io.github.kit-clj/kit-xtdb {:mvn/version "1.0.4"}` 326 | 327 | - Bump dependencies 328 | 329 | ### `io.github.kit-clj/kit-xtdb {:mvn/version "1.0.3"}` 330 | 331 | - Bump dependencies 332 | 333 | ### `io.github.kit-clj/kit-xtdb {:mvn/version "1.0.1"}` 334 | 335 | - Bump dependencies 336 | 337 | ### `io.github.kit-clj/kit-xtdb {:mvn/version "1.0.0"}` 338 | 339 | - Initial release 340 |
341 | 342 | 343 | 344 |
345 | kit-selmer 346 | 347 | ### `io.github.kit-clj/kit-selmer {:mvn/version "1.0.2"}` 348 | 349 | - Change: Bump dependencies 350 | 351 | ### `io.github.kit-clj/kit-selmer {:mvn/version "1.0.1"}` 352 | 353 | - Change: Bump dependencies 354 | 355 | ### `io.github.kit-clj/kit-selmer {:mvn/version "1.0.0"}` 356 | 357 | - Initial release 358 |
359 | 360 | 361 | 362 |
363 | lein-template 364 | 365 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.38"}` 366 | 367 | - support deps-new [PR 72](https://github.com/kit-clj/kit/pull/72). Thanks [@rads](https://github.com/rads) 368 | - bump dependencies 369 | 370 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.38"}` 371 | 372 | - fix unused templating element [PR 86](https://github.com/kit-clj/kit/pull/86). Thanks [@dspearson](https://github.com/dspearson) 373 | - improve CIDER REPL support [PR 84](https://github.com/kit-clj/kit/pull/84) [PR 85](https://github.com/kit-clj/kit/pull/85). Thanks [@dspearson](https://github.com/dspearson) 374 | 375 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.37"}` 376 | 377 | - bump various dependencies 378 | 379 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.23"}` 380 | 381 | - bump kit-undertow 382 | 383 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.22"}` 384 | 385 | - bump kit-generator 386 | 387 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.21"}` 388 | 389 | - bump dependencies 390 | 391 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.20"}` 392 | 393 | - bump kit-xtdb 394 | 395 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.19"}` 396 | 397 | - add rocksdb and xtdb http server for dev profile (thanks [@green-coder](https://github.com/green-coder)) 398 | 399 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.18"}` 400 | 401 | - fix cookie name in incorrect place (thanks [@jaimesangcap](https://github.com/jaimesangcap)) 402 | 403 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.17"}` 404 | 405 | - fix issue with default cookie session store configuration 406 | - bump to `org.clojure/clojure {:mvn/version "1.11.1"}` 407 | 408 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.16"}` 409 | 410 | - bump to `io.github.kit-clj/kit-sql-conman {:mvn/version "1.0.1"}` 411 | 412 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.15"}` 413 | 414 | - bump to `org.clojure/clojure {:mvn/version "1.11.0"}` 415 | - bump to `metosin/reitit {:mvn/version "0.5.17"}` 416 | - include deps hot loading by default 417 | 418 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.12"}` 419 | - added `clojure.tools.namespace.rep/refresh` in `user` namespace 420 | - added `bb.edn` script with tasks for starting nREPL, testing, and building an uberjar 421 | 422 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.11"}` 423 | 424 | - Change default cookie secret to randomly generated secret at template generation 425 | 426 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.10"}` 427 | 428 | - Fix missing require in test utils 429 | - Add test stub in template 430 | 431 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.9"}` 432 | 433 | - Add symlink to kit libs so no need to manually bump versions when releasing template 434 | - Update Dockerfile 435 | - Refactor sql profiles 436 | - Add clj-kondo cache to default gitignore 437 | 438 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.8"}` 439 | 440 | - Update kit-generator lib 441 | 442 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.7"}` 443 | 444 | - Update log config to exclude jgit debug noise 445 | 446 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.6"}` 447 | 448 | - Template updated for the sql variants 449 | 450 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.5"}` 451 | 452 | - New: Add `+socket-repl` profile for socket REPL 453 | - Change: Default socket REPL host changed to `"127.0.0.1"` 454 | - Change: Bump dependencies 455 | - Change: Remove `kit-repl` library from default template profile 456 | - Change: Remove `+bare` profile 457 | - Change: Make socket repl as default in `+full` profile 458 | 459 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.4"}` 460 | 461 | - Change: Add `nrepl` and `cider` deps aliases in template as default 462 | 463 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.3"}` 464 | 465 | - Change: Default socket REPL port to 7200 466 | - Fix: Default local nREPL port to 127.0.0.1 467 | 468 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.2"}` 469 | 470 | - Change: Add `+nrepl` profile 471 | - Change: Bump `kit-redis` to 1.0.1 472 | - Change: Bump `kit-undertow` to 1.0.1 473 | - Change: Bump `kit-repl` to 1.0.1 474 | 475 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.1"}` 476 | 477 | - Change: repository URL for public modules to use HTTPS instead of SSH URL. Prevents breakage when SSH key fails to load 478 | 479 | ### `io.github.kit-clj/lein-template {:mvn/version "0.1.0"}` 480 | 481 | - Initial ALPHA release, API subject to change 482 |
483 | 484 | 485 | 486 |
487 | kit-generator 488 | 489 | ### `io.github.kit-clj/kit-generator {:mvn/version "0.1.8"}` 490 | 491 | - Change: bump dependencies 492 | 493 | ### `io.github.kit-clj/kit-generator {:mvn/version "0.1.7"}` 494 | 495 | - Change: bump dependencies 496 | 497 | ### `io.github.kit-clj/kit-generator {:mvn/version "0.1.5"}` 498 | 499 | - New: `feature-requires` support for modules to chain deep merge features 500 | 501 | ### `io.github.kit-clj/kit-generator {:mvn/version "0.1.4"}` 502 | 503 | - bump dependencies 504 | 505 | ### `io.github.kit-clj/kit-generator {:mvn/version "0.1.3"}` 506 | 507 | - Fix issue with [git clone](https://github.com/kit-clj/kit/pull/30) 508 | 509 | ### `io.github.kit-clj/kit-generator {:mvn/version "0.1.2"}` 510 | 511 | - New: Snippet generation 512 | - Change: Bump dependencies 513 | 514 | ### `io.github.kit-clj/kit-generator {:mvn/version "0.1.0"}` 515 | 516 | - Initial ALPHA release, API subject to change 517 |
518 | 519 | 520 | -------------------------------------------------------------------------------- /libs/kit-generator/src/kit/generator/modules/injections.clj: -------------------------------------------------------------------------------- 1 | (ns kit.generator.modules.injections 2 | (:require 3 | [kit.generator.renderer :as renderer] 4 | [kit.generator.io :as io] 5 | [borkdude.rewrite-edn :as rewrite-edn] 6 | [clojure.pprint :refer [pprint]] 7 | [clojure.walk :refer [prewalk]] 8 | [cljstyle.config :as fmt-config] 9 | [net.cgrand.enlive-html :as html] 10 | [rewrite-clj.node :as n] 11 | [rewrite-clj.parser :as parser] 12 | [rewrite-clj.zip :as z] 13 | [cljfmt.core :as cljfmt]) 14 | (:import org.jsoup.Jsoup)) 15 | 16 | (defmulti inject :type) 17 | 18 | (defn topmost [z-loc] 19 | (loop [z-loc z-loc] 20 | (if-let [parent (z/up z-loc)] 21 | (recur parent) 22 | z-loc))) 23 | 24 | (defn format-str [s] 25 | (cljfmt/reformat-string 26 | s 27 | {:indentation? true 28 | :split-keypairs-over-multiple-lines? true 29 | :insert-missing-whitespace? true 30 | :remove-multiple-non-indenting-spaces? true})) 31 | 32 | (defn reformat-string [form-string rules-config] 33 | (-> form-string 34 | (format-str) 35 | (parser/parse-string-all) 36 | ;(format/reformat-form rules-config) 37 | )) 38 | 39 | (defn format-zloc [zloc] 40 | (z/replace zloc (reformat-string (z/string zloc) (:rules fmt-config/default-config)))) 41 | 42 | (defn conflicting-keys 43 | [node value-keys] 44 | (filter #(contains? node %) 45 | value-keys)) 46 | 47 | (defn zipper-insert-kw-pairs 48 | [zloc kw-zipper] 49 | (let [k kw-zipper 50 | v (z/right kw-zipper)] 51 | (if-not (and (some? k) (some? v)) 52 | (format-zloc (z/up zloc)) 53 | (recur 54 | (-> zloc 55 | (z/insert-right (z/node k)) 56 | (z/right) 57 | (z/insert-newline-left) 58 | (z/insert-right (z/node v)) 59 | (z/right)) 60 | (-> kw-zipper 61 | (z/right) 62 | (z/right)))))) 63 | 64 | (defn spaces-of-zloc 65 | [zloc] 66 | (-> zloc 67 | (z/node) 68 | (meta) 69 | :col)) 70 | 71 | (defn edn-merge-value [value] 72 | (fn [node] 73 | (if-let [inside-map (z/down node)] 74 | (-> inside-map 75 | (z/rightmost) 76 | (zipper-insert-kw-pairs (z/down value))) 77 | (z/replace node (z/node (format-zloc value)))))) 78 | 79 | (comment 80 | (z/root-string ((edn-merge-value 81 | {:c {:d 1 82 | {:e 3} 4} 83 | :d 3}) 84 | (z/of-string "{:a 1 85 | :b 2}"))) 86 | 87 | (z/root-string ((edn-merge-value 88 | {:c {:d 1 89 | {:e 3} 4} 90 | :d 3}) 91 | (z/of-string "{}"))) 92 | 93 | (z/root-string ((edn-merge-value 94 | (io/str->edn "{:reitit.routes/pages\n {:base-path \"\"\n :env #ig/ref :system/env}}")) 95 | (z/of-string "{:a 1}")))) 96 | 97 | (defn edn-safe-merge [zloc value] 98 | (try 99 | (let [value-keys (keys (z/sexpr value)) 100 | target-value (z/sexpr zloc)] 101 | (let [conflicts (conflicting-keys target-value value-keys)] 102 | (if (seq conflicts) 103 | (do (println "file has conflicting keys! Skipping" 104 | "\n keys:" conflicts) 105 | zloc) 106 | ((edn-merge-value value) zloc)))) 107 | (catch Exception e 108 | (throw (Exception. (str "error merging!\n target:" zloc "\n value:" value) e))))) 109 | 110 | (defn zloc-get-in 111 | [zloc [k & ks]] 112 | (if-not k 113 | zloc 114 | (recur (z/get zloc k) ks))) 115 | 116 | (defn zloc-conj [zloc value] 117 | (-> zloc 118 | (z/down) 119 | (z/rightmost) 120 | (z/insert-right (z/node value)) 121 | (z/up))) 122 | 123 | (defn z-assoc-in [zloc [k & ks] v] 124 | (if (empty? ks) 125 | (z/assoc zloc k v) 126 | (z/assoc zloc k (z/node (z-assoc-in (z/get zloc k) ks v))))) 127 | 128 | (defn z-update-in [zloc [k & ks] f] 129 | (if k 130 | (z-update-in (z/get zloc k) ks f) 131 | (when zloc 132 | (f zloc)))) 133 | 134 | (defn normalize-value [value] 135 | (if (string? value) 136 | (z/of-string (str "\"" value "\"")) 137 | (z/replace (z/of-string "") 138 | (n/sexpr value)))) 139 | 140 | (defmethod inject :edn [{:keys [data target action value ctx]}] 141 | (let [value (normalize-value value)] 142 | (-> 143 | (case action 144 | :append 145 | (if (empty? target) 146 | (zloc-conj data value) 147 | (or (z-update-in data target #(zloc-conj % value)) 148 | (println "could not find injection target:" target "in data:" (z/node data)))) 149 | :merge 150 | (if-let [zloc (zloc-get-in data target)] 151 | (edn-safe-merge zloc value) 152 | (println "could not find injection target:" target "in data:" (z/node data)))) 153 | ;;TODO find a better way to do this 154 | z/root-string 155 | z/of-string))) 156 | 157 | (comment 158 | 159 | (binding [*print-namespace-maps* false] 160 | (let [data (z/of-string "{:foo :bar}") 161 | value (io/str->edn "{:db.sql/connection #profile\n {:prod {:jdbc-url #env JDBC_URL}}}")] 162 | (clojure.walk/postwalk 163 | (fn [node] 164 | (if (and (seq? node) #_(= 'read-string (first node))) 165 | (println ">>>" (first node)) 166 | node)) 167 | (z/assoc data :z (n/sexpr value))) 168 | #_(-> (z/assoc data :z (n/sexpr value)) 169 | z/node 170 | str)) 171 | ) 172 | 173 | (let [data (z/of-string "{:foo :bar}") 174 | value (io/str->edn "{:db.sql/connection #profile\n {:prod {:jdbc-url #env JDBC_URL}}}")] 175 | (z/assoc data :z (n/sexpr value))) 176 | 177 | (str (z/node (z/of-string "{:db.sql/connection #profile\n {:prod {:jdbc-url #env JDBC_URL}}}"))) 178 | 179 | (let [data (z/of-string "{:foo {:paths [\"foo\" \"bar\"]}}") 180 | value {:foo "baz"}] 181 | (z/sexpr (z/assoc data :foo value))) 182 | 183 | (if-let [zloc (zloc-get-in data target)] 184 | (if (empty? target) 185 | (zloc-conj zloc value) 186 | (z-assoc-in data target (-> (zloc-conj zloc value) 187 | (z/node)))) 188 | (println "could not find injection target:" target "in data:" data)) 189 | 190 | 191 | (z/root-string (z/edit 192 | (z/of-string "{:z :r :deps {:wooo :waaa} :paths [\"foo\"]}") 193 | (fn [x] (update x :paths conj "bar")))) 194 | 195 | (type (clojure.edn/read-string "foo")) 196 | (zloc-get-in (z/of-string "{:z :r :deps {:wooo :waaa}}") []) 197 | 198 | 199 | (let [data (z/of-string "{:z :r :deps {:foo :bar}}") 200 | updated (inject 201 | {:type :edn 202 | :data data 203 | :target [] 204 | :action :merge 205 | :value (io/str->edn "{:db.sql/connection #profile\n {:prod {:jdbc-url #env JDBC_URL}}}")})] 206 | #_(z/root-string updated) 207 | (z/root-string 208 | (inject 209 | {:type :edn 210 | :data updated 211 | :target [] 212 | :action :merge 213 | :value (io/str->edn "{:x :y}")}))) 214 | 215 | ;; get-in test 216 | (z/root-string (edn-safe-merge 217 | (zloc-get-in (z/of-string "{:a 1 218 | :b 2 219 | :q {:jj 1}}") [:q]) 220 | "{:c {:d 1 221 | {:e 3} 4} 222 | :d 3}")) 223 | ;; get-in empty map test 224 | (z/root-string (edn-safe-merge 225 | (zloc-get-in (z/of-string "{:a 1 226 | :b 2 227 | :q {}}") [:q]) 228 | "{:c {:d 1 229 | {:e 3} 4} 230 | :d 3}"))) 231 | 232 | (defn require-exists? [requires require] 233 | (boolean (some #{require} requires))) 234 | 235 | (defn append-requires [zloc requires] 236 | (let [zloc-ns (z/find-value zloc z/next 'ns) 237 | zloc-require (z/up (z/find-value zloc-ns z/next :require))] 238 | (reduce 239 | (fn [zloc child] 240 | (let [child-data (io/str->edn child)] 241 | (if (require-exists? (z/sexpr zloc) child-data) 242 | (do 243 | (println "require" child-data "already exists, skipping") 244 | zloc) 245 | ;; TODO: formatting 246 | (-> zloc 247 | ;; change #1: I might replace this line: 248 | ;; (z/insert-newline-right) 249 | ;; with this line: 250 | (z/append-child (n/newline-node "\n")) 251 | ;; change #2: and now indent to first existing require 252 | (z/append-child* (n/spaces (-> zloc (z/down) (spaces-of-zloc)))) 253 | (z/append-child child-data #_(format-zloc child-data)))))) 254 | zloc-require 255 | requires))) 256 | 257 | (defn append-build-task [zloc child] 258 | (let [ns-loc (z/up (z/find-value zloc z/next 'ns))] 259 | (if (z/find-value zloc z/next (second child)) 260 | (println "task called" (second child) "already exists" 261 | "\nplease add the following task manually:\n" 262 | (pr-str child)) 263 | (-> ns-loc 264 | (z/insert-right child) 265 | (z/insert-right (n/newline-node "\n\n")))))) 266 | 267 | (defn append-build-task-call [zloc child] 268 | (let [uber-loc (some-> zloc 269 | (z/find-value z/next 'uber) 270 | (z/find-value z/next 'b/compile-clj) 271 | (z/up)) 272 | ;;todo might want to be more clever checking whether the child exist 273 | child-in-target (some-> (z/find-value uber-loc z/next (first child)) 274 | (z/up))] 275 | (cond 276 | (nil? uber-loc) 277 | (println "could not locate uber task in build.clj") 278 | child-in-target 279 | (println "call to" (pr-str child) "already exists") 280 | :else 281 | (-> uber-loc 282 | (z/insert-right child) 283 | (z/insert-space-right) 284 | (z/insert-right (n/newline-node "\n")))))) 285 | 286 | (defmethod inject :clj [{:keys [data action value]}] 287 | (println "applying\n action:" action "\n value:" (pr-str value)) 288 | (topmost 289 | ((case action 290 | :append-requires append-requires 291 | :append-build-task append-build-task 292 | :append-build-task-call append-build-task-call) 293 | data value))) 294 | 295 | (defmethod inject :html [{:keys [data action target value]}] 296 | (case action 297 | :append (apply str ((html/template (html/html-snippet data) 298 | [] 299 | target 300 | (html/append 301 | (html/html value))))))) 302 | 303 | (defmethod inject :default [{:keys [type] :as injection}] 304 | (println "unrecognized injection type" type "for injection\n" 305 | (with-out-str (pprint injection)))) 306 | 307 | (defmulti serialize :type) 308 | 309 | (defmethod serialize :edn [{:keys [path data]}] 310 | (->> (z/root-string data) 311 | (spit path))) 312 | 313 | (defmethod serialize :clj [{:keys [path data]}] 314 | (->> (z/root-string data) 315 | (spit path))) 316 | 317 | (defmethod serialize :html [{:keys [path data]}] 318 | (->> (Jsoup/parse data) 319 | (.html) 320 | (spit path))) 321 | 322 | (defmulti read-file (fn [path _] 323 | (let [extension (.substring path (inc (.lastIndexOf path ".")))] 324 | (if (empty? extension) 325 | :default 326 | (keyword extension))))) 327 | 328 | (defmethod read-file :clj [_ data-str] 329 | (z/of-string data-str)) 330 | 331 | (defmethod read-file :edn [_ data-str] 332 | (z/of-string data-str)) 333 | 334 | (defmethod read-file :html [_ data-str] 335 | data-str) 336 | 337 | (defmethod read-file :default [_ data-str] 338 | data-str) 339 | 340 | (defn read-files [ctx paths] 341 | (reduce 342 | (fn [path->data path] 343 | (try 344 | (->> (slurp path) 345 | (renderer/render-template ctx) 346 | (read-file path) 347 | (assoc path->data path)) 348 | (catch Exception e 349 | (println "failed to read asset in project:" path 350 | "\nerror:" (.getMessage e))))) 351 | {} paths)) 352 | 353 | (defn inject-at-path [ctx data path injections] 354 | {:type (-> injections first :type) 355 | :path path 356 | :data (reduce 357 | (fn [data injection] 358 | (inject (assoc injection :ctx ctx :data data))) 359 | data injections)}) 360 | 361 | (defn group-by-path [xs] 362 | (reduce 363 | (fn [m {:keys [path] :as item}] 364 | (update m path (fnil conj []) item)) 365 | {} 366 | xs)) 367 | 368 | (defn inject-data [ctx injections] 369 | (let [injections (->> injections 370 | (map (fn [injection] (update injection :path #(renderer/render-template ctx %)))) 371 | (group-by-path)) 372 | path->data (read-files ctx (keys injections))] 373 | (doseq [[path injections] injections] 374 | (println "updating file:" path) 375 | (->> (inject-at-path ctx (path->data path) path injections) 376 | (serialize))))) 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | (comment 386 | 387 | (let [zloc (z/of-string "(ns foo) (defn cljs-build [])")] 388 | (z/find-value zloc z/next 'cljs-build)) 389 | 390 | (let [zloc (z/of-string "(ns build\n (:require [clojure.tools.build.api :as b]\n [clojure.string :as string]\n [clojure.java.shell :refer [sh]]\n [deps-deploy.deps-deploy :as deploy]))\n\n 391 | (defn uber [_]\n (b/compile-clj {:basis basis\n :src-dirs [\"src/clj\" \"env/prod/clj\"]\n :class-dir class-dir})\n (build-cljs)\n (println \"Making uberjar...\")\n (b/uber {:class-dir class-dir\n :uber-file uber-file\n :main main-cls\n :basis basis}))") 392 | child (io/str->edn "(build-cljs)") 393 | uber-loc (-> zloc 394 | (z/find-value z/next 'uber) 395 | (z/find-value z/next 'b/compile-clj) 396 | (z/up)) 397 | child-in-target (z/up (z/find-value uber-loc z/next (first child)))] 398 | (= (z/sexpr child-in-target) child) 399 | #_(-> uber-loc 400 | (z/insert-right child) 401 | (z/insert-space-right) 402 | (z/insert-right (n/newline-node "\n"))) 403 | 404 | ) 405 | 406 | (z/root-string 407 | (inject 408 | {:type :clj 409 | :data (z/of-string "(ns foo (:require [bar.baz] [web.routes.pages]))") 410 | :action :append-requires 411 | :value ["[web.routes.pages]"]})) 412 | 413 | (println 414 | (str 415 | (inject 416 | {:type :edn 417 | :data (z/of-string "{:z :r :deps {:wooo :waaa}}") 418 | :target [] 419 | :action :merge 420 | :value "{:foo #ig/ref :bar :baz \"\"}"}))) 421 | 422 | (let [zloc (-> #_(slurp "test/resources/sample-system.edn") 423 | "{:z :r :deps {:wooo :waaa}}" 424 | (rewrite-edn/parse-string)) 425 | child (->> (io/str->edn "{:x {:foo #ig/ref :bar}}") 426 | (prewalk 427 | (fn [node] 428 | (if (string? node) 429 | (renderer/render-template {} node) 430 | node))))] 431 | (str (rewrite-edn/assoc zloc [:deps] (-> child (io/edn->str) (rewrite-edn/parse-string)))) 432 | #_(str (rewrite-edn/assoc-in zloc [:deps] (-> child (io/edn->str) (rewrite-edn/parse-string))))) 433 | 434 | (->> (renderer/render-template {} "{:foo #ig/ref :bar}") 435 | (io/str->edn)) 436 | 437 | (rewrite-edn/sexpr (rewrite-edn/parse-string "{:foo #ig/ref :bar}")) 438 | 439 | (append-requires 440 | "(ns wake.guestbook.core\n (:require\n [clojure.tools.logging :as log]\n [integrant.core :as ig]\n [wake.guestbook.config :as config]\n [wake.guestbook.env :refer [defaults]]\n\n ;; Edges\n\n\n\n\n\n\n\n [kit.edge.utils.repl]\n [kit.edge.server.undertow]\n [wake.guestbook.web.handler]\n\n ;; Routes\n [wake.guestbook.web.routes.api]\n [wake.guestbook.web.routes.pages] )\n (:gen-class))" 441 | ['[myapp.core :as foo] 442 | '[myapp.core.roures :as routes]]) 443 | 444 | 445 | (let [child "(defn build-cljs [_]\n (println \"npx shadow-cljs release app...\")\n (let [{:keys [exit] :as s} (sh \"npx\" \"shadow-cljs\" \"release\" \"app\")]\n (when-not (zero? exit)\n (throw (ex-info \"could not compile cljs\" s)))))" 446 | ctx {}] 447 | (io/str->edn (template-value ctx child))) 448 | 449 | 450 | {:default 451 | {:require-restart? true 452 | :actions 453 | {:assets [["assets/shadow-cljs.edn" "shadow-cljs.edn"] 454 | ["assets/package.json" "package.json"] 455 | ["assets/src/core.cljs" "src/cljs/<>/core.cljs"]] 456 | :injections [{:type :html 457 | :path "resources/html/home.html" 458 | :action :append 459 | :target [:body] 460 | :value [:div {:id "app"}]} 461 | {:type :clj 462 | :path "build.clj" 463 | :action :append-build-task 464 | :value (defn build-cljs [] 465 | (println "npx shadow-cljs release app...") 466 | (let [{:keys [exit] 467 | :as s} (sh "npx" "shadow-cljs" "release" "app")] 468 | (when-not (zero? exit) 469 | (throw (ex-info "could not compile cljs" s)))))} 470 | {:type :clj 471 | :path "build.clj" 472 | :action :append-build-task-call 473 | :value (build-cljs)}]}}} 474 | 475 | 476 | (defn uber [_] 477 | (b/compile-clj {:basis basis 478 | :src-dirs ["src/clj" "env/prod/clj"] 479 | :class-dir class-dir}) 480 | 481 | (println "Making uberjar...") 482 | (b/uber {:class-dir class-dir 483 | :uber-file uber-file 484 | :main main-cls 485 | :basis basis})) 486 | ) 487 | --------------------------------------------------------------------------------