Makefile 将目标变量从模式匹配传递到静态
我正在编写一个Makefile来包装弹性beanstalk应用程序在多个环境中的部署。这是我第一次编写“高级”makefile,我遇到了一些麻烦 我的目标如下:Makefile 将目标变量从模式匹配传递到静态,makefile,gnu-make,Makefile,Gnu Make,我正在编写一个Makefile来包装弹性beanstalk应用程序在多个环境中的部署。这是我第一次编写“高级”makefile,我遇到了一些麻烦 我的目标如下: makedeploy本身应该使用ENVIRONMENT=$(USER)和ENV\u TYPE=staging进行部署 可以通过环境变量设置要部署到的环境。如果ENVIRONMENT=production则ENV_TYPE=production,否则ENV_TYPE=staging 作为设置环境变量的简写,可以在deploy目标后面加上-
makedeploy
本身应该使用ENVIRONMENT=$(USER)
和ENV\u TYPE=staging
进行部署ENVIRONMENT=production
则ENV_TYPE=production
,否则ENV_TYPE=staging
deploy
目标后面加上-
和环境名称。例如:make-deploy-production
ENVIRONMENT = $(USER)
ifeq ($ENVIRONMENT, production)
ENV_TYPE=production
else
ENV_TYPE=staging
endif
DOCKER_TAG ?= $(USER)
CONTAINER_PORT ?= 8000
ES_HOST = logging-ingest.$(ENV_TYPE).internal:80
.PHONY: deploy
deploy:
-pip install --upgrade awsebcli
sed "s/<<ES_HOST>>/$(ES_HOST)/" < 01-filebeat.template > .ebextensions/01-filebeat.config
sed "s/<<DOCKER_TAG>>/$(DOCKER_TAG)/" < Dockerrun.template | sed "s/<<CONTAINER_PORT>>/$(CONTAINER_PORT)/" > Dockerrun.aws.json
eb labs cleanup-versions --num-to-leave 10 --older-than 5 --force -v --region us-west-2
eb deploy -v coolapp-$(ENVIRONMENT)
.PHONY: deploy-%
deploy-%: ENVIRONMENT=$*
deploy-%: deploy
@echo # Noop required
.PHONY: deploy-production
deploy-production: ENVIRONMENT=production
deploy-production: ENV_TYPE=production
deploy-production: deploy
@echo # Noop required
期望输出:
18:42 $ make -n deploy-staging
pip install --upgrade awsebcli
sed "s/<<ES_HOST>>/logging-ingest.staging.internal:80/" < 01-filebeat.template > .ebextensions/01-filebeat.config
sed "s/<<DOCKER_TAG>>/schultjo/" < Dockerrun.template | sed "s/<<CONTAINER_PORT>>/8000/" > Dockerrun.aws.json
eb labs cleanup-versions --num-to-leave 10 --older-than 5 --force -v --region us-west-2
eb deploy -v coolapp-staging
echo # Noop required
当我运行makeproduction
时,如果围绕ENV_TYPE
定义的语句不再运行,则看起来像是。以下是我的实际输出:
12:50 $ make -n deploy-production
/Applications/Xcode.app/Contents/Developer/usr/bin/make --no-print-directory ENVIRONMENT=production deploy
echo production
echo staging
echo logging-ingest.staging.internal:80
最后两行应该是production
,而不是staging
,这意味着我的条件有问题,但我没有在它工作时编辑早期版本中的条件,所以我是一个很困惑的人。如果使用手动设置的ENVIRONMENT
调用make(例如ENVIRONMENT=production make deploy
),也会发生相同的错误。由于与RenaudPacalet的对话,我已经了解到,我的方法之所以有效,主要是因为deploy-%
规则中定义的变量在任何地方都没有使用,而是在配方中使用……在配方中,它们会在传递到shell之前延迟展开。这使我可以在变量定义中使用$*
,因为变量定义直到第二阶段才展开,此时$*
实际上有一个值
设置ENV_TYPE
的方法使用patsubst
的技巧,通过从$ENVIRONMENT
的内容中去掉“production”
一词,为if
生成条件;在此上下文中,空字符串选择else
大小写。因此,如果$ENVIRONMENT
正好等于“production”
,则patsubst
生成一个空字符串,if
计算结果为production
,否则计算结果为staging
对于deploy-
,在底部有一个显式规则,因为该目标会调用一些疯狂的隐式模式规则,试图编译deploy-.o
发现这也使我考虑了可能出现的其他错误情况,所以前几行定义了一个函数,以确保如果用户同时指定<代码>环境= x并使用后缀<代码> y>代码>,则会有一个适当的错误消息(而不仅仅是后缀获胜)。您可以将对该函数的调用视为
deploy-%
配方的第一行。如果将$ENVIRONMENT
定义为具有多个单词,则存在另一个潜在问题;第二个deploy:
行实现了一个在这种情况下会出错的测试——它使用与上面相同的patsubst/if
技巧测试$ENVIRONMENT
中的字数是否正好是1
还应注意,此生成文件假定实际工作将在deploy-%
下的配方中实现
# define a function to detect mismatch between ENV and suffix
ORIG_ENV := $(ENVIRONMENT)
ENV_CHECK = $(if $(ORIG_ENV),$(if $(subst $(ORIG_ENV),,$(ENVIRONMENT)),\
$(error $$ENVIRONMENT differs from deploy-<suffix>.),),)
ENVIRONMENT ?= $(USER)
.PHONY: deploy
deploy: deploy-$(ENVIRONMENT)
deploy: $(if $(patsubst 1%,%,$(words $(ENVIRONMENT))),$(error Bad $$ENVIRONMENT: "$(ENVIRONMENT)"),)
.PHONY: deploy-%
deploy-%: ENVIRONMENT=$*
deploy-%: ENV_TYPE=$(if $(patsubst production%,%,$(ENVIRONMENT)),staging,production)
deploy-%:
$(call ENV_CHECK)
@echo ENVIRONMENT: $(ENVIRONMENT)
@echo ENV_TYPE: $(ENV_TYPE)
# keep it from going haywire if user specifies:
# ENVIRONMENT= make deploy
# or
# make deploy-
.PHONY: deploy-
deploy-:
$(error Cannot build with empty $$ENVIRONMENT)
#定义一个函数来检测ENV和后缀之间的不匹配
原始环境:=$(环境)
环境检查=$(如果$(原始环境),$(如果$(子$(原始环境),,$(环境))\
$(错误$$环境不同于部署-),),)
环境?=$(用户)
.冒牌货:部署
部署:部署-$(环境)
部署:$(如果$(patsubst 1%,%,$(words$(ENVIRONMENT)),$(error Bad$$ENVIRONMENT:“$(ENVIRONMENT)”,)
.虚假:部署-%
部署-%:环境=$*
部署-%:环境类型=$(如果$(patsubst生产%,%,$(环境)),暂存,生产)
部署-%:
$(调用环境检查)
@回声环境:$(环境)
@回声环境类型:$(环境类型)
#如果用户指定:
#环境=进行部署
#或
#部署-
.冒牌货:部署-
部署-:
$(无法使用空的$$环境生成错误)
给予
$USER=匿名进行部署
环境:匿名
环境类型:暂存
$ENVIRONMENT=生产制造部署
环境:生产
环境类型:生产
$ENVIRONMENT=testmakedeploy
环境:测试
环境类型:暂存
$makedeployfoo
环境:富
环境类型:暂存
$make部署生产
环境:生产
环境类型:生产
$ENVIRONMENT=foo使部署生产
Makefile:14:**$环境不同于部署-。。停止
$ENVIRONMENT=make-deploy
Makefile:24:**Bad$环境:“”。停止
$make部署-
Makefile:24:**无法使用空$ENVIRONMENT生成。停止
$ENVIRONMENT=“越多越好”进行部署
Makefile:10:**Bad$环境:“越多越好”。停止
回想一下这是怎么回事,一点也不简单。对$ENVIRONMENT
有各种解释……例如在部署:部署-$(ENVIRONMENT)
行中,$ENVIRONMENT
的意思是从shell的环境中得到的(如果不存在,可能被设置为$(USER)
)。配方行@echo-ENVIRONMENT:$(ENVIRONMENT)
中还有另一种含义,它将是在上面的deploy-%:ENVIRONMENT=$*
中分配的,但在扩展之后。我对编程中变量的作用域或阴影的类比印象深刻。您的问题来自于特定于目标的变量值被目标先决条件继承的方式。你想干什么
12:50 $ make -n deploy-production
/Applications/Xcode.app/Contents/Developer/usr/bin/make --no-print-directory ENVIRONMENT=production deploy
echo production
echo staging
echo logging-ingest.staging.internal:80
# define a function to detect mismatch between ENV and suffix
ORIG_ENV := $(ENVIRONMENT)
ENV_CHECK = $(if $(ORIG_ENV),$(if $(subst $(ORIG_ENV),,$(ENVIRONMENT)),\
$(error $$ENVIRONMENT differs from deploy-<suffix>.),),)
ENVIRONMENT ?= $(USER)
.PHONY: deploy
deploy: deploy-$(ENVIRONMENT)
deploy: $(if $(patsubst 1%,%,$(words $(ENVIRONMENT))),$(error Bad $$ENVIRONMENT: "$(ENVIRONMENT)"),)
.PHONY: deploy-%
deploy-%: ENVIRONMENT=$*
deploy-%: ENV_TYPE=$(if $(patsubst production%,%,$(ENVIRONMENT)),staging,production)
deploy-%:
$(call ENV_CHECK)
@echo ENVIRONMENT: $(ENVIRONMENT)
@echo ENV_TYPE: $(ENV_TYPE)
# keep it from going haywire if user specifies:
# ENVIRONMENT= make deploy
# or
# make deploy-
.PHONY: deploy-
deploy-:
$(error Cannot build with empty $$ENVIRONMENT)
$ USER=anonymous make deploy
ENVIRONMENT: anonymous
ENV_TYPE: staging
$ ENVIRONMENT=production make deploy
ENVIRONMENT: production
ENV_TYPE: production
$ ENVIRONMENT=test make deploy
ENVIRONMENT: test
ENV_TYPE: staging
$ make deploy-foo
ENVIRONMENT: foo
ENV_TYPE: staging
$ make deploy-production
ENVIRONMENT: production
ENV_TYPE: production
$ ENVIRONMENT=foo make deploy-production
Makefile:14: *** $ENVIRONMENT differs from deploy-<suffix>.. Stop.
$ ENVIRONMENT= make deploy
Makefile:24: *** Bad $ENVIRONMENT: "". Stop.
$ make deploy-
Makefile:24: *** Cannot build with empty $ENVIRONMENT. Stop.
$ ENVIRONMENT="the more the merrier" make deploy
Makefile:10: *** Bad $ENVIRONMENT: "the more the merrier". Stop.
$ cat Makefile
ENVIRONMENT = default
deploy:
@echo '$@: ENVIRONMENT = $(ENVIRONMENT)'
deploy-foo: ENVIRONMENT = foo
deploy-foo: deploy
@echo '$@: ENVIRONMENT = $(ENVIRONMENT)'
$ make deploy
deploy: ENVIRONMENT = default
$ make deploy-foo
deploy: ENVIRONMENT = foo
deploy-foo: ENVIRONMENT = foo
$ cat Makefile
ENVIRONMENT = default
deploy:
@echo '$@: ENVIRONMENT = $(ENVIRONMENT)'
deploy-%: ENVIRONMENT = $*
deploy-%: deploy
@echo '$@: ENVIRONMENT = $(ENVIRONMENT)'
$ make deploy
$ deploy: ENVIRONMENT = default
$ make deploy-foo
deploy: ENVIRONMENT =
deploy-foo: ENVIRONMENT = foo
deploy-%: ENVIRONMENT := $*
deploy-%:
@$(MAKE) ENVIRONMENT=$* deploy
$ cat Makefile
ENVIRONMENT = default
deploy:
@echo '$(ENVIRONMENT)'
deploy-%:
@$(MAKE) --no-print-directory ENVIRONMENT=$* deploy
$ make
default
$ make deploy
default
$ make deploy-foo
foo
$ cat Makefile
deplo%:
@{ [[ "$*" == "y" ]] && ENVIRONMENT=$(USER); } || \
{ [[ "$*" =~ y-(.*) ]] && ENVIRONMENT=$${BASH_REMATCH[1]}; } || \
{ echo "$@: unknown target" && exit 1; }; \
echo "$@: ENVIRONMENT = $$ENVIRONMENT" && \
<do-whatever-else-is-needed>
$ USER=bar make deploy
deploy: ENVIRONMENT = bar
$ make deploy-foo
deploy-foo: ENVIRONMENT = foo
$ make deplorable
deplorable: unknown target
make: *** [Makefile:2: deplorable] Error 1