#!/usr/bin/env bash # Exit immediately if the script encounters a non-zero status. set -e # If set, Bash includes filenames beginning with a `.` in the results of # filename expansion. The filenames `.` and `..` must always be matched # explicitly, even if dotglob is set. shopt -s dotglob extglob # ============================================================ # PROLOGUE # ============================================================ # Create a new top-level directory as fallback in case $BUILD (defined below) # is ever empty. mkdir -p "/tmp/bs.phoenix" # Create an intermediate build directory. The final step of this script will # copy the content from this directory to $OUT. BUILD=$(mktemp -d -p "/tmp/bs.phoenix") if [ -z "$BUILD" ]; then >&2 echo "Failed to create temp directory." exit 1 fi # Deletes the intermediate build directory on exit. We use a concatenation of # the intermediate directory with the basename of the generated temp directory # to ensure we never evaluate to root (i.e. `/`). That should never actually # happen but a good habit to establish nonetheless. function cleanup { rm -r "/tmp/bs.phoenix/$(basename "$BUILD")" } trap cleanup EXIT # ============================================================ # ENVIRONMENT # ============================================================ if [ -z "$MODULE" ]; then MODULE_ARG= else MODULE_ARG="--module '$MODULE'" fi if [ -n "$ECTO" ]; then ECTO_ARG= else ECTO_ARG="--no-ecto" fi # ============================================================ # BUILD # ============================================================ # Copy template contents over to the intermediate build directory. cp -r template/!(README*) "$BUILD" # Explicitly set permissions on all copied template files. find "$BUILD" -type f -execdir chmod 644 {} + find "$BUILD" -type d -execdir chmod 755 {} + chmod 755 "$BUILD"/.githooks/pre-commit # Generate a new project with the specified name using `mix`. Generate in a # subdirectory to avoid interactive conflict resolution. nix develop "$BUILD" \ --command bash \ -c "mix phx.new $BUILD/bs.project --app '$APP' $MODULE_ARG $ECTO_ARG" # Copy the generated files into the intermediate build directory. mv -f "$BUILD"/bs.project/* "$BUILD" rmdir "$BUILD"/bs.project # Overwrite the generated README in favor of that defined in our template. if [ -n "$ECTO" ]; then cp template/README-ecto.md "$BUILD"/README.md else cp template/README-no-ecto.md "$BUILD"/README.md fi chmod 644 "$BUILD"/README.md # Include additional build files for our assets. Group into subdirectory so # the `chmod` command can take advantage of globbing. mkdir -p "$BUILD"/bs.assets cp assets/* "$BUILD"/bs.assets chmod 644 "$BUILD"/bs.assets/* mv "$BUILD"/bs.assets/* "$BUILD"/assets rmdir "$BUILD"/bs.assets # Create a new database cluster. if [ -n "$ECTO" ]; then nix develop "$BUILD" --command bash -c "pg_ctl initdb -D $BUILD/db" fi # ============================================================ # REWRITES # ============================================================ # The mix generator would fail if $APP did not consist of just lowercase ASCII # letters, numbers, or underscores. Thus $APP is safe to interpolate into the # following command. for file in flake.nix assets/{package.json,package-lock.json,node-packages.nix} do sed -i "s//$APP/g" "$BUILD/$file" done # Allow specifying a custom path to our :esbuild and :tailwind configs. # Typically when building a Phoenix application, Mix will download # esbuild/tailwind binaries on demand. Within nix environments this is not # possible. Instead, specify them directly with these environment variables. sed -i '/config :esbuild/, /^$/ { s/0.17.11/0.19.7/; s/]$/],/; s/^$/\ \ path: System.get_env("MIX_ESBUILD_PATH")\n/}' \ "$BUILD"/config/config.exs sed -i '/config :tailwind/, /^$/ { s/3.3.2/3.3.5/; s/]$/],/; s/^$/\ \ path: System.get_env("MIX_TAILWIND_PATH")\n/}' \ "$BUILD"/config/config.exs # By default Phoenix generates a postgres configuration with assumed username # `postgres`. This flake encourages a local postgres database with username # `$(whoami)`. Reflect this in the config. sed -i "s/username: \"postgres\"/username: \"$(whoami)\"/g" "$BUILD/config/dev.exs" # Append an additional rule to `.gitignore` to ignore the database cluster. cat <> "$BUILD"/.gitignore # Directory used by \`direnv\` to hold \`use flake\`-generated profiles. /.direnv/ # A symlink produced by default when running \`nix build\`. /result EOF if [ -n "$ECTO" ]; then cat <> "$BUILD"/.gitignore # The default location of the generated database cluster. /db/ EOF fi # ============================================================ # EPILOGUE # ============================================================ # Success! Copy contents to target directory. cp -a "$BUILD"/* "$OUT"