APP=$(shell basename $(CURDIR))
PACKAGE=$(subst _,-,$(APP))
STAGE?=dev

VENV_NAME ?= venv
VENV_ACTIVATE=. $(VENV_NAME)/bin/activate

PYTHON = $(VENV_NAME)/bin/python3
PIP = $(PYTHON) -m pip
PYTEST = $(VENV_NAME)/bin/pytest
PYLINT = $(VENV_NAME)/bin/pylint
TWINE = $(VENV_NAME)/bin/twine
MYPY = $(VENV_NAME)/bin/mypy

DOCKER_VENV_NAME ?= dockerenv
BUILD_VENV_NAME ?= /tmp/buildenv
WHEELHOUSE ?= wheels

# Set AWS ECR address if your tools is going to be executed in a cloud
REGISTRY ?= $(APP)
REVISION ?= $(shell git rev-parse --short=8 HEAD)
VERSION ?= $(shell git rev-parse --abbrev-ref HEAD)
BUILDTIME = $(shell date -u +"%Y%m%d%H%M%S")

TEST_IMAGE = 475275892927.dkr.ecr.us-east-1.amazonaws.com/python:3.10-aws2-testing
TEST_MARKS ?= "not integration"
DOCKER_PIP_ARGS ?= --find-links=/app/$(WHEELHOUSE)

TEST_ID = $(subst .,_,${VERSION})
PG_CONTAINER_NAME = PG__${TEST_ID}
NETWORK = ${PACKAGE}__${TEST_ID}
PG_IMAGE = postgres:12.6
WORKFLOW_DB_SCHEMA_IMAGE = 475275892927.dkr.ecr.us-east-1.amazonaws.com/delphi/workflowdb-schema:qa
ETL_DB_SCHEMA_IMAGE = 475275892927.dkr.ecr.us-east-1.amazonaws.com/delphi/pd-etldb-schema:0.8.6

.DEFAULT_GOAL := help

## -
## Local commands:

##   venv - create local virtual env (base.pip dependencies)
$(VENV_NAME)/bin/activate:
	python3.10 -m venv $(VENV_NAME)

$(VENV_NAME): $(VENV_NAME)/bin/activate setup.py
	@echo "Creating virtual environment"
	@cp pip.conf $(VENV_NAME)/
	$(PIP) install -U pip
	$(PIP) install -e .

##   testenv - create local virtual env (test.pip dependencies)
.PHONY:testenv
testenv: $(VENV_NAME)
	@echo "Installing test requirements"
	$(PIP) install -r requirements/test.pip

##   devenv - create local virtual env (dev.pip dependencies)
.PHONY:devenv
devenv: $(VENV_NAME)
	@echo "Installing dev requirements"
	$(PIP) install -r requirements/dev.pip

##   test - run tests
.PHONY:test
test: testenv
	@echo "Running tests"
	$(PYTEST) --junitxml=./junitreport.xml --cov=$(APP) -m ${TEST_MARKS} ./tests

##   lint - run pylint check
.PHONY:lint
lint: testenv
	@echo "Running linter"
	$(PYLINT) $(APP)
	$(PYLINT) tests

##   typecheck - run mypy check
.PHONY:typecheck
typecheck: testenv
	@echo "Running typecheck"
	$(MYPY) $(APP)

##   build - build package
.PHONY:build
build: clean $(VENV_NAME)
	@echo "Building python package"
	@cp pip.conf ./$(VENV_NAME)/ && \
	$(PIP) install -U pip setuptools wheel && \
	$(PYTHON) setup.py bdist_wheel

##   upload - upload package on PyPI
.PHONY:upload
upload: build
	@echo "Uploading python package to PyPI"
	@cp pip.conf ./$(VENV_NAME)/ && \
	$(PIP) install -U pip twine==4.0.2 urllib3==1.26.15 && \
	$(TWINE) upload -r pypi --config-file .pypirc ./dist/*

##   deps - build wheels of dependencies and upload to PyPI
.PHONY: deps
deps: clean
	@echo "Building python dependencies"
	python3 -m venv $(BUILD_VENV_NAME)
	@cp pip.conf $(BUILD_VENV_NAME)
	$(BUILD_VENV_NAME)/bin/pip install -U pip wheel setuptools twine==4.0.2 urllib3==1.26.15 && \
	GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS=8 \
		$(BUILD_VENV_NAME)/bin/pip wheel -r requirements/base.pip -w $(WHEELHOUSE) && \
	$(BUILD_VENV_NAME)/bin/pip wheel -r requirements/test.pip -w $(WHEELHOUSE)
	@echo "Uploading wheels"
	$(BUILD_VENV_NAME)/bin/twine upload -r pypi --config-file .pypirc $(WHEELHOUSE)/*
	@rm -rf $(BUILD_VENV_NAME)

##   clean - delete unnecessary files
.PHONY: clean
clean:
	@echo "Deleting unnecessary files"
	@rm -rf build/
	@rm -rf dist/
	@rm -rf *.egg-info
	@rm -f $(PACKAGE)-*.tar.gz
	@rm -rf .*_cache
	@rm -rf __pycache__/
	@rm -rf ./$(DOCKER_VENV_NAME)/

## -
## Docker commands:

##   docker/login - login to AWS docker, aws configuration need to be set first
.PHONY: docker/login
docker/login:
	@echo "Docker login"
	$$(aws ecr get-login --no-include-email --region us-east-1)

##   docker/pg/start - start test pg instance
.PHONY: docker/pg/start
docker/pg/start:
	docker network create ${NETWORK}
	docker run -d \
		--network ${NETWORK} \
		-e POSTGRES_USER=admin \
		-e POSTGRES_PASSWORD=admin \
		-e POSTGRES_DB=workflowdb \
		-p 5544:5432 \
		--name=${PG_CONTAINER_NAME} ${PG_IMAGE}
	docker exec ${PG_CONTAINER_NAME} sh -c 'until pg_isready -U postgres; do sleep 1; done; sleep 1; createdb -U admin etldb'
	docker run --rm --network ${NETWORK} \
		-e CREATE_USERS=1 \
		-e LIQUIBASE_URL=jdbc:postgresql://${PG_CONTAINER_NAME}:5432/workflowdb \
		-e LIQUIBASE_USERNAME=admin \
		-e LIQUIBASE_PASSWORD=admin \
		-e LIQUIBASE_CHANGELOG=/liquibase/db.changelog-master.xml \
		${WORKFLOW_DB_SCHEMA_IMAGE} update
	docker run --rm --network ${NETWORK} \
		-e CREATE_USERS=1 \
		-e LIQUIBASE_URL=jdbc:postgresql://${PG_CONTAINER_NAME}:5432/etldb \
		-e LIQUIBASE_USERNAME=admin \
		-e LIQUIBASE_PASSWORD=admin \
		-e LIQUIBASE_CHANGELOG=/liquibase/db.changelog-master.xml \
		${ETL_DB_SCHEMA_IMAGE} update

##   docker/pg/stop - shutdown test pg instance
.PHONY: docker/pg/stop
docker/pg/stop:
	-docker kill ${PG_CONTAINER_NAME}
	-docker rm ${PG_CONTAINER_NAME}
	-docker network rm ${NETWORK}

##   docker/test - run integration tests
.PHONY: docker/test
docker/test: docker/pg/stop
	$(MAKE) docker/pg/start
	docker run --rm \
		-v /app/$(DOCKER_VENV_NAME) \
		-v $(PWD)/:/$(APP)/ \
		-w /$(APP)/ \
		-e PG_HOST=${PG_CONTAINER_NAME} \
		-e PG_PORT=5432 \
		-e PG_USER=admin \
		-e PG_PASSWORD=admin \
		-e PG_WORKFLOW_DB=workflowdb \
		-e PG_ETL_DB=etldb \
		-e STAGE=$(STAGE) \
		--network=${NETWORK} \
		${TEST_IMAGE} make VENV_NAME=$(DOCKER_VENV_NAME) TEST_MARKS="integration" test
	$(MAKE) docker/pg/stop

##   docker/test/image - pull image used for tests execution
.PHONY: docker/test/image
docker/test/image: docker/login
	@echo "Pulling image for running tests"
	docker pull ${TEST_IMAGE}

##   docker/<local target> - universal docker wrapper for local targets
docker/%: docker/login
	-docker network create ${NETWORK}
	docker run --rm \
		-v $(PWD)/:/$(APP)/ \
		-w /$(APP)/ \
		-e STAGE=$(STAGE) \
		--network=${NETWORK} \
		${TEST_IMAGE} make VENV_NAME=$(DOCKER_VENV_NAME) PIP_ARGS=$(DOCKER_PIP_ARGS) $*
	-docker network rm ${NETWORK}


## -
## help - this message
.PHONY: help
help: Makefile
	@echo "Application: ${APP}\n"
	@echo "Run command:\n  make <target>\n"
	@grep -E -h '^## .*' $(MAKEFILE_LIST) | sed -n 's/^##//p'  | column -t -s '-' |  sed -e 's/^/ /'
