#!/usr/bin/env bash # This script defines common commands used during building / developing # and makes it easy to run them. SCRIPT_DIR=$(cd `dirname "${BASH_SOURCE[0]}"` && pwd) PROJECT_ROOT=$SCRIPT_DIR THIS=$0 COMMAND=${1:-watch} shift ARGS=("$@") # NOTE: This is a bash array! BOLD="\033[1m" UNDERLINED="\033[4m" RESET="\033[0m" LIGHT_CYAN="\033[96m" GREEN="\033[32m" RED="\033[31m" DEFAULT_COLOR="\033[39m" BUILD_CMD="cabal build all" BUILD_ALL_CMD="cabal build all --enable-tests --enable-benchmarks" TEST_CMD="cabal test" TEST_UNIT_CMD="cabal test waspc-test" TEST_CLI_CMD="cabal test cli-test" TEST_E2E_CMD="cabal test e2e-test" TEST_E2E_DELETE_GOLDENS="rm -rf $PROJECT_ROOT/e2e-test/test-outputs/*-golden" TEST_E2E_ACCEPT_ALL_CMD="$TEST_E2E_DELETE_GOLDENS && $TEST_E2E_CMD" RUN_CMD="cabal run wasp-cli ${ARGS[@]}" GHCID_CMD="ghcid --command=cabal repl" GHCID_TEST_CMD="ghcid --command=cabal repl" DEV_TOOLS_BIN="$PROJECT_ROOT/.bin" function install_dev_tool () { echo "cabal --project-file=$PROJECT_ROOT/dev-tool.project install $1 --installdir=$DEV_TOOLS_BIN --install-method=copy --overwrite-policy=always" } function dev_tool_path () { echo "$DEV_TOOLS_BIN/$1" } STAN_CMD="$BUILD_ALL_CMD && $(install_dev_tool stan) && $(dev_tool_path stan) report ${ARGS[@]}" HLINT_CMD="$(install_dev_tool hlint) && $(dev_tool_path hlint) . ${ARGS[@]}" PRUNE_JUICE_CMD="$(install_dev_tool prune-juice) && $(dev_tool_path prune-juice) ${ARGS[@]}" ORMOLU_BASE_CMD="$(install_dev_tool ormolu) && $(dev_tool_path ormolu) --color always --check-idempotence" ORMOLU_CHECK_CMD="$ORMOLU_BASE_CMD --mode check "'$'"(git ls-files '*.hs' '*.hs-boot')" ORMOLU_FORMAT_CMD="$ORMOLU_BASE_CMD --mode inplace "'$'"(git ls-files '*.hs' '*.hs-boot')" WASP_DEPLOY_COMPILE="$SCRIPT_DIR/tools/install_deploy_package_to_data_dir.sh" echo_and_eval () { echo -e $"${LIGHT_CYAN}Running:${DEFAULT_COLOR}" $1 "\n" eval $1 } echo_bold () { echo -e $"${BOLD}${1}${RESET}"; } print_usage () { print_usage_cmd () { echo -e $" ${UNDERLINED}${1}${RESET}" echo -e " $2"; } echo_bold "Usage: run <command>" echo "Commands:" print_usage_cmd "build" \ "Builds the project." print_usage_cmd "test" \ "Executes all tests (unit + e2e). Builds the project first if needed." print_usage_cmd "test:unit [pattern]" \ "Executes only unit tests. Builds the project first if needed. If pattern is provided, it will run only tests whose description/name matches the pattern. Check https://github.com/UnkindPartition/tasty#patterns to learn more about valid patterns." print_usage_cmd "test:cli" \ "Executes only cli unit tests. Builds the project first if needed." print_usage_cmd "test:e2e" \ "Executes only e2e tests. Builds the project first if needed." print_usage_cmd "test:e2e:accept-all" \ "Accepts any diffs in the generated code in e2e tests. Does so by deleting current golden output and re-running e2e tests to produce new golden output." print_usage_cmd "wasp-cli <args>" \ "Runs the wasp executable while forwarding arguments. Builds the project first if needed." print_usage_cmd "ghcid" \ "Runs ghcid, which watches source file changes and reports errors. Does not watch tests." print_usage_cmd "ghcid-test" \ "Runs ghcid on both source and tests." print_usage_cmd "code-check" \ "Checks code by running it through formatter, linter and static analysis." print_usage_cmd "stan <args>" \ "Runs static code analysis on the code, generating stan.html. Builds the project first if needed." print_usage_cmd "hlint <args>" \ "Runs linter on the codebase." print_usage_cmd "prune-juice <args>" \ "Runs prune-juice on the codebase, which detects unused dependencies." print_usage_cmd "ormolu:check" \ "Runs the code formatter and reports if code is correctly formatted or not." print_usage_cmd "ormolu:format" \ "Runs the code formatter and formats the code in place." print_usage_cmd "module-graph" \ "Creates graph of modules in the project. Needs graphmod (available on hackage) and graphviz (your os distribution) installed." print_usage_cmd "wasp-deploy:compile" \ "Compiles the TS project under packages/deploy" } exitStatusToString () { if (( $1 == 0 )); then echo "${GREEN}OK${RESET}"; else echo "${RED}FAIL${RESET}"; fi } case $COMMAND in build) echo_and_eval "$BUILD_CMD" ;; ghcid) echo_and_eval "$GHCID_CMD" ;; ghcid-test) # --color always is needed for Tasty to turn on the coloring. # NOTE: I did not put this into variable because I was not able to put single quotes # around :main --color always that way and it was not working. ghcid -T=':main --color always' --command=cabal repl test/TastyDiscoverDriver.hs ;; test) echo_and_eval "$TEST_CMD" ;; test:unit) TEST_PATTERN="${ARGS[0]}" if [[ -z "$TEST_PATTERN" ]] then echo_and_eval "$TEST_UNIT_CMD" else echo_and_eval "$TEST_UNIT_CMD --test-options \"-p \\\"$TEST_PATTERN\\\"\"" fi ;; test:cli) echo_and_eval "$TEST_CLI_CMD" ;; test:e2e) echo_and_eval "$TEST_E2E_CMD" ;; test:e2e:accept-all) echo_and_eval "$TEST_E2E_ACCEPT_ALL_CMD" ;; wasp-cli) echo_and_eval "$RUN_CMD" ;; stan) echo_and_eval "$STAN_CMD" ;; hlint) echo_and_eval "$HLINT_CMD" ;; prune-juice) echo_and_eval "$PRUNE_JUICE_CMD" ;; ormolu:check) echo_and_eval "$ORMOLU_CHECK_CMD" ;; ormolu:format) echo_and_eval "$ORMOLU_FORMAT_CMD" ;; code-check) echo_and_eval "$ORMOLU_CHECK_CMD" ORMOLU_RESULT=$? echo_and_eval "$HLINT_CMD" HLINT_RESULT=$? echo_and_eval "$STAN_CMD" STAN_RESULT=$? TOTAL_RESULT=$(($ORMOLU_RESULT || $HLINT_RESULT || $STAN_RESULT)) echo echo echo "======================================" echo " SUMMARY" echo "======================================" echo echo -e "Formatter (ormolu): $(exitStatusToString $ORMOLU_RESULT)" echo -e "Linter (hlint): $(exitStatusToString $HLINT_RESULT)" echo -e "Static analysis (stan): $(exitStatusToString $STAN_RESULT)" echo "-----------------------" echo -e "All together: $(exitStatusToString $TOTAL_RESULT)" exit $TOTAL_RESULT ;; module-graph) echo_and_eval "graphmod --quiet --prune-edges $PROJECT_ROOT/src/**/*.hs | dot -Gsize=60,60! -Tpng -o module-graph.png" && echo "Printed module graph to module-graph.png." ;; wasp-deploy:compile) echo_and_eval "$WASP_DEPLOY_COMPILE" ;; *) print_usage exit 1 esac