Skip to content

Instantly share code, notes, and snippets.

@leonelag
Last active April 13, 2021 00:58
Show Gist options
  • Save leonelag/c6b6aeea3502f25dd6603d33a287f129 to your computer and use it in GitHub Desktop.
Save leonelag/c6b6aeea3502f25dd6603d33a287f129 to your computer and use it in GitHub Desktop.
Clojure launcher for cygwin
#!/usr/bin/env bash
#
# From: https://raw.githubusercontent.com/clojure/brew-install/1.9.0/src/main/resources/clojure
#
# Version = 1.10.3.814
project_version=1.10.3.814
# Check for cygwin
cygwin=false
case "`uname`" in
CYGWIN*) cygwin=true;;
esac
set -e
function join { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }
# Extract opts
print_classpath=false
describe=false
verbose=false
trace=false
force=false
repro=false
tree=false
pom=false
help=false
prep=false
jvm_opts=()
resolve_aliases=()
classpath_aliases=()
repl_aliases=()
mode="repl"
while [ $# -gt 0 ]
do
case "$1" in
-version)
>&2 echo "Clojure CLI version 1.10.3.814"
exit 0
;;
--version)
echo "Clojure CLI version 1.10.3.814"
exit 0
;;
-J*)
jvm_opts+=("${1:2}")
shift
;;
-R*)
resolve_aliases+=("${1:2}")
shift
>&2 echo "-R is deprecated, use -A with repl, -M for main, or -X for exec"
;;
-C*)
classpath_aliases+=("${1:2}")
shift
>&2 echo "-C is deprecated, use -A with repl, -M for main, or -X for exec"
;;
-O*)
>&2 echo "-O is no longer supported, use -A with repl, -M for main, or -X for exec"
exit 1
;;
-T*)
>&2 echo "-T is no longer supported, use -A with repl, -M for main, or -X for exec"
exit 1
;;
-A)
>&2 echo "-A requires an alias"
exit 1
;;
-A*)
repl_aliases+=("${1:2}")
shift
;;
-M)
mode="main"
shift
break
;;
-M*)
mode="main"
main_aliases="${1:2}"
shift
break
;;
-X)
mode="exec"
shift
break
;;
-X*)
mode="exec"
exec_aliases="${1:2}"
shift
break
;;
-P)
prep=true
shift
;;
-Sdeps)
shift
deps_data="${1}"
shift
;;
-Scp)
shift
force_cp="${1}"
shift
;;
-Spath)
print_classpath=true
shift
;;
-Sverbose)
verbose=true
shift
;;
-Sthreads)
shift
threads="${1}"
shift
;;
-Strace)
trace=true
shift
;;
-Sdescribe)
describe=true
shift
;;
-Sforce)
force=true
shift
;;
-Srepro)
repro=true
shift
;;
-Stree)
tree=true
shift
;;
-Spom)
pom=true
shift
;;
-Sresolve-tags)
>&2 echo "Option changed, use: clj -X:deps git-resolve-tags"
exit 1
;;
-S*)
>&2 echo "Invalid option: $1"
exit 1
;;
-h|--help|"-?")
if [[ -n "$main_aliases" ]] || [[ -n "$repl_aliases" ]]; then
break
else
help=true
shift
fi
;;
--)
shift
break
;;
*)
break
;;
esac
done
# Find java executable
if [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then
JAVA_CMD=$(cygpath --mixed --absolute "$JAVA_HOME/bin/java.exe")
else
>&2 echo "Couldn't find 'java'. Please set JAVA_HOME."
exit 1
fi
if "$help"; then
cat <<-END
Version: 1.10.3.814
You use the Clojure tools ('clj' or 'clojure') to run Clojure programs
on the JVM, e.g. to start a REPL or invoke a specific function with data.
The Clojure tools will configure the JVM process by defining a classpath
(of desired libraries), an execution environment (JVM options) and
specifying a main class and args.
Using a deps.edn file (or files), you tell Clojure where your source code
resides and what libraries you need. Clojure will then calculate the full
set of required libraries and a classpath, caching expensive parts of this
process for better performance.
The internal steps of the Clojure tools, as well as the Clojure functions
you intend to run, are parameterized by data structures, often maps. Shell
command lines are not optimized for passing nested data, so instead you
will put the data structures in your deps.edn file and refer to them on the
command line via 'aliases' - keywords that name data structures.
'clj' and 'clojure' differ in that 'clj' has extra support for use as a REPL
in a terminal, and should be preferred unless you don't want that support,
then use 'clojure'.
Usage:
Start a REPL clj [clj-opt*] [-Aaliases] [init-opt*]
Exec function clojure [clj-opt*] -X[aliases] [a/fn] [kpath v]*
Run main clojure [clj-opt*] -M[aliases] [init-opt*] [main-opt] [arg*]
Prepare clojure [clj-opt*] -P [other exec opts]
exec-opts:
-Aaliases Use concatenated aliases to modify classpath
-X[aliases] Use concatenated aliases to modify classpath or supply exec fn/args
-M[aliases] Use concatenated aliases to modify classpath or supply main opts
-P Prepare deps - download libs, cache classpath, but don't exec
clj-opts:
-Jopt Pass opt through in java_opts, ex: -J-Xmx512m
-Sdeps EDN Deps data to use as the last deps file to be merged
-Spath Compute classpath and echo to stdout only
-Spom Generate (or update) pom.xml with deps and paths
-Stree Print dependency tree
-Scp CP Do NOT compute or cache classpath, use this one instead
-Srepro Ignore the ~/.clojure/deps.edn config file
-Sforce Force recomputation of the classpath (don't use the cache)
-Sverbose Print important path info to console
-Sdescribe Print environment and command parsing info as data
-Sthreads Set specific number of download threads
-Strace Write a trace.edn file that traces deps expansion
-- Stop parsing dep options and pass remaining arguments to clojure.main
--version Print the version to stdout and exit
-version Print the version to stderr and exit
init-opt:
-i, --init path Load a file or resource
-e, --eval string Eval exprs in string; print non-nil values
--report target Report uncaught exception to "file" (default), "stderr", or "none"
main-opt:
-m, --main ns-name Call the -main function from namespace w/args
-r, --repl Run a repl
path Run a script from a file or resource
- Run a script from standard input
-h, -?, --help Print this help message and exit
Programs provided by :deps alias:
-X:deps mvn-install Install a maven jar to the local repository cache
-X:deps git-resolve-tags Resolve git coord tags to shas and update deps.edn
For more info, see:
https://clojure.org/guides/deps_and_cli
https://clojure.org/reference/repl_and_main
END
exit 0
fi
# Set dir containing the installed files
install_dir=/usr/local/lib/clojure
tools_cp=$(cygpath --windows --absolute "$install_dir/libexec/clojure-tools-1.10.3.814.jar")
# Determine user config directory
if [[ -n "$CLJ_CONFIG" ]]; then
config_dir="$CLJ_CONFIG"
elif [[ -n "$XDG_CONFIG_HOME" ]]; then
config_dir="$XDG_CONFIG_HOME/clojure"
else
config_dir="$HOME/.clojure"
fi
# If user config directory does not exist, create it
if [[ ! -d "$config_dir" ]]; then
mkdir -p "$config_dir"
fi
if [[ ! -e "$config_dir/deps.edn" ]]; then
cp "$install_dir/example-deps.edn" "$config_dir/deps.edn"
fi
# Determine user cache directory
if [[ -n "$CLJ_CACHE" ]]; then
user_cache_dir="$CLJ_CACHE"
elif [[ -n "$XDG_CACHE_HOME" ]]; then
user_cache_dir="$XDG_CACHE_HOME/clojure"
else
user_cache_dir="$config_dir/.cpcache"
fi
# Chain deps.edn in config paths. repro=skip config dir
config_project="deps.edn"
if "$repro"; then
config_paths=("$install_dir/deps.edn" "deps.edn")
else
config_user=$(cygpath --windows --absolute "$config_dir/deps.edn")
config_paths=("$install_dir/deps.edn" "$config_dir/deps.edn" "deps.edn")
fi
config_str=$(printf ",%s" "${config_paths[@]}")
config_str=${config_str:1}
# Determine whether to use user or project cache
if [[ -f deps.edn ]]; then
cache_dir=.cpcache
else
cache_dir="$user_cache_dir"
fi
# Construct location of cached classpath file
val="$(join '' ${resolve_aliases[@]})|$(join '' ${classpath_aliases[@]})|$(join '' ${repl_aliases[@]})|$exec_aliases|$main_aliases|$deps_data"
for config_path in "${config_paths[@]}"; do
if [[ -f "$config_path" ]]; then
val="$val|$config_path"
else
val="$val|NIL"
fi
done
ck=$(echo "$val" | cksum | cut -d" " -f 1)
libs_file=$(cygpath --windows --absolute "$cache_dir/$ck.libs")
cp_file=$(cygpath --windows --absolute "$cache_dir/$ck.cp")
jvm_file=$(cygpath --windows --absolute "$cache_dir/$ck.jvm")
main_file=$(cygpath --windows --absolute "$cache_dir/$ck.main")
basis_file=$(cygpath --windows --absolute "$cache_dir/$ck.basis")
# Print paths in verbose mode
if "$verbose"; then
echo "version = 1.10.3.814"
echo "install_dir = $install_dir"
echo "config_dir = $config_dir"
echo "config_paths =" "${config_paths[@]}"
echo "cache_dir = $cache_dir"
echo "cp_file = $cp_file"
echo
fi
# Check for stale classpath file
stale=false
if "$force" || "$trace" || "$tree" || "$prep" || [ ! -f "$cp_file" ]; then
stale=true
else
for config_path in "${config_paths[@]}"; do
if [ "$config_path" -nt "$cp_file" ]; then
stale=true
break
fi
done
fi
# Make tools args if needed
if "$stale" || "$pom"; then
tools_args=()
if [[ -n "$deps_data" ]]; then
tools_args+=("--config-data" "$deps_data")
fi
if [[ ${#resolve_aliases[@]} -gt 0 ]]; then
tools_args+=("-R$(join '' ${resolve_aliases[@]})")
fi
if [[ ${#classpath_aliases[@]} -gt 0 ]]; then
tools_args+=("-C$(join '' ${classpath_aliases[@]})")
fi
if [[ -n "$main_aliases" ]]; then
tools_args+=("-M$main_aliases")
fi
if [[ ${#repl_aliases[@]} -gt 0 ]]; then
tools_args+=("-A$(join '' ${repl_aliases[@]})")
fi
if [[ -n "$exec_aliases" ]]; then
tools_args+=("-X$exec_aliases")
fi
if [[ -n "$force_cp" ]]; then
tools_args+=("--skip-cp")
fi
if [[ -n "$threads" ]]; then
tools_args+=("--threads" "$threads")
fi
if "$trace"; then
tools_args+=("--trace")
fi
if "$tree"; then
tools_args+=("--tree")
fi
fi
# If stale, run make-classpath to refresh cached classpath
if [[ "$stale" = true && "$describe" = false ]]; then
if "$verbose"; then
>&2 echo "Refreshing classpath"
fi
"$JAVA_CMD" -classpath "$tools_cp" clojure.main -m clojure.tools.deps.alpha.script.make-classpath2 --config-user "$config_user" --config-project "$config_project" --basis-file "$basis_file" --libs-file "$libs_file" --cp-file "$cp_file" --jvm-file "$jvm_file" --main-file "$main_file" "${tools_args[@]}"
fi
if "$describe"; then
cp=
elif [[ -n "$force_cp" ]]; then
cp="$force_cp"
else
cp=$(cat "$cp_file")
fi
if "$prep"; then
exit 0
elif "$pom"; then
exec "$JAVA_CMD" -classpath "$tools_cp" clojure.main -m clojure.tools.deps.alpha.script.generate-manifest2 --config-user "$config_user" --config-project "$config_project" --gen=pom "${tools_args[@]}"
elif "$print_classpath"; then
echo "$cp"
elif "$describe"; then
for config_path in "${config_paths[@]}"; do
if [[ -f "$config_path" ]]; then
path_vector="$path_vector\"$config_path\" "
fi
done
cat <<-END
{:version "1.10.3.814"
:config-files [$path_vector]
:config-user "$config_user"
:config-project "$config_project"
:install-dir "$install_dir"
:config-dir "$config_dir"
:cache-dir "$cache_dir"
:force $force
:repro $repro
:main-aliases "$main_aliases"
:repl-aliases "$repl_aliases"}
END
elif "$tree"; then
exit 0
elif "$trace"; then
>&2 echo "Wrote trace.edn"
else
set -f
if [[ -e "$jvm_file" ]]; then
set +e
IFS=$'\n' read -ra jvm_cache_opts -d '' <"$jvm_file"
set -e
fi
if [ "$mode" == "exec" ]; then
exec_args=()
if [[ -n "$exec_aliases" ]]; then
exec_args+=("--aliases" "$exec_aliases")
fi
exec "$JAVA_CMD" "${jvm_cache_opts[@]}" "${jvm_opts[@]}" "-Dclojure.basis=$basis_file" -classpath "$cp:$install_dir/libexec/exec.jar" clojure.main -m clojure.run.exec "${exec_args[@]}" "$@"
else
if [[ -e "$main_file" ]]; then
set +e
IFS=$'\n' read -ra main_cache_opts -d '' <"$main_file"
set -e
fi
if [ "$#" -gt 0 ] && [ "$mode" == "repl" ]; then
>&2 echo "WARNING: When invoking clojure.main, use -M"
fi
exec "$JAVA_CMD" "${jvm_cache_opts[@]}" "${jvm_opts[@]}" "-Dclojure.basis=$basis_file" -classpath "$cp" clojure.main "${main_cache_opts[@]}" "$@"
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment