SHELL=bash # MAKE=make -d export CONTAINER_COMMAND ?= podman export CONTAINER_BGRUN ?= $(CONTAINER_COMMAND) run -dit --network=host export CONTAINER_FGRUN ?= $(CONTAINER_COMMAND) run -it --network=host export IN_CONTAINER ?= false export IN_CI ?= false export WATCH export UNIWORXDB_OPTS ?= -cf export CONTAINER_ID export FRADRIVE_SERVICE export DEV_PORT_HTTP export DEV_PORT_HTTPS export HOOGLE_PORT 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 DEVELOP export CONTAINER_FILE export CONTAINER_FILE_CONTENT export PROD ?= false export LOGSIZE ?= 1024 # HELP HEADER START # To see the definition of all available targets, take a look into the Makefile. # Targets starting with '--' are not meant to be directly called. # If you want to do so anyway please use 'make -- [--target]' to avoid # '[--target]' being treated as option to 'make'. # # # Targets meant to be used by humans are: # HELP HEADER END ########################### ##### GENERAL TARGETS ##### .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: remove all compilation results in the directory but leave containers and images unharmed clean: -rm -rf node_modules .npm .cache assets/icons assets/favicons static well-known -rm -rf .stack-work .stack-work-build .stack-work-run .stack-work-test .stack-work-doc -rm -rf bin .Dockerfile develop .PHONY: clean-all # HELP: like clean but with container and image prune clean-all: clean -rm -rf .stack -$(CONTAINER_COMMAND) system prune --all --force --volumes -$(CONTAINER_COMMAND) image prune --all --force -$(CONTAINER_COMMAND) volume prune --force .PHONY: release # HELP: create, commit and push a new release release: ./.gitlab-ci/version.pl -changelog CHANGELOG.md git add CHANGELOG.md VERSION=`.gitlab-ci/version.pl` git tag $${VERSION} git commit -m "chore(release): $${VERSION}" git push # TODO: rewrite shell targets to enter shell inside currently running containers, do not just launch new containers! .PHONY: %-shell # HELP: launches bash-shell inside backend/frontend container %-shell: ENTRYPOINT=/bin/bash %-shell: --%-shell; --%-shell: MOUNT_DIR=/mnt/fradrive ; \ FRADRIVE_SERVICE=$* ; \ $(MAKE) -- --image-build FRADRIVE_SERVICE=$${FRADRIVE_SERVICE} ; \ $(CONTAINER_FGRUN) -v $(PWD):$${MOUNT_DIR} --env IN_CONTAINER=true --env CONTAINER_FILE=$(CONTAINER_FILE) --entrypoint $(ENTRYPOINT) --name fradrive.$${FRADRIVE_SERVICE}.interactive.$$(date +'%Y-%m-%dT%H-%M-%S') fradrive/$${FRADRIVE_SERVICE} ##### GENERAL TARGETS ##### ########################### ############################################ ##### UNIFIED FRONTEND/BACKEND TARGETS ##### .PHONY: start # HELP: start database services, frontend and backend start: new-develop start-database start-memcached start-minio start-frontend start-backend; .PHONY: compile # HELP: compile frontend and backend compile: compile-frontend compile-backend; .PHONY: lint # HELP: lint frontend and backend lint: lint-frontend lint-backend; .PHONY: test # HELP: test frontend, backend, and check internationalization test: test-frontend test-backend i18n-check; ##### UNIFIED FRONTEND/BACKEND TARGETS ##### ############################################ ############################ ##### FRONTEND TARGETS ##### .PHONY: %-frontend %-frontend: FRADRIVE_SERVICE=frontend %-frontend: --image-build --containerized---%-frontend; --%-frontend: --containerized-static-frontend --containerized-well-known-frontend; # HELP(compile-frontend): compile frontend --compile-frontend: static well-known; .PHONY: serve-frontend # HELP: serve frontend (watch file changes) serve-frontend: $(MAKE) -- --containerized---compile-frontend WATCH=--watch # --serve-frontend: WATCH=--watch # --serve-frontend: --compile-frontend; # HELP(lint-frontend): lint frontend --lint-frontend: eslint.config.js npx -- eslint frontend/src $(FIX) @echo Hooray! There are no hints. # HELP(test-frontend): test frontend --test-frontend: karma.conf.cjs @echo Karma frontend tests are currently broken after npm update and have therefor been temporarily disabled. # npx -- karma start --conf karma.conf.cjs $(WATCH) node_modules: package.json package-lock.json npm ci --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 ./utils/renamer.pl node_modules/@fortawesome/fontawesome-free/svgs/solid utils/rename-fa.json assets/icons/fradrive ./utils/renamer.pl node_modules/@fortawesome/fontawesome-free/svgs/regular utils/rename-fa.json assets/icons/fradrive static: node_modules esbuild.config.mjs assets npm run build well-known: static; ##### FRONTEND TARGETS ##### ############################ ########################### ##### BACKEND TARGETS ##### .PHONY: %-backend %-backend: FRADRIVE_SERVICE=backend %-backend: --image-build --containerized---%-backend; # TODO: to be deprecated by start-% .PHONY: serve-backend # HELP: serve backend serve-backend: DEV_PORT_HTTP=`utils/next_free_port.pl 3000 | tee .dev-port-http`; \ DEV_PORT_HTTPS=`utils/next_free_port.pl 3443 | tee .dev-port-https`; \ $(MAKE) -- --containerized---serve-dev-backend DEV_PORT_HTTP=$${DEV_PORT_HTTP} DEV_PORT_HTTPS=$${DEV_PORT_HTTPS} # DEV_PORT_HTTP=`grep 'https:' develop/$(DATE)/backend/$(CONTAINER_ID) | sed 's/.*://'`; \ # DEV_PORT_HTTPS=`grep 'https:' develop/$(DATE)/backend/$(CONTAINER_ID) | sed 's/.*://'`; \ # DEVELOP=$(MAKE) develop/ --serve-dev-backend: start.sh DEV_PORT_HTTP=`cat .dev-port-http`; \ DEV_PORT_HTTPS=`cat .dev-port-https`; \ ./start.sh # ./utils/watchrun.sh develop/ ./start.sh # HELP(compile-backend): compile backend --compile-backend: stack build --fast --work-dir .stack-work-build --profile --library-profiling --executable-profiling --flag uniworx:-library-only --local-bin-path $$(pwd)/bin $(stackopts) # HELP(lint-backend): lint backend --lint-backend: stack build --test --fast --work-dir .stack-work-test --flag uniworx:library-only uniworx:test:hlint $(stackopts) # HELP(test-backend): test backend --test-backend: stack build --test --coverage --fast --workdir .stack-work-test --flag uniworx:library-only $(stackopts) # TODO: better name .PHONY: db # HELP: clear and fill database. requires running postgres db: FRADRIVE_SERVICE=backend db: --image-build --containerized---db; # TODO (db-m-$MIGRATION-backend): apply migration (see src/Model/Migration/Definition.hs for list of available migrations) --db-backend: .stack SERVER_SESSION_ACID_FALLBACK=${SERVER_SESSION_ACID_FALLBACK:-true} ; \ AVSPASS=${AVSPASS:-nopasswordset} ; \ stack exec uniworxdb -- $(UNIWORXDB_OPTS) .PHONY: .stack .stack: if [ "$(IN_CONTAINER)" == "true" ] ; then \ $(MAKE) -- --.stack ; \ else \ $(MAKE) -- --image-run---.stack ; \ fi --.stack: stack.yaml stack.yaml.lock package.yaml stack build --fast --only-dependencies $(stackopts) ##### BACKEND TARGETS ##### ########################### ############################ ##### DATABASE TARGETS ##### # TODO: to be deprecated by start-% .PHONY: serve-database # HELP: serve database serve-database: --containerized-database; --containerized-database: FRADRIVE_SERVICE=database # port forwarding is disabled in --network=host mode; nevertheless it is stated here for documentation reasons --containerized-database: docker/database/initdb.sh docker/database/pg_hba.conf docker/database/postgresql.conf docker/database/schema.sql --image-build if [ "$(IN_CONTAINER)" == "false" ] ; then \ $(CONTAINER_BGRUN) --name fradrive.$(FRADRIVE_SERVICE).$$(date +'%Y-%m-%dT%H-%M-%S') fradrive/$(FRADRIVE_SERVICE) ; \ fi ##### DATABASE TARGETS ##### ############################ ############################# ##### CONTAINER TARGETS ##### --containerized-%-frontend: FRADRIVE_SERVICE=frontend --containerized-%-frontend: --image-build $(MAKE) -- --image-run-$*-frontend --containerized-%-backend: FRADRIVE_SERVICE=backend --containerized-%-backend: --image-build $(MAKE) -- --image-run-$*-backend --containerized-%-hoogle: --containerized-%-hoogle-backend; --containerized---db: --containerized-db-backend; # --containerized-%-minio: FRADRIVE_SERVICE=minio # --containerized-%-minio: --image-build # $(MAKE) -- --image-run-$*-minio --containerized---start-minio: MINIO_DIR=`mktemp` ; \ ./utils/watchcontainerrun.sh "$(CONTAINER_COMMAND)" "$(CONTAINER_FILE)" "" "rm -rf $${MINIO_DIR}" & \ CONTAINER_ID=`$(CONTAINER_BGRUN) --name fradrive.minio.$$(date +'%Y-%m-%dT%H-%M-%S') $(MINIO_IMAGE) -- server $${MINIO_DIR}` ; \ echo "CONTAINER_ID=$${CONTAINER_ID}" >> $(CONTAINER_FILE) # --containerized-%-memcached: FRADRIVE_SERVICE=memcached # --containerized-%-memcached: --image-build # $(MAKE) -- --image-run-$*-memcached --containerized---start-memcached: ./utils/watchcontainerrun.sh "$(CONTAINER_COMMAND)" "$(CONTAINER_FILE)" & CONTAINER_ID=`$(CONTAINER_BGRUN) $(MEMCACHED_IMAGE)` ; \ echo "CONTAINER_ID=$${CONTAINER_ID}" >> $(CONTAINER_FILE) --containerized-%-database: FRADRIVE_SERVICE=database --containerized-%-database: --image-build $(MAKE) -- --image-run-$*-database .PHONY: image-rebuild # HELP(image-rebuild-{backend,frontend,database,memcached,minio}): force-rebuild the stated docker image image-rebuild-%: $(MAKE) -- --image-build FRADRIVE_SERVICE=$* NO_CACHE=--no-cache --image-build: rm -f .Dockerfile ln -s docker/$(FRADRIVE_SERVICE)/Dockerfile .Dockerfile MOUNT_DIR=/mnt/fradrive; \ PROJECT_DIR=/mnt/fradrive; \ if [ "$(IN_CI)" == "true" ] ; then \ PROJECT_DIR=/fradrive; \ fi; \ if [ "$(IN_CONTAINER)" == "false" ] ; then \ $(CONTAINER_COMMAND) build $(NO_CACHE) -v $(PWD):$${MOUNT_DIR} --env IN_CONTAINER=true --build-arg MOUNT_DIR=$${MOUNT_DIR} --build-arg PROJECT_DIR=$${PROJECT_DIR} --tag fradrive/$(FRADRIVE_SERVICE) --file $(PWD)/.Dockerfile ; \ fi --image-run-%: docker/$(FRADRIVE_SERVICE)/Dockerfile MOUNT_DIR=/mnt/fradrive; \ if [ "$(IN_CONTAINER)" == "true" ] ; then \ $(MAKE) -- $* ; \ else \ if [ -z "$(CONTAINER_FILE)" ] ; then \ $(CONTAINER_FGRUN) -v $(PWD):$${MOUNT_DIR} --env IN_CONTAINER=true --env FRADRIVE_MAKE_TARGET=$* --env CONTAINER_FILE=$(CONTAINER_FILE) --env CONTAINER_FILE_CONTENT=$(CONTAINER_FILE_CONTENT) --env WATCH=$(WATCH) --name fradrive.$(FRADRIVE_SERVICE).$$(date +'%Y-%m-%dT%H-%M-%S') localhost/fradrive/$(FRADRIVE_SERVICE) ; \ else \ CONTAINER_ID=`$(CONTAINER_BGRUN) -v $(PWD):$${MOUNT_DIR} --env IN_CONTAINER=true --env FRADRIVE_MAKE_TARGET=$* --env CONTAINER_FILE=$(CONTAINER_FILE) --env CONTAINER_FILE_CONTENT=$(CONTAINER_FILE_CONTENT) --env WATCH=$(WATCH) --name fradrive.$(FRADRIVE_SERVICE).$$(date +'%Y-%m-%dT%H-%M-%S') localhost/fradrive/$(FRADRIVE_SERVICE)` ; \ echo "CONTAINER_ID=$${CONTAINER_ID}" >> "$(CONTAINER_FILE)"; \ fi \ fi # .PHONY: new-backend # new-backend: # LAST_DATE=`ls -1 develop | tail -n1` # if [[ -z "$${LAST_DATE}" || -e `ls develop/$${LAST_DATE}/database` ]]; then \ # mkdir -p develop/$$(date +'%Y-%m-%dT%H-%M-%S') \ # fi # serve-backend #new-database: # mkdir -p develop/$$(date +'%Y-%m-%dT%H-%M-%S') # $(MAKE) serve-database # TODO: work in progress # - compute used ports and provide as env vars # - start container in detached mode # - save container id with ports as content as file # .PHONY: serve-% # serve-backend: # DEV_PORT_HTTP=`docker/backend/dev_port.pl 3000 | tee develop/$${DATE}/fradrive.backend.$${DATE}`; \ # DEV_PORT_HTTPS=`docker/backend/dev_port.pl 3443 | tee .dev-port-https`; \ # $(MAKE) -- --containerized---start-dev-backend DEV_PORT_HTTP=$${DEV_PORT_HTTP} DEV_PORT_HTTPS=$${DEV_PORT_HTTPS} #--serve-dev-backend: start.sh # DEV_PORT_HTTP=`grep 'https:' develop/$(DATE)/backend/$(CONTAINER_ID) | sed 's/.*://'`; \ # DEV_PORT_HTTPS=`grep 'https:' develop/$(DATE)/backend/$(CONTAINER_ID) | sed 's/.*://'`; \ # ./utils/watchrun.sh develop/ ./start.sh DATE := $(shell date +'%Y-%m-%dT%H-%M-%S') SET_DEVELOP = $(eval DEVELOP=develop/`ls -1 develop | tail -n1`) NEW_DEVELOP = $(eval DEVELOP=develop/$$(DATE)) .PHONY: new-develop new-develop: $(NEW_DEVELOP) mkdir -p $(DEVELOP) $(MAKE) develop/.current .PHONY: --develop --develop: if ! [[ -e develop ]]; then \ $(MAKE) new-develop; \ fi $(MAKE) develop/.current .PHONY: develop/.current develop/.current: $(SET_DEVELOP) echo "$(DEVELOP)" > develop/.current start-database: BASE_PORTS = "PGPORT=5432" start-database: SINGLETON = true start-memcached: BASE_PORTS = "MEMCACHED_PORT=11211" start-memcached: SINGLETON = true start-minio: BASE_PORTS = "UPLOAD_S3_PORT=9000" start-minio: SINGLETON = true start-backend: BASE_PORTS = "DEV_PORT_HTTP=3000" "DEV_PORT_HTTPS=3443" start-backend: SINGLETON = false start-backend: static start-hoogle: BASE_PORTS = "HOOGLE_PORT=8081" start-hoogle: SINGLETON = true start-frontend: SINGLETON = false start-frontend: WATCH = false # HELP(start-database): start postgres server # HELP(start-memcached): start memcached server # HELP(start-minio): start minio server # HELP(start-backend): serve yesod development site # HELP(start-frontend): start frontend watcher. Watches frontend source files for changes and recompiles on change. (TODO: watcher functionality currently broken!) # HELP(start-hoogle): serve local hoogle instance start-%: FRADRIVE_SERVICE = % start-%: PORTS = $(foreach PORT,$(BASE_PORTS),$(shell utils/next_free_port.pl $(PORT))) start-%: --develop echo "$*" echo "$(DATE)" echo "DEV $(DEVELOP)" if [[ "$(SINGLETON)" = "true" ]]; then \ CONTAINER_FILE=$(DEVELOP)/$* ; \ if ! [[ -e $${CONTAINER_FILE} ]]; then \ >&2 echo "Another $* service is already running! Use \"make new-develop\" or \"make start\" to start a new develop instance despite currently running services." ; \ exit 1 ; \ fi \ else \ DEVDIR=$(DEVELOP)/$*; \ I=`ls $${DEVDIR} | sort -n | tail -n1`; \ echo "$${I}"; \ CONTAINER_FILE=$${DEVDIR}-$$(($${I}+1)); \ fi ; \ echo "$(PORTS)" | sed 's/ /\n/g' > $${CONTAINER_FILE} ; \ $(MAKE) -- --containerized---start-$* CONTAINER_FILE=$${CONTAINER_FILE} --start-backend: start.sh DEV_PORT_HTTP=`cat $(CONTAINER_FILE) | grep 'DEV_PORT_HTTP=' | sed 's/DEV_PORT_HTTP=//'`; \ DEV_PORT_HTTPS=`cat $(CONTAINER_FILE) | grep 'DEV_PORT_HTTPS=' | sed 's/DEV_PORT_HTTPS=//'`; \ ./start.sh --start-hoogle-backend: HOOGLE_PORT=`cat $(CONTAINER_FILE) | grep 'HOOGLE_PORT=' | sed 's/HOOGLE_PORT=//'` ; \ echo "${HOOGLE_PORT}" ; \ stack --work-dir .stack-work-doc hoogle -- -server --local --port $${HOOGLE_PORT} --start-frontend: static npm run start # --start-database: docker/database/initdb.sh docker/database/pg_hba.conf docker/database/postgresql.conf docker/database/schema.sql; # ./utils/watchrun.sh "$(CONTAINER_FILE)" # TODO: mkdir inside develop/$(DATE)/minio instead of mktemp # TODO: remove dir in stop-minio #--containerized---start-minio: # MINIO_DIR=`mktemp` ; \ # echo "MINIO_DIR=$${MINIO_DIR}" > $(DEVELOP)/minio ; \ # CONTAINER_ID=`$(CONTAINER_RUN) -v $(PWD):/mnt/fradrive --file docker/minio/Dockerfile -- (server $${MINIO_DIR})` ; \ # echo "CONTAINER_ID=$${CONTAINER_ID}" >> $(DEVELOP)/minio .PHONY: stop # HELP: stop all currently running develop instances stop: rm -rf develop .PHONY: stop-% # HELP(stop-{database,memcached,minio,backend,frontend,hoogle}): stop all currently running develop instances of a given type stop-%: --stop-% rm -rf $(DEVELOP)/$* stop-container-by-file: rm $(CONTAINER_FILE) stop-container-by-id: $(CONTAINER_COMMAND) stop $(CONTAINER_ID) # CONTAINER_ID=`grep 'CONTAINER_ID=' $(CONTAINER_FILE) | sed 's/CONTAINER_ID=//'` ; \ # $(MAKE) stop-container-by-id CONTAINER_ID=$${CONTAINER_ID} .PHONY: log-% # HELP(log-{database,memcached,minio,backend,frontend,hoogle}): inspect output of a given (currently running) service. 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-%: $(CONTAINER_COMMAND) logs --follow --tail=$(LOGSIZE) `cat develop/$(CURRENT_DEVELOP)/$* | grep CONTAINER_ID= | sed 's/^CONTAINER_ID=//'` ##### CONTAINER TARGETS ##### ############################# # TODO: move targets below to better location # Some convenience aliases: .PHONY: hoogle # HELP: alias for start-hoogle hoogle: start-hoogle; .PHONY: i18n-check # HELP: check internationalization i18n-check: --image-run---i18n-check --i18n-check: ./missing-translations.sh @echo No missing translations. %.lock: [ -e $@ ] || touch $@ flock -en $@ true .PHONY: --%