export SHELL=bash # MAKE=make -f Makefile-loggingsymbols # MAKE=make -d # System information export CPU_CORES = $(shell cat /proc/cpuinfo | grep '^processor' | wc -l) export CONTAINER_COMMAND ?= podman export CONTAINER_BGRUN ?= $(CONTAINER_COMMAND) run -dit --network=host --replace export CONTAINER_FGRUN ?= $(CONTAINER_COMMAND) run -it --network=host --replace export IMAGE_REGISTRY = docker.io export MEMCACHED_IMAGE = $(IMAGE_REGISTRY)/memcached:latest export MINIO_IMAGE = $(IMAGE_REGISTRY)/minio/minio:latest export MAILDEV_IMAGE = $(IMAGE_REGISTRY)/maildev/maildev:latest # TODO: needs different port than 1025 to avoid conflicts export IN_CONTAINER ?= false export IN_CI ?= false export CONTAINER_FILE export CONTAINER_IDENT export CF_PREFIX export DEVELOP export CONTAINER_ATTACHED export CONTAINER_INIT export CONTAINER_CLEANUP export PROJECT_DIR=/fradrive export SERVICE export SERVICE_VARIANT ?= $(SERVICE) export JOB export IMAGE export SET_IMAGE export ENTRYPOINT export EXEC_OPTS export STACK_CORES = $(shell echo $(($(CPU_CORES)/2))) export BASE_PORTS export UNIWORXDB_OPTS ?= -cf export PROD ?= false export SRC ifneq ($(PROD),true) export --DEVELOPMENT=--flag uniworx:dev endif export DATE := $(shell date +'%Y-%m-%dT%H-%M-%S') export CURR_DEV = $(shell cat develop/.current 2>/dev/null) export SET_DEVELOP = $(eval DEVELOP=develop/$$(CURR_DEV)) export NEW_DEVELOP = $(eval DEVELOP=develop/$$(DATE)) .PHONY: help # HELP: print out this help message help: @if [ -z "$$(which perl 2>/dev/null)" ] ; then \ $(CONTAINER_FGRUN) .:/mnt 'debian:12.5' '/mnt/utils/makehelp.pl' '/mnt/Makefile' ; \ else \ utils/makehelp.pl Makefile ; \ fi .PHONY: clean # HELP: stop all running containers and remove all compilation results in the directory (but leave images including dependencies unharmed) clean: rm -rf develop -rm -rf node_modules .npm .cache assets/icons assets/favicons static well-known config/manifest.json frontend/src/env.sass -rm -rf .stack-work .stack-work.lock -rm -rf bin .Dockerfile develop -$(CONTAINER_COMMAND) container prune --force .PHONY: clean-images # HELP: stop all running containers and clean all images from local repositories clean-images: rm -rf develop sleep 5 -$(CONTAINER_COMMAND) system prune --all --force --volumes -$(CONTAINER_COMMAND) image prune --all --force -$(CONTAINER_COMMAND) volume prune --force .PHONY: clean-all # HELP: like clean but with full container, image, and volume prune clean-all: clean -rm -rf .stack $(CONTAINER_COMMAND) system reset --force .PHONY: release # HELP: create, commit and push a new release # TODO: only release when build and tests are passing!!! release: VERSION=`./utils/version.pl -changelog CHANGELOG.md -v` ; \ git add CHANGELOG.md ; \ git commit -m "chore(release): $${VERSION}" ; \ git push ; \ git tag $${VERSION} ; \ git push origin $${VERSION} .PHONY: compile # HELP: perform full compilation (frontend and backend) compile: $(MAKE) compile-frontend $(MAKE) compile-backend .PHONY: start # HELP: start complete development environment with a fresh test database start: $(MAKE) start-postgres $(MAKE) start-memcached $(MAKE) start-minio $(MAKE) start-maildev $(MAKE) compile-frontend $(MAKE) compile-uniworxdb $(MAKE) start-backend .PHONY: %-backend %-backend: SERVICE=backend %-backend: SERVICE_VARIANT=backend %-backend: IMAGE=localhost/fradrive/backend %-backend: BASE_PORTS = "DEV_PORT_HTTP=3000" "DEV_PORT_HTTPS=3443" .PHONY: %-uniworxdb %-uniworxdb: SERVICE=backend %-uniworxdb: SERVICE_VARIANT=uniworxdb %-uniworxdb: IMAGE=localhost/fradrive/backend .PHONY: %-ghci %-ghci: SERVICE=backend %-ghci: SERVICE_VARIANT=ghci %-ghci: IMAGE=localhost/fradrive/backend .PHONY: %-hoogle %-hoogle: SERVICE=backend %-hoogle: SERVICE_VARIANT=hoogle %-hoogle: BASE_PORTS = "HOOGLE_PORT=8081" %-hoogle: IMAGE=localhost/fradrive/backend --start-hoogle: HOOGLE_PORT=`cat $(CONTAINER_FILE) | grep 'HOOGLE_PORT=' | sed 's/HOOGLE_PORT=//'` ; \ stack $(STACK_CORES) hoogle -- server --local --port $${HOOGLE_PORT} .PHONY: %-frontend %-frontend: SERVICE=frontend %-frontend: SERVICE_VARIANT=frontend %-frontend: IMAGE=localhost/fradrive/frontend .PHONY: %-postgres %-postgres: SERVICE=postgres %-postgres: SERVICE_VARIANT=postgres %-postgres: BASE_PORTS = "PGPORT=5432" %-postgres: SET_IMAGE=localhost/fradrive/postgres .PHONY: %-memcached %-memcached: SERVICE=memcached %-memcached: SERVICE_VARIANT=memcached %-memcached: SET_IMAGE=$$(MEMCACHED_IMAGE) --port=`cat $$(CONTAINER_FILE) | grep 'MEMCACHED_PORT=' | sed 's/MEMCACHED_PORT=//'` %-memcached: BASE_PORTS = "MEMCACHED_PORT=11211" .PHONY: %-maildev %-maildev: SERVICE=maildev %-maildev: SERVICE_VARIANT=maildev %-maildev: SET_IMAGE=$$(MAILDEV_IMAGE) --port=`cat $$(CONTAINER_FILE) | grep 'MAILDEV_PORT=' | sed 's/MAILDEV_PORT=//'` %-maildev: BASE_PORTS = "MAILDEV_PORT=1025" .PHONY: %-release %-release: PROD=true %-release: SERVICE=fradrive %-release: SERVICE_VARIANT=fradrive %-release: IMAGE=localhost/fradrive/fradrive .PHONY: %-minio %-minio: SERVICE=minio %-minio: SERVICE_VARIANT=minio %-minio: SET_IMAGE=$$(MINIO_IMAGE) -- server `mktemp` --address=:`cat $$(CONTAINER_FILE) | grep 'UPLOAD_S3_PORT=' | sed 's/UPLOAD_S3_PORT=//'` %-minio: BASE_PORTS = "UPLOAD_S3_PORT=9000" .PHONY: start-% start-%: JOB=start start-%: CF_PREFIX = start- start-%: CONTAINER_ATTACHED = false start-%: --act ; .PHONY: compile-% compile-%: JOB=compile compile-%: CF_PREFIX = compile- compile-%: CONTAINER_ATTACHED = true compile-%: --act ; .PHONY: dependencies-% dependencies-%: JOB=dependencies dependencies-%: CF_PREFIX = dependencies- dependencies-%: CONTAINER_ATTACHED = true dependencies-%: --act ; .PHONY: test-% test-%: JOB=test test-%: CF_PREFIX = test- test-%: CONTAINER_ATTACHED = true test-%: --act ; .PHONY: lint-% lint-%: JOB=lint lint-%: CF_PREFIX = lint- lint-%: CONTAINER_ATTACHED = true lint-%: --act ; .PHONY: shell-% # HELP(shell-$SERVICE): launch (bash) shell inside a new $SERVICE container shell-%: JOB=shell shell-%: CF_PREFIX=shell- shell-%: CONTAINER_ATTACHED=true shell-%: --act ; .PHONY: ghci # HELP(ghci): launch new backend instance and enter interactive ghci shell ghci: shell-ghci; --act: --develop_containerized; --develop_%: PORTS = $(foreach PORT,$(BASE_PORTS),$(shell utils/next_free_port.pl $(PORT))) --develop_%: --ensure-develop DEVELOP=develop/`cat develop/.current` ; \ CONTAINER_IDENT=$(CF_PREFIX)$(SERVICE_VARIANT) ; \ CONTAINER_FILE=$${DEVELOP}/$${CONTAINER_IDENT} ; \ if [[ -e $${CONTAINER_FILE} ]]; then \ >&2 echo "Another $* service is already running! Use \"make new-develop\" to start a new develop instance despite currently running services." ; \ exit 1 ; \ fi ; \ echo "$(PORTS)" | sed 's/ /\n/g' > $${CONTAINER_FILE} ; \ $(MAKE) -- --$* CONTAINER_FILE=$${CONTAINER_FILE} CONTAINER_IDENT=$${CONTAINER_IDENT} JOB=$(JOB) .PHONY: rebuild-% # HELP(rebuild-{backend,frontend,database,memcached,minio}): force-rebuild a given container image rebuild-%: $(MAKE) -- --image-build SERVICE=$* NO_CACHE=--no-cache --image-build: ifeq "$(IMAGE)" "localhost/fradrive/$(SERVICE)" rm -f .Dockerfile ln -s docker/$(SERVICE)/Dockerfile .Dockerfile PROJECT_DIR=/fradrive; \ if [ "$(IN_CONTAINER)" == "false" ] ; then \ $(CONTAINER_COMMAND) build $(NO_CACHE) \ -v $(PWD):$${PROJECT_DIR}:rw \ --build-arg PROJECT_DIR=$${PROJECT_DIR} \ --env IN_CONTAINER=true \ --env JOB=$(JOB) \ --tag fradrive/$(SERVICE) \ --file $(PWD)/.Dockerfile ; \ fi else : endif --containerized: --image-build DEVELOP=`cat develop/.current` ; \ ./utils/watchcontainerrun.sh "$(CONTAINER_COMMAND)" "$(CONTAINER_FILE)" "$(CONTAINER_INIT)" "$(CONTAINER_CLEANUP)" & \ CONTAINER_NAME=fradrive.$(CURR_DEV).$(CONTAINER_IDENT) ; \ if ! [ -z "$(SET_IMAGE)" ] ; \ then \ IMAGE="$(SET_IMAGE)" ; \ else \ IMAGE=$(IMAGE) ; \ MAKECALL="make -- --$(JOB)-$(SERVICE_VARIANT) IN_CONTAINER=true" ; \ fi ; \ CONTAINER_ID=`$(CONTAINER_BGRUN) \ -v $(PWD):$(PROJECT_DIR):rw \ --env IN_CONTAINER=true \ --env CONTAINER_FILE=$(CONTAINER_FILE) \ --env CONTAINER_NAME=$${CONTAINER_NAME} \ --env JOB=$(JOB) \ --env SRC=$(SRC) \ --name $${CONTAINER_NAME} \ $${IMAGE} \ $${MAKECALL} \ ` ; \ printf "CONTAINER_ID=$${CONTAINER_ID}" >> "$(CONTAINER_FILE)" ; \ if [[ "true" == "$(CONTAINER_ATTACHED)" ]] ; then \ $(CONTAINER_COMMAND) attach $${CONTAINER_ID} || : ; \ fi # For Reverse Proxy Problem see: https://groups.google.com/g/yesodweb/c/2EO53kSOuy0/m/Lw6tq2VYat4J # HELP(start-backend): start development instance --start-backend: --dependencies-backend export YESOD_IP_FROM_HEADER=true; \ export DEV_PORT_HTTP=`cat $(CONTAINER_FILE) | grep 'DEV_PORT_HTTP=' | sed 's/DEV_PORT_HTTP=//'`; \ export DEV_PORT_HTTPS=`cat $(CONTAINER_FILE) | grep 'DEV_PORT_HTTPS=' | sed 's/DEV_PORT_HTTPS=//'`; \ export HOST=127.0.0.1 ; \ export PORT=$${PORT:-$${DEV_PORT_HTTP}} ; \ export DETAILED_LOGGING=$${DETAILED_LOGGING:-true} ; \ export LOG_ALL=$${LOG_ALL:-false} ; \ export LOGLEVEL=$${LOGLEVEL:-info} ; \ export DUMMY_LOGIN=$${DUMMY_LOGIN:-true} ; \ export SERVER_SESSION_ACID_FALLBACK=$${SERVER_SESSION_ACID_FALLBACK:-true} ; \ export SERVER_SESSION_COOKIES_SECURE=$${SERVER_SESSION_COOKIES_SECURE:-false} ; \ export COOKIES_SECURE=$${COOKIES_SECURE:-false} ; \ export ALLOW_DEPRECATED=$${ALLOW_DEPRECATED:-true} ; \ export ENCRYPT_ERRORS=$${ENCRYPT_ERRORS:-false} ; \ export RIBBON=$${RIBBON:-$${HOST:-localhost}} ; \ export APPROOT=$${APPROOT:-http://localhost:$${DEV_PORT_HTTP}} ; \ export AVSPASS=$${AVSPASS:-nopasswordset} ; \ stack $(STACK_CORES) exec --local-bin-path $$(pwd)/bin --copy-bins -- yesod devel -p "$${DEV_PORT_HTTP}" -q "$${DEV_PORT_HTTPS}" # HELP(compile-backend): compile backend binaries --compile-backend: --dependencies-backend stack build $(STACK_CORES) --fast --profile --library-profiling --executable-profiling --flag uniworx:-library-only $(--DEVELOPMENT) --local-bin-path $$(pwd)/bin --copy-bins # HELP(dependencies-backend): (re-)build backend dependencies --dependencies-backend: #uniworx.cabal chown -R `id -un`:`id -gn` "$(PROJECT_DIR)"; \ stack install hpack; stack install yesod-bin; \ stack build -j2 --only-dependencies # HELP(lint-backend): lint backend --lint-backend: stack build $(STACK_CORES) --test --fast --flag uniworx:library-only $(--DEVELOPMENT) uniworx:test:hlint # HELP(test-backend): test backend --test-backend: stack build $(STACK_CORES) --test --coverage --fast --flag uniworx:library-only $(--DEVELOPMENT) # uniworx.cabal: # stack exec -- hpack --force # HELP(compile-frontend): compile frontend assets --compile-frontend: --dependencies-frontend npm run build --start-frontend: --compile-frontend; --dependencies-frontend: node_modules assets esbuild.config.mjs frontend/src/env.sass; node_modules: package.json package-lock.json npm install --cache .npm --prefer-offline package-lock.json: package.json npm install --cache .npm --prefer-offline assets: assets/favicons assets/icons; assets/favicons: ./utils/faviconize.pl assets/favicon.svg long assets/favicons assets/icons: node_modules assets/icons-src/fontawesome.json ./utils/renamer.pl node_modules/@fortawesome/fontawesome-free/svgs/solid assets/icons-src/fontawesome.json assets/icons/fradrive ./utils/renamer.pl node_modules/@fortawesome/fontawesome-free/svgs/regular assets/icons-src/fontawesome.json assets/icons/fradrive -cp assets/icons-src/*.svg assets/icons/fradrive frontend/src/env.sass: echo "\$$path: '$${PROJECT_DIR}'" > frontend/src/env.sass static: --dependencies-frontend npm run build well-known: static; --lint-frontend: --compile-frontend npm run lint --test-frontend: --compile-frontend npm run test # HELP(compile-uniworxdb): clear and fill database. requires running postgres instance (use "make start-postgres" to start one) # TODO (db-m-$MIGRATION-backend): apply migration (see src/Model/Migration/Definition.hs for list of available migrations) --compile-uniworxdb: --compile-backend SERVER_SESSION_ACID_FALLBACK=${SERVER_SESSION_ACID_FALLBACK:-true} ; \ AVSPASS=${AVSPASS:-nopasswordset} ; \ ./bin/uniworxdb $(UNIWORXDB_OPTS) # HELP(shell-ghci): enter ghci shell. Use "make ghci SRC=" to load specific source modules." --shell-ghci: stack ghci -- $(SRC) # --main-is uniworx:exe:uniworx # HELP(shell-{backend,frontend,memcached,minio,postgres}): enter (bash) shell inside a new container of a given service --shell-%: /bin/bash # HELP(start-minio): start minio service .PHONY: status # HELP: print develop status: running containers, used ports status: @./utils/develop-status.pl -a .PHONY: log-% # HELP(log-$(JOB)-$(SERVICE)): inspect output of a given service. The service must be currently running When a service supports multiple running instances in one develop (i.e. backend), you need to specify the exact instance by its associated file (e.g. backend-1, backend-2, etc.), please check the contents of the develop/ directory for a list of running instances. log-%: DEVELOP=develop/`cat develop/.current` ; \ SEARCH_FILE="$${DEVELOP}/$*" ; \ if [[ ! -e "$${SEARCH_FILE}" ]] ; then \ SEARCH_FILE="$${DEVELOP}/.exited.$*" ; \ fi ; \ if [[ -e "$${SEARCH_FILE}" ]] ; then \ $(CONTAINER_COMMAND) logs --follow `cat "$${SEARCH_FILE}" | grep CONTAINER_ID= | sed 's/^CONTAINER_ID=//'` ; \ else \ >&2 echo "Cannot show log: No develop file found for '$*'" ; \ exit 1 ; \ fi .PHONY: enter # HELP: launch (bash) shell inside a currently running container. Use ./enter shell wrapper for more convenient usage, possibly with tab-completion in the future enter: --ensure-develop $(MAKE) -- --enter .PHONY: psql # HELP: enter psql (postgresql) cli inside a currently running database container psql: ENTRYPOINT=/usr/bin/psql -d uniworx psql: EXEC_OPTS=--user postgres psql: --ensure-develop $(MAKE) -- --enter CONTAINER_FILE=develop/`cat develop/.current`/start-postgres --enter: CONTAINER_ID=`cat $(CONTAINER_FILE) | grep 'CONTAINER_ID=' | sed 's/CONTAINER_ID=//'` ; \ $(CONTAINER_COMMAND) exec -it $(EXEC_OPTS) $${CONTAINER_ID} $(if $(ENTRYPOINT),$(ENTRYPOINT),/bin/bash) .PHONY: stop # HELP: stop all currently running develop instances stop: rm -rf develop .PHONY: stop-% # HELP(stop-SERVICE): stop all currently running develop instances of a given service (i.e. backend,frontend,uniworxdb,hoogle,postgres,...) # HELP(stop-JOB): stop all currently running develop instances of a given job (i.e. compile,start,test,lint) stop-compile: CF_PREFIX=compile- stop-start: CF_PREFIX=start- stop-test: CF_PREFIX=test- stop-lint: CF_PREFIX=lint- stop-%: --stop; --stop: $(SET_DEVELOP) ifdef CF_PREFIX rm -rf $(DEVELOP)/$(CF_PREFIX)* endif ifdef SERVICE_VARIANT rm -rf $(DEVELOP)/*-$(SERVICE_VARIANT) endif .PHONY: new-develop # HELP: instantiate new development bundle, i.e. create new directory under develop/ new-develop: $(NEW_DEVELOP) mkdir -p $(DEVELOP) $(MAKE) develop/.current .PHONY: switch-develop # HELP: switch current develop instance to DEVELOP=... switch-develop: if ! [ -e develop/$(DEVELOP) ]; then \ echo "Specified develop $(DEVELOP) does not exist! Not switching." ; \ exit 1 ; \ fi ; \ echo "$(DEVELOP)" > develop/.current --ensure-develop: if ! [[ -e develop ]]; then \ $(MAKE) new-develop; \ fi $(MAKE) develop/.current $(SET_DEVELOP) .PHONY: develop/.current develop/.current: ls -1 develop | tail -n1 > develop/.current .PHONY: --% .SUFFIXES: # Delete all default suffixes