import files
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
##
|
||||
# APP
|
||||
|
||||
.PHONY: start-up
|
||||
start-up:
|
||||
@@ -0,0 +1,3 @@
|
||||
BUILD_APP_VARS ?= APP BRANCH COMMIT DEPLOY_SLACK_HOOK ENV VERSION
|
||||
COMPOSE_IGNORE_ORPHANS ?= false
|
||||
ENV_VARS += CONSUL_HTTP_TOKEN
|
||||
@@ -0,0 +1,46 @@
|
||||
##
|
||||
# BUILD
|
||||
|
||||
# target build: Build application docker images on local host
|
||||
.PHONY: build
|
||||
build: docker-compose-build ## Build application docker images
|
||||
|
||||
# target build@%: Build application docker images to deploy
|
||||
.PHONY: build@% app-build
|
||||
build@%: infra-base
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(eval docker_images += $(foreach service,$(SERVICES),$(if $(shell docker images -q $(DOCKER_REPOSITORY)/$(service):$(DOCKER_IMAGE_TAG) 2>/dev/null),$(service))))
|
||||
$(eval build_app := $(or $(filter $(DOCKER_BUILD_CACHE),false),$(filter-out $(docker_images),$(SERVICES))))
|
||||
$(if $(build_app),$(call make,app-build),$(if $(filter $(VERBOSE),true),$(foreach service,$(SERVICES),echo "docker image $(DOCKER_REPOSITORY)/$(service):$(DOCKER_IMAGE_TAG) has id $(shell docker images -q $(DOCKER_REPOSITORY)/$(service):$(DOCKER_IMAGE_TAG) 2>/dev/null)" &&) true))
|
||||
|
||||
# target build-env: Build .env file in docker $(SERVICE) to deploy
|
||||
.PHONY: build-env
|
||||
build-env: SERVICE ?= $(DOCKER_SERVICE)
|
||||
build-env: bootstrap
|
||||
$(call docker-compose-exec,$(SERVICE),rm -f .env && make .env ENV=$(ENV) && echo BUILD=true >> .env && echo BUILD_DATE='"\'"'$(shell date "+%d/%m/%Y %H:%M:%S %z" 2>/dev/null)'"\'"' >> .env && echo BUILD_STATUS='"\'"'$(shell git status -uno --porcelain 2>/dev/null)'"\'"' >> .env && echo DOCKER=false >> .env && $(foreach var,$(BUILD_APP_VARS),$(if $($(var)),sed -i '/^$(var)=/d' .env && echo $(var)='$($(var))' >> .env &&)) true)
|
||||
|
||||
# target build-rm: Empty build directory
|
||||
.PHONY: build-rm
|
||||
build-rm:
|
||||
$(call exec,rm -rf build && mkdir -p build)
|
||||
|
||||
# target build-$(SHARED): Create shared folder in docker $(SERVICE) to deploy
|
||||
.PHONY: build-$(SHARED)
|
||||
build-$(SHARED): SERVICE ?= $(DOCKER_SERVICE)
|
||||
build-$(SHARED): bootstrap
|
||||
$(call docker-compose-exec,$(SERVICE),mkdir -p /$(SHARED) && $(foreach folder,$(SHARED_FOLDERS),rm -rf $(folder) && mkdir -p $(dir $(folder)) && ln -s /$(SHARED)/$(notdir $(folder)) $(folder) &&) true)
|
||||
|
||||
# target rebuild: Rebuild application docker images on local host
|
||||
.PHONY: rebuild
|
||||
rebuild: docker-compose-rebuild ## Rebuild application dockers images
|
||||
|
||||
# target rebuild@%: Rebuild application docker images on local host
|
||||
.PHONY: rebuild@%
|
||||
rebuild@%: ## Rebuild application dockers images
|
||||
$(call make,build@$* DOCKER_BUILD_CACHE=false)
|
||||
|
||||
# target rebuild-images: Rebuild docker/* images
|
||||
.PHONY: rebuild-images
|
||||
rebuild-images: docker-rebuild-images ## Rebuild docker/* images
|
||||
@@ -0,0 +1,14 @@
|
||||
##
|
||||
# CLEAN
|
||||
|
||||
.PHONY: clean app-clean
|
||||
clean: app-clean docker-compose-down clean-env ## Clean application and docker images
|
||||
|
||||
# target clean@%: Clean deployed application and docker images
|
||||
.PHONY: clean@%
|
||||
clean@%:
|
||||
$(call make,docker-compose-down DOCKER_COMPOSE_DOWN_OPTIONS='--rmi all -v')
|
||||
|
||||
.PHONY: clean-env
|
||||
clean-env:
|
||||
rm -i .env || true
|
||||
@@ -0,0 +1,124 @@
|
||||
##
|
||||
# COMMON
|
||||
|
||||
.PHONY: bootstrap
|
||||
bootstrap: bootstrap-git bootstrap-docker ## Bootstrap application
|
||||
|
||||
.PHONY: boostrap-docker
|
||||
bootstrap-docker: docker-network-create
|
||||
$(if $(filter bootstrap-$(APP),$(MAKETARGETS)),$(call make,bootstrap-$(APP)))
|
||||
$(call make,docker-compose-up)
|
||||
|
||||
.PHONY: bootstrap-git
|
||||
bootstrap-git:
|
||||
ifneq ($(SUBREPO),)
|
||||
if ! git config remote.subrepo/$(SUBREPO).url > /dev/null ; \
|
||||
then git remote add subrepo/$(SUBREPO) $(GIT_REPOSITORY); \
|
||||
fi
|
||||
endif
|
||||
|
||||
.PHONY: config
|
||||
config: docker-compose-config ## View docker compose file
|
||||
|
||||
.PHONY: connect
|
||||
connect: docker-compose-connect ## Connect to docker $(SERVICE)
|
||||
|
||||
.PHONY: connect@%
|
||||
connect@%: SERVICE ?= $(DOCKER_SERVICE)
|
||||
connect@%: ## Connect to docker $(SERVICE) on first remote host
|
||||
$(call make,ssh-connect,../infra,APP SERVICE)
|
||||
|
||||
.PHONY: down
|
||||
down: docker-compose-down ## Remove application dockers
|
||||
|
||||
.PHONY: exec
|
||||
exec: ## Exec a command in docker $(SERVICE)
|
||||
ifneq (,$(filter $(ENV),$(ENV_DEPLOY)))
|
||||
$(call exec,$(ARGS))
|
||||
else
|
||||
$(call make,docker-compose-exec,,ARGS)
|
||||
endif
|
||||
|
||||
.PHONY: exec@%
|
||||
exec@%: SERVICE ?= $(DOCKER_SERVICE)
|
||||
exec@%: ## Exec a command in docker $(SERVICE) on all remote hosts
|
||||
$(call make,ssh-exec,../infra,APP ARGS SERVICE)
|
||||
|
||||
.PHONY: logs
|
||||
logs: docker-compose-logs ## Display application dockers logs
|
||||
|
||||
.PHONY: ps
|
||||
ps: docker-compose-ps ## List application dockers
|
||||
|
||||
.PHONY: recreate
|
||||
recreate: docker-compose-recreate start-up ## Recreate application dockers
|
||||
|
||||
.PHONY: reinstall
|
||||
reinstall: clean ## Reinstall application
|
||||
$(call make,.env)
|
||||
$(call make,install)
|
||||
|
||||
.PHONY: restart
|
||||
restart: docker-compose-restart start-up ## Restart application
|
||||
|
||||
.PHONY: run
|
||||
run: ## Run a command in a new docker
|
||||
ifneq (,$(filter $(ENV),$(ENV_DEPLOY)))
|
||||
$(call run,$(ARGS))
|
||||
else
|
||||
$(call make,docker-compose-run,,ARGS)
|
||||
endif
|
||||
|
||||
.PHONY: run@%
|
||||
run@%: SERVICE ?= $(DOCKER_SERVICE)
|
||||
run@%: ## Run a command on all remote hosts
|
||||
$(call make,ssh-run,../infra,APP ARGS)
|
||||
|
||||
.PHONY: scale
|
||||
scale: docker-compose-scale ## Scale application to NUM dockers
|
||||
|
||||
.PHONY: ssh@%
|
||||
ssh@%: ## Connect to first remote host
|
||||
$(call make,ssh,../infra,APP)
|
||||
|
||||
# target stack: Call docker-stack function with each value of $(STACK)
|
||||
.PHONY: stack
|
||||
stack:
|
||||
$(foreach stackz,$(STACK),$(call docker-stack,$(stackz)))
|
||||
|
||||
# target stack-%: Call docker-compose-* command on a given stack
|
||||
## ex: calling stack-base-up will fire the docker-compose-up target on the base stack
|
||||
## it splits $* on dashes and extracts stack from the beginning of $* and command
|
||||
## from the last part of $*
|
||||
.PHONY: stack-%
|
||||
stack-%:
|
||||
$(eval stack := $(subst -$(lastword $(subst -, ,$*)),,$*))
|
||||
$(eval command := $(lastword $(subst -, ,$*)))
|
||||
$(if $(findstring -,$*), \
|
||||
$(if $(filter $(command),$(filter-out %-%,$(patsubst docker-compose-%,%,$(filter docker-compose-%,$(MAKETARGETS))))), \
|
||||
$(call make,docker-compose-$(command) STACK="$(stack)" $(if $(filter node,$(stack)),COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT_NAME_INFRA_NODE)),,ARGS COMPOSE_IGNORE_ORPHANS SERVICE)))
|
||||
|
||||
.PHONY: start
|
||||
start: docker-compose-start ## Start application dockers
|
||||
|
||||
.PHONY: stop
|
||||
stop: docker-compose-stop ## Stop application dockers
|
||||
|
||||
.PHONY: tests app-tests
|
||||
tests: app-tests ## Test application
|
||||
|
||||
.PHONY: up
|
||||
up: docker-compose-up start-up ## Create application dockers
|
||||
|
||||
.PHONY: update app-update
|
||||
update: app-update ## Update application
|
||||
|
||||
# target %: Always fired target
|
||||
## this target is fired everytime make is runned to call the stack target and
|
||||
## update COMPOSE_FILE variable with all .yml files of the current project stack
|
||||
.PHONY: FORCE
|
||||
%: FORCE stack %-rule-exists ;
|
||||
|
||||
# target %-rule-exists: Print a warning message if $* target does not exists
|
||||
%-rule-exists:
|
||||
$(if $(filter $*,$(MAKECMDGOALS)),$(if $(filter-out $*,$(MAKETARGETS)),printf "${COLOR_BROWN}WARNING${COLOR_RESET}: ${COLOR_GREEN}target${COLOR_RESET} $* ${COLOR_GREEN}not available in app${COLOR_RESET} $(APP).\n" >&2))
|
||||
@@ -0,0 +1,34 @@
|
||||
CODEDEPLOY_APP_NAME ?= $(APP)
|
||||
CODEDEPLOY_DEPLOYMENT_GROUP ?= $(CODEDEPLOY_APP_NAME)_$(ENV)
|
||||
CODEDEPLOY_DEPLOYMENT_CONFIG ?= CodeDeployDefault.AllAtOnce
|
||||
CODEDEPLOY_DESCRIPTION ?= deploy $(ENV) $(APP) branch: $(BRANCH) commit: $(SUBREPO_COMMIT) tag: $(TAG) version: $(VERSION)
|
||||
CODEDEPLOY_GITHUB_REPO ?= $(patsubst ssh://git@github.com/%,%,$(GIT_REPOSITORY))
|
||||
CODEDEPLOY_GITHUB_COMMIT_ID ?= $(SUBREPO_COMMIT)
|
||||
DEPLOY ?= false
|
||||
DEPLOY_PING_TEXT ?= app: *$(APP)* branch: *$(BRANCH)* env: *$(ENV)* version: *$(VERSION)* container: *$(CONTAINER)* host: *$(HOST)*
|
||||
DEPLOY_SLACK_HOOK ?= https://hooks.slack.com/services/123456789/123456789/ABCDEFGHIJKLMNOPQRSTUVWX
|
||||
HASH ?= $(shell date +%s)
|
||||
SERVER_NAME ?= $(DOCKER_REGISTRY_USERNAME).$(ENV).$(APP)
|
||||
OXA_SERVER_NAME ?= web
|
||||
|
||||
ifeq ($(APP),marketplace)
|
||||
CODEDEPLOY_APP_NAME := front
|
||||
EC2_SERVER_NAME := front
|
||||
else ifeq ($(APP),medias)
|
||||
CODEDEPLOY_APP_NAME := apimedia
|
||||
EC2_SERVER_NAME := api
|
||||
else ifeq ($(APP),partners)
|
||||
CODEDEPLOY_APP_NAME := api
|
||||
EC2_SERVER_NAME := api
|
||||
else ifeq ($(APP),workers)
|
||||
CODEDEPLOY_APP_NAME := worker
|
||||
EC2_SERVER_NAME := worker
|
||||
endif
|
||||
ifeq ($(ENV), preprod)
|
||||
CODEDEPLOY_APP_NAME := $(CODEDEPLOY_APP_NAME)pp
|
||||
CODEDEPLOY_DEPLOYMENT_GROUP := $(CODEDEPLOY_APP_NAME)_preprod
|
||||
OXA_SERVER_NAME := $(EC2_SERVER_NAME)pp-0x
|
||||
else ifeq ($(ENV), prod)
|
||||
CODEDEPLOY_DEPLOYMENT_GROUP := $(CODEDEPLOY_APP_NAME)_prod
|
||||
OXA_SERVER_NAME := $(EC2_SERVER_NAME)-xx
|
||||
endif
|
||||
@@ -0,0 +1,154 @@
|
||||
CMDS += docker-compose-exec docker-run docker-run-%
|
||||
COMPOSE_FILE ?= $(wildcard docker/docker-compose.yml $(foreach file,$(patsubst docker/docker-compose.%,%,$(basename $(wildcard docker/docker-compose.*.yml))),$(if $(filter true,$(COMPOSE_FILE_$(file)) $(COMPOSE_FILE_$(call UPPERCASE,$(file)))),docker/docker-compose.$(file).yml)))
|
||||
COMPOSE_FILE_$(ENV) ?= true
|
||||
COMPOSE_FILE_DEBUG ?= $(DEBUG)
|
||||
COMPOSE_FILE_NFS ?= $(MOUNT_NFS)
|
||||
COMPOSE_FILE_SSH ?= true
|
||||
ifneq ($(SUBREPO),)
|
||||
COMPOSE_FILE_SUBREPO ?= true
|
||||
else
|
||||
COMPOSE_FILE_APP ?= true
|
||||
endif
|
||||
ifneq (,$(filter $(ENV),$(ENV_DEPLOY)))
|
||||
COMPOSE_FILE_TMPFS ?= false
|
||||
else
|
||||
COMPOSE_FILE_TMPFS ?= true
|
||||
endif
|
||||
COMPOSE_PROJECT_NAME ?= $(USER)_$(ENV)_$(APP)
|
||||
COMPOSE_SERVICE_NAME ?= $(subst _,-,$(COMPOSE_PROJECT_NAME))
|
||||
CONTEXT += COMPOSE_FILE COMPOSE_PROJECT_NAME DOCKER_IMAGE_TAG DOCKER_REPOSITORY DOCKER_SERVICE
|
||||
DOCKER_BUILD_ARGS ?= $(if $(filter $(DOCKER_BUILD_NO_CACHE),true),--pull --no-cache) $(foreach var,$(DOCKER_BUILD_VARS),$(if $($(var)),--build-arg $(var)='$($(var))'))
|
||||
DOCKER_BUILD_CACHE ?= true
|
||||
DOCKER_BUILD_NO_CACHE ?= false
|
||||
DOCKER_BUILD_TARGET ?= $(if $(filter $(ENV),$(DOCKER_BUILD_TARGETS)),$(ENV),$(DOCKER_BUILD_TARGET_DEFAULT))
|
||||
DOCKER_BUILD_TARGET_DEFAULT ?= local
|
||||
DOCKER_BUILD_TARGETS ?= local debug tests preprod prod
|
||||
DOCKER_BUILD_VARS ?= APP BRANCH DOCKER_GID DOCKER_REPOSITORY GID GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME TARGET UID USER VERSION
|
||||
DOCKER_COMPOSE_DOWN_OPTIONS ?=
|
||||
DOCKER_COMPOSE_UP_OPTIONS ?= -d
|
||||
DOCKER_GID ?= $(call getent-group,docker)
|
||||
DOCKER_IMAGE_TAG ?= $(if $(filter-out $(APP),infra),$(if $(filter $(ENV),$(ENV_DEPLOY)),$(VERSION),$(if $(DRONE_BUILD_NUMBER),$(DRONE_BUILD_NUMBER),latest)),latest)
|
||||
DOCKER_IMAGES ?= $(patsubst %/,%,$(patsubst docker/%,%,$(dir $(wildcard docker/*/Dockerfile))))
|
||||
DOCKER_PLUGIN ?= rexray/s3fs:latest
|
||||
DOCKER_PLUGIN_ARGS ?= $(foreach var,$(DOCKER_PLUGIN_VARS),$(if $(DOCKER_PLUGIN_$(var)),$(var)='$(DOCKER_PLUGIN_$(var))'))
|
||||
DOCKER_PLUGIN_OPTIONS ?= --grant-all-permissions
|
||||
DOCKER_PLUGIN_S3FS_ACCESSKEY ?= $(shell $(call conf,$(HOME)/.aws/credentials,$(or $(AWS_PROFILE),default),aws_access_key_id))
|
||||
DOCKER_PLUGIN_S3FS_OPTIONS ?= allow_other,nonempty,use_path_request_style,url=https://s3-eu-west-1.amazonaws.com
|
||||
DOCKER_PLUGIN_S3FS_SECRETKEY ?= $(shell $(call conf,$(HOME)/.aws/credentials,$(or $(AWS_PROFILE),default),aws_secret_access_key))
|
||||
DOCKER_PLUGIN_S3FS_REGION ?= eu-west-1
|
||||
DOCKER_PLUGIN_VARS ?= S3FS_ACCESSKEY S3FS_OPTIONS S3FS_SECRETKEY S3FS_REGION
|
||||
DOCKER_REGISTRY ?= registry
|
||||
DOCKER_REGISTRY_USERNAME ?= $(USER)
|
||||
DOCKER_REGISTRY_REPOSITORY ?= $(addsuffix /,$(DOCKER_REGISTRY))$(subst $(USER),$(DOCKER_REGISTRY_USERNAME),$(DOCKER_REPOSITORY))
|
||||
DOCKER_REPOSITORY ?= $(subst _,/,$(COMPOSE_PROJECT_NAME))
|
||||
DOCKER_SHELL ?= $(SHELL)
|
||||
ENV_VARS += COMPOSE_PROJECT_NAME COMPOSE_SERVICE_NAME DOCKER_BUILD_TARGET DOCKER_GID DOCKER_HOST_IFACE DOCKER_HOST_INET DOCKER_IMAGE_TAG DOCKER_REGISTRY DOCKER_REPOSITORY DOCKER_SHELL
|
||||
|
||||
# https://github.com/docker/libnetwork/pull/2348
|
||||
ifeq ($(HOST_SYSTEM), DARWIN)
|
||||
DOCKER_HOST_IFACE ?= $(shell docker run --rm -it --net=host alpine /sbin/ip -4 route list match 0/0 2>/dev/null |awk '{print $$5}' |awk '!seen[$$0]++' |head -1)
|
||||
DOCKER_HOST_INET ?= $(shell docker run --rm -it --net=host alpine /sbin/ip -4 addr show $(DOCKER_HOST_IFACE) 2>/dev/null |awk '$$1 == "inet" {sub(/\/.*/,"",$$2); print $$2}')
|
||||
DOCKER_INTERNAL_DOCKER_GATEWAY ?= $(shell docker run --rm -it alpine getent hosts gateway.docker.internal |awk '{print $$1}' |head -1)
|
||||
DOCKER_INTERNAL_DOCKER_HOST ?= $(shell docker run --rm -it alpine getent hosts host.docker.internal |awk '{print $$1}' |head -1)
|
||||
else
|
||||
DOCKER_HOST_IFACE ?= $(shell /sbin/ip -4 route list match 0/0 2>/dev/null |awk '{print $$5}' |awk '!seen[$$0]++' |head -1)
|
||||
DOCKER_HOST_INET ?= $(shell /sbin/ip -4 addr show $(DOCKER_HOST_IFACE) 2>/dev/null |awk '$$1 == "inet" {sub(/\/.*/,"",$$2); print $$2}')
|
||||
DOCKER_INTERNAL_DOCKER_GATEWAY ?= $(shell /sbin/ip -4 route list match 0/0 2>/dev/null |awk '{print $$3}' |awk '!seen[$$0]++' |head -1)
|
||||
DOCKER_INTERNAL_DOCKER_HOST ?= $(shell /sbin/ip addr show docker0 2>/dev/null |awk '$$1 == "inet" {sub(/\/.*/,"",$$2); print $$2}')
|
||||
endif
|
||||
|
||||
ifeq ($(DRONE), true)
|
||||
DOCKER_COMPOSE_DOWN_OPTIONS := --rmi all -v
|
||||
DOCKER_COMPOSE_UP_OPTIONS := -d --build
|
||||
DOCKER_BUILD_CACHE := false
|
||||
ENV_SUFFIX := $(DRONE_BUILD_NUMBER)
|
||||
ifneq ($(APP), infra)
|
||||
COMPOSE_PROJECT_NAME := $(USER)_$(ENV)$(ENV_SUFFIX)_$(APP)
|
||||
COMPOSE_SERVICE_NAME := $(subst _,-,$(COMPOSE_PROJECT_NAME))
|
||||
DOCKER_REPOSITORY := $(USER)/$(ENV)/$(APP)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(DOCKER), true)
|
||||
|
||||
define docker-compose
|
||||
$(call run,docker/compose:$(COMPOSE_VERSION) $(patsubst %,-f %,$(COMPOSE_FILE)) -p $(COMPOSE_PROJECT_NAME) $(1))
|
||||
endef
|
||||
define docker-compose-exec
|
||||
$(call run,docker/compose:$(COMPOSE_VERSION) $(patsubst %,-f %,$(COMPOSE_FILE)) -p $(COMPOSE_PROJECT_NAME) exec -T $(1) sh -c '$(2)')
|
||||
endef
|
||||
|
||||
else
|
||||
|
||||
SHELL := /bin/bash
|
||||
define docker-compose
|
||||
$(call run,docker-compose $(patsubst %,-f %,$(COMPOSE_FILE)) -p $(COMPOSE_PROJECT_NAME) $(1))
|
||||
endef
|
||||
define docker-compose-exec
|
||||
$(call run,docker-compose $(patsubst %,-f %,$(COMPOSE_FILE)) -p $(COMPOSE_PROJECT_NAME) exec -T $(1) sh -c '$(2)')
|
||||
endef
|
||||
|
||||
endif
|
||||
|
||||
define docker-build
|
||||
$(eval path := $(patsubst %/,%,$(1)))
|
||||
$(eval tag := $(or $(2),$(DOCKER_REPOSITORY)/$(lastword $(subst /, ,$(path))):$(DOCKER_IMAGE_TAG)))
|
||||
$(eval target := $(subst ",,$(subst ',,$(or $(3),$(DOCKER_BUILD_TARGET)))))
|
||||
$(eval image_id := $(shell docker images -q $(tag) 2>/dev/null))
|
||||
$(eval build_image := $(or $(filter $(DOCKER_BUILD_CACHE),false),$(if $(image_id),,true)))
|
||||
$(if $(build_image),$(ECHO) docker build $(DOCKER_BUILD_ARGS) --build-arg DOCKER_BUILD_DIR="$(path)" --tag $(tag) $(if $(target),--target $(target)) -f $(path)/Dockerfile .,$(if $(filter $(VERBOSE),true),echo "docker image $(tag) has id $(image_id)",true))
|
||||
endef
|
||||
define docker-commit
|
||||
$(eval service := $(or $(1),$(DOCKER_SERVICE)))
|
||||
$(eval container := $(or $(2),$(firstword $(shell $(call docker-compose,--log-level critical ps -q $(service))))))
|
||||
$(eval repository := $(or $(3),$(DOCKER_REPOSITORY)/$(service)))
|
||||
$(eval tag := $(or $(4),$(DOCKER_IMAGE_TAG)))
|
||||
$(if $(filter $(VERBOSE),true),echo docker commit $(container) $(repository):$(tag))
|
||||
$(ECHO) docker commit $(container) $(repository):$(tag)
|
||||
endef
|
||||
define docker-push
|
||||
$(eval service := $(or $(1),$(DOCKER_SERVICE)))
|
||||
$(eval name := $(or $(2),$(DOCKER_REGISTRY_REPOSITORY)/$(service)))
|
||||
$(eval tag := $(or $(3),$(DOCKER_IMAGE_TAG)))
|
||||
$(if $(filter $(VERBOSE),true),echo docker push $(name):$(tag))
|
||||
$(ECHO) docker push $(name):$(tag)
|
||||
endef
|
||||
##
|
||||
# docker-stack
|
||||
# docker-stack: if 1st arg is a variable and can be expand to values, it calls
|
||||
# itself again, once whith each value, else calls docker-stack-update function
|
||||
# 1st arg: stacks, extract it from stack_names:stack_versions
|
||||
# 2nd arg: versions, extract it from stack_names:stack_versions or 2nd arg
|
||||
define docker-stack
|
||||
$(eval stacks := $(firstword $(subst :, ,$(1))))
|
||||
$(eval versions := $(or $(if $(findstring :,$(1)),$(lastword $(subst :, ,$(1)))),$(2)))
|
||||
$(if $($(stacks)),$(foreach substack,$($(stacks)),$(call docker-stack,$(substack),$(if $(findstring :,$(1)),$(versions)))),$(call docker-stack-update,$(stacks),$(versions)))
|
||||
endef
|
||||
##
|
||||
# docker-stack-update
|
||||
# docker-stack-update: adds all .yml files of the stack to COMPOSE_FILE variable
|
||||
# and update the .env file with the .env.dist files of the stack
|
||||
# 1st arg: stack_path/stack_name:stack_version
|
||||
# stack: get stack_name:stack_version from 1st arg
|
||||
# name: get stack name from $(stack)
|
||||
# 2nd arg: stack version, or extract it from $(stack), default to latest
|
||||
# 3rd arg: stack path, or extract it from $(stack), default to stack/$(name)
|
||||
# add $(path)/$(name).yml, $(path)/$(name).$(ENV).yml and $(path)/$(name).$(version).yml to COMPOSE_FILE variable
|
||||
# if $(path)/.env.dist file exists, update .env file
|
||||
define docker-stack-update
|
||||
$(eval stack := $(patsubst %.yml,%,$(notdir $(1))))
|
||||
$(eval name := $(firstword $(subst :, ,$(stack))))
|
||||
$(eval version := $(or $(2),$(if $(findstring :,$(stack)),$(lastword $(subst :, ,$(stack))),latest)))
|
||||
$(eval path := $(patsubst %/,%,$(or $(3),$(if $(findstring /,$(1)),$(if $(wildcard stack/$(1) stack/$(1).yml),stack/$(if $(findstring .yml,$(1)),$(dir $(1)),$(if $(wildcard stack/$(1).yml),$(dir $(1)),$(1))),$(dir $(1)))),stack/$(name))))
|
||||
$(eval COMPOSE_FILE += $(wildcard $(path)/$(name).yml $(path)/$(name).$(ENV).yml $(path)/$(name).$(ENV).$(version).yml $(path)/$(name).$(version).yml))
|
||||
$(if $(wildcard $(path)/.env.dist),$(call .env,,$(path)/.env.dist,$(wildcard ../$(PARAMETERS)/$(ENV)/$(APP)/.env $(path)/.env.$(ENV) .env)))
|
||||
endef
|
||||
define docker-tag
|
||||
$(eval service := $(or $(1),$(DOCKER_SERVICE)))
|
||||
$(eval source := $(or $(2),$(DOCKER_REPOSITORY)/$(service)))
|
||||
$(eval source_tag := $(or $(3),$(DOCKER_IMAGE_TAG)))
|
||||
$(eval target := $(or $(4),$(DOCKER_REGISTRY_REPOSITORY)/$(service)))
|
||||
$(eval target_tag := $(or $(5),$(source_tag)))
|
||||
$(if $(filter $(VERBOSE),true),echo docker tag $(source):$(source_tag) $(target):$(target_tag))
|
||||
$(ECHO) docker tag $(source):$(source_tag) $(target):$(target_tag)
|
||||
endef
|
||||
@@ -0,0 +1,7 @@
|
||||
define install-parameters
|
||||
$(eval path:=$(or $(1),$(APP)))
|
||||
$(eval file:=$(or $(2),$(DOCKER_SERVICE)/parameters.yml))
|
||||
$(eval dest:=$(or $(3),app/config))
|
||||
$(eval env:=$(or $(4),$(ENV)))
|
||||
$(if $(wildcard $(dest)/$(file)),,$(if $(wildcard ../$(PARAMETERS)/$(env)/$(path)/$(file)),$(ECHO) cp -a ../$(PARAMETERS)/$(env)/$(path)/$(file) $(dest)))
|
||||
endef
|
||||
@@ -0,0 +1,4 @@
|
||||
ENV_VARS += NFS_CONFIG
|
||||
MOUNT_NFS ?= false
|
||||
NFS_CONFIG ?= addr=$(NFS_HOST),actimeo=3,intr,noacl,noatime,nocto,nodiratime,nolock,soft,rsize=32768,wsize=32768,tcp,rw,vers=3
|
||||
NFS_HOST ?= host.docker.internal
|
||||
@@ -0,0 +1,88 @@
|
||||
##########
|
||||
# DEPLOY #
|
||||
##########
|
||||
|
||||
.PHONY: deploy app-deploy
|
||||
# target deploy: Run post install hooks in the deployed application
|
||||
## Called by ansible after creation of the docker application on remote host
|
||||
deploy: app-deploy ## Run post install hooks in the deployed application
|
||||
|
||||
.PHONY: deploy@%
|
||||
# target deploy@%: Deploy application docker images
|
||||
## tag and push docker images to docker registry
|
||||
## run ansible-pull on hosts to pull docker images from the registry
|
||||
## tag and push docker images as latest to docker registry
|
||||
deploy@%: infra-base build@% ## Deploy application docker images
|
||||
$(call make,docker-login docker-tag docker-push)
|
||||
$(call make,infra-ansible-pull@$(ENV) ANSIBLE_DOCKER_IMAGE_TAG=$(VERSION) ANSIBLE_TAGS=aws,,APP AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY)
|
||||
$(call make,docker-tag-latest docker-push-latest)
|
||||
|
||||
.PHONY: deploy-aws-codedeploy-%
|
||||
deploy-aws-codedeploy-%:
|
||||
$(call exec,git fetch subrepo/$(SUBREPO))
|
||||
ifneq ($(wildcard ../infra),)
|
||||
$(call make,aws-codedeploy,../infra,CODEDEPLOY_APP_NAME CODEDEPLOY_DEPLOYMENT_CONFIG CODEDEPLOY_DEPLOYMENT_GROUP CODEDEPLOY_DESCRIPTION CODEDEPLOY_GITHUB_REPO CODEDEPLOY_GITHUB_COMMIT_ID)
|
||||
endif
|
||||
|
||||
.PHONY: deploy-assets-install
|
||||
deploy-assets-install:
|
||||
su -s /bin/sh www-data -c "php app/console --no-interaction assets:install --env=prod"
|
||||
su -s /bin/sh www-data -c "php app/console --no-interaction assetic:dump --env=prod"
|
||||
|
||||
.PHONY: deploy-cache-clear
|
||||
deploy-cache-clear:
|
||||
su -s /bin/sh www-data -c "php app/console --no-interaction cache:clear --env=prod"
|
||||
|
||||
.PHONY: deploy-cache-warmup
|
||||
deploy-cache-warmup:
|
||||
su -s /bin/sh www-data -c "php app/console --no-interaction cache:warmup --env=prod"
|
||||
|
||||
.PHONY: deploy-composer
|
||||
deploy-composer:
|
||||
su -s /bin/sh www-data -c "composer install --prefer-dist --optimize-autoloader --no-progress --no-interaction --no-dev"
|
||||
|
||||
.PHONY: deploy-doctrine-migrations-migrate
|
||||
deploy-doctrine-migrations-migrate:
|
||||
su -s /bin/sh www-data -c "php app/console --no-interaction doctrine:migrations:migrate"
|
||||
|
||||
.PHONY: deploy-npm
|
||||
deploy-npm: deploy-npm-install deploy-npm-run-build
|
||||
|
||||
.PHONY: deploy-npm-install
|
||||
deploy-npm-install:
|
||||
npm set progress=false
|
||||
npm install -s
|
||||
|
||||
.PHONY: deploy-npm-run-build
|
||||
deploy-npm-run-build:
|
||||
npm run build:prod
|
||||
|
||||
.PHONY: deploy-ping
|
||||
deploy-ping: deploy-ping-slack
|
||||
|
||||
.PHONY: deploy-ping-slack
|
||||
deploy-ping-slack:
|
||||
curl -X POST --data-urlencode 'payload={"text": "$(DEPLOY_PING_TEXT)"}' $(DEPLOY_SLACK_HOOK) ||:
|
||||
|
||||
.PHONY: deploy-supervisorctl-restart-all
|
||||
deploy-supervisorctl-restart-all:
|
||||
supervisorctl restart all
|
||||
|
||||
.PHONY: deploy-supervisorctl-start-all
|
||||
deploy-supervisorctl-start-all:
|
||||
supervisorctl start all
|
||||
|
||||
.PHONY: deploy-supervisorctl-stop-all
|
||||
deploy-supervisorctl-stop-all:
|
||||
supervisorctl stop all
|
||||
|
||||
.PHONY: deploy-yarn
|
||||
deploy-yarn: deploy-yarn-install
|
||||
|
||||
.PHONY: deploy-yarn-build
|
||||
deploy-yarn-build:
|
||||
yarn build:prod
|
||||
|
||||
.PHONY: deploy-yarn-install
|
||||
deploy-yarn-install:
|
||||
yarn install
|
||||
@@ -0,0 +1,211 @@
|
||||
##
|
||||
# DOCKER
|
||||
|
||||
.PHONY: docker-build
|
||||
docker-build: docker-images-infra
|
||||
$(foreach image,$(or $(SERVICE),$(DOCKER_IMAGES)),$(call make,docker-build-$(image)))
|
||||
|
||||
.PHONY: docker-build-%
|
||||
docker-build-%:
|
||||
if grep -q DOCKER_REPOSITORY docker/$*/Dockerfile 2>/dev/null; then $(eval DOCKER_BUILD_ARGS:=$(subst $(DOCKER_REPOSITORY),$(DOCKER_REPOSITORY_INFRA),$(DOCKER_BUILD_ARGS))) true; fi
|
||||
$(if $(wildcard docker/$*/Dockerfile),$(call docker-build,docker/$*))
|
||||
$(if $(findstring :,$*),$(eval DOCKERFILES := $(wildcard docker/$(subst :,/,$*)/Dockerfile)),$(eval DOCKERFILES := $(wildcard docker/$*/*/Dockerfile)))
|
||||
$(foreach dockerfile,$(DOCKERFILES),$(call docker-build,$(dir $(dockerfile)),$(DOCKER_REPOSITORY)/$(word 2,$(subst /, ,$(dir $(dockerfile)))):$(lastword $(subst /, ,$(dir $(dockerfile)))),"") && true)
|
||||
|
||||
.PHONY: docker-commit
|
||||
docker-commit:
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(foreach service,$(or $(SERVICE),$(SERVICES)),$(call docker-commit,$(service)))
|
||||
|
||||
.PHONY: docker-commit-%
|
||||
docker-commit-%:
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(foreach service,$(or $(SERVICE),$(SERVICES)),$(call docker-commit,$(service),,,$*))
|
||||
|
||||
.PHONY: docker-compose-build
|
||||
docker-compose-build: docker-images-infra
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(call docker-compose,build $(if $(filter $(DOCKER_BUILD_NO_CACHE),true),--pull --no-cache) $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
|
||||
|
||||
.PHONY: docker-compose-config
|
||||
docker-compose-config:
|
||||
$(call docker-compose,config)
|
||||
|
||||
.PHONY: docker-compose-connect
|
||||
docker-compose-connect: SERVICE ?= $(DOCKER_SERVICE)
|
||||
docker-compose-connect:
|
||||
$(call docker-compose,exec $(SERVICE) $(DOCKER_SHELL)) || true
|
||||
|
||||
.PHONY: docker-compose-down
|
||||
docker-compose-down:
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(if $(filter $(SERVICE),$(SERVICES)),$(call docker-compose,rm -fs $(SERVICE)),$(call docker-compose,down $(DOCKER_COMPOSE_DOWN_OPTIONS)))
|
||||
|
||||
.PHONY: docker-compose-exec
|
||||
docker-compose-exec: SERVICE ?= $(DOCKER_SERVICE)
|
||||
docker-compose-exec:
|
||||
$(call docker-compose-exec,$(SERVICE),$(ARGS)) || true
|
||||
|
||||
.PHONY: docker-compose-logs
|
||||
docker-compose-logs:
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(call docker-compose,logs -f --tail=100 $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE))) || true
|
||||
|
||||
.PHONY: docker-compose-ps
|
||||
docker-compose-ps:
|
||||
$(call docker-compose,ps)
|
||||
|
||||
.PHONY: docker-compose-rebuild
|
||||
docker-compose-rebuild: docker-images-infra
|
||||
$(call make,docker-compose-build DOCKER_BUILD_NO_CACHE=true)
|
||||
|
||||
.PHONY: docker-compose-recreate
|
||||
docker-compose-recreate: docker-compose-rm docker-compose-up
|
||||
|
||||
.PHONY: docker-compose-restart
|
||||
docker-compose-restart:
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(call docker-compose,restart $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
|
||||
|
||||
.PHONY: docker-compose-rm
|
||||
docker-compose-rm:
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(call docker-compose,rm -fs $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
|
||||
|
||||
.PHONY: docker-compose-run
|
||||
docker-compose-run: SERVICE ?= $(DOCKER_SERVICE)
|
||||
docker-compose-run:
|
||||
$(call docker-compose,run $(SERVICE) $(ARGS))
|
||||
|
||||
.PHONY: docker-compose-scale
|
||||
docker-compose-scale: SERVICE ?= $(DOCKER_SERVICE)
|
||||
docker-compose-scale:
|
||||
$(call docker-compose,up $(DOCKER_COMPOSE_UP_OPTIONS) --scale $(SERVICE)=$(NUM))
|
||||
|
||||
.PHONY: docker-compose-start
|
||||
docker-compose-start:
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(call docker-compose,start $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
|
||||
|
||||
.PHONY: docker-compose-stop
|
||||
docker-compose-stop:
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(call docker-compose,stop $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
|
||||
|
||||
.PHONY: docker-compose-up
|
||||
docker-compose-up: docker-images-infra
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(call docker-compose,up $(DOCKER_COMPOSE_UP_OPTIONS) $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
|
||||
|
||||
.PHONY: docker-images-infra
|
||||
docker-images-infra:
|
||||
$(foreach image,$(subst $(quote),,$(DOCKER_IMAGES_INFRA)),$(call make,infra-docker-build-$(image)))
|
||||
|
||||
.PHONY: docker-login
|
||||
docker-login: infra-aws-ecr-login
|
||||
|
||||
.PHONY: docker-network-create
|
||||
docker-network-create: docker-network-create-$(DOCKER_NETWORK)
|
||||
|
||||
.PHONY: docker-network-create-%
|
||||
docker-network-create-%:
|
||||
[ -n "$(shell docker network ls -q --filter name='^$*$$' 2>/dev/null)" ] \
|
||||
|| { echo -n "Creating docker network $* ... " && $(ECHO) docker network create $* >/dev/null 2>&1 && echo "done" || echo "ERROR"; }
|
||||
|
||||
.PHONY: docker-network-rm
|
||||
docker-network-rm: docker-network-rm-$(DOCKER_NETWORK)
|
||||
|
||||
.PHONY: docker-network-rm-%
|
||||
docker-network-rm-%:
|
||||
[ -z "$(shell docker network ls -q --filter name='^$*$$' 2>/dev/null)" ] \
|
||||
|| { echo -n "Removing docker network $* ... " && $(ECHO) docker network rm $* >/dev/null 2>&1 && echo "done" || echo "ERROR"; }
|
||||
|
||||
.PHONY: docker-plugin-install
|
||||
docker-plugin-install:
|
||||
$(eval docker_plugin_state := $(shell docker plugin ls | awk '$$2 == "$(DOCKER_PLUGIN)" {print $$NF}') )
|
||||
$(if $(docker_plugin_state),$(if $(filter $(docker_plugin_state),false),echo -n "Enabling docker plugin $(DOCKER_PLUGIN) ... " && $(ECHO) docker plugin enable $(DOCKER_PLUGIN) >/dev/null 2>&1 && echo "done" || echo "ERROR"),echo -n "Installing docker plugin $(DOCKER_PLUGIN) ... " && $(ECHO) docker plugin install $(DOCKER_PLUGIN_OPTIONS) $(DOCKER_PLUGIN) $(DOCKER_PLUGIN_ARGS) >/dev/null 2>&1 && echo "done" || echo "ERROR")
|
||||
|
||||
.PHONY: docker-push
|
||||
docker-push:
|
||||
ifneq ($(filter $(DEPLOY),true),)
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(foreach service,$(or $(SERVICE),$(SERVICES)),$(call docker-push,$(service)))
|
||||
else
|
||||
printf "${COLOR_BROWN}WARNING${COLOR_RESET}: ${COLOR_GREEN}target${COLOR_RESET} $@ ${COLOR_GREEN}not enabled in${COLOR_RESET} $(APP).\n" >&2
|
||||
endif
|
||||
|
||||
.PHONY: docker-push-%
|
||||
docker-push-%:
|
||||
ifneq ($(filter $(DEPLOY),true),)
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(foreach service,$(or $(SERVICE),$(SERVICES)),$(call docker-push,$(service),,$*))
|
||||
else
|
||||
printf "${COLOR_BROWN}WARNING${COLOR_RESET}: ${COLOR_GREEN}target${COLOR_RESET} $@ ${COLOR_GREEN}not enabled in${COLOR_RESET} $(APP).\n" >&2
|
||||
endif
|
||||
|
||||
.PHONY: docker-rebuild
|
||||
docker-rebuild:
|
||||
$(call make,docker-build DOCKER_BUILD_CACHE=false)
|
||||
|
||||
.PHONY: docker-rebuild-%
|
||||
docker-rebuild-%:
|
||||
$(call make,docker-build-$* DOCKER_BUILD_CACHE=false)
|
||||
|
||||
.PHONY: docker-run
|
||||
docker-run: SERVICE ?= $(DOCKER_SERVICE)
|
||||
docker-run:
|
||||
$(call make,docker-run-$(SERVICE),,ARGS)
|
||||
|
||||
.PHONY: docker-run-%
|
||||
docker-run-%: docker-build-%
|
||||
$(eval command := $(ARGS))
|
||||
$(eval path := $(patsubst %/,%,$*))
|
||||
$(eval image := $(DOCKER_REPOSITORY)/$(lastword $(subst /, ,$(path)))$(if $(findstring :,$*),,:$(DOCKER_IMAGE_TAG)))
|
||||
$(eval image_id := $(shell docker images -q $(image) 2>/dev/null))
|
||||
$(call docker-run,$(if $(image_id),$(image),$(path)),$(command))
|
||||
|
||||
.PHONY: docker-tag
|
||||
docker-tag:
|
||||
ifneq ($(filter $(DEPLOY),true),)
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(foreach service,$(or $(SERVICE),$(SERVICES)),$(call docker-tag,$(service)))
|
||||
else
|
||||
printf "${COLOR_BROWN}WARNING${COLOR_RESET}: ${COLOR_GREEN}target${COLOR_RESET} $@ ${COLOR_GREEN}not enabled in${COLOR_RESET} $(APP).\n" >&2
|
||||
endif
|
||||
|
||||
.PHONY: docker-tag-%
|
||||
docker-tag-%:
|
||||
ifneq ($(filter $(DEPLOY),true),)
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval SERVICES ?= $(shell $(call docker-compose,--log-level critical config --services)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(foreach service,$(or $(SERVICE),$(SERVICES)),$(call docker-tag,$(service),,,,$*))
|
||||
else
|
||||
printf "${COLOR_BROWN}WARNING${COLOR_RESET}: ${COLOR_GREEN}target${COLOR_RESET} $@ ${COLOR_GREEN}not enabled in${COLOR_RESET} $(APP).\n" >&2
|
||||
endif
|
||||
@@ -0,0 +1,26 @@
|
||||
.PHONY: ansible
|
||||
ansible: docker-build-ansible
|
||||
ifneq ($(ARGS),)
|
||||
$(call ansible,$(ANSIBLE_ARGS) $(ARGS))
|
||||
else
|
||||
$(call make,ansible-run)
|
||||
endif
|
||||
|
||||
.PHONY: ansible-playbook
|
||||
ansible-playbook:
|
||||
$(call ansible-playbook,$(ANSIBLE_ARGS) $(ARGS))
|
||||
|
||||
.PHONY: ansible-pull
|
||||
ansible-pull:
|
||||
$(call ansible-pull,--url $(ANSIBLE_GIT_REPOSITORY) $(if $(ANSIBLE_GIT_KEY_FILE),--key-file $(ANSIBLE_GIT_KEY_FILE)) $(if $(ANSIBLE_GIT_VERSION),--checkout $(ANSIBLE_GIT_VERSION)) $(if $(ANSIBLE_GIT_DIRECTORY),--directory $(ANSIBLE_GIT_DIRECTORY)) $(if $(ANSIBLE_TAGS),--tags $(ANSIBLE_TAGS)) $(if $(ANSIBLE_EXTRA_VARS),--extra-vars '$(ANSIBLE_EXTRA_VARS)') $(if $(findstring true,$(FORCE)),--force) $(if $(findstring true,$(DRYRUN)),--check) --full $(if $(ANSIBLE_INVENTORY),--inventory $(ANSIBLE_INVENTORY)) $(ANSIBLE_PLAYBOOK))
|
||||
|
||||
.PHONY: ansible-pull@%
|
||||
ansible-pull@%: aws-ec2-get-PrivateIpAddress-$(SERVER_NAME)
|
||||
$(call ssh-exec,$(AWS_INSTANCE_IP),make ansible-pull ANSIBLE_DOCKER_IMAGE_TAG=$(ANSIBLE_DOCKER_IMAGE_TAG) ANSIBLE_TAGS=$(ANSIBLE_TAGS) FORCE=$(FORCE))
|
||||
|
||||
.PHONY: ansible-run
|
||||
ansible-run: base-ssh-add docker-build-ansible ansible-run-localhost
|
||||
|
||||
.PHONY: ansible-run-%
|
||||
ansible-run-%:
|
||||
$(call ansible-playbook,$(if $(ANSIBLE_TAGS),--tags $(ANSIBLE_TAGS)) $(if $(ANSIBLE_EXTRA_VARS),--extra-vars '$(patsubst target=localhost,target=$*,$(ANSIBLE_EXTRA_VARS))') $(if $(findstring true,$(DRYRUN)),--check) $(if $(ANSIBLE_INVENTORY),--inventory $(ANSIBLE_INVENTORY)) $(ANSIBLE_PLAYBOOK))
|
||||
@@ -0,0 +1,170 @@
|
||||
.PHONY: aws
|
||||
aws: docker-build-aws
|
||||
$(call aws,$(ARGS))
|
||||
|
||||
.PHONY: aws-codedeploy
|
||||
aws-codedeploy:
|
||||
$(call aws,deploy create-deployment \
|
||||
--application-name $(CODEDEPLOY_APP_NAME) \
|
||||
--deployment-config-name $(CODEDEPLOY_DEPLOYMENT_CONFIG) \
|
||||
--deployment-group-name $(CODEDEPLOY_DEPLOYMENT_GROUP) \
|
||||
--description "$(CODEDEPLOY_DESCRIPTION)" \
|
||||
--github-location repository=$(CODEDEPLOY_GITHUB_REPO)$(comma)commitId=$(CODEDEPLOY_GITHUB_COMMIT_ID))
|
||||
|
||||
.PHONY: aws-role-create-import-image
|
||||
aws-role-create-import-image: aws-iam-create-role-$(AWS_VM_IMPORT_ROLE_NAME) aws-iam-put-role-policy-$(AWS_VM_IMPORT_ROLE_NAME)
|
||||
|
||||
.PHONY: aws-ecr-login
|
||||
aws-ecr-login:
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval docker_login := $(shell $(call aws,ecr get-login --no-include-email --region $(AWS_DEFAULT_REGION))))
|
||||
$(eval DRYRUN_IGNORE := FALSE)
|
||||
$(ECHO) $(docker_login)
|
||||
|
||||
.PHONY: aws-iam-create-role-%
|
||||
aws-iam-create-role-%: base docker-build-aws
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval json := $(shell $(call exec,envsubst < aws/policies/$*-trust.json)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(call aws,iam create-role --role-name $* --assume-role-policy-document '$(json)')
|
||||
|
||||
.PHONY: aws-iam-put-role-policy-%
|
||||
aws-iam-put-role-policy-%: base docker-build-aws
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval json := $(shell $(call exec,envsubst < aws/policies/$*.json)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(call aws,iam put-role-policy --role-name $* --policy-name $* --policy-document '$(json)')
|
||||
|
||||
.PHONY: aws-s3-check-upload
|
||||
aws-s3-check-upload: docker-build-aws aws-s3api-head-object-query-etag
|
||||
$(eval upload := true)
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(if $(AWS_S3_KEY_ETAG),$(if $(filter $(AWS_S3_KEY_ETAG),"$(shell cat $(PACKER_ISO_INFO) |awk '$$1 == "etag:" {print $$2}' 2>/dev/null)"),$(eval upload := false)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
|
||||
.PHONY: aws-s3-cp
|
||||
aws-s3-cp: docker-build-aws $(PACKER_ISO_FILE) aws-s3-check-upload
|
||||
$(if $(filter $(upload),true),$(call aws,s3 cp $(PACKER_ISO_FILE) s3://$(AWS_S3_BUCKET)/$(AWS_S3_KEY)) $(call make,aws-s3-etag-save))
|
||||
|
||||
.PHONY: aws-s3-etag-save
|
||||
aws-s3-etag-save: docker-build-aws aws-s3api-head-object-query-etag
|
||||
echo "etag: $(AWS_S3_KEY_ETAG)" >> $(PACKER_ISO_INFO)
|
||||
|
||||
.PHONY: aws-s3api-head-object-query-etag
|
||||
aws-s3api-head-object-query-etag: docker-build-aws
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval AWS_S3_KEY_ETAG := $(shell $(call aws,s3api head-object --bucket $(AWS_S3_BUCKET) --key $(AWS_S3_KEY) --output text --query ETag) |grep -v 'operation: Not Found' 2>/dev/null))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
echo ETag: $(AWS_S3_KEY_ETAG)
|
||||
|
||||
.PHONY: aws-s3api-head-object-query-lastmodified
|
||||
aws-s3api-head-object-query-lastmodified: docker-build-aws
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval AWS_S3_KEY_DATE := $(shell $(call aws,s3api head-object --bucket $(AWS_S3_BUCKET) --key $(AWS_S3_KEY) --output text --query LastModified) |grep -v 'operation: Not Found' 2>/dev/null))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
echo LastModified: $(AWS_S3_KEY_DATE)
|
||||
|
||||
.PHONY: aws-ec2-import-snapshot
|
||||
aws-ec2-import-snapshot: base docker-build-aws aws-s3api-head-object-query-etag aws-s3api-head-object-query-lastmodified
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval json := $(shell $(call exec,envsubst < aws/import-snapshot.json)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(eval AWS_TASK_ID := $(shell $(call aws,ec2 import-snapshot --description '$(AWS_SNAP_DESCRIPTION)' --output text --query ImportTaskId --disk-container '$(json)')))
|
||||
echo ImportTaskId: $(AWS_TASK_ID)
|
||||
|
||||
.PHONY: aws-ec2-describe-import-snapshot-task-%
|
||||
aws-ec2-describe-import-snapshot-task-%: docker-build-aws
|
||||
$(call aws,ec2 describe-import-snapshot-tasks --import-task-ids $*)
|
||||
|
||||
.PHONY: aws-ec2-describe-import-snapshot-tasks
|
||||
aws-ec2-describe-import-snapshot-tasks: docker-build-aws
|
||||
$(call aws,ec2 describe-import-snapshot-tasks)
|
||||
|
||||
.PHONY: aws-ec2-describe-instance-PrivateIpAddress
|
||||
aws-ec2-describe-instance-PrivateIpAddress: docker-build-aws
|
||||
$(call aws,ec2 describe-instances --no-paginate --query 'Reservations[*].Instances[*].[Tags[?Key==`Name`].Value$(comma)PrivateIpAddress]' --output text) |sed '$$!N;s/\r\n/ /' |awk 'BEGIN {printf "%-24s%s\r\n"$(comma)"PrivateIpAddress"$(comma)"Name"}; $$1 != "None" {printf "%-24s%s\n"$(comma)$$1$(comma)$$2}'
|
||||
|
||||
.PHONY: aws-ec2-describe-instance-PrivateIpAddress-%
|
||||
aws-ec2-describe-instance-PrivateIpAddress-%: docker-build-aws
|
||||
$(call aws,ec2 describe-instances --no-paginate --query 'Reservations[*].Instances[*].[Tags[?Key==`Name`].Value$(comma)PrivateIpAddress]' --output text) |sed '$$!N;s/\r\n/ /' |awk 'BEGIN {printf "%-24s%s\r\n"$(comma)"PrivateIpAddress"$(comma)"Name"}; $$1 != "None" && $$2 ~ /$*/ {printf "%-24s%s\n"$(comma)$$1$(comma)$$2}'
|
||||
|
||||
.PHONY: aws-ec2-get-PrivateIpAddress
|
||||
aws-ec2-get-PrivateIpAddress: docker-build-aws
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval AWS_INSTANCE_IP := $(shell $(call aws,ec2 describe-instances --no-paginate --query 'Reservations[*].Instances[*].PrivateIpAddress' --output text) 2>/dev/null))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
echo PrivateIpAddress: $(AWS_INSTANCE_IP)
|
||||
|
||||
.PHONY: aws-ec2-get-PrivateIpAddress-%
|
||||
aws-ec2-get-PrivateIpAddress-%:
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval AWS_INSTANCE_IP := $(shell $(call aws,ec2 describe-instances --no-paginate --filter 'Name=tag:Name$(comma)Values=$**' --query 'Reservations[*].Instances[*].PrivateIpAddress' --output text) 2>/dev/null))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
echo PrivateIpAddress: $(AWS_INSTANCE_IP)
|
||||
|
||||
.PHONY: aws-ec2-get-snap-id-import-snapshot-task
|
||||
aws-ec2-get-snap-id-import-snapshot-task: aws-ec2-get-snap-id-import-snapshot-task-$(AWS_TASK_ID)
|
||||
|
||||
.PHONY: aws-ec2-get-snap-id-import-snapshot-task-%
|
||||
aws-ec2-get-snap-id-import-snapshot-task-%: docker-build-aws
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval AWS_SNAP_ID := $(shell $(call aws,ec2 describe-import-snapshot-tasks --import-task-ids $* --output text --query ImportSnapshotTasks[0].SnapshotTaskDetail.SnapshotId) 2>/dev/null))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
echo SnapshotId: $(AWS_SNAP_ID)
|
||||
|
||||
.PHONY: aws-ec2-get-snap-message-import-snapshot-task-%
|
||||
aws-ec2-get-snap-message-import-snapshot-task-%: docker-build-aws
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval AWS_SNAP_MESSAGE := $(shell $(call aws,ec2 describe-import-snapshot-tasks --import-task-ids $* --output text --query ImportSnapshotTasks[0].SnapshotTaskDetail.StatusMessage) 2>/dev/null))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
echo StatusMessage: $(AWS_SNAP_MESSAGE)
|
||||
|
||||
.PHONY: aws-ec2-get-snap-progress-import-snapshot-task-%
|
||||
aws-ec2-get-snap-progress-import-snapshot-task-%: docker-build-aws
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval AWS_SNAP_PROGRESS := $(shell $(call aws,ec2 describe-import-snapshot-tasks --import-task-ids $* --output text --query ImportSnapshotTasks[0].SnapshotTaskDetail.Progress) 2>/dev/null))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
echo Progress: $(AWS_SNAP_PROGRESS)
|
||||
|
||||
.PHONY: aws-ec2-get-snap-size-import-snapshot-task-%
|
||||
aws-ec2-get-snap-size-import-snapshot-task-%: docker-build-aws
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval AWS_SNAP_SIZE := $(shell $(call aws,ec2 describe-import-snapshot-tasks --import-task-ids $* --output text --query ImportSnapshotTasks[0].SnapshotTaskDetail.DiskImageSize) 2>/dev/null))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
echo DiskImageSize: $(AWS_SNAP_SIZE)
|
||||
|
||||
.PHONY: aws-ec2-get-snap-status-import-snapshot-task-%
|
||||
aws-ec2-get-snap-status-import-snapshot-task-%: docker-build-aws
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval AWS_SNAP_STATUS := $(shell $(call aws,ec2 describe-import-snapshot-tasks --import-task-ids $* --output text --query ImportSnapshotTasks[0].SnapshotTaskDetail.Status) 2>/dev/null))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
echo Status: $(AWS_SNAP_STATUS)
|
||||
|
||||
.PHONY: aws-ec2-wait-snap-completed-import-snapshot-task
|
||||
aws-ec2-wait-snap-completed-import-snapshot-task: aws-ec2-wait-snap-completed-import-snapshot-task-$(AWS_TASK_ID)
|
||||
|
||||
.PHONY: aws-ec2-wait-snap-completed-import-snapshot-task-%
|
||||
aws-ec2-wait-snap-completed-import-snapshot-task-%: docker-build-aws
|
||||
while [ `$(call aws,ec2 describe-import-snapshot-tasks --import-task-ids $* --output text --query ImportSnapshotTasks[0].SnapshotTaskDetail.Status)` != "completed$$(printf '\r')" ]; \
|
||||
do \
|
||||
count=$$(( $${count:-0}+1 )); \
|
||||
[ "$${count}" -eq 99 ] && exit 1; \
|
||||
sleep 10; \
|
||||
done
|
||||
|
||||
.PHONY: aws-ec2-wait-snapshot-%
|
||||
aws-ec2-wait-snapshot-%: docker-build-aws
|
||||
$(call aws,ec2 wait snapshot-completed --snapshot-ids $* --output text)
|
||||
|
||||
.PHONY: aws-ec2-register-image
|
||||
aws-ec2-register-image: base docker-build-aws aws-ec2-get-snap-id-import-snapshot-task
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval json := $(shell $(call exec,envsubst < aws/register-image-device-mappings.json)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(eval AWS_AMI_ID := $(shell $(call aws,ec2 register-image --name '$(AWS_AMI_NAME)' --description '$(AWS_AMI_DESCRIPTION)' --architecture x86_64 --root-device-name /dev/sda1 --virtualization-type hvm --block-device-mappings '$(json)') 2>/dev/null))
|
||||
echo ImageId: $(AWS_AMI_ID)
|
||||
|
||||
.PHONY: aws-ami
|
||||
aws-ami: aws-s3-cp aws-ec2-import-snapshot
|
||||
$(call make,aws-ec2-wait-snap-completed-import-snapshot-task,,AWS_TASK_ID)
|
||||
$(call make,aws-ec2-register-image,,AWS_TASK_ID)
|
||||
@@ -0,0 +1,10 @@
|
||||
##
|
||||
# BOOTSTRAP
|
||||
|
||||
.PHONY: bootstrap-infra
|
||||
bootstrap-infra: setup-sysctl
|
||||
ifeq ($(SETUP_NFSD),true)
|
||||
ifeq ($(HOST_SYSTEM),DARWIN)
|
||||
$(call setup-nfsd-osx)
|
||||
endif
|
||||
endif
|
||||
@@ -0,0 +1,18 @@
|
||||
##
|
||||
# CLEAN
|
||||
|
||||
.PHONY: clean-docker-%
|
||||
clean-docker-%:
|
||||
docker ps -a |awk '$$NF ~ /_$*/ && $$NF !~ /_infra_/ {print $$NF}' |while read docker; do docker rm -f $$docker; done
|
||||
|
||||
.PHONY: clean-elasticsearch-%
|
||||
clean-elasticsearch-%:
|
||||
docker ps |awk '$$NF ~ /infra_elasticsearch/' |sed 's/^.*:\([0-9]*\)->9200\/tcp.*$$/\1/' |while read port; do echo -e "DELETE /$* HTTP/1.0\n\n" |nc localhost $$port; done
|
||||
|
||||
.PHONY: clean-images-%
|
||||
clean-images-%:
|
||||
docker images |awk '$$1 ~ /\/$*/ && $$1 !~ /\/infra\// {print $$3}' |sort -u |while read image; do docker rmi -f $$image; done
|
||||
|
||||
.PHONY: clean-volumes-%
|
||||
clean-volumes-%:
|
||||
docker volume ls |awk '$$2 ~ /_$*/ && $$2 !~ /_infra_/ {print $$2}' |sort -u |while read volume; do docker volume rm $$volume; done
|
||||
@@ -0,0 +1,50 @@
|
||||
ANSIBLE_AWS_ACCESS_KEY_ID ?= $(AWS_ACCESS_KEY_ID)
|
||||
ANSIBLE_AWS_DEFAULT_OUTPUT ?= $(AWS_DEFAULT_OUTPUT)
|
||||
ANSIBLE_AWS_DEFAULT_REGION ?= $(AWS_DEFAULT_REGION)
|
||||
ANSIBLE_AWS_SECRET_ACCESS_KEY ?= $(AWS_SECRET_ACCESS_KEY)
|
||||
ANSIBLE_CONFIG ?= ansible/ansible.cfg
|
||||
ANSIBLE_DISKS_NFS_DISK ?= $(NFS_DISK)
|
||||
ANSIBLE_DISKS_NFS_OPTIONS ?= $(NFS_OPTIONS)
|
||||
ANSIBLE_DISKS_NFS_PATH ?= $(NFS_PATH)
|
||||
ANSIBLE_DOCKER_IMAGE_TAG ?= $(DOCKER_IMAGE_TAG)
|
||||
ANSIBLE_DOCKER_REGISTRY ?= $(DOCKER_REGISTRY)
|
||||
ANSIBLE_EXTRA_VARS ?= target=localhost
|
||||
ANSIBLE_GIT_DIRECTORY ?= /src/$(subst git@,,$(subst ssh://,,$(GIT_REPOSITORY)))
|
||||
ANSIBLE_GIT_KEY_FILE ?= ~$(ANSIBLE_USERNAME)/.ssh/$(notdir $(ANSIBLE_SSH_PRIVATE_KEY))
|
||||
ANSIBLE_GIT_REPOSITORY ?= $(GIT_REPOSITORY)
|
||||
ANSIBLE_GIT_VERSION ?= $(BRANCH)
|
||||
ANSIBLE_INVENTORY ?= ansible/inventories
|
||||
ANSIBLE_PLAYBOOK ?= ansible/playbook.yml
|
||||
ANSIBLE_SSH_PRIVATE_KEY ?= ~/.ssh/id_rsa
|
||||
ANSIBLE_SERVER_NAME ?= $(SERVER_NAME)
|
||||
ANSIBLE_USERNAME ?= root
|
||||
ANSIBLE_VERBOSE ?= -v
|
||||
CMDS += ansible ansible-playbook
|
||||
ENV_VARS += ANSIBLE_AWS_ACCESS_KEY_ID ANSIBLE_AWS_DEFAULT_OUTPUT ANSIBLE_AWS_DEFAULT_REGION ANSIBLE_AWS_SECRET_ACCESS_KEY ANSIBLE_CONFIG ANSIBLE_DISKS_NFS_DISK ANSIBLE_DISKS_NFS_OPTIONS ANSIBLE_DISKS_NFS_PATH ANSIBLE_DOCKER_IMAGE_TAG ANSIBLE_DOCKER_REGISTRY ANSIBLE_EXTRA_VARS ANSIBLE_GIT_DIRECTORY ANSIBLE_GIT_KEY_FILE ANSIBLE_GIT_REPOSITORY ANSIBLE_GIT_VERSION ANSIBLE_INVENTORY ANSIBLE_PLAYBOOK ANSIBLE_SSH_PRIVATE_KEY ANSIBLE_USERNAME ANSIBLE_VERBOSE
|
||||
|
||||
ifeq ($(DEBUG), true)
|
||||
ANSIBLE_VERBOSE := -vvvv
|
||||
endif
|
||||
|
||||
ifeq ($(DOCKER), true)
|
||||
define ansible
|
||||
$(call run,$(DOCKER_SSH_AUTH) -v ~/.aws:/home/$(USER)/.aws --add-host=host.docker.internal:$(DOCKER_INTERNAL_DOCKER_HOST) $(DOCKER_REPOSITORY)/ansible:$(DOCKER_IMAGE_TAG) $(ANSIBLE_ARGS) -i $(ANSIBLE_INVENTORY)/.host.docker.internal $(ANSIBLE_VERBOSE) $(1))
|
||||
endef
|
||||
define ansible-playbook
|
||||
$(call run,$(DOCKER_SSH_AUTH) -v ~/.aws:/home/$(USER)/.aws --add-host=host.docker.internal:$(DOCKER_INTERNAL_DOCKER_HOST) --entrypoint=ansible-playbook $(DOCKER_REPOSITORY)/ansible:$(DOCKER_IMAGE_TAG) $(ANSIBLE_ARGS) -i $(ANSIBLE_INVENTORY)/.host.docker.internal $(ANSIBLE_VERBOSE) $(1))
|
||||
endef
|
||||
define ansible-pull
|
||||
# TODO : run ansible in docker and target localhost outside docker
|
||||
IFS=$$'\n'; $(ECHO) env $(foreach var,$(ENV_VARS),$(if $($(var)),$(var)='$($(var))')) $(shell printenv |awk -F '=' 'NR == FNR { if($$1 !~ /^(\#|$$)/) { A[$$1]; next } } ($$1 in A)' .env.dist - 2>/dev/null) $$(cat $(ENV_FILE) 2>/dev/null |awk -F "=" '$$1 ~! /^\(#|$$\)/') ansible-pull $(ANSIBLE_ARGS) $(ANSIBLE_VERBOSE) $(1)
|
||||
endef
|
||||
else
|
||||
define ansible
|
||||
$(call run,ansible $(ANSIBLE_ARGS) $(ANSIBLE_VERBOSE) $(1))
|
||||
endef
|
||||
define ansible-playbook
|
||||
$(call run,ansible-playbook $(ANSIBLE_ARGS) $(ANSIBLE_VERBOSE) $(1))
|
||||
endef
|
||||
define ansible-pull
|
||||
$(call run,ansible-pull $(ANSIBLE_ARGS) $(ANSIBLE_VERBOSE) $(1))
|
||||
endef
|
||||
endif
|
||||
@@ -0,0 +1,23 @@
|
||||
AWS_ACCESS_KEY_ID ?= $(shell $(call conf,$(HOME)/.aws/credentials,$(or $(AWS_PROFILE),default),aws_access_key_id))
|
||||
AWS_AMI_DESCRIPTION ?= app: $(APP) branch: $(BRANCH) env: $(ENV) iso: $(AWS_S3_KEY) user: $(USER) version: $(VERSION)
|
||||
AWS_AMI_NAME ?= $(USER)/$(ENV)/$(APP)/ami/$(VERSION)/$(shell date +%Y%m%dT%H%M%S)
|
||||
AWS_DEFAULT_REGION ?= eu-west-1
|
||||
AWS_DEFAULT_OUTPUT ?= text
|
||||
AWS_INSTANCE_ID ?= $(shell timeout 0.1 curl -s http://169.254.169.254/latest/meta-data/instance-id 2>/dev/null)
|
||||
AWS_VM_IMPORT_ROLE_NAME ?= vmimport
|
||||
AWS_S3_BUCKET ?= $(USER)-$(ENV)-config
|
||||
AWS_S3_KEY ?= $(PACKER_ISO_FILE)
|
||||
AWS_SECRET_ACCESS_KEY ?= $(shell $(call conf,$(HOME)/.aws/credentials,$(or $(AWS_PROFILE),default),aws_secret_access_key))
|
||||
AWS_SNAP_DESCRIPTION ?= iso: $(AWS_S3_KEY) env: $(ENV) app: $(APP) branch: $(BRANCH) version: $(VERSION) user: $(USER) etag: $(AWS_S3_KEY_ETAG) date: $(AWS_S3_KEY_DATE)
|
||||
CMDS += aws
|
||||
ENV_VARS += AWS_ACCESS_KEY_ID AWS_AMI_DESCRIPTION AWS_AMI_NAME AWS_DEFAULT_OUTPUT AWS_DEFAULT_REGION AWS_INSTANCE_ID AWS_PROFILE AWS_S3_BUCKET AWS_S3_KEY AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN AWS_SNAP_DESCRIPTION AWS_SNAP_ID
|
||||
|
||||
ifeq ($(DOCKER), true)
|
||||
define aws
|
||||
$(call run,$(DOCKER_SSH_AUTH) -v $$HOME/.aws:/root/.aws:ro anigeo/awscli:latest $(1))
|
||||
endef
|
||||
else
|
||||
define aws
|
||||
$(call run,aws $(1))
|
||||
endef
|
||||
endif
|
||||
@@ -0,0 +1,36 @@
|
||||
CMDS += openstack ssh-run terraform
|
||||
COMPOSE_IGNORE_ORPHANS ?= true
|
||||
CONTEXT += GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
|
||||
DOCKER_BUILD_VARS += SSH_BASTION_HOSTNAME SSH_BASTION_USERNAME SSH_PUBLIC_HOST_KEYS SSH_PRIVATE_IP_RANGE
|
||||
DOCKER_SERVICE ?= cli
|
||||
ELASTICSEARCH_HOST ?= elasticsearch
|
||||
ELASTICSEARCH_PORT ?= 9200
|
||||
ELASTICSEARCH_PROTOCOL ?= http
|
||||
ENV_VARS += COMPOSE_IGNORE_ORPHANS DOCKER_IMAGE_CLI DOCKER_IMAGE_SSH DOCKER_NAME_CLI DOCKER_NAME_SSH ELASTICSEARCH_HOST ELASTICSEARCH_PASSWORD ELASTICSEARCH_PORT ELASTICSEARCH_PROTOCOL ELASTICSEARCH_USERNAME GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME SETUP_SYSCTL_CONFIG SSH_BASTION_HOSTNAME SSH_BASTION_USERNAME SSH_PUBLIC_HOST_KEYS SSH_PRIVATE_IP_RANGE
|
||||
GIT_AUTHOR_EMAIL ?= $(shell git config user.email 2>/dev/null)
|
||||
GIT_AUTHOR_NAME ?= $(shell git config user.name 2>/dev/null)
|
||||
HOME ?= /home/$(USER)
|
||||
NFS_DISK ?= $(NFS_HOST):/$(SHARED)
|
||||
NFS_OPTIONS ?= rw,rsize=8192,wsize=8192,bg,hard,intr,nfsvers=3,noatime,nodiratime,actimeo=3
|
||||
NFS_PATH ?= /srv/$(subst :,,$(NFS_DISK))
|
||||
SETUP_NFSD ?= false
|
||||
SETUP_NFSD_OSX_CONFIG ?= nfs.server.bonjour=0 nfs.server.mount.regular_files=1 nfs.server.mount.require_resv_port=0 nfs.server.nfsd_threads=16 nfs.server.async=1
|
||||
SETUP_SYSCTL ?= false
|
||||
SETUP_SYSCTL_CONFIG ?= vm.max_map_count=262144 vm.overcommit_memory=1 fs.file-max=8388608 net.core.somaxconn=1024
|
||||
SHELL ?= /bin/sh
|
||||
SSH_BASTION_HOSTNAME ?=
|
||||
SSH_BASTION_USERNAME ?=
|
||||
SSH_PUBLIC_HOST_KEYS ?= $(SSH_REMOTE_HOSTS) $(SSH_BASTION_HOSTNAME)
|
||||
SSH_PRIVATE_IP_RANGE ?= 10.10.*
|
||||
SSH_REMOTE_HOSTS ?= github.com gitlab.com
|
||||
STACK ?= base logs services
|
||||
|
||||
define setup-nfsd-osx
|
||||
$(eval dir:=$(or $(1),$(MONOREPO_DIR)))
|
||||
$(eval uid:=$(or $(2),$(UID)))
|
||||
$(eval gid:=$(or $(3),$(GID)))
|
||||
grep "$(dir)" /etc/exports >/dev/null 2>&1 || echo "$(dir) -alldirs -mapall=$(uid):$(gid) localhost" |sudo tee -a /etc/exports >/dev/null
|
||||
$(foreach config,$(SETUP_NFSD_OSX_CONFIG),grep "$(config)" /etc/nfs.conf >/dev/null 2>&1 || echo "$(config)" |sudo tee -a /etc/nfs.conf >/dev/null &&) true
|
||||
nfsd status >/dev/null || sudo nfsd enable
|
||||
showmount -e localhost |grep "$(dir)" >/dev/null 2>&1 || sudo nfsd restart
|
||||
endef
|
||||
@@ -0,0 +1,17 @@
|
||||
ENV_VARS += OS_AUTH_URL OS_TENANT_ID OS_TENANT_NAME OS_USERNAME OS_PASSWORD OS_REGION_NAME OS_USER_DOMAIN_NAME OS_PROJECT_DOMAIN_NAME
|
||||
ifeq ($(DEBUG), true)
|
||||
OPENSTACK_ARGS += --debug
|
||||
endif
|
||||
ifeq ($(ENV), local)
|
||||
OPENSTACK_ARGS += -v
|
||||
endif
|
||||
|
||||
ifeq ($(DOCKER), true)
|
||||
define openstack
|
||||
$(call run,$(DOCKER_SSH_AUTH) $(DOCKER_REPOSITORY)/openstack:$(DOCKER_IMAGE_TAG) $(1))
|
||||
endef
|
||||
else
|
||||
define openstack
|
||||
$(call run,openstack $(1))
|
||||
endef
|
||||
endif
|
||||
@@ -0,0 +1,6 @@
|
||||
PACKER_ALPINE_ARCH ?= x86_64
|
||||
PACKER_ALPINE_RELEASE ?= 3.12.0
|
||||
PACKER_BUILD_VARS += alpine_arch alpine_release alpine_version
|
||||
alpine_arch ?= $(PACKER_ALPINE_ARCH)
|
||||
alpine_release ?= $(PACKER_ALPINE_RELEASE)
|
||||
alpine_version ?= $(subst $(eval) ,.,$(wordlist 1, 2, $(subst ., ,$(alpine_release))))
|
||||
@@ -0,0 +1,4 @@
|
||||
PACKER_BUILD_VARS += ansible_extra_vars ansible_user ansible_verbose
|
||||
ansible_extra_vars ?= $(patsubst target=%,target=default,$(ANSIBLE_EXTRA_VARS))
|
||||
ansible_user ?= $(ANSIBLE_USERNAME)
|
||||
ansible_verbose ?= $(ANSIBLE_VERBOSE)
|
||||
@@ -0,0 +1,126 @@
|
||||
CMDS += packer
|
||||
ENV_VARS += PACKER_CACHE_DIR PACKER_KEY_INTERVAL PACKER_LOG
|
||||
KVM_GID ?= $(call getent-group,kvm)
|
||||
PACKER_ARCH ?= $(PACKER_ALPINE_ARCH)
|
||||
PACKER_BOOT_WAIT ?= 11s
|
||||
PACKER_BUILD_ARGS ?= -on-error=cleanup $(foreach var,$(PACKER_BUILD_VARS),$(if $($(var)),-var $(var)='$($(var))'))
|
||||
PACKER_BUILD_VARS += accelerator boot_wait hostname iso_name iso_size output password qemuargs ssh_wait_timeout template username
|
||||
PACKER_CACHE_DIR ?= build/cache
|
||||
PACKER_HOSTNAME ?= $(PACKER_TEMPLATE)
|
||||
PACKER_ISO_DATE ?= $(shell stat -c %y $(PACKER_ISO_FILE) 2>/dev/null)
|
||||
PACKER_ISO_FILES ?= $(wildcard build/iso/*/*/*.iso)
|
||||
PACKER_ISO_FILE = $(PACKER_OUTPUT)/$(PACKER_ISO_NAME).iso
|
||||
PACKER_ISO_INFO = $(PACKER_OUTPUT)/$(PACKER_ISO_NAME).nfo
|
||||
PACKER_ISO_NAME = $(PACKER_TEMPLATE)-$(PACKER_RELEASE)-$(PACKER_ARCH)
|
||||
PACKER_ISO_SIZE ?= 1024
|
||||
PACKER_KEY_INTERVAL ?= 10ms
|
||||
PACKER_LOG ?= 1
|
||||
PACKER_OUTPUT ?= build/iso/$(ENV)/$(PACKER_TEMPLATE)/$(PACKER_RELEASE)-$(PACKER_ARCH)
|
||||
PACKER_PASSWORD ?= $(PACKER_TEMPLATE)
|
||||
PACKER_QEMU_ACCELERATOR ?= kvm
|
||||
PACKER_QEMU_ARCH ?= $(PACKER_ARCH)
|
||||
PACKER_QEMU_ARGS ?= -machine type=pc,accel=$(PACKER_QEMU_ACCELERATOR) -device virtio-rng-pci,rng=rng0,bus=pci.0,addr=0x7 -object rng-random,filename=/dev/urandom,id=rng0
|
||||
PACKER_RELEASE ?= $(PACKER_ALPINE_RELEASE)
|
||||
PACKER_SSH_ADDRESS ?= $(if $(ssh_bind_address),$(ssh_bind_address),0.0.0.0)
|
||||
PACKER_SSH_PORT ?= $(if $(ssh_port_max),$(ssh_port_max),2222)
|
||||
PACKER_SSH_WAIT_TIMEOUT ?= 42s
|
||||
PACKER_TEMPLATES ?= $(wildcard packer/*/*.json)
|
||||
PACKER_TEMPLATE ?= alpine
|
||||
PACKER_USERNAME ?= root
|
||||
PACKER_VNC_PORT ?= $(if $(vnc_port_max),$(vnc_port_max),5900)
|
||||
PACKER_VNC_ADDRESS ?= $(if $(vnc_bind_address),$(vnc_bind_address),0.0.0.0)
|
||||
ifeq ($(DEBUG), true)
|
||||
PACKER_BUILD_ARGS += -debug
|
||||
endif
|
||||
ifeq ($(FORCE), true)
|
||||
PACKER_BUILD_ARGS += -force
|
||||
endif
|
||||
ifeq ($(ENV), local)
|
||||
PACKER_BUILD_ARGS += -var ssh_port_max=$(PACKER_SSH_PORT) -var vnc_port_max=$(PACKER_VNC_PORT) -var vnc_bind_address=$(PACKER_VNC_ADDRESS)
|
||||
endif
|
||||
|
||||
accelerator ?= $(PACKER_QEMU_ACCELERATOR)
|
||||
boot_wait ?= $(PACKER_BOOT_WAIT)
|
||||
hostname ?= $(PACKER_HOSTNAME)
|
||||
iso_name ?= $(PACKER_ISO_NAME)
|
||||
iso_size ?= $(PACKER_ISO_SIZE)
|
||||
output ?= $(PACKER_OUTPUT)
|
||||
password ?= $(PACKER_PASSWORD)
|
||||
qemuargs ?= $(call arrays_of_dquoted_args, $(PACKER_QEMU_ARGS))
|
||||
ssh_wait_timeout ?= $(PACKER_SSH_WAIT_TIMEOUT)
|
||||
template ?= $(PACKER_TEMPLATE)
|
||||
username ?= $(PACKER_USERNAME)
|
||||
|
||||
ifneq ($(filter $(ENV),$(ENV_DEPLOY)),)
|
||||
ifeq ($(password), $(template))
|
||||
password := $(or $(shell pwgen -csy -r\' 64 1 2>/dev/null),$(shell date +%s | shasum -a 256 2>/dev/null | base64 | head -c 64))
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HOST_SYSTEM),DARWIN)
|
||||
ifneq ($(DOCKER), true)
|
||||
PACKER_QEMU_ACCELERATOR := hvf
|
||||
else
|
||||
PACKER_QEMU_ACCELERATOR := tcg
|
||||
PACKER_QEMU_ARGS += -cpu max,vendor=GenuineIntel,vmware-cpuid-freq=on,+invtsc,+aes,+vmx
|
||||
endif
|
||||
else ifeq ($(HOST_SYSTEM),LINUX)
|
||||
DOCKER_RUN_OPTIONS_PACKER := $(if $(KVM_GID),--group-add $(KVM_GID)) --device /dev/kvm
|
||||
else ifeq ($(HOST_SYSTEM),WINDOWS)
|
||||
PACKER_QEMU_ACCELERATOR := hax
|
||||
endif
|
||||
|
||||
ifeq ($(DOCKER), true)
|
||||
|
||||
# packer ansible provisionner needs:
|
||||
## empty local ssh agent (ssh-add -D)
|
||||
## ANSIBLE_SSH_PRIVATE_KEY set to a key giving access to ANSIBLE_GIT_REPOSITORY without password
|
||||
## ANSIBLE_AWS_ACCESS_KEY_ID and ANSIBLE_AWS_SECRET_ACCESS_KEY
|
||||
define packer
|
||||
$(call run,$(DOCKER_RUN_OPTIONS_PACKER) $(DOCKER_SSH_AUTH) -p $(PACKER_SSH_PORT):$(PACKER_SSH_PORT) -p $(PACKER_VNC_PORT):$(PACKER_VNC_PORT) $(DOCKER_REPOSITORY)/packer:$(DOCKER_IMAGE_TAG) $(1))
|
||||
endef
|
||||
define packer-qemu
|
||||
echo Running $(1)
|
||||
$(call run,$(DOCKER_RUN_OPTIONS_PACKER) -p $(PACKER_SSH_PORT):$(PACKER_SSH_PORT) -p $(PACKER_VNC_PORT):$(PACKER_VNC_PORT) --entrypoint=qemu-system-$(PACKER_QEMU_ARCH) $(DOCKER_REPOSITORY)/packer:$(DOCKER_IMAGE_TAG) $(PACKER_QEMU_ARGS) -m 512m -drive file=$(1)$(comma)format=raw -net nic$(comma)model=virtio -net user$(comma)hostfwd=tcp:$(PACKER_SSH_ADDRESS):$(PACKER_SSH_PORT)-:22 -vnc $(PACKER_VNC_ADDRESS):$(subst 590,,$(PACKER_VNC_PORT)))
|
||||
endef
|
||||
|
||||
else
|
||||
|
||||
define packer
|
||||
$(call run,packer $(1))
|
||||
endef
|
||||
define packer-qemu
|
||||
echo Running $(1)
|
||||
$(call run,qemu-system-$(PACKER_QEMU_ARCH) $(PACKER_QEMU_ARGS) -m 512m -drive file=$(1)$(comma)format=raw -net nic$(comma)model=virtio -net user$(comma)hostfwd=tcp:$(PACKER_SSH_ADDRESS):$(PACKER_SSH_PORT)-:22 -vnc $(PACKER_VNC_ADDRESS):$(subst 590,,$(PACKER_VNC_PORT)))
|
||||
endef
|
||||
|
||||
endif
|
||||
|
||||
define packer-build
|
||||
$(eval PACKER_TEMPLATE := $(notdir $(basename $(1))))
|
||||
echo Building $(PACKER_ISO_FILE)
|
||||
$(call packer,build $(PACKER_BUILD_ARGS) $(1))
|
||||
echo 'aws_id: $(ANSIBLE_AWS_ACCESS_KEY_ID)' > $(PACKER_ISO_INFO)
|
||||
echo 'aws_key: $(ANSIBLE_AWS_SECRET_ACCESS_KEY)' >> $(PACKER_ISO_INFO)
|
||||
echo 'aws_region: $(ANSIBLE_AWS_DEFAULT_REGION)' >> $(PACKER_ISO_INFO)
|
||||
echo 'docker_image_tag: $(ANSIBLE_DOCKER_IMAGE_TAG)' >> $(PACKER_ISO_INFO)
|
||||
echo 'docker_registry: $(ANSIBLE_DOCKER_REGISTRY)' >> $(PACKER_ISO_INFO)
|
||||
echo 'env: $(ENV)' >> $(PACKER_ISO_INFO)
|
||||
echo 'file: $(PACKER_ISO_FILE)' >> $(PACKER_ISO_INFO)
|
||||
echo 'git_branch: $(ANSIBLE_GIT_VERSION)' >> $(PACKER_ISO_INFO)
|
||||
echo 'git_repository: $(ANSIBLE_GIT_REPOSITORY)' >> $(PACKER_ISO_INFO)
|
||||
echo 'git_version: $(VERSION)' >> $(PACKER_ISO_INFO)
|
||||
echo 'host: $(hostname)' >> $(PACKER_ISO_INFO)
|
||||
echo 'link: s3://$(AWS_S3_BUCKET)/$(AWS_S3_KEY)' >> $(PACKER_ISO_INFO)
|
||||
echo 'name: $(iso_name)' >> $(PACKER_ISO_INFO)
|
||||
echo 'nfs_disk: $(ANSIBLE_DISKS_NFS_DISK)' >> $(PACKER_ISO_INFO)
|
||||
echo 'nfs_path: $(ANSIBLE_DISKS_NFS_PATH)' >> $(PACKER_ISO_INFO)
|
||||
echo 'pass: $(password)' >> $(PACKER_ISO_INFO)
|
||||
echo 'size: $(iso_size)' >> $(PACKER_ISO_INFO)
|
||||
echo 'ssh_key: $(ANSIBLE_SSH_PRIVATE_KEY)' >> $(PACKER_ISO_INFO)
|
||||
echo 'user: $(username)' >> $(PACKER_ISO_INFO)
|
||||
endef
|
||||
|
||||
define arrays_of_dquoted_args
|
||||
[ $(subst $(dquote) $(dquote),$(dquote)$(comma) $(dquote),$(subst $(dquote) $(dquote)-,$(dquote) ]$(comma) [ $(dquote)-,$(patsubst %,$(dquote)%$(dquote),$1))) ]
|
||||
endef
|
||||
@@ -0,0 +1,14 @@
|
||||
define ssh-connect
|
||||
$(eval hosts := $(1))
|
||||
$(eval command := $(2))
|
||||
$(eval user := $(or $(3),root))
|
||||
$(eval DOCKER_EXEC_OPTIONS := -it)
|
||||
$(foreach host,$(hosts),$(call exec,ssh -t -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $(user)@$(host) "$(command)") ||) true
|
||||
endef
|
||||
|
||||
define ssh-exec
|
||||
$(eval hosts := $(1))
|
||||
$(eval command := $(2))
|
||||
$(eval user := $(or $(3),root))
|
||||
$(foreach host,$(hosts),$(call exec,ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $(user)@$(host) "$(command)") &&) true
|
||||
endef
|
||||
@@ -0,0 +1,21 @@
|
||||
CMDS += terraform
|
||||
|
||||
ifeq ($(DOCKER), true)
|
||||
|
||||
# packer ansible provisionner needs:
|
||||
## empty local ssh agent (ssh-add -D)
|
||||
## ANSIBLE_SSH_PRIVATE_KEY set to a key giving access to ANSIBLE_GIT_REPOSITORY without password
|
||||
## ANSIBLE_AWS_ACCESS_KEY_ID and ANSIBLE_AWS_SECRET_ACCESS_KEY
|
||||
define terraform
|
||||
$(call run,hashicorp/terraform:light $(1))
|
||||
endef
|
||||
|
||||
else
|
||||
|
||||
define terraform
|
||||
$(call run,terraform $(1))
|
||||
endef
|
||||
|
||||
endif
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
##
|
||||
# INFRA
|
||||
|
||||
.PHONY: setup-sysctl
|
||||
setup-sysctl:
|
||||
ifeq ($(SETUP_SYSCTL),true)
|
||||
$(call docker-run,--privileged alpine:latest,/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled ||:' >/dev/null)
|
||||
$(foreach config,$(SETUP_SYSCTL_CONFIG),$(call docker-run,--privileged alpine:latest,sysctl -q -w $(config)) &&) true
|
||||
endif
|
||||
|
||||
.PHONY: start-up
|
||||
start-up: base-ssh-add
|
||||
@@ -0,0 +1,7 @@
|
||||
.PHONY: openstack
|
||||
openstack: docker-build-openstack
|
||||
$(call openstack,$(ARGS))
|
||||
|
||||
.PHONY: openstack-image-create
|
||||
openstack-image-create: $(PACKER_ISO_FILE) docker-build-openstack
|
||||
$(call openstack,$(OPENSTACK_ARGS) image create --disk-format raw --container-format bare --file $(PACKER_ISO_FILE) "$(PACKER_ISO_NAME)")
|
||||
@@ -0,0 +1,36 @@
|
||||
.PHONY: packer
|
||||
packer:
|
||||
$(call packer,$(ARGS))
|
||||
|
||||
$(PACKER_ISO_FILE):
|
||||
$(eval FORCE := true)
|
||||
$(call make,packer-build,,FORCE)
|
||||
|
||||
.PHONY: packer-build
|
||||
packer-build: packer-build-$(PACKER_TEMPLATE) ## Build default packer template
|
||||
|
||||
.PHONY: packer-build-templates
|
||||
packer-build-templates: $(PACKER_TEMPLATES) ## Build all packer templates
|
||||
|
||||
.PHONY: $(PACKER_TEMPLATES)
|
||||
ifeq ($(HOST_SYSTEM),DARWIN)
|
||||
$(PACKER_TEMPLATES): DOCKER ?= false
|
||||
endif
|
||||
$(PACKER_TEMPLATES):
|
||||
$(call packer-build,$@)
|
||||
|
||||
.PHONY: packer-build-%
|
||||
packer-build-%: docker-build-packer
|
||||
$(if $(wildcard packer/*/$*.json),\
|
||||
$(call packer-build,$(wildcard packer/*/$*.json)))
|
||||
|
||||
.PHONY: packer-qemu
|
||||
packer-qemu: packer-qemu-$(PACKER_ISO_NAME) ## Launch iso image in qemu
|
||||
|
||||
.PHONY: packer-qemu-%
|
||||
ifeq ($(HOST_SYSTEM),DARWIN)
|
||||
packer-qemu-%: DOCKER ?= false
|
||||
endif
|
||||
packer-qemu-%: docker-build-packer ## Run iso image in qemu
|
||||
$(if $(wildcard $(PACKER_OUTPUT)/$*.iso),\
|
||||
$(call packer-qemu,$(wildcard $(PACKER_OUTPUT)/$*.iso)))
|
||||
@@ -0,0 +1,18 @@
|
||||
##
|
||||
# SSH
|
||||
|
||||
.PHONY: ssh
|
||||
ssh: aws-ec2-get-PrivateIpAddress-$(SERVER_NAME)
|
||||
$(call ssh-connect,$(AWS_INSTANCE_IP),$(SHELL))
|
||||
|
||||
.PHONY: ssh-connect
|
||||
ssh-connect: aws-ec2-get-PrivateIpAddress-$(SERVER_NAME)
|
||||
$(call ssh-connect,$(AWS_INSTANCE_IP),make connect $(if $(SERVICE),SERVICE=$(SERVICE)))
|
||||
|
||||
.PHONY: ssh-exec
|
||||
ssh-exec: aws-ec2-get-PrivateIpAddress-$(SERVER_NAME)
|
||||
$(call ssh-exec,$(AWS_INSTANCE_IP),make exec $(if $(SERVICE),SERVICE=$(SERVICE)) $(if $(ARGS),ARGS='\''"$(ARGS)"'\''))
|
||||
|
||||
.PHONY: ssh-run
|
||||
ssh-run: aws-ec2-get-PrivateIpAddress-$(SERVER_NAME)
|
||||
$(call ssh-exec,$(AWS_INSTANCE_IP),make run $(if $(SERVICE),SERVICE=$(SERVICE)) $(if $(ARGS),ARGS='\''"$(ARGS)"'\''))
|
||||
@@ -0,0 +1,4 @@
|
||||
.PHONY: terraform
|
||||
terraform:
|
||||
$(call terraform,$(ARGS))
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
##
|
||||
# INSTALL
|
||||
|
||||
.PHONY: install app-install
|
||||
install: app-install ## Install application
|
||||
|
||||
.PHONY: install-mysql-database-%
|
||||
install-mysql-database-%: infra-base
|
||||
$(call exec,mysql -h mysql -u root -proot $* -e "use $*" >/dev/null 2>&1 || mysql -h mysql -u root -proot mysql -e "create database $* character set utf8 collate utf8_unicode_ci;")
|
||||
$(call exec,mysql -h mysql -u $* -p$* $* -e "use $*" >/dev/null 2>&1 || mysql -h mysql -u root -proot mysql -e "grant all privileges on $*.* to '\''$*'\''@'\''%'\'' identified by '\''$*'\''; flush privileges;")
|
||||
$(call exec,[ $$(mysql -h mysql -u $* -p$* $* -e "show tables" 2>/dev/null |wc -l) -eq 0 ] && [ -f "${APP_DIR}/$*.mysql.gz" ] && gzip -cd "${APP_DIR}/$*.mysql.gz" |mysql -h mysql -u root -proot $* || true)
|
||||
|
||||
.PHONY: install-pgsql-database-%
|
||||
install-pgsql-database-%: infra-base
|
||||
$(call exec,PGPASSWORD=$* psql -h postgres -U $* template1 -c "\q" >/dev/null 2>&1 || PGPASSWORD=postgres psql -h postgres -U postgres -c "create user $* with createdb password '\''$*'\'';")
|
||||
$(call exec,PGPASSWORD=$* psql -h postgres -U $* -d $* -c "" >/dev/null 2>&1 || PGPASSWORD=postgres psql -h postgres -U postgres -c "create database $* owner $* ;")
|
||||
$(call exec,[ $$(PGPASSWORD=$* psql -h postgres -U $* -d $* -c "\d" 2>/dev/null |wc -l) -eq 0 ] && [ -f "${APP_DIR}/$*.pgsql.gz" ] && gzip -cd "${APP_DIR}/$*.pgsql.gz" |PGPASSWORD="postgres" psql -h postgres -U postgres -d $* || true)
|
||||
$(call exec,[ $$(PGPASSWORD=$* psql -h postgres -U $* -d $* -c "\d" 2>/dev/null |wc -l) -eq 0 ] && [ -f "${APP_DIR}/$*.pgsql" ] && PGPASSWORD="postgres" psql -h postgres -U postgres -c "ALTER ROLE $* WITH SUPERUSER" && PGPASSWORD="postgres" pg_restore -h postgres --no-owner --role=$* -U postgres -d $* ${APP_DIR}/$*.pgsql && PGPASSWORD="postgres" psql -h postgres -U postgres -c "ALTER ROLE $* WITH NOSUPERUSER" || true)
|
||||
|
||||
.PHONY: install-infra
|
||||
install-infra: infra-install
|
||||
|
||||
.PHONY: install-parameters
|
||||
install-parameters:
|
||||
$(call install-parameters)
|
||||
|
||||
.PHONY: install-parameters-%
|
||||
install-parameters-%:
|
||||
$(call install-parameters,$*)
|
||||
@@ -0,0 +1,9 @@
|
||||
##
|
||||
# CLEAN
|
||||
|
||||
.PHONY: clean-js-app
|
||||
clean-js-app: clean-js-assets-deps
|
||||
|
||||
.PHONY: clean-js-assets-deps
|
||||
clean-js-assets-deps: bootstrap
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -Rf node_modules/*)
|
||||
@@ -0,0 +1,21 @@
|
||||
##
|
||||
# DEV
|
||||
|
||||
## Build assets
|
||||
.PHONY: dev-assets
|
||||
dev-assets: ## Build assets
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn build:dev:watch)
|
||||
|
||||
.PHONY: dev-outdated
|
||||
dev-outdated:
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn outdated)
|
||||
|
||||
# compile webpack assets (REACT)
|
||||
.PHONY: dev-webpack-compile
|
||||
dev-webpack-compile: bootstrap ## Compile dev assets
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn encore dev)
|
||||
|
||||
# watch webpack assets updates (REACT)
|
||||
.PHONY: dev-webpack-watch
|
||||
dev-webpack-watch: bootstrap ## Watch dev assets update
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn encore dev --watch)
|
||||
@@ -0,0 +1,22 @@
|
||||
##
|
||||
# INSTALL
|
||||
|
||||
.PHONY: install-bower
|
||||
install-bower: bootstrap
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),npm install bower --allow-root)
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),./node_modules/bower/bin/bower install --allow-root)
|
||||
|
||||
.PHONY: install-npm
|
||||
install-npm: bootstrap
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),npm install)
|
||||
|
||||
.PHONY: install-npm-run-build
|
||||
install-npm-run-build: install-npm-run-build-$(SYMFONY_ENV)
|
||||
|
||||
.PHONY: install-npm-run-build-%
|
||||
install-npm-run-build-%: bootstrap
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),npm run build:$*)
|
||||
|
||||
.PHONY: install-yarn
|
||||
install-yarn: bootstrap
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn install)
|
||||
@@ -0,0 +1,17 @@
|
||||
##
|
||||
# TEST
|
||||
|
||||
.PHONY: test-assets
|
||||
test-assets: bootstrap
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn test)
|
||||
|
||||
## Run functional tests (make test-func TEST="S01-U1-find-product")
|
||||
.PHONY: test-func-js
|
||||
test-func-js: bootstrap ## Run functional tests (js)
|
||||
ifdef TEST
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn test:func -- --test tests/Functional/specs/$(TEST).js --env $(TESTENV))
|
||||
else ifdef TESTSUITE
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn test:func -- --tag $(TESTSUITE) --env $(TESTENV))
|
||||
else
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),yarn test:func -- --env $(TESTENV))
|
||||
endif
|
||||
@@ -0,0 +1,6 @@
|
||||
##
|
||||
# UPDATE
|
||||
|
||||
.PHONY: update-npm
|
||||
update-npm: bootstrap
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),npm upgrade)
|
||||
@@ -0,0 +1,23 @@
|
||||
##
|
||||
# CACHE
|
||||
|
||||
## Clear symfony cache
|
||||
.PHONY: cache-clear
|
||||
cache-clear: cache-clear-dev cache-clear-prod
|
||||
|
||||
.PHONY: cache-clear-%
|
||||
cache-clear-%: bootstrap ## Clear symfony cache
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),app/console cache:clear --env=$*)
|
||||
|
||||
.PHONY: cache-rm
|
||||
cache-rm: bootstrap
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -Rf app/cache/* app/logs/*)
|
||||
$(if $(filter $(ENV),$(ENV_DEPLOY)),$(call docker-compose-exec,$(DOCKER_SERVICE),chown www-data app/cache/ app/logs/))
|
||||
|
||||
.PHONY: cache-warmup
|
||||
cache-warmup: cache-warmup-$(SYMFONY_ENV)
|
||||
$(if $(filter $(ENV),$(ENV_DEPLOY)),$(call docker-compose-exec,$(DOCKER_SERVICE),chown -R www-data app/cache/ app/logs/))
|
||||
|
||||
.PHONY: cache-warmup-%
|
||||
cache-warmup-%: bootstrap
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),app/console cache:warmup --env=$*)
|
||||
@@ -0,0 +1,12 @@
|
||||
##
|
||||
# CLEAN
|
||||
|
||||
.PHONY: clean-php-app
|
||||
clean-php-app: bootstrap
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -rf app/bootstrap.php.cache)
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -rf app/cache/* app/cach~)
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -rf app/logs/*)
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -rf var/cache/* var/cach~)
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -rf var/logs/*)
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -rf vendor/*)
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),rm -rf node_modules/*)
|
||||
@@ -0,0 +1,24 @@
|
||||
COMPOSER_ARGS ?= --optimize-autoloader
|
||||
COMPOSER_MEMORY_LIMIT ?= -1
|
||||
CONTEXT += COMPOSER_ARGS
|
||||
|
||||
ifeq ($(SYMFONY_ENV), prod)
|
||||
COMPOSER_ARGS += --classmap-authoritative --prefer-dist --no-dev --no-interaction
|
||||
endif
|
||||
ifeq ($(DRONE), true)
|
||||
COMPOSER_ARGS += --no-progress
|
||||
endif
|
||||
|
||||
define composer
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),COMPOSER_MEMORY_LIMIT=$(COMPOSER_MEMORY_LIMIT) SYMFONY_ENV=$(SYMFONY_ENV) composer $(1) $(COMPOSER_ARGS))
|
||||
endef
|
||||
|
||||
define composer-require-vendor-binary
|
||||
$(eval vendor:=$(1))
|
||||
$(eval binary:=$(or $(2),$(lastword $(subst /, ,$(vendor)))))
|
||||
$(eval version:=$(or $(addprefix :,$(3)),$(shell awk '/'$(subst /,\\/,$(vendor))'/ {gsub("[\",]","",$$2); print ":"$$2}' composer.json 2>/dev/null)))
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval COMPOSER_REQUIRE := $(shell $(call docker-compose-exec,$(DOCKER_SERVICE),[ -f vendor/$(vendor)/$(binary) ] || echo true)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
$(if $(COMPOSER_REQUIRE),$(call docker-compose-exec,$(DOCKER_SERVICE),mkdir -p vendor/$(vendor) && cd /tmp && COMPOSER_MEMORY_LIMIT=$(COMPOSER_MEMORY_LIMIT) SYMFONY_ENV=$(SYMFONY_ENV) composer require "$(vendor)$(version)" --prefer-source --no-interaction --dev && cd - && ln -s /tmp/vendor/$(vendor)/$(binary) vendor/$(vendor)/$(binary)))
|
||||
endef
|
||||
@@ -0,0 +1,8 @@
|
||||
BUILD_APP_VARS += SYMFONY_ENV
|
||||
DOCKER_SERVICE ?= php
|
||||
|
||||
ifneq (,$(filter $(ENV),$(ENV_DEPLOY)))
|
||||
SYMFONY_ENV ?= prod
|
||||
else
|
||||
SYMFONY_ENV ?= dev
|
||||
endif
|
||||
@@ -0,0 +1,10 @@
|
||||
##
|
||||
# DEV
|
||||
|
||||
.PHONY: dev-phpcs
|
||||
dev-phpcs: bootstrap install-phpcs
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/phpcs --standard=PSR2 --colors -p ./src)
|
||||
|
||||
.PHONY: dev-phpcbf
|
||||
dev-phpcbf: bootstrap install-phpcbf
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/phpcbf ./src/ --ignore=*.js)
|
||||
@@ -0,0 +1,43 @@
|
||||
##
|
||||
# INSTALL
|
||||
|
||||
.PHONY: install-assets
|
||||
install-assets: install-assets-$(SYMFONY_ENV)
|
||||
|
||||
.PHONY: install-assets-%
|
||||
install-assets-%: bootstrap
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),app/console assetic:dump --env=$*)
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),app/console assets:install --env=$*)
|
||||
$(if $(filter $(ENV),$(ENV_DEPLOY)),$(call docker-compose-exec,$(DOCKER_SERVICE),chown -R www-data web/bundles/ web/css/ web/js/))
|
||||
|
||||
.PHONY: install-codecept
|
||||
install-codecept: bootstrap install-phpunit vendor/codeception/codeception/codecept
|
||||
|
||||
vendor/codeception/codeception/codecept:
|
||||
$(call composer-require-vendor-binary,codeception/codeception,codecept)
|
||||
|
||||
.PHONY: install-composer
|
||||
install-composer: bootstrap
|
||||
$(call composer,install)
|
||||
|
||||
.PHONY: install-doctrine-schema-update
|
||||
install-doctrine-schema-update: bootstrap
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),php app/console doctrine:schema:update --force)
|
||||
|
||||
.PHONY: install-phpcbf
|
||||
install-phpcbf: bootstrap vendor/squizlabs/php_codesniffer/bin/phpcbf
|
||||
|
||||
vendor/squizlabs/php_codesniffer/bin/phpcbf:
|
||||
$(call composer-require-vendor-binary,squizlabs/php_codesniffer,bin/phpcbf)
|
||||
|
||||
.PHONY: install-phpcs
|
||||
install-phpcs: bootstrap vendor/squizlabs/php_codesniffer/bin/phpcs
|
||||
|
||||
vendor/squizlabs/php_codesniffer/bin/phpcs:
|
||||
$(call composer-require-vendor-binary,squizlabs/php_codesniffer,bin/phpcs)
|
||||
|
||||
.PHONY: install-phpunit
|
||||
install-phpunit: bootstrap vendor/phpunit/phpunit/phpunit
|
||||
|
||||
vendor/phpunit/phpunit/phpunit:
|
||||
$(call composer-require-vendor-binary,phpunit/phpunit)
|
||||
@@ -0,0 +1,52 @@
|
||||
##
|
||||
# TEST
|
||||
|
||||
## Run unit tests
|
||||
.PHONY: test
|
||||
test: test-unit ## Run unit tests
|
||||
|
||||
## Run codeception tests
|
||||
.PHONY: test-codeception-%
|
||||
test-codeception-%: bootstrap install-codecept ## Run codeception tests
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/codecept run $*)
|
||||
|
||||
## Run old unit tests with code coverage
|
||||
.PHONY: test-coverage
|
||||
test-coverage: bootstrap install-phpunit ## Run code coverage
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/phpunit --testsuite unit --coverage-text)
|
||||
|
||||
## Run codeception tests with coverage
|
||||
.PHONY: test-coverage-codeception-%
|
||||
test-coverage-codeception-%: bootstrap install-codecept ## Run codeception tests with coverage
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/codecept run $* --coverage --coverage-html)
|
||||
|
||||
## Run phpunit functional tests
|
||||
.PHONY: test-func
|
||||
test-func: bootstrap install-phpunit ## Run functional tests
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/phpunit --testsuite functional)
|
||||
|
||||
## Loop unit tests
|
||||
.PHONY: test-loop
|
||||
test-loop: bootstrap install-phpunit ## Loop unit tests
|
||||
while true; \
|
||||
do $(MAKE) test; \
|
||||
read continue; \
|
||||
done;
|
||||
|
||||
## Run search tests
|
||||
.PHONY: test-search
|
||||
test-search: bootstrap install-phpunit ## Run search tests
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/phpunit --testsuite search)
|
||||
|
||||
.PHONY: test-templates
|
||||
test-templates: bootstrap
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),php app/console lint:twig @UIBundle)
|
||||
|
||||
## Run old unit tests
|
||||
.PHONY: test-unit
|
||||
test-unit: bootstrap install-phpunit ## Run unit tests
|
||||
ifdef FILTER
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/phpunit --testsuite unit --filter $(FILTER))
|
||||
else
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),bin/phpunit --testsuite unit)
|
||||
endif
|
||||
@@ -0,0 +1,6 @@
|
||||
##
|
||||
# UPDATE
|
||||
|
||||
.PHONY: update-database
|
||||
update-database: bootstrap
|
||||
$(call docker-compose-exec,$(DOCKER_SERVICE),app/console --no-interaction doctrine:migration:migrate)
|
||||
@@ -0,0 +1,75 @@
|
||||
COMPOSE_VERSION ?= 1.24.1
|
||||
COMPOSE_PROJECT_NAME_INFRA ?= $(USER)_$(ENV)_infra
|
||||
COMPOSE_PROJECT_NAME_INFRA_NODE ?= node_infra
|
||||
DOCKER_EXEC_OPTIONS ?=
|
||||
DOCKER_IMAGE ?= $(DOCKER_IMAGE_CLI)
|
||||
DOCKER_IMAGE_CLI ?= $(DOCKER_REPOSITORY_INFRA)/cli
|
||||
DOCKER_IMAGE_SSH ?= $(DOCKER_REPOSITORY_INFRA)/ssh
|
||||
DOCKER_NAME ?= $(DOCKER_NAME_CLI)
|
||||
DOCKER_NAME_CLI ?= $(COMPOSE_PROJECT_NAME_INFRA)_cli
|
||||
DOCKER_NAME_SSH ?= $(COMPOSE_PROJECT_NAME_INFRA)_ssh
|
||||
DOCKER_NETWORK ?= $(DOCKER_NETWORK_PRIVATE)
|
||||
DOCKER_NETWORK_PRIVATE ?= $(ENV)
|
||||
DOCKER_NETWORK_PUBLIC ?= node
|
||||
DOCKER_REPOSITORY_INFRA ?= $(subst _,/,$(COMPOSE_PROJECT_NAME_INFRA))
|
||||
DOCKER_REPOSITORY_INFRA_NODE ?= $(subst _,/,$(COMPOSE_PROJECT_NAME_INFRA_NODE))
|
||||
# DOCKER_RUN_OPTIONS: default options to `docker run` command
|
||||
DOCKER_RUN_OPTIONS ?= --rm -it
|
||||
# DOCKER_RUN_VOLUME: options to `docker run` command to mount additionnal volumes
|
||||
DOCKER_RUN_VOLUME ?= -v $$PWD:$$PWD
|
||||
DOCKER_RUN_WORKDIR ?= -w $$PWD
|
||||
DOCKER_VOLUME_SSH ?= $(COMPOSE_PROJECT_NAME_INFRA)_ssh
|
||||
ENV_VARS += DOCKER_NETWORK_PRIVATE DOCKER_NETWORK_PUBLIC DOCKER_REPOSITORY_INFRA DOCKER_REPOSITORY_INFRA_NODE DOCKER_VOLUME_SSH
|
||||
|
||||
ifeq ($(DRONE), true)
|
||||
DOCKER_RUN_OPTIONS := --rm --network $(DOCKER_NETWORK)
|
||||
# When running docker command in drone, we are already in a docker (dind).
|
||||
# Whe need to find the volume mounted in the current docker (runned by drone) to mount it in our docker command.
|
||||
# If we do not mount the volume in our docker, we wont be able to access the files in this volume as the /drone/src directory would be empty.
|
||||
DOCKER_RUN_VOLUME := -v /var/run/docker.sock:/var/run/docker.sock -v $$(docker inspect $$(basename $$(cat /proc/1/cpuset)) 2>/dev/null |awk 'BEGIN {FS=":"} $$0 ~ /"drone-[a-zA-Z0-9]*:\/drone"$$/ {gsub(/^[ \t\r\n]*"/,"",$$1); print $$1; exit}'):/drone $(if $(wildcard /root/.netrc),-v /root/.netrc:/root/.netrc)
|
||||
else
|
||||
DOCKER_RUN_VOLUME := -v /var/run/docker.sock:/var/run/docker.sock -v $(or $(MONOREPO_DIR),$(APP_DIR)):$(or $(WORKSPACE_DIR),$(MONOREPO_DIR),$(APP_DIR))
|
||||
endif
|
||||
|
||||
ifeq ($(DOCKER), true)
|
||||
|
||||
DOCKER_SSH_AUTH := -e SSH_AUTH_SOCK=/tmp/ssh-agent/socket -v $(DOCKER_VOLUME_SSH):/tmp/ssh-agent
|
||||
|
||||
define docker-run
|
||||
$(call run,$(or $(1),$(DOCKER_IMAGE):$(DOCKER_IMAGE_TAG)) $(2))
|
||||
endef
|
||||
ifeq ($(DRONE), true)
|
||||
define exec
|
||||
$(call run,$(DOCKER_SSH_AUTH) $(DOCKER_IMAGE) sh -c '$(or $(1),$(SHELL))')
|
||||
endef
|
||||
else
|
||||
define exec
|
||||
$(ECHO) docker exec $(ENV_ARGS) $(DOCKER_EXEC_OPTIONS) $(DOCKER_RUN_WORKDIR) $(DOCKER_NAME) sh -c '$(or $(1),$(SHELL))'
|
||||
endef
|
||||
endif
|
||||
define run
|
||||
$(ECHO) docker run $(DOCKER_RUN_OPTIONS) $(patsubst %,--env-file %,$(ENV_FILE)) $(ENV_ARGS) $(DOCKER_RUN_VOLUME) $(DOCKER_RUN_WORKDIR) $(1)
|
||||
endef
|
||||
|
||||
else
|
||||
|
||||
SHELL := /bin/bash
|
||||
define docker-run
|
||||
$(ECHO) docker run $(DOCKER_RUN_OPTIONS) $(patsubst %,--env-file %,$(ENV_FILE)) $(foreach var,$(ENV_VARS),$(if $($(var)),-e $(var)='$($(var))')) $(shell printenv |awk -F '=' 'NR == FNR { if($$1 !~ /^(\#|$$)/) { A[$$1]; next } } ($$1 in A) {print "-e "$$0}' .env.dist - 2>/dev/null) $(DOCKER_RUN_VOLUME) $(DOCKER_RUN_WORKDIR) $(or $(1),$(DOCKER_IMAGE):$(DOCKER_IMAGE_TAG)) $(2)
|
||||
endef
|
||||
define exec
|
||||
$(call run,sh -c '$(or $(1),$(SHELL))')
|
||||
endef
|
||||
define run
|
||||
IFS=$$'\n'; $(ECHO) env $(ENV_ARGS) $$(cat $(ENV_FILE) 2>/dev/null |awk -F "=" '$$1 ~! /^\(#|$$\)/') $(1)
|
||||
endef
|
||||
|
||||
endif
|
||||
|
||||
define docker-volume-copy
|
||||
$(eval from := $(1))
|
||||
$(eval to := $(2))
|
||||
$(ECHO) docker volume inspect $(from) >/dev/null
|
||||
$(ECHO) docker volume inspect $(to) >/dev/null 2>&1 || $(ECHO) docker volume create $(to) >/dev/null
|
||||
$(ECHO) docker run --rm -v $(from):/from -v $(to):/to alpine ash -c "cd /from; cp -a . /to"
|
||||
endef
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
comma ?= ,
|
||||
dollar ?= $
|
||||
dquote ?= "
|
||||
quote ?= '
|
||||
APP ?= $(if $(wildcard .git),$(if $(wildcard */.gitrepo),,$(notdir $(CURDIR))),$(notdir $(CURDIR)))
|
||||
APP_DIR ?= $(if $(APP),$(CURDIR))
|
||||
BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||
CMDS ?= exec exec:% exec@% run run:% run@%
|
||||
COMMIT ?= $(shell git rev-parse $(BRANCH) 2>/dev/null)
|
||||
CONTEXT ?= $(shell awk 'BEGIN {FS="="}; $$1 !~ /^(\#|$$)/ {print $$1}' .env.dist 2>/dev/null) BRANCH ENV_FILE UID USER VERSION
|
||||
DEBUG ?= false
|
||||
DOCKER ?= true
|
||||
DRONE ?= false
|
||||
DRYRUN ?= false
|
||||
DRYRUN_IGNORE ?= false
|
||||
DRYRUN_RECURSIVE ?= false
|
||||
ENV ?= local
|
||||
ENV_DEPLOY ?= preprod prod
|
||||
ENV_FILE ?= $(wildcard ../$(PARAMETERS)/$(ENV)/$(APP)/.env) .env
|
||||
ENV_LIST ?= local dev tests preprod prod
|
||||
ENV_RESET ?= false
|
||||
ENV_VARS ?= APP APP_DIR BRANCH ENV HOSTNAME GID MONOREPO MONOREPO_DIR TAG UID USER VERSION
|
||||
GID ?= $(shell id -g)
|
||||
GIT_PARAMETERS_REPOSITORY ?= $(call pop,$(GIT_UPSTREAM_REPOSITORY))/$(PARAMETERS)
|
||||
GIT_REPOSITORY ?= $(if $(SUBREPO),$(shell awk -F ' = ' '$$1 ~ /^[[\s\t]]*remote$$/ {print $$2}' .gitrepo),$(shell git config --get remote.origin.url))
|
||||
GIT_UPSTREAM_REPOSITORY ?= $(if $(findstring ://,$(GIT_REPOSITORY)),$(call pop,$(call pop,$(GIT_REPOSITORY)))/,$(call pop,$(GIT_REPOSITORY),:):)$(GIT_UPSTREAM_USER)/$(lastword $(subst /, ,$(GIT_REPOSITORY)))
|
||||
GIT_UPSTREAM_USER ?= $(MONOREPO)
|
||||
HOSTNAME ?= $(shell hostname |sed 's/\..*//')
|
||||
MAKE_ARGS ?= $(foreach var,$(MAKE_VARS),$(if $($(var)),$(var)='$($(var))'))
|
||||
MAKE_VARS ?= ENV
|
||||
MAKECMDVARS ?= $(strip $(foreach var, $(filter-out .VARIABLES,$(.VARIABLES)), $(if $(filter command\ line,$(origin $(var))),$(var))))
|
||||
MAKECMDARGS ?= $(foreach var,$(MAKECMDVARS),$(var)='$($(var))')
|
||||
MAKETARGETS ?= $(filter-out $(.VARIABLES),$(shell $(MAKE) -qp |awk -F':' '/^[a-zA-Z0-9][^$$\#\/\t=]*:([^=]|$$)/ {print $$1}' |sort -u))
|
||||
MONOREPO ?= $(if $(wildcard .git),$(if $(wildcard */.gitrepo),$(notdir $(CURDIR))),$(if $(SUBREPO),$(notdir $(realpath $(CURDIR)/..))))
|
||||
MONOREPO_DIR ?= $(if $(wildcard .git),$(if $(wildcard */.gitrepo),$(CURDIR)),$(if $(SUBREPO),$(realpath $(CURDIR)/..)))
|
||||
PARAMETERS ?= parameters
|
||||
RECURSIVE ?= true
|
||||
SHARED ?= shared
|
||||
SUBREPO ?= $(if $(wildcard .gitrepo),$(notdir $(CURDIR)))
|
||||
SUBREPO_DIR ?= $(if $(SUBREPO),$(CURDIR))
|
||||
SUBREPO_COMMIT ?= $(if $(SUBREPO),$(shell git rev-parse subrepo/$(SUBREPO)/$(BRANCH) 2>/dev/null))
|
||||
TAG ?= $(shell git tag -l --points-at $(BRANCH) 2>/dev/null)
|
||||
UID ?= $(shell id -u)
|
||||
USER ?= $(shell id -nu)
|
||||
VERBOSE ?= true
|
||||
VERSION ?= $(shell git describe --tags $(BRANCH) 2>/dev/null || git rev-parse $(BRANCH) 2>/dev/null)
|
||||
|
||||
ifeq ($(DOCKER), true)
|
||||
ENV_ARGS = $(foreach var,$(ENV_VARS),$(if $($(var)),-e $(var)='$($(var))')) $(shell printenv |awk -F '=' 'NR == FNR { if($$1 !~ /^(\#|$$)/) { A[$$1]; next } } ($$1 in A) {print "-e "$$0}' .env.dist - 2>/dev/null)
|
||||
else
|
||||
ENV_ARGS = $(foreach var,$(ENV_VARS),$(if $($(var)),$(var)='$($(var))')) $(shell printenv |awk -F '=' 'NR == FNR { if($$1 !~ /^(\#|$$)/) { A[$$1]; next } } ($$1 in A)' .env.dist - 2>/dev/null)
|
||||
endif
|
||||
|
||||
# Guess OS
|
||||
ifeq ($(OSTYPE),cygwin)
|
||||
HOST_SYSTEM := CYGWIN
|
||||
else ifeq ($(OS),Windows_NT)
|
||||
HOST_SYSTEM := WINDOWS
|
||||
else
|
||||
UNAME_S := $(shell uname -s 2>/dev/null)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
HOST_SYSTEM := LINUX
|
||||
endif
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
HOST_SYSTEM := DARWIN
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(DEBUG), true)
|
||||
.SILENT:
|
||||
endif
|
||||
ifeq ($(DRYRUN), true)
|
||||
ECHO = $(if $(filter $(DRYRUN_IGNORE),true),,printf '${COLOR_BROWN}$(APP)${COLOR_RESET}[${COLOR_GREEN}$(MAKELEVEL)${COLOR_RESET}] ${COLOR_BLUE}$@${COLOR_RESET}:${COLOR_RESET} '; echo)
|
||||
ifeq ($(RECURSIVE), true)
|
||||
DRYRUN_RECURSIVE := true
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HOST_SYSTEM),DARWIN)
|
||||
define getent-group
|
||||
$(shell dscl . -read /Groups/$(1) 2>/dev/null |awk '$$1 == "PrimaryGroupID:" {print $$2}')
|
||||
endef
|
||||
ifneq ($(DOCKER),true)
|
||||
SED_SUFFIX='\'\''
|
||||
endif
|
||||
else
|
||||
define getent-group
|
||||
$(shell getent group $(1) 2>/dev/null |awk -F: '{print $$3}')
|
||||
endef
|
||||
endif
|
||||
|
||||
define conf
|
||||
$(eval file := $(1))
|
||||
$(eval block := $(2))
|
||||
$(eval variable := $(3))
|
||||
[ -r "$(file)" ] && while IFS='=' read -r key value; do \
|
||||
case $${key} in \
|
||||
\#*) \
|
||||
continue; \
|
||||
;; \
|
||||
\[*\]) \
|
||||
current_bloc="$${key##\[}"; \
|
||||
current_bloc="$${current_bloc%%\]}"; \
|
||||
[ -z "$(block)" ] && [ -z "$(variable)" ] && printf '%s\n' "$${current_bloc}" ||:; \
|
||||
;; \
|
||||
*) \
|
||||
key=$${key%$${key##*[![:space:]]}}; \
|
||||
value=$${value#$${value%%[![:space:]]*}}; \
|
||||
if [ "$(block)" = "$${current_bloc}" ] && [ "$${key}" ]; then \
|
||||
[ -z "$(variable)" ] && printf '%s=%s\n' "$${key}" "$${value}" ||:; \
|
||||
[ "$(variable)" = "$${key}" ] && printf '%s\n' "$${value}" ||:; \
|
||||
fi \
|
||||
;; \
|
||||
esac \
|
||||
done < "$(file)"
|
||||
endef
|
||||
|
||||
define force
|
||||
while true; do [ $$(ps x |awk 'BEGIN {nargs=split("'"$$*"'",args)} $$field == args[1] { matched=1; for (i=1;i<=NF-field;i++) { if ($$(i+field) == args[i+1]) {matched++} } if (matched == nargs) {found++} } END {print found+0}' field=4) -eq 0 ] && $(ECHO) $(1) || sleep 1; done
|
||||
endef
|
||||
|
||||
pop = $(patsubst %$(or $(2),/)$(lastword $(subst $(or $(2),/), ,$(1))),%,$(1))
|
||||
|
||||
define sed
|
||||
$(call exec,sed -i $(SED_SUFFIX) '\''$(1)'\'' $(2))
|
||||
endef
|
||||
|
||||
##
|
||||
# function make
|
||||
## call make with predefined options and variables
|
||||
# 1st arg: make command line (targets and arguments)
|
||||
# 2nd arg: directory to call make from
|
||||
# 3rd arg: list of variables to pass to make (ENV by default)
|
||||
# 4th arg: path to .env file with additional arguments to call make with (file must exist when calling make)
|
||||
# add list of VARIABLE=VALUE from vars to MAKE_ARGS
|
||||
# add list of arguments from file to MAKE_ARGS
|
||||
# eval MAKE_DIR option to -C $(2) if $(2) given
|
||||
# add current target to MAKE_OLDFILE (list of already fired targets)
|
||||
# print command that will be run if VERBOSE mode
|
||||
# actually run make command
|
||||
# if DRYRUN_RECURSIVE mode, run make command in DRYRUN mode
|
||||
define make
|
||||
$(eval cmd := $(1))
|
||||
$(eval dir := $(2))
|
||||
$(eval vars := $(3))
|
||||
$(eval file := $(4))
|
||||
$(if $(vars),$(eval MAKE_ARGS += $(foreach var,$(vars),$(if $($(var)),$(var)='$($(var))'))))
|
||||
$(if $(wildcard $(file)),$(eval MAKE_ARGS += $(shell cat $(file) |sed '/^$$/d; /^#/d; /=/!d; s/^[[\s\t]]*//; s/[[\s\t]]*=[[\s\t]]*/=/;' |awk -F '=' '{print $$1"='\''"$$2"'\''"}')))
|
||||
$(eval MAKE_DIR := $(if $(dir),-C $(dir)))
|
||||
$(eval MAKE_OLDFILE += $(filter-out $(MAKE_OLDFILE), $^))
|
||||
$(if $(filter $(VERBOSE),true),printf '${COLOR_GREEN}Running${COLOR_RESET} "'"make $(MAKE_ARGS) $(cmd)"'" $(if $(dir),${COLOR_BLUE}in folder${COLOR_RESET} $(dir) )\n')
|
||||
$(ECHO) $(MAKE) $(MAKE_DIR) $(patsubst %,-o %,$(MAKE_OLDFILE)) MAKE_OLDFILE="$(MAKE_OLDFILE)" $(MAKE_ARGS) $(cmd)
|
||||
$(if $(filter $(DRYRUN_RECURSIVE),true),$(MAKE) $(MAKE_DIR) $(patsubst %,-o %,$(MAKE_OLDFILE)) MAKE_OLDFILE="$(MAKE_OLDFILE)" DRYRUN=$(DRYRUN) RECURSIVE=$(RECURSIVE) $(MAKE_ARGS) $(cmd))
|
||||
endef
|
||||
|
||||
ifneq ($(MONOREPO),)
|
||||
ifneq ($(wildcard .gitrepo),)
|
||||
INFRA := ../infra
|
||||
MAKE_SUBDIRS := subrepo
|
||||
else
|
||||
INFRA := infra
|
||||
MAKE_SUBDIRS := monorepo
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(APP),)
|
||||
MAKE_SUBDIRS += apps $(foreach type,$(APP_TYPE),$(if $(wildcard $(MAKE_DIR)/apps/$(type)),apps/$(type)))
|
||||
endif
|
||||
|
||||
# include .env files
|
||||
include $(wildcard $(ENV_FILE))
|
||||
# include variables definitions
|
||||
include $(wildcard $(MAKE_DIR)/def.*.mk)
|
||||
include $(foreach subdir,$(MAKE_SUBDIRS),$(wildcard $(MAKE_DIR)/$(subdir)/def.mk $(MAKE_DIR)/$(subdir)/def.*.mk))
|
||||
|
||||
# set ENV=$(env) for each target ending with :$(env) and call $* target
|
||||
# set ../$(PARAMETERS)/$(env)/$(APP)/.env as last .env readed file to override values of .env file
|
||||
define TARGET:ENV
|
||||
.PHONY: $(TARGET)
|
||||
$(TARGET): $(ASSIGN_ENV)
|
||||
$(TARGET): $(ASSIGN_ENV_FILE)
|
||||
$(TARGET):
|
||||
$$(call make,$$*,,ENV_FILE)
|
||||
endef
|
||||
$(foreach env,$(ENV_LIST),$(eval TARGET := %\:$(env)) $(eval ASSIGN_ENV := ENV:=$(env)) $(eval ASSIGN_ENV_FILE := ENV_FILE+=$(wildcard ../$(PARAMETERS)/$(env)/$(APP)/.env)) $(eval $(TARGET:ENV)))
|
||||
|
||||
# set ENV=$(env) for each target ending with @$(env)
|
||||
$(foreach env,$(ENV_LIST),$(eval %@$(env): ENV:=$(env)))
|
||||
|
||||
# Accept arguments for CMDS targets
|
||||
ifneq ($(filter $(CMDS),$(firstword $(MAKECMDGOALS))),)
|
||||
# set $ARGS with following arguments
|
||||
ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
|
||||
ARGS := $(subst :,\:,$(ARGS))
|
||||
ARGS := $(subst &,\&,$(ARGS))
|
||||
# ...and turn them into do-nothing targets
|
||||
$(eval $(ARGS):;@:)
|
||||
endif
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
##
|
||||
# target .env:
|
||||
# update .env file when .env.dist file is newer
|
||||
.env: .env.dist
|
||||
$(call .env,,,$(wildcard ../$(PARAMETERS)/$(ENV)/$(APP)/.env .env.$(ENV)))
|
||||
|
||||
# include .env file
|
||||
-include .env
|
||||
|
||||
ifneq (,$(filter true,$(ENV_RESET)))
|
||||
env_reset := -i
|
||||
endif
|
||||
|
||||
SHELL:=/bin/bash
|
||||
|
||||
##
|
||||
# function .env
|
||||
## set .env file path and call .env_update function if .env.dist file exists
|
||||
# 1st arg: path to .env file to update, default to .env
|
||||
# 2nd arg: path to .env.dist file, default to .env.dist
|
||||
# 3rd arg: path to .env override files, default to .env.$(ENV)
|
||||
# if .env.dist exists then call .env_update function
|
||||
define .env
|
||||
$(eval env_file:=$(or $(1),.env))
|
||||
$(eval env_dist:=$(or $(2),$(env_file).dist))
|
||||
$(eval env_over:=$(or $(wildcard $(3)),$(wildcard $(env_file).$(ENV))))
|
||||
$(if $(wildcard $(env_dist)), $(call .env_update))
|
||||
endef
|
||||
|
||||
##
|
||||
# function .env_update
|
||||
## update .env file with vars from .env.dist not set in environment.
|
||||
## this function adds variables from the .env.dist to the .env file
|
||||
## and does substitution to replace variables with their value when
|
||||
## adding it to the .env. It reads variables first from environment,
|
||||
## make command line, .env override files and finish with .env.dist
|
||||
## to do the substitution. It does not write to .env file variables
|
||||
## that already exist in .env file or comes from system environment.
|
||||
# create the .env file
|
||||
# read environment variables
|
||||
# keep variables from .env.dist that does not exist in environment
|
||||
# add variables definition from .env override files at the beginning of the list
|
||||
# add variables definition from make command line at the beginning of the list
|
||||
# remove duplicate variables
|
||||
# keep variables that exists in .env.dist
|
||||
# keep variables that does not exist in .env
|
||||
# read variables definition in a subshell with multiline support
|
||||
# create a new environment (empty if $(ENV_RESET) is true)
|
||||
# read environment variables and keep only those existing in .env.dist
|
||||
# add .env overrides variables definition
|
||||
# add .env.dist variables definition
|
||||
# remove empty lines or comments
|
||||
# remove duplicate variables
|
||||
# replace variabless in stdin with their value from the new environment
|
||||
# remove residual empty lines or comments
|
||||
# sort alphabetically
|
||||
# add variables definition to the .env file
|
||||
define .env_update
|
||||
touch $(env_file)
|
||||
printenv \
|
||||
|awk -F '=' 'NR == FNR { if($$1 !~ /^(#|$$)/) { A[$$1]; next } } !($$1 in A)' - $(env_dist) \
|
||||
|cat $(env_over) - \
|
||||
|awk 'BEGIN {split("$(MAKECMDVARS)",vars," "); for (var in vars) {print vars[var]"="ENVIRON[vars[var]]};} {print}' \
|
||||
|awk -F '=' '!seen[$$1]++' \
|
||||
|awk -F '=' 'ARGV[1] == FILENAME { A[$$1]; next } ($$1 in A)' $(env_dist) - 2>/dev/null \
|
||||
|awk -F '=' 'ARGV[1] == FILENAME { A[$$1]; next } !($$1 in A)' $(env_file) - 2>/dev/null \
|
||||
|(IFS=$$'\n'; \
|
||||
env $(env_reset) \
|
||||
$$(env |awk -F '=' 'NR == FNR { if($$1 !~ /^(#|$$)/) { A[$$1]; next } } ($$1 in A)' $(env_dist) - \
|
||||
|cat - $(env_over) \
|
||||
|cat - $(env_dist) \
|
||||
|sed -e /^$$/d -e /^#/d \
|
||||
|awk -F '=' '!seen[$$1]++') \
|
||||
awk '{while(match($$0,"[$$]{[^}]*}")) {var=substr($$0,RSTART+2,RLENGTH-3);gsub("[$$]{"var"}",ENVIRON[var])} print}') \
|
||||
|sed -e /^$$/d -e /^#/d \
|
||||
|sort \
|
||||
>> $(env_file)
|
||||
endef
|
||||
@@ -0,0 +1,39 @@
|
||||
.DEFAULT_GOAL := help
|
||||
COLOR_RESET ?= \033[0m
|
||||
COLOR_GREEN ?= \033[32m
|
||||
COLOR_BROWN ?= \033[33m
|
||||
COLOR_BLUE ?= \033[36m
|
||||
|
||||
##
|
||||
# HELP
|
||||
|
||||
.PHONY: help
|
||||
help: usage blank1 target blank2 context ## This help
|
||||
|
||||
.PHONY: usage
|
||||
usage:
|
||||
printf "${COLOR_BROWN}Usage:${COLOR_RESET}\n"
|
||||
printf "make [target]\n"
|
||||
|
||||
.PHONY: blank1 blank2
|
||||
blank1 blank2:
|
||||
printf "\n"
|
||||
|
||||
.PHONY: target
|
||||
## Show available targets
|
||||
target:
|
||||
printf "${COLOR_BROWN}Targets:${COLOR_RESET}\n"
|
||||
awk 'BEGIN {FS = ":.*?## "}; $$0 ~ /^[a-zA-Z_-]+:.*?## .*$$/ {printf "${COLOR_BLUE}%-30s${COLOR_RESET} %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||
|
||||
.PHONY: context
|
||||
## Show current context
|
||||
context:
|
||||
printf "${COLOR_BROWN}Context:${COLOR_RESET}\n"
|
||||
$(MAKE) $(CONTEXT)
|
||||
|
||||
.PHONY: $(CONTEXT)
|
||||
$(CONTEXT):
|
||||
@printf "${COLOR_BLUE}%-30s${COLOR_RESET} ${COLOR_GREEN}%s${COLOR_RESET}\n" $@ "$($@)"
|
||||
|
||||
.PHONY: print-%
|
||||
print-%: ; @printf "${COLOR_BLUE}%-30s${COLOR_RESET} ${COLOR_GREEN}%s${COLOR_RESET}\n" $* "$($*)"
|
||||
@@ -0,0 +1,5 @@
|
||||
MAKE_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
|
||||
MAKE_FILES := env.mk def.mk
|
||||
include $(wildcard $(patsubst %,$(MAKE_DIR)/%,$(MAKE_FILES))) $(filter-out $(wildcard $(patsubst %,$(MAKE_DIR)/%,include.mk def.*.mk $(MAKE_FILES))),$(wildcard $(MAKE_DIR)/*.mk))
|
||||
include $(foreach subdir,$(MAKE_SUBDIRS),$(filter-out $(wildcard $(MAKE_DIR)/$(subdir)/def.mk $(MAKE_DIR)/$(subdir)/def.*.mk),$(wildcard $(MAKE_DIR)/$(subdir)/*.mk)))
|
||||
include $(wildcard *.mk docker/*.mk stack/*.mk)
|
||||
@@ -0,0 +1,8 @@
|
||||
##
|
||||
# INFRA
|
||||
|
||||
.PHONY: infra-%
|
||||
infra-%: ;
|
||||
ifneq ($(wildcard $(INFRA)),)
|
||||
$(call make,$*,$(INFRA))
|
||||
endif
|
||||
@@ -0,0 +1,67 @@
|
||||
##
|
||||
# COMMON
|
||||
|
||||
.PHONY: build
|
||||
build: $(APPS) ## Build applications
|
||||
|
||||
.PHONY: build@%
|
||||
build@%: $(APPS);
|
||||
|
||||
.PHONY: clean
|
||||
clean: $(APPS) ## Clean applications
|
||||
|
||||
.PHONY: clean@%
|
||||
clean@%: $(APPS);
|
||||
|
||||
.PHONY: config
|
||||
config: $(APPS)
|
||||
|
||||
.PHONY: copy
|
||||
copy:
|
||||
$(foreach app,$(APPS),$(foreach file,$(ARGS),$(if $(wildcard $(file)),$(ECHO) $(if $(filter LINUX,$(HOST_SYSTEM)),cp -a --parents $(file) $(app)/,rsync -a $(file) $(app)/$(file)) &&)) true &&) true
|
||||
|
||||
.PHONY: deploy
|
||||
deploy: $(APPS) ## Deploy applications
|
||||
|
||||
.PHONY: deploy@%
|
||||
deploy@%: $(APPS);
|
||||
|
||||
.PHONY: down
|
||||
down: $(APPS) ## Remove application dockers
|
||||
|
||||
.PHONY: ps
|
||||
ps: $(APPS)
|
||||
|
||||
.PHONY: rebuild
|
||||
rebuild: $(APPS) ## Rebuild applications
|
||||
|
||||
.PHONY: recreate
|
||||
recreate: $(APPS) ## Recreate applications
|
||||
|
||||
.PHONY: reinstall
|
||||
reinstall: $(APPS) ## Reinstall applications
|
||||
|
||||
.PHONY: restart
|
||||
restart: $(APPS) ## Restart applications
|
||||
|
||||
.PHONY: start
|
||||
start: $(APPS) ## Start applications
|
||||
|
||||
.PHONY: stop
|
||||
stop: $(APPS) ## Stop applications
|
||||
|
||||
.PHONY: tests
|
||||
tests: $(APPS) ## Test applications
|
||||
|
||||
.PHONY: up
|
||||
up: $(APPS) ## Create application dockers
|
||||
|
||||
.PHONY: $(APPS)
|
||||
$(APPS):
|
||||
$(if $(wildcard $@/Makefile), \
|
||||
$(call make,-o install-infra $(patsubst apps-%,%,$(MAKECMDGOALS)) STATUS=0,$(patsubst %/,%,$@),ENV_SUFFIX), \
|
||||
printf "${COLOR_BROWN}WARNING${COLOR_RESET}: ${COLOR_GREEN}no app available in folder${COLOR_RESET} $@.\n" >&2)
|
||||
|
||||
# run targets in $(APPS)
|
||||
.PHONY: apps-%
|
||||
apps-%: $(APPS) ; ## run % targets in $(APPS)
|
||||
@@ -0,0 +1,15 @@
|
||||
ifneq (,$(filter true,$(DRONE)))
|
||||
# limit to APPS impacted by the commit
|
||||
ifneq (,$(filter $(DRONE_BUILD_EVENT),pull_request push))
|
||||
COMMIT_AFTER := $(DRONE_COMMIT_AFTER)
|
||||
COMMIT_BEFORE := $(if $(filter 0000000000000000000000000000000000000000,$(DRONE_COMMIT_BEFORE)),upstream/master,$(DRONE_COMMIT_BEFORE))
|
||||
endif
|
||||
ifneq (,$(filter $(DRONE_BUILD_EVENT),tag))
|
||||
COMMIT_AFTER := $(DRONE_TAG)
|
||||
COMMIT_BEFORE := $(shell git describe --abbrev=0 --tags $(DRONE_TAG)^)
|
||||
endif
|
||||
APPS_IMPACTED := $(shell git diff --name-only $(COMMIT_BEFORE) $(COMMIT_AFTER) 2>/dev/null |awk -F '/' 'NF>1 && !seen[$$1]++ {print $$1}')
|
||||
# prevent drone to make down in infra
|
||||
APPS := $(if $(filter-out down,$(MAKECMDGOALS)),$(filter $(INFRA),$(APPS_IMPACTED))) $(sort $(filter-out $(DIRS) $(INFRA),$(APPS_IMPACTED)))
|
||||
CONTEXT += DRONE_BRANCH DRONE_BUILD_EVENT DRONE_BUILD_NUMBER DRONE_COMMIT_AFTER DRONE_COMMIT_AUTHOR DRONE_COMMIT_AUTHOR_EMAIL DRONE_COMMIT_BEFORE DRONE_COMMIT_REF GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
|
||||
endif
|
||||
@@ -0,0 +1,8 @@
|
||||
APPS ?= $(INFRA) $(sort $(filter-out $(DIRS) $(INFRA), $(patsubst %/,%,$(wildcard */)) ))
|
||||
APPS_NAME ?= $(foreach app,$(APPS),$(or $(shell awk -F '=' '$$1 == "APP" {print $$2}' $(or $(wildcard $(app)/.env),$(wildcard $(app)/.env.$(ENV)),$(app)/.env.dist) 2>/dev/null),$(app)))
|
||||
CMDS += copy master-tag release release-check release-create release-finish subrepo-push update-subrepo
|
||||
CONTEXT += APPS APPS_NAME ENV RELEASE_INSTALL
|
||||
DIRS ?= $(MAKE_DIR) $(PARAMETERS) $(SHARED)
|
||||
RELEASE_UPGRADE ?= $(filter v%, $(shell git tag -l |sort -V |awk '/$(RELEASE_INSTALL)/,0'))
|
||||
RELEASE_VERSION ?= $(firstword $(subst -, ,$(VERSION)))
|
||||
SUBREPOS ?= $(filter subrepo/%, $(shell git remote))
|
||||
@@ -0,0 +1,85 @@
|
||||
##
|
||||
# GIT
|
||||
|
||||
## Check if monorepo is up to date with subrepo. subrepo-push saves the parent commit in .gitrepo
|
||||
.PHONY: git-diff-subrepo
|
||||
git-diff-subrepo: infra-base subrepo-check
|
||||
## Get parent commit in .gitrepo : awk '$1 == "parent" {print $3}' subrepo/.gitrepo
|
||||
## Get child of parent commit : git rev-list --ancestry-path parent..HEAD |tail -n 1
|
||||
## Compare child commit with our tree : git diff --quiet child -- subrepo
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval DIFF = $(shell $(call exec,git diff --quiet $(shell $(call exec,git rev-list --ancestry-path $(shell awk '$$1 == "parent" {print $$3}' $(SUBREPO)/.gitrepo)..HEAD |tail -n 1)) -- $(SUBREPO); echo $$?)) )
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
|
||||
.PHONY: git-fetch-subrepo
|
||||
git-fetch-subrepo: infra-base subrepo-check
|
||||
$(call exec,git fetch --prune $(REMOTE))
|
||||
|
||||
.PHONY: git-stash
|
||||
git-stash: infra-base git-status
|
||||
if [ ! $(STATUS) -eq 0 ]; then \
|
||||
$(call exec,git stash); \
|
||||
fi
|
||||
|
||||
.PHONY: git-status
|
||||
git-status: infra-base
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval STATUS := $(shell $(call exec,git status -uno --porcelain 2>/dev/null |wc -l)))
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
|
||||
.PHONY: git-unstash
|
||||
git-unstash: infra-base
|
||||
$(eval STATUS ?= 0)
|
||||
if [ ! $(STATUS) -eq 0 ]; then \
|
||||
$(call exec,git stash pop); \
|
||||
fi
|
||||
|
||||
# Create branch $(BRANCH) from upstream/$* branch
|
||||
.PHONY: branch-create-upstream-%
|
||||
branch-create-upstream-%: infra-base update-upstream
|
||||
$(call exec,git fetch --prune upstream)
|
||||
$(call exec,git rev-parse --verify $(BRANCH) >/dev/null 2>&1 && echo Unable to create $(BRANCH). || git branch $(BRANCH) upstream/$*)
|
||||
$(call exec,[ $$(git ls-remote --heads upstream $(BRANCH) |wc -l) -eq 0 ] && git push upstream $(BRANCH) || echo Unable to create branch $(BRANCH) on remote upstream.)
|
||||
$(call exec,git checkout $(BRANCH))
|
||||
|
||||
# Delete branch $(BRANCH)
|
||||
.PHONY: branch-delete
|
||||
branch-delete: infra-base update-upstream
|
||||
$(call exec,git rev-parse --verify $(BRANCH) >/dev/null 2>&1 && git branch -d $(BRANCH) || echo Unable to delete branch $(BRANCH).)
|
||||
$(foreach remote,upstream, $(call exec,[ $$(git ls-remote --heads $(remote) $(BRANCH) |wc -l) -eq 1 ] && git push $(remote) :$(BRANCH) || echo Unable to delete branch $(BRANCH) on remote $(remote).) &&) true
|
||||
|
||||
# Merge branch $(BRANCH) into upstream/$* branch
|
||||
.PHONY: branch-merge-upstream-%
|
||||
branch-merge-upstream-%: infra-base update-upstream
|
||||
$(call exec,git rev-parse --verify $(BRANCH) >/dev/null 2>&1)
|
||||
$(call exec,git checkout $(BRANCH))
|
||||
$(call exec,git pull --ff-only upstream $(BRANCH))
|
||||
$(call exec,git push upstream $(BRANCH))
|
||||
$(call exec,git checkout $*)
|
||||
$(call exec,git pull --ff-only upstream $*)
|
||||
$(call exec,git merge --no-ff --no-edit $(BRANCH))
|
||||
$(call exec,git push upstream $*)
|
||||
|
||||
# Create $(TAG) tag to reference upstream/$* branch
|
||||
.PHONY: tag-create-upstream-%
|
||||
tag-create-upstream-%: infra-base update-upstream
|
||||
ifneq ($(words $(TAG)),0)
|
||||
$(call exec,git checkout $*)
|
||||
$(call exec,git pull --tags --prune upstream $*)
|
||||
$(call sed,s/^##\? $(TAG).*/## $(TAG) - $(shell date +%Y-%m-%d)/,CHANGELOG.md)
|
||||
$(call exec,[ $$(git diff CHANGELOG.md 2>/dev/null |wc -l) -eq 0 ] || git commit -m "$$(cat CHANGELOG.md |sed -n '\''/$(TAG)/,/^$$/{s/##\(.*\)/release\1\n/;p;}'\'')" CHANGELOG.md)
|
||||
$(call exec,[ $$(git tag -l $(TAG) |wc -l) -eq 0 ] || git tag -d $(TAG))
|
||||
$(call exec,git tag $(TAG))
|
||||
$(call exec,[ $$(git ls-remote --tags upstream $(TAG) |wc -l) -eq 0 ] || git push upstream :refs/tags/$(TAG))
|
||||
$(call exec,git push --tags upstream $*)
|
||||
endif
|
||||
|
||||
# Merge tag $(TAG) into upstream/$* branch
|
||||
.PHONY: tag-merge-upstream-%
|
||||
tag-merge-upstream-%: infra-base update-upstream
|
||||
ifneq ($(words $(TAG)),0)
|
||||
$(call exec,git fetch --tags -u --prune upstream $*:$*)
|
||||
$(call exec,git checkout $*)
|
||||
$(call exec,git merge --ff --no-edit $(TAG))
|
||||
$(call exec,git push upstream $*)
|
||||
endif
|
||||
@@ -0,0 +1,11 @@
|
||||
##
|
||||
# INSTALL
|
||||
|
||||
.PHONY: install-infra
|
||||
install-infra: infra-install
|
||||
|
||||
.PHONY: install-$(SHARED)
|
||||
install-$(SHARED): $(SHARED)
|
||||
|
||||
$(SHARED):
|
||||
$(ECHO) mkdir -p $(SHARED)
|
||||
@@ -0,0 +1,35 @@
|
||||
##
|
||||
# RELEASE
|
||||
|
||||
.PHONY: release
|
||||
release: release-create # Create release [version]
|
||||
|
||||
.PHONY: release-check
|
||||
release-check:
|
||||
ifneq ($(words $(ARGS)),0)
|
||||
$(eval RELEASE_VERSION := $(word 1, $(ARGS)))
|
||||
$(eval RELEASE_BRANCH := release/$(RELEASE_VERSION))
|
||||
else
|
||||
ifneq ($(findstring $(firstword $(subst /, ,$(BRANCH))),release),)
|
||||
$(eval RELEASE_BRANCH := $(BRANCH))
|
||||
$(eval RELEASE_VERSION := $(word 2, $(subst /, ,$(BRANCH))))
|
||||
endif
|
||||
endif
|
||||
$(if $(filter VERSION=%,$(MAKEFLAGS)), $(eval RELEASE_VERSION:=$(VERSION)) $(eval RELEASE_BRANCH := release/$(RELEASE_VERSION)))
|
||||
$(if $(findstring $(firstword $(subst /, ,$(RELEASE_BRANCH))),release),,$(error Please provide a VERSION or a release BRANCH))
|
||||
|
||||
.PHONY: release-create
|
||||
release-create: release-check git-stash ## Create release [version]
|
||||
$(call make,branch-create-upstream-develop BRANCH=$(RELEASE_BRANCH))
|
||||
$(call make,git-unstash,,STATUS)
|
||||
|
||||
.PHONY: release-finish
|
||||
release-finish: release-check git-stash ## Finish release [version]
|
||||
$(call make,branch-merge-upstream-master BRANCH=$(RELEASE_BRANCH))
|
||||
$(call make,update-subrepos)
|
||||
$(call make,tag-create-upstream-master TAG=$(RELEASE_VERSION))
|
||||
$(call make,subrepos-tag-create-master TAG=$(RELEASE_VERSION))
|
||||
$(call make,tag-merge-upstream-develop TAG=$(RELEASE_VERSION))
|
||||
$(call make,branch-delete BRANCH=$(RELEASE_BRANCH))
|
||||
$(call make,subrepos-branch-delete BRANCH=$(RELEASE_BRANCH))
|
||||
$(call make,git-unstash,,STATUS)
|
||||
@@ -0,0 +1,59 @@
|
||||
##
|
||||
# SUBREPO
|
||||
|
||||
.PHONY: subrepo-check
|
||||
subrepo-check:
|
||||
ifeq ($(words $(ARGS)), 0)
|
||||
ifeq ($(words $(SUBREPO)), 0)
|
||||
$(error Please provide a SUBREPO)
|
||||
endif
|
||||
endif
|
||||
$(eval SUBREPO ?= $(word 1, $(ARGS)))
|
||||
$(eval REMOTE := subrepo/$(SUBREPO))
|
||||
|
||||
## Delete branch $(BRANCH) on $(SUBREPO) remote
|
||||
.PHONY: subrepo-branch-delete
|
||||
subrepo-branch-delete: infra-base subrepo-check
|
||||
ifneq ($(words $(BRANCH)),0)
|
||||
$(call exec,[ $$(git ls-remote --heads $(REMOTE) $(BRANCH) |wc -l) -eq 1 ] && git push $(REMOTE) :$(BRANCH) || echo Unable to delete branch $(BRANCH) on remote $(REMOTE).)
|
||||
endif
|
||||
|
||||
.PHONY: subrepo-tag-create-%
|
||||
subrepo-tag-create-%: infra-base subrepo-check git-fetch-subrepo ## Create $(TAG) tag to reference $(REMOTE)/$* branch
|
||||
ifneq ($(words $(TAG)),0)
|
||||
$(call exec,[ $$(git ls-remote --tags $(REMOTE) $(TAG) |wc -l) -eq 0 ] || git push $(REMOTE) :refs/tags/$(TAG))
|
||||
$(call exec,git push $(REMOTE) refs/remotes/subrepo/$(SUBREPO)/$*:refs/tags/$(TAG))
|
||||
endif
|
||||
|
||||
## Push to subrepo.
|
||||
.PHONY: subrepo-push
|
||||
subrepo-push: infra-base subrepo-check git-fetch-subrepo git-diff-subrepo
|
||||
# update .gitrepo only on master branch
|
||||
ifeq ($(BRANCH),master)
|
||||
$(eval UPDATE_SUBREPO_OPTIONS += -u)
|
||||
endif
|
||||
# if release|story|hotfix branch, delete remote branch before push and recreate it from master
|
||||
ifneq ($(findstring $(firstword $(subst /, ,$(BRANCH))),release story hotfix),)
|
||||
$(eval DRYRUN_IGNORE := true)
|
||||
$(eval DELETE = $(shell $(call exec,git ls-remote --heads $(REMOTE) $(BRANCH) |wc -l)) )
|
||||
$(eval DRYRUN_IGNORE := false)
|
||||
else
|
||||
$(eval DELETE = 0)
|
||||
endif
|
||||
if [ $(DIFF) -eq 0 ]; then \
|
||||
echo subrepo $(SUBREPO) already up to date.; \
|
||||
else \
|
||||
if [ $(DELETE) -eq 1 ]; then \
|
||||
$(call exec,git push $(REMOTE) :$(BRANCH)); \
|
||||
$(call exec,git push $(REMOTE) refs/remotes/$(REMOTE)/master:refs/heads/$(BRANCH)); \
|
||||
fi; \
|
||||
$(call exec,git subrepo fetch $(SUBREPO) -b $(BRANCH)); \
|
||||
$(call exec,git subrepo push $(SUBREPO) -b $(BRANCH) $(UPDATE_SUBREPO_OPTIONS)); \
|
||||
$(call exec,git subrepo clean $(SUBREPO)); \
|
||||
fi
|
||||
|
||||
.PHONY: subrepos-branch-delete
|
||||
subrepos-branch-delete: $(APPS) ;
|
||||
|
||||
.PHONY: subrepos-tag-create-%
|
||||
subrepos-tag-create-%: $(APPS) ;
|
||||
@@ -0,0 +1,47 @@
|
||||
##
|
||||
# UPDATE
|
||||
|
||||
## Update /etc/hosts
|
||||
.PHONY: update-hosts
|
||||
update-hosts:
|
||||
ifneq (,$(filter $(ENV),local))
|
||||
cat */.env 2>/dev/null |grep -Eo 'urlprefix-[^/]+' |sed 's/urlprefix-//' |while read host; do grep $$host /etc/hosts >/dev/null 2>&1 || { echo "Adding $$host to /etc/hosts"; echo 127.0.0.1 $$host |$(ECHO) sudo tee -a /etc/hosts >/dev/null; }; done
|
||||
endif
|
||||
|
||||
.PHONY: update-$(PARAMETERS)
|
||||
update-$(PARAMETERS): $(PARAMETERS)
|
||||
|
||||
$(PARAMETERS): SSH_PUBLIC_HOST_KEYS := $(PARAMETERS_REMOTE_HOST) $(SSH_BASTION_HOSTNAME) $(SSH_REMOTE_HOSTS)
|
||||
$(PARAMETERS): MAKE_VARS += SSH_BASTION_HOSTNAME SSH_BASTION_USERNAME SSH_PRIVATE_IP_RANGE SSH_PUBLIC_HOST_KEYS
|
||||
$(PARAMETERS): infra-base
|
||||
$(call exec,[ -d $(PARAMETERS) ] && cd $(PARAMETERS) && git pull --quiet || git clone --quiet $(GIT_PARAMETERS_REPOSITORY))
|
||||
|
||||
## Update release version number in .env
|
||||
.PHONY: update-release
|
||||
update-release:
|
||||
$(ECHO) awk -v s=RELEASE_INSTALL=$(RELEASE_VERSION) '/^RELEASE_INSTALL=/{$$0=s;f=1} {a[++n]=$$0} END{if(!f)a[++n]=s;for(i=1;i<=n;i++)print a[i]>ARGV[1]}' .env
|
||||
|
||||
## Update remotes
|
||||
.PHONY: update-remotes
|
||||
update-remotes: infra-base
|
||||
$(call exec,git fetch --all --prune --tags -u)
|
||||
|
||||
.PHONY: update-remote-%
|
||||
update-remote-%: infra-base
|
||||
$(call exec,git fetch --prune --tags -u $*)
|
||||
|
||||
## Update subrepos
|
||||
.PHONY: update-subrepos
|
||||
update-subrepos: infra-base git-stash $(APPS) git-unstash ## Update subrepos
|
||||
$(call exec,git push upstream $(BRANCH))
|
||||
|
||||
.PHONY: update-subrepo-%
|
||||
update-subrepo-%:
|
||||
$(if $(wildcard $*/Makefile),$(call make,update-subrepo,$*))
|
||||
|
||||
.PHONY: update-upstream
|
||||
update-upstream: infra-base .git/refs/remotes/upstream/master
|
||||
$(call exec,git fetch --tags upstream)
|
||||
|
||||
.git/refs/remotes/upstream/master: infra-base
|
||||
$(call exec,git remote add upstream $(GIT_UPSTREAM_REPOSITORY) 2>/dev/null ||:)
|
||||
@@ -0,0 +1,9 @@
|
||||
##
|
||||
# UPGRADE
|
||||
|
||||
.PHONY: upgrade
|
||||
upgrade: $(patsubst %,upgrade-from-release-%,$(RELEASE_UPGRADE)) update-release ## Update monorepo version
|
||||
|
||||
.PHONY: upgrade-from-release-%
|
||||
upgrade-from-release-%:
|
||||
# echo "Upgrading from release: $*"
|
||||
@@ -0,0 +1,23 @@
|
||||
## Update subrepos
|
||||
.PHONY: update-subrepo update-subrepos
|
||||
update-subrepo update-subrepos: bootstrap-git git-stash subrepos-push git-unstash
|
||||
|
||||
.PHONY: subrepos-branch-delete
|
||||
subrepos-branch-delete:
|
||||
$(call make,subrepo-branch-delete,..,SUBREPO BRANCH)
|
||||
|
||||
.PHONY: subrepos-tag-create-%
|
||||
subrepos-tag-create-%:
|
||||
$(call make,subrepo-tag-create-$*,..,SUBREPO TAG)
|
||||
|
||||
.PHONY: subrepos-push
|
||||
subrepos-push:
|
||||
$(call make,subrepo-push,..,SUBREPO BRANCH)
|
||||
|
||||
.PHONY: git-stash
|
||||
git-stash:
|
||||
$(call make,git-stash,..)
|
||||
|
||||
.PHONY: git-unstash
|
||||
git-unstash:
|
||||
$(call make,git-unstash,..)
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
################################################################################
|
||||
#
|
||||
# This file contains various utility macros and variables used about
|
||||
# everywhere in make constructs.
|
||||
#
|
||||
################################################################################
|
||||
# source : https://raw.githubusercontent.com/buildroot/buildroot/master/support/misc/utils.mk
|
||||
|
||||
# Strip quotes and then whitespaces
|
||||
qstrip = $(strip $(subst ",,$(1)))
|
||||
#"))
|
||||
|
||||
# Variables for use in Make constructs
|
||||
comma := ,
|
||||
empty :=
|
||||
space := $(empty) $(empty)
|
||||
|
||||
# make 4.3:
|
||||
# https://lwn.net/Articles/810071/
|
||||
# Number signs (#) appearing inside a macro reference or function invocation
|
||||
# no longer introduce comments and should not be escaped with backslashes:
|
||||
# thus a call such as:
|
||||
# foo := $(shell echo '#')
|
||||
# is legal. Previously the number sign needed to be escaped, for example:
|
||||
# foo := $(shell echo '\#')
|
||||
# Now this latter will resolve to "\#". If you want to write makefiles
|
||||
# portable to both versions, assign the number sign to a variable:
|
||||
# H := \#
|
||||
# foo := $(shell echo '$H')
|
||||
SHARP_SIGN := \#
|
||||
|
||||
# Case conversion macros. This is inspired by the 'up' macro from gmsl
|
||||
# (http://gmsl.sf.net). It is optimised very heavily because these macros
|
||||
# are used a lot. It is about 5 times faster than forking a shell and tr.
|
||||
#
|
||||
# The caseconvert-helper creates a definition of the case conversion macro.
|
||||
# After expansion by the outer $(eval ), the UPPERCASE macro is defined as:
|
||||
# $(strip $(eval __tmp := $(1)) $(eval __tmp := $(subst a,A,$(__tmp))) ... )
|
||||
# In other words, every letter is substituted one by one.
|
||||
#
|
||||
# The caseconvert-helper allows us to create this definition out of the
|
||||
# [FROM] and [TO] lists, so we don't need to write down every substition
|
||||
# manually. The uses of $ and $$ quoting are chosen in order to do as
|
||||
# much expansion as possible up-front.
|
||||
#
|
||||
# Note that it would be possible to conceive a slightly more optimal
|
||||
# implementation that avoids the use of __tmp, but that would be even
|
||||
# more unreadable and is not worth the effort.
|
||||
|
||||
[FROM] := a b c d e f g h i j k l m n o p q r s t u v w x y z - .
|
||||
[TO] := A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ _
|
||||
|
||||
define caseconvert-helper
|
||||
$(1) = $$(strip \
|
||||
$$(eval __tmp := $$(1))\
|
||||
$(foreach c, $(2),\
|
||||
$$(eval __tmp := $$(subst $(word 1,$(subst :, ,$c)),$(word 2,$(subst :, ,$c)),$$(__tmp))))\
|
||||
$$(__tmp))
|
||||
endef
|
||||
|
||||
$(eval $(call caseconvert-helper,UPPERCASE,$(join $(addsuffix :,$([FROM])),$([TO]))))
|
||||
$(eval $(call caseconvert-helper,LOWERCASE,$(join $(addsuffix :,$([TO])),$([FROM]))))
|
||||
|
||||
# Reverse the orders of words in a list. Again, inspired by the gmsl
|
||||
# 'reverse' macro.
|
||||
reverse = $(if $(1),$(call reverse,$(wordlist 2,$(words $(1)),$(1))) $(firstword $(1)))
|
||||
|
||||
# Sanitize macro cleans up generic strings so it can be used as a filename
|
||||
# and in rules. Particularly useful for VCS version strings, that can contain
|
||||
# slashes, colons (OK in filenames but not in rules), and spaces.
|
||||
sanitize = $(subst $(space),_,$(subst :,_,$(subst /,_,$(strip $(1)))))
|
||||
|
||||
# MESSAGE Macro -- display a message in bold type
|
||||
MESSAGE = echo "$(TERM_BOLD)>>> $($(PKG)_NAME) $($(PKG)_VERSION) $(call qstrip,$(1))$(TERM_RESET)"
|
||||
TERM_BOLD := $(shell tput smso 2>/dev/null)
|
||||
TERM_RESET := $(shell tput rmso 2>/dev/null)
|
||||
|
||||
# Utility functions for 'find'
|
||||
# findfileclauses(filelist) => -name 'X' -o -name 'Y'
|
||||
findfileclauses = $(call notfirstword,$(patsubst %,-o -name '%',$(1)))
|
||||
# finddirclauses(base, dirlist) => -path 'base/dirX' -o -path 'base/dirY'
|
||||
finddirclauses = $(call notfirstword,$(patsubst %,-o -path '$(1)/%',$(2)))
|
||||
|
||||
# Miscellaneous utility functions
|
||||
# notfirstword(wordlist): returns all but the first word in wordlist
|
||||
notfirstword = $(wordlist 2,$(words $(1)),$(1))
|
||||
|
||||
# build a comma-separated list of quoted items, from a space-separated
|
||||
# list of unquoted items: a b c d --> "a", "b", "c", "d"
|
||||
make-comma-list = $(subst $(space),$(comma)$(space),$(patsubst %,"%",$(strip $(1))))
|
||||
|
||||
# Needed for the foreach loops to loop over the list of hooks, so that
|
||||
# each hook call is properly separated by a newline.
|
||||
define sep
|
||||
|
||||
|
||||
endef
|
||||
|
||||
PERCENT = %
|
||||
QUOTE = '
|
||||
# ' # Meh... syntax-highlighting
|
||||
|
||||
# This macro properly escapes a command string, then prints it with printf:
|
||||
#
|
||||
# - first, backslash '\' are self-escaped, so that they do not escape
|
||||
# the following char and so that printf properly outputs a backslash;
|
||||
#
|
||||
# - next, single quotes are escaped by closing an existing one, adding
|
||||
# an escaped one, and re-openning a new one (see below for the reason);
|
||||
#
|
||||
# - then '%' signs are self-escaped so that the printf does not interpret
|
||||
# them as a format specifier, in case the variable contains an actual
|
||||
# printf with a format;
|
||||
#
|
||||
# - finally, $(sep) is replaced with the literal '\n' so that make does
|
||||
# not break on the so-expanded variable, but so that the printf does
|
||||
# correctly output an LF.
|
||||
#
|
||||
# Note: this must be escaped in this order to avoid over-escaping the
|
||||
# previously escaped elements.
|
||||
#
|
||||
# Once everything has been escaped, it is passed between single quotes
|
||||
# (that's why the single-quotes are escaped they way they are, above,
|
||||
# and why the dollar sign is not escaped) to printf(1). A trailing
|
||||
# newline is apended, too.
|
||||
#
|
||||
# Note: leading or trailing spaces are *not* stripped.
|
||||
#
|
||||
define PRINTF
|
||||
printf '$(subst $(sep),\n,\
|
||||
$(subst $(PERCENT),$(PERCENT)$(PERCENT),\
|
||||
$(subst $(QUOTE),$(QUOTE)\$(QUOTE)$(QUOTE),\
|
||||
$(subst \,\\,$(1)))))\n'
|
||||
endef
|
||||
Reference in New Issue
Block a user