我正在编写一个 Makefile 来将弹性 beantalk 应用程序的部署包装到多个环境中。这是我第一次编写“高级”makefile,遇到了一些麻烦。
我的目标如下:
make deploy本身应该使用ENVIRONMENT=$(USER)和部署ENV_TYPE=staging。ENVIRONMENT=production那么ENV_TYPE=production,否则ENV_TYPE=staging。deploy目标后缀a-和环境名称。例如:make deploy-production。给我带来最大麻烦的是第 3 点。由于任何未命名为 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
Run Code Online (Sandbox Code Playgroud)
问题出在deploy目标的最后一步。即,$(ENVIRONMENT)似乎未设置。
示例输出:
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-
echo # Noop required
Run Code Online (Sandbox Code Playgroud)
期望输出:
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
Run Code Online (Sandbox Code Playgroud)
所以我试图实现 Renaud 的递归 Make 解决方案,但遇到了一个小问题。这是我正在使用的简化 Makefile:
ENVIRONMENT ?= $(USER)
ifeq ($ENVIRONMENT, production)
ENV_TYPE = production
else
ENV_TYPE = staging
endif
ES_HOST = logging-ingest.$(ENV_TYPE).internal:80
.PHONY: deploy
deploy:
@echo $(ENVIRONMENT)
@echo $(ENV_TYPE)
@echo $(ES_HOST)
.PHONY: deploy-%
deploy-%:
@$(MAKE) --no-print-directory ENVIRONMENT=$* deploy
Run Code Online (Sandbox Code Playgroud)
当我运行时make production,看起来if围绕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
Run Code Online (Sandbox Code Playgroud)
最后两行应该说production而不是staging,暗示我的条件有问题,但我没有在早期版本中编辑该条件,所以我很困惑。如果我ENVIRONMENT手动调用 make 和set会发生同样的错误(例如ENVIRONMENT=production make deploy)。
您的问题来自于目标先决条件继承目标特定变量值的方式。您尝试执行的操作适用于明确的特定于目标的变量:
$ 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
Run Code Online (Sandbox Code Playgroud)
因为deploy-foo-specificENVIRONMENT变量foo在第一个扩展阶段(在此期间扩展了特定于目标的变量分配、目标列表和先决条件列表)被赋值。所以,deploy继承了这个值。
但它不适用于使用$*自动变量的特定于模式的变量:
$ 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
Run Code Online (Sandbox Code Playgroud)
原因是deploy-foo-specificENVIRONMENT变量在 make 方言中称为递归扩展变量(因为您使用了=赋值运算符)。它被递归扩展,但仅在 make 需要其值时,而不是在分配时。因此,在 的上下文中deploy-foo,它被分配$*,而不是模式词干。ENVIRONMENT按原样传递给deploy先决条件的上下文,在此上下文中,$(ENVIRONMENT)递归扩展到$*空字符串,然后再扩展到空字符串,因为deploy规则中没有模式。您可以尝试简单的扩展(非递归)变量风格:
deploy-%: ENVIRONMENT := $*
Run Code Online (Sandbox Code Playgroud)
立即扩展,但结果将相同,因为$*在第一次扩展期间扩展为空字符串。它仅在第二次扩展期间设置,因此只能在配方中使用(即在第二阶段扩展)。
一个简单(但不是超级高效)的解决方案是再次调用 make:
deploy-%:
@$(MAKE) ENVIRONMENT=$* deploy
Run Code Online (Sandbox Code Playgroud)
例子:
$ cat Makefile
ENVIRONMENT = default
deploy:
@echo '$(ENVIRONMENT)'
deploy-%:
@$(MAKE) --no-print-directory ENVIRONMENT=$* deploy
$ make
default
$ make deploy
default
$ make deploy-foo
foo
Run Code Online (Sandbox Code Playgroud)
注意:GNU make 支持二次扩展,可以认为可以用它来解决这个问题。不幸的是不是:二次扩展只扩展了先决条件,而不是特定于目标的变量定义。
如上所述,这种递归 make 效率不高。如果效率至关重要,则最好使用单个 make 调用。如果您在单个模式规则的配方中移动所有变量处理,则可以完成此操作。如果 make 使用的 shell 是 bash 的示例:
$ 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
Run Code Online (Sandbox Code Playgroud)
不要忘记通过 make ( $$ENVIRONMENT)来逃避配方扩展。
| 归档时间: |
|
| 查看次数: |
534 次 |
| 最近记录: |