fradrive/Makefile

508 lines
18 KiB
Makefile

include .gnumake/*.Mak
SHELL=bash
# MAKE=make -d
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 CONTAINER_NAME ?= $(FRADRIVE_SERVICE)
export ENTRYPOINT
export IN_CONTAINER ?= false
export IN_CI ?= false
export SINGLETON
export WATCH
export UNIWORXDB_OPTS ?= -cf
export CONTAINER_ID
export FRADRIVE_SERVICE
export SERVICE_VARIANT
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 LOGSIZE ?= 1024
export PROD ?= false
ifneq ($(PROD),true)
export --DEVELOPMENT=--flag uniworx:dev
endif
# 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: stop all running containers and remove all compilation results in the directory (but leave images including dependencies unharmed)
clean:
$(MAKE) stop
-rm -rf node_modules .npm .cache assets/icons assets/favicons static well-known config/manifest.json
-rm -rf .stack-work .stack-work-run .stack-work-test .stack-work-doc .stack-work.lock
-rm -rf bin .Dockerfile develop
-$(CONTAINER_COMMAND) container 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 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
.PHONY: %-shell
# HELP: launch shell (bash) inside a currently running container
%-shell: --%-shell;
--shell:
$(CONTAINER_COMMAND) exec -it $(EXEC_OPTS) fradrive.$(CURR_DEV).$* $(if $(ENTRYPOINT),$(ENTRYPOINT),/bin/bash)
compile-%: --%-containerized-compile;
##### GENERAL TARGETS #####
###########################
##############################################
##### SERVICE DEPENDENCIES AND VARIABLES #####
--frontend-%: FRADRIVE_SERVICE=frontend
--frontend-%: SERVICE_VARIANT=frontend
--frontend-%: SINGLETON = false
--frontend-%: WATCH = false
--frontend-%:
# TODO --containerized-% is not yet working; comment this in again as soon as it does
# $(MAKE) -- --containerized-static --containerized-well-known
$(MAKE) -- --$*
--backend-%: FRADRIVE_SERVICE=backend
--backend-%: SERVICE_VARIANT=backend
--backend-%: BASE_PORTS = "DEV_PORT_HTTP=3000" "DEV_PORT_HTTPS=3443"
--backend-%: SINGLETON = false
--backend-%:
$(MAKE) -- --frontend-containerized-compile
$(MAKE) -- --$*
--hoogle-%: FRADRIVE_SERVICE=backend
--hoogle-%: SERVICE_VARIANT=hoogle
--hoogle-%: BASE_PORTS = "HOOGLE_PORT=8081"
--hoogle-%: SINGLETON = true
--hoogle-%:
$(MAKE) -- --$*
# --uniworxdb was --db in old versions
--uniworxdb-%: FRADRIVE_SERVICE=backend
--uniworxdb-%: SERVICE_VARIANT=uniworxdb
--uniworxdb-%:
$(MAKE) -- --$*
--minio-%: FRADRIVE_SERVICE=minio
--minio-%: SERVICE_VARIANT=minio
--minio-%:
$(MAKE) -- --$*
--memcached-%: FRADRIVE_SERVICE=memcached
--memcached-%: SERVICE_VARIANT=memcached
--memcached-%:
$(MAKE) -- --$*
# --postgres was --database in old versions
--postgres-%: BASE_PORTS = "PGPORT=5432"
--postgres-%: SINGLETON = true
--postgres-%:
$(MAKE) -- --$*
##### SERVICE DEPENDENCIES AND VARIABLES #####
##############################################
############################################
##### UNIFIED FRONTEND/BACKEND TARGETS #####
.PHONY: start
# HELP: start database services, frontend and backend
start: start-database start-memcached start-minio start-frontend start-backend;
.PHONY: compile
# HELP: compile frontend and backend
compile:
$(MAKE) compile-frontend
$(MAKE) compile-backend
--compile-%: --checkvarsset --develop --%
.PHONY: lint
# HELP: lint frontend and backend
lint: lint-frontend lint-backend;
.PHONY: test
# HELP: test frontend, backend, and check internationalization
test: start-database test-frontend test-backend i18n-check;
##### UNIFIED FRONTEND/BACKEND TARGETS #####
############################################
--checkvarsset:
echo "FS:$(FRADRIVE_SERVICE) SV:$(SERVICE_VARIANT) DE:$(DEVELOP) CF:$(CONTAINER_FILE)"
@:
ifeq "$(FRADRIVE_SERVICE)" ""
>&2 echo "Variable FRADRIVE_SERVICE is not set; this hints to an internal error in the Makefile unless you have manually requested a '--'-target"
exit 1
endif
ifeq "$(SERVICE_VARIANT)" ""
>&2 echo "Variable SERVICE_VARIANT is not set; this hints to an internal error in the Makefile unless you have manually requested a '--'-target"
exit 1
endif
#ifeq "$(DEVELOP)" ""
# >&2 echo "Variable DEVELOP is not set; this hints to an internal error in the Makefile unless you have manually requested a '--'-target"
# exit 1
#endif
#ifeq "$(CONTAINER_FILE)" ""
# >&2 echo "Variable CONTAINER_FILE is not set; this hints to an internal error in the Makefile unless you have manually requested a '--'-target"
# exit 1
#endif
############################
##### FRONTEND TARGETS #####
#--frontend-%: --image-build --containerized---%-frontend;
#--%-frontend: --containerized-static-frontend --containerized-well-known-frontend
#--frontend-start: static
# npm run start
ifeq ($(SERVICE_VARIANT), frontend)
--start: --checkvarsset
npm run start
# HELP(compile-frontend): compile frontend
--compile: static well-known --checkvarsset;
# HELP(lint-frontend): lint frontend
--lint: eslint.config.js --checkvarsset
npx -- eslint frontend/src $(FIX)
@echo Hooray! There are no hints.
# HELP(test-frontend): test frontend
--test: karma.conf.cjs --checkvarsset
@echo Karma frontend tests are currently broken after npm update and have therefor been temporarily disabled.
# npx -- karma start --conf karma.conf.cjs $(WATCH)
endif
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 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
static: node_modules assets esbuild.config.mjs
npm run build
well-known: static;
##### FRONTEND TARGETS #####
############################
###########################
##### BACKEND TARGETS #####
ifeq ($(SERVICE_VARIANT), backend)
--start: --checkvarsset
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=//'`; \
stack --work-dir=.stack-work-run $(--DEVELOPMENT) exec -- yesod devel -p "$${DEV_PORT_HTTP}" -q "$${DEV_PORT_HTTPS}"
endif
ifeq ($(SERVICE_VARIANT), hoogle)
--start:
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}
endif
# HELP(compile-backend): compile backend
ifeq ($(SERVICE_VARIANT), backend)
--compile: --checkvarsset
stack build --fast --profile --library-profiling --executable-profiling --flag uniworx:-library-only $(--DEVELOPMENT) --local-bin-path $$(pwd)/bin
# HELP(lint-backend): lint backend
--lint: --checkvarsset
stack build --test --fast --work-dir=.stack-work-test --flag uniworx:library-only $(--DEVELOPMENT) uniworx:test:hlint
# HELP(test-backend): test backend
--test: --checkvarsset
stack build --test --coverage --fast --work-dir=.stack-work-test --flag uniworx:library-only $(--DEVELOPMENT)
endif
# HELP(uniworxdb): clear and fill database. requires running postgres
uniworxdb: --frontend-compile --backend-imagebuild-containerized-uniworxdb-start;
# TODO (db-m-$MIGRATION-backend): apply migration (see src/Model/Migration/Definition.hs for list of available migrations)
ifeq ($(SERVICE_VARIANT), uniworxdb)
--start: .stack
SERVER_SESSION_ACID_FALLBACK=${SERVER_SESSION_ACID_FALLBACK:-true} ; \
AVSPASS=${AVSPASS:-nopasswordset} ; \
stack $(--DEVELOPMENT) exec uniworxdb -- $(UNIWORXDB_OPTS)
endif
.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
##### BACKEND TARGETS #####
###########################
############################
##### DATABASE TARGETS #####
ifeq ($(SERVICE_VARIANT), postgres)
--containerized-%: --checkvarsset docker/database/initdb.sh docker/database/pg_hba.conf docker/database/postgresql.conf docker/database/schema.sql --image-build
$(MAKE) -- --imagerun-$*
else
--containerized-%: --checkvarsset
$(MAKE) -- --imagerun-$*
endif
.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: --database-shell;
##### DATABASE TARGETS #####
############################
#############################
##### CONTAINER TARGETS #####
#--containerized-%-frontend: FRADRIVE_SERVICE=frontend
#--containerized-%-frontend: SERVICE_VARIANT=frontend
#--containerized-%-frontend: --image-build
# $(MAKE) -- --image-run-$*-frontend
#
#--containerized-%-backend: FRADRIVE_SERVICE=backend
#--containerized-%-backend: SERVICE_VARIANT?=backend
#--containerized-%-backend: --image-build
# $(MAKE) -- --image-run-$*-backend
#--containerized-%-hoogle: FRADRIVE_SERVICE=backend
#--containerized-%-hoogle: SERVICE_VARIANT=hoogle
#--containerized-%-hoogle: --image-build
# $(MAKE) -- --image-run-$*-hoogle-backend
# --containerized-%-minio: FRADRIVE_SERVICE=minio
# --containerized-%-minio: --image-build
# $(MAKE) -- --image-run-$*-minio
ifeq ($(SERVICE_VARIANT), minio)
--containerized-start:
UPLOAD_S3_PORT=`cat $(CONTAINER_FILE) | grep 'UPLOAD_S3_PORT=' | sed 's/UPLOAD_S3_PORT=//'`; \
MINIO_DIR=`mktemp` ; \
./utils/watchcontainerrun.sh "$(CONTAINER_COMMAND)" "$(CONTAINER_FILE)" "" "rm -rf $${MINIO_DIR}" & \
CONTAINER_ID=`$(CONTAINER_BGRUN) --name fradrive.$(CURR_DEV).minio $(MINIO_IMAGE) -- server $${MINIO_DIR} --address=:$${UPLOAD_S3_PORT}` ; \
printf "CONTAINER_ID=$${CONTAINER_ID}\nUPLOAD_S3_PORT=$${UPLOAD_S3_PORT}\nMINIO_DIR=$${MINIO_DIR}" >> $(CONTAINER_FILE)
endif
# --containerized-%-memcached: FRADRIVE_SERVICE=memcached
# --containerized-%-memcached: --image-build
# $(MAKE) -- --image-run-$*-memcached
ifeq ($(SERVICE_VARIANT), memcached)
--containerized-start:
MEMCACHED_PORT=`cat $(CONTAINER_FILE) | grep 'MEMCACHED_PORT=' | sed 's/MEMCACHED_PORT=//'`; \
./utils/watchcontainerrun.sh "$(CONTAINER_COMMAND)" "$(CONTAINER_FILE)" & \
CONTAINER_ID=`$(CONTAINER_BGRUN) --name fradrive.$(CURR_DEV).memcached $(MEMCACHED_IMAGE) --port=$${MEMCACHED_PORT}` ; \
printf "CONTAINER_ID=$${CONTAINER_ID}\nMEMCACHED_PORT=$${MEMCACHED_PORT}" >> $(CONTAINER_FILE)
endif
.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
# runs --% in the container. Targets meant to be called manually cannot be run in the container via this target. If that is ever needed split this target into two targets, one for manually one for automatic (one may use the other) so that not at every usage a '---' has to be after containerized
--imagerun-%: --checkvarsset 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 FRADRIVE_SERVICE=$(FRADRIVE_SERVICE) --env SERVICE_VARIANT=$(SERVICE_VARIANT) --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.$(CURR_DEV).$(SERVICE_VARIANT) localhost/fradrive/$(FRADRIVE_SERVICE) ; \
else \
./utils/watchcontainerrun.sh "$(CONTAINER_COMMAND)" "$(CONTAINER_FILE)" & \
CONTAINER_ID=`$(CONTAINER_BGRUN) -v $(PWD):$${MOUNT_DIR} --env FRADRIVE_SERVICE=$(FRADRIVE_SERVICE) --env SERVICE_VARIANT=$(SERVICE_VARIANT) --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.$(CURR_DEV).$(SERVICE_VARIANT) localhost/fradrive/$(FRADRIVE_SERVICE)` ; \
echo "CONTAINER_ID=$${CONTAINER_ID}" >> "$(CONTAINER_FILE)"; \
fi \
fi
# 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}
.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-%:
$(SET_DEVELOP)
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: status
# HELP: print develop status: running containers, used ports
status:
@./utils/develop-status.pl
.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-%: --develop
$(CONTAINER_COMMAND) logs --follow --tail=$(LOGSIZE) `cat $(DEVELOP)/$* | grep CONTAINER_ID= | sed 's/^CONTAINER_ID=//'`
##### CONTAINER TARGETS #####
#############################
# TODO: move targets below to better location
DATE := $(shell date +'%Y-%m-%dT%H-%M-%S')
CURR_DEV = $(shell ls -1 develop | tail -n1)
SET_DEVELOP = $(eval DEVELOP=develop/$$(CURR_DEV))
NEW_DEVELOP = $(eval DEVELOP=develop/$$(DATE))
.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
.PHONY: --develop
--develop:
if ! [[ -e develop ]]; then \
$(MAKE) new-develop; \
fi
$(SET_DEVELOP)
$(MAKE) develop/.current
.PHONY: develop/.current
develop/.current:
$(SET_DEVELOP)
echo "$(DEVELOP)" > develop/.current
# 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: --%
.SUFFIXES: # Delete all default suffixes