Skip to content

Instantly share code, notes, and snippets.

@semperos
Created February 12, 2018 22:47
Show Gist options
  • Save semperos/5c03bfafd291ac5e8b30205a352ea6ce to your computer and use it in GitHub Desktop.
Save semperos/5c03bfafd291ac5e8b30205a352ea6ce to your computer and use it in GitHub Desktop.
Project scaffolding relying on clj/clojure at system level
#!/bin/bash
#
# Usage: clj-new <project-name>
#
# The project-name will be sanitized to handle JVM directory requirements.
# Relies on clj/clojure being installed at the system level.
#
# TODO Support app vs. lib scripts and code
# TODO Support "all defaults" rather than requiring user interactivity
# TODO For dot-nested project name, make final root directory only the final portion of the project name (i.e., `foo` instead of `com.example.foo`)
set -e -u
[[ $# -ne 1 ]] && echo "Usage: clj-new <project-name>" && exit 1
PROJECT_NS_NAME=$1
PROJECT_DIR_NAME=$(echo "${PROJECT_NS_NAME//-/_}")
PROJECT_DIR_NAME=$(echo "${PROJECT_DIR_NAME//.//}")
[ -d "$PROJECT_DIR_NAME" ] && echo "Directory $PROJECT_DIR_NAME already exists. Quitting." && exit 1
SCRATCH=$(mktemp -d -t tmp.XXXXXXXXXX)
mkdir -p $SCRATCH/script
function cleanUp {
rm -rf $SCRATCH
}
trap cleanUp EXIT
DEPS_EDN=$(cat <<'DEPS_EDN'
{:aliases {:dev {:extra-deps
{org.clojure/tools.nrepl {:mvn/version "0.2.13"}
cider/cider-nrepl {:mvn/version "0.17.0-SNAPSHOT"}
rebel-readline {:mvn/version "0.1.0-SNAPSHOT"}}}
:1.8 {:override-deps {org.clojure/clojure {:mvn/version "1.8.0"}}}
:std {:extra-paths ["resources"]}
:test {:extra-paths ["test"]}}
:deps {}
:mvn/repos {"internal-repo" {:url "https://example.com/repository/maven-releases/"}}}
DEPS_EDN
)
echo "$DEPS_EDN" > $SCRATCH/deps.edn
echo "Specify desired port for nREPL usage: [7889]"
read REPL_PORT
if [ -z "$REPL_PORT" ]
then
REPL_PORT="7889"
fi
USER_CLJ=$(cat <<'USER_CLJ'
(ns user
(:require [clojure.tools.nrepl.server :refer [start-server stop-server]]
[cider.nrepl :refer (cider-nrepl-handler)]))
(defonce nrepl-server (start-server :port (Integer/parseInt (or (get (System/getenv) "REPL_PORT") "__REPL_PORT__")) :handler cider-nrepl-handler))
USER_CLJ
)
# Default to No, ask if user would like a local user.clj to override one
# at $HOME/opt/user.clj.
if [ -f "$HOME/opt/user.clj" ]
then
echo "Do you want to override $HOME/opt/user.clj with a local user.clj file in this project? [y/N]"
read ADD_LOCAL_USER_CLJ
if [ -z "$ADD_LOCAL_USER_CLJ" ]
then
ADD_LOCAL_USER_CLJ="n"
fi
ADD_LOCAL_USER_CLJ="$(echo $ADD_LOCAL_USER_CLJ | tr '[:upper]' '[:lower:]')"
fi
if [ "$ADD_LOCAL_USER_CLJ" = "y" ]
then
echo "Writing project-local user.clj file..."
echo "$USER_CLJ" > $SCRATCH/user.clj_template
sed -e "s/__REPL_PORT__/$REPL_PORT/g" $SCRATCH/user.clj_template > $SCRATCH/user.clj
rm $SCRATCH/user.clj_template
echo "Writing scripts leverage project-local user.clj file..."
SCRIPT_REPL_LOCAL=$(cat <<'SCRIPT_REPL_LOCAL'
#!/bin/bash
set -e -u
cd "$(dirname $0)/.."
export REPL_PORT=__REPL_PORT__
echo "Starting nREPL on port $REPL_PORT..."
clojure -C:std -R:std:dev -i user.clj -m rebel-readline.main
# clj -C:std -R:std:dev -i user.clj -r
SCRIPT_REPL_LOCAL
)
echo "$SCRIPT_REPL_LOCAL" > $SCRATCH/script/repl_template
sed -e "s/__REPL_PORT__/$REPL_PORT/g" $SCRATCH/script/repl_template > $SCRATCH/script/repl
rm $SCRATCH/script/repl_template
else
echo "Writing scripts leveraging global $HOME/opt/user.clj..."
SCRIPT_REPL_GLOBAL=$(cat <<'SCRIPT_REPL_GLOBAL'
#!/bin/bash
set -e -u
cd "$(dirname $0)/.."
export REPL_PORT=__REPL_PORT__
echo "Starting nREPL on port $REPL_PORT..."
clojure -C:std -R:std:dev -i $HOME/opt/user.clj -m rebel-readline.main
# clj -C:std -R:std:dev -i $HOME/opt/user.clj -r
SCRIPT_REPL_GLOBAL
)
echo "$SCRIPT_REPL_GLOBAL" > $SCRATCH/script/repl_template
sed -e "s/__REPL_PORT__/$REPL_PORT/g" $SCRATCH/script/repl_template > $SCRATCH/script/repl
rm $SCRATCH/script/repl_template
fi
echo "Writing remaining scripts..."
SCRIPT_RUN=$(cat <<'SCRIPT_RUN'
#!/bin/bash
MAIN_NS="__PROJECT_NS_NAME__.core"
echo "Running $MAIN_NS..."
echo ""
clj -C:std -m $MAIN_NS $*
SCRIPT_RUN
)
echo "$SCRIPT_RUN" > $SCRATCH/script/run_template
SCRIPT_TEST=$(cat <<'SCRIPT_TEST'
#!/bin/bash
set -e -u
cd "$(dirname $0)/.."
echo "Running test suite..."
TEST_NS="'__PROJECT_NS_NAME__.core-test"
clj -C:std:test -R:std -e "(do (require 'clojure.test $TEST_NS) (clojure.test/run-tests $TEST_NS))"
SCRIPT_TEST
)
echo "$SCRIPT_TEST" > $SCRATCH/script/test_template
sed -e "s/__PROJECT_NS_NAME__/$PROJECT_NS_NAME/g" $SCRATCH/script/run_template > $SCRATCH/script/run
rm $SCRATCH/script/run_template
sed -e "s/__PROJECT_NS_NAME__/$PROJECT_NS_NAME/g" $SCRATCH/script/test_template > $SCRATCH/script/test
rm $SCRATCH/script/test_template
chmod a+x $SCRATCH/script/repl
chmod a+x $SCRATCH/script/run
chmod a+x $SCRATCH/script/test
echo "Creating start src and test files..."
mkdir -p $SCRATCH/src/$PROJECT_DIR_NAME
mkdir -p $SCRATCH/test/$PROJECT_DIR_NAME
PROJECT_CORE_CLJ=$(cat <<'PROJECT_CORE_CLJ'
(ns __PROJECT_NS_NAME__.core)
(defn it-odd? [a] (odd? a))
PROJECT_CORE_CLJ
)
echo "$PROJECT_CORE_CLJ" > $SCRATCH/src/$PROJECT_DIR_NAME/core.clj_template
PROJECT_CORE_TEST_CLJ=$(cat <<'PROJECT_CORE_TEST_CLJ'
(ns __PROJECT_NS_NAME__.core-test
(:require [clojure.test :refer :all]
[__PROJECT_NS_NAME__.core :as sut]))
(deftest test-example
(is (sut/it-odd? 2)))
PROJECT_CORE_TEST_CLJ
)
echo "$PROJECT_CORE_TEST_CLJ" > $SCRATCH/test/$PROJECT_DIR_NAME/core_test.clj_template
sed -e "s/__PROJECT_NS_NAME__/$PROJECT_NS_NAME/g" $SCRATCH/src/$PROJECT_DIR_NAME/core.clj_template > $SCRATCH/src/$PROJECT_DIR_NAME/core.clj
rm $SCRATCH/src/$PROJECT_DIR_NAME/core.clj_template
sed -e "s/__PROJECT_NS_NAME__/$PROJECT_NS_NAME/g" $SCRATCH/test/$PROJECT_DIR_NAME/core_test.clj_template > $SCRATCH/test/$PROJECT_DIR_NAME/core_test.clj
rm $SCRATCH/test/$PROJECT_DIR_NAME/core_test.clj_template
mv $SCRATCH $PROJECT_NS_NAME
[[ $(type -P "tree") ]] && tree $PROJECT_NS_NAME
echo "Finished. See folder: $PROJECT_NS_NAME"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment