PNAME := {{name}}
PKGNAME := {{python-pkg-name}}
PYTHON_MODULES := $(PKGNAME)
PYTHONPATH := .
VENV := .venv
WHEELHOUSE := wheelhouse
TZ := CST-8
PYTEST := env PYTHONPATH=$(PYTHONPATH) PYTEST=1 $(VENV)/bin/py.test
PYLINT := env PYTHONPATH=$(PYTHONPATH) $(VENV)/bin/pylint --disable=I0011 --msg-template="{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}"
PEP8 := env PYTHONPATH=$(PYTHONPATH) $(VENV)/bin/pycodestyle --repeat --ignore=E202,E501,E402,W503,W504,E122,E129
PYTHON := env PYTHONPATH=$(PYTHONPATH) $(VENV)/bin/python
PIP := $(VENV)/bin/pip
PYPI_MIRROR ?= https://mirrors.aliyun.com/pypi/simple
# required system packages when installing python dependencies
#DEV_PKGS := python3-dev libpq-dev

DEFAULT_PYTHON ?= $(shell ./utils/choose_default_python.sh)
VIRTUALENV := $(wildcard ./utils/virtualenv-*/virtualenv.py)

REQUIREMENTS := requirements.txt
REQUIREMENTS_DEV := requirements-dev.txt

VERSION := $(shell grep '__version__' $(PKGNAME)/__init__.py |cut -d'"' -f 2)
# docker hub user name or private registry URL with username. do not end with /.
DOCKER_IMAGE_PREFIX ?= de02-reg.emacsos.com/sylecn
KUBECTL_CA_PATH ?= /etc/kubernetes/pki/ca.crt

BUILD_DOCKER_IMAGE := $(DOCKER_IMAGE_PREFIX)/python-build-image:1.2.1-stretch

CI_BUILD_GLOBAL_CACHE := $(HOME)/.cache/ci_build/$(GO_PIPELINE_NAME)
wheelhouse_hash_dir := wheelhouse-$(shell sha1sum $(REQUIREMENTS) | cut -d' ' -f1)
venv_hash_dir := venv-$(shell cat $(REQUIREMENTS) $(REQUIREMENTS_DEV) | sha1sum | cut -d' ' -f1)
pip_cache_dir := $(CI_BUILD_GLOBAL_CACHE)/cache
host_venvs_dir := $(CI_BUILD_GLOBAL_CACHE)/venvs
host_wheelhouses_dir := $(CI_BUILD_GLOBAL_CACHE)/wheelhouses

default: check-coding-style
dist: bootstrap
	rm -rf dist/*
	$(PYTHON) setup.py -q sdist
	$(PYTHON) setup.py -q bdist_wheel --universal
upload: dist
	test -e $(VENV)/bin/twine || $(PIP) install -q -i $(PYPI_MIRROR) twine
	$(VENV)/bin/twine check dist/*.whl
	$(VENV)/bin/twine check dist/*.tar.gz
	@if ! [ -n "$(TWINE_USERNAME)" -o -e ~/.pypirc ]; then \
		echo "You may want to save pypi user/password in env var or ~/.pypirc file."; \
	fi
	$(VENV)/bin/twine upload dist/*
build:

version:
	@echo $(VERSION)
debug:
	env DEBUG=1 $(PYTHON) $(PKGNAME)/main.py
run:
	$(PYTHON) $(PKGNAME)/main.py
uwsgi:
	$(VENV)/bin/uwsgi --processes=2 --threads=4 --wsgi-file=$(PKGNAME)/main.py --env=PYTHONPATH=. --http=localhost:8082 --disable-logging
shell:
	$(PYTHON) -i

$(VENV)/runtime-venv-ready: $(REQUIREMENTS)
	test -d "$(VENV)/bin" || $(DEFAULT_PYTHON) $(VIRTUALENV) --no-download -q "$(VENV)"
	@if [ -e "$(WHEELHOUSE)/ready" ]; then \
		$(PIP) install -q --isolated --no-index --find-links="$(WHEELHOUSE)" -r $(REQUIREMENTS); \
	else \
		$(PIP) install -q -i $(PYPI_MIRROR) -r $(REQUIREMENTS); \
	fi
	touch "$(VENV)/runtime-venv-ready"
$(VENV)/dev-venv-ready: $(VENV)/runtime-venv-ready $(REQUIREMENTS_DEV)
	./utils/ensure_pkg_installed $(DEV_PKGS)
	$(PIP) install -q -i $(PYPI_MIRROR) -r $(REQUIREMENTS_DEV)
	touch "$(VENV)/dev-venv-ready"
logdir:
	@if [ ! -d /var/log/$(PNAME) ]; then \
		sudo mkdir /var/log/$(PNAME); \
		sudo chown -R ${USER} /var/log/$(PNAME); \
	fi
bootstrap: $(VENV)/runtime-venv-ready
bootstrap-dev: $(VENV)/dev-venv-ready
install: bootstrap
	$(PIP) install -q --no-index .
uninstall: bootstrap
	$(PIP) uninstall -q -y $(PKGNAME)
deb:
	utils/build-deb
docker: deb
	docker build -t $(DOCKER_IMAGE_PREFIX)/$(PNAME):$(VERSION) .
	@echo "You may push it with: docker push $(DOCKER_IMAGE_PREFIX)/$(PNAME):$(VERSION)"
pipfreeze:
	$(PIP) freeze
wheel: $(REQUIREMENTS)
	if [ ! -f "$(WHEELHOUSE)/ready" ]; then \
		test -d "$(VENV)/bin" || $(DEFAULT_PYTHON) $(VIRTUALENV) --no-download -q "$(VENV)" && \
		echo "building wheelhouse in dir $(WHEELHOUSE)..." && \
		$(PIP) install wheel && \
		$(PIP) wheel -w $(WHEELHOUSE) -i $(PYPI_MIRROR) -r $(REQUIREMENTS) && \
		touch "$(WHEELHOUSE)/ready"; \
	fi
check: just-test
sanity-check: bootstrap
	$(PYTHON) $(PKGNAME)/sanity_check.py
check-coding-style: bootstrap-dev
	$(PEP8) $(PYTHON_MODULES)
	$(PYLINT) -E $(PYTHON_MODULES)
	$(PYTHON) $(PKGNAME)/config.py
pylint-full: check-coding-style
	$(PYLINT) $(PYTHON_MODULES)
test: check-coding-style
	$(PYTEST) $(PYTHON_MODULES)
just-test:
	$(PYTEST) $(PYTHON_MODULES)

# run test, build deb in python build image container, then create docker
# image and push image on host.
ci-build:
	echo '$(value DOCKER_PASSWORD)' | docker login -u '$(DOCKER_USER)' --password-stdin '$(BUILD_DOCKER_IMAGE)'
	mkdir -p $(pip_cache_dir) \
		$(host_venvs_dir)/$(venv_hash_dir) \
		$(host_wheelhouses_dir)/$(wheelhouse_hash_dir)
	docker run --rm --name $(PNAME)-test \
		-v "$(CURDIR)":/app \
		-v "$(pip_cache_dir)":/.cache \
		-v "$(host_venvs_dir)/$(venv_hash_dir)":/app/$(VENV) \
		-v "$(host_wheelhouses_dir)/$(wheelhouse_hash_dir)":/app/$(WHEELHOUSE) \
		-u $(shell id -u):$(shell id -g) \
		-e TZ=$(TZ) \
		$(BUILD_DOCKER_IMAGE) \
		make test deb -C /app
	docker build -t $(DOCKER_IMAGE_PREFIX)/$(PNAME):$(VERSION) .
	docker push $(DOCKER_IMAGE_PREFIX)/$(PNAME):$(VERSION)
	@echo "removing obsolete .venv-<hash> and wheelhouse-<hash> dirs..."
	find $(CI_BUILD_GLOBAL_CACHE) -maxdepth 2 -type d \
		\( \( -name "venv-*" -a ! -name "$(venv_hash_dir)" \) -o \
		   \( -name "wheelhouse-*" -a ! -name "$(wheelhouse_hash_dir)" \) \) \
		-mtime +180 -execdir rm -rf {} \;
deploy:
	sed "s/IMAGE_TAG/$(VERSION)/" app.yaml > $(VERSION).yaml
	kubectl --certificate-authority='$(KUBECTL_CA_PATH)' -s '$(KUBECTL_API)' --token='$(KUBECTL_TOKEN)' apply -f $(VERSION).yaml

test-prod: bootstrap-dev test

clean:
	find . -name "__pycache__" -type d -exec rm -rf {} \; || true
	find . -name "*.pyc" -type f -exec rm -rf {} \; || true
full-clean:
	rm -rf "$(VENV)" build/ dist/ "$(WHEELHOUSE)" $(PKGNAME).egg-info/ distribute-*.tar.gz
	find . -name "__pycache__" -type d -exec rm -rf {} \; || true
	find . -name "*.pyc" -type f -exec rm -rf {} \; || true
todo:
	@rgrep -I -n --exclude=Makefile --exclude=TAGS --exclude-dir=$(VENV) -E '(TODO|FIXME|XXX|not_implemented)' $(PYTHON_MODULES)
TAGS:
	etags -R --exclude=static $(PYTHON_MODULES)
update-git-hooks: install-git-hooks-force
install-git-hooks:
	./utils/install-git-hooks
install-git-hooks-force:
	./utils/install-git-hooks -f
loc:
	find . -regex '.*\.pyw?$$' -exec wc -l {} \+ | tail -n 1
	which cloc >/dev/null && cloc $(PYTHON_MODULES)
.PHONY: default build debug run uwsgi shell bootstrap bootstrap-dev install uninstall deb pipfreeze wheel check check-coding-style pylint-full test just-test test-prod clean full-clean todo TAGS update-git-hooks install-git-hooks install-git-hooks-force loc
