#makefile #gnu-make
Вопрос:
Я пытаюсь автоматизировать некоторые команды, которые я регулярно использую в файле Makefile, но, похоже, не могу понять правильный синтаксис для этого.
Учитывая следующие цели:
.PHONY: params-list params-list: @aws ssm get-parameters-by-path --path /${SERVICE}/${ENV} | jq -c -r '.Parameters[] | .Name' .PHONY: params-get params-get: @aws ssm get-parameter --name ${PARAM} --with-decryption | jq -c -r .Parameter.Value
Я пытался позвонить params-list
, а затем передать результаты в params-get
. Моя лучшая попытка заключалась в том, чтобы:
.PHONY: params params: for param in $(MAKE) params-list; do $(MAKE) params-get PARAM=${param}; done
Но, очевидно, это не работает. Каков правильный способ достижения этого?
Ответ №1:
Один из советов состоит в том, чтобы отказаться от конструкций оболочки для создания. Продвигаясь здесь по одному шагу за раз.
Для операции get мы кодируем одну цель для каждого параметра. Поэтому для парама p1
(скажем) мы придумываем цель params-getlt;p1gt;
. Мы отмечаем, что внутри рецепта (т. Е. команд оболочки), которые $@
будут расширяться до params-getlt;p1gt;
. Поэтому ${@:params-getlt;%gt;=%}
будет расширяться до p1
.
Написание этого в синтаксисе make:
.PHONY: params-getlt;p1gt; params-getlt;p1gt;: @aws ssm get-parameter --name ${@:params-getlt;%gt;=%} --with-decryption | jq -c -r .Parameter.Value
Я отмечаю, что с промежуточной переменной у нас может быть точно такой же рецепт, который вы использовали в своем предыдущем заклинании.
PARAM = ${@:params-getlt;%gt;=%} .PHONY: params-getlt;p1gt; params-getlt;p1gt;: @aws ssm get-parameter --name ${PARAM} --with-decryption | jq -c -r .Parameter.Value
Если у нас есть второй параметр pa
(скажем), его легко добавить:
PARAM = ${@:params-getlt;%gt;=%} .PHONY: params-getlt;p1gt; params-getlt;pagt; params-getlt;p1gt; params-getlt;pagt;: @aws ssm get-parameter --name ${PARAM} …
Я надеюсь, вы увидите, как здесь появится какая-нибудь котельная плита.
Переходя к более динамически генерируемым моделям, а не к жесткому кодированию каждого параметра, давайте поместим все возможные параметры в список под названием $PARAMS
PARAMS := p1 pa another get-targets := ${PARAMS:%=params-getlt;%gt;} PARAM = ${@:params-getlt;%gt;=%} .PHONY: ${get-targets} ${get-targets}: @aws ssm get-parameter --name ${PARAM} … .PHONY: params-get params-get: ${get-targets} echo $@ Done
Я добавил вашу первоначальную params-get
цель. Теперь вся работа выполняется зависимостями.
- Контура оболочки не видно.
- Код выхода каждого
aws ssm get-parameter
из них проверяется с помощью make. - Код безопасен для параллельного выполнения: make-j9 будет выполнять 9 заданий параллельно, пока работа не будет завершена. Хорошо, если у вас 8 процессоров. (Если ваша марка не является безопасной, то, кстати, она сломана.)
Сейчас мы довольно близки. Мы просто должны убедиться $PARAMS
, что настроено на выход ssm get-parameters-by-path
.
Что-то вроде:
.PHONY: params-list params-list: @aws ssm get-parameters-by-path --path /${SERVICE}/${ENV} | jq -c -r '.Parameters[] | .Name' PARAMS := $(shell ${MAKE} params-list) get-targets := ${PARAMS:%=params-getlt;%gt;} PARAM = ${@:params-getlt;%gt;=%} .PHONY: ${get-targets} ${get-targets}: @aws ssm get-parameter --name ${PARAM} --with-decryption | jq -c -r .Parameter.Value .PHONY: params-get params-get: ${get-targets} echo $@ Done
Определенно не фанат использования $(shell …)
, но это всего лишь набросок.
Ответ №2:
Вы можете выполнить одну (длинную) цель/рецепт следующим образом:
.PHONY: params-get params-get: @for p in $(aws ssm get-parameters-by-path --path /${SERVICE}/${ENV} | jq -c -r '.Parameters[] | .Name'); do aws ssm get-parameter --name $p --with-decryption | jq -c -r .Parameter.Value; done
Это предполагает, что в ваших параметрах нет пробелов
———— РЕДАКТИРОВАТЬ —————
Чтобы получить доступ к параметрам в другом рецепте, вы можете создать правило для создания файла со списком файлов в одном рецепте, а затем получить доступ к этому файлу в другом рецепте следующим образом:
# note that in this case .params-list is actually the name of a file, # but it is declared as phony to force it to be rebuilt every time. .PHONY: .params-list .params-list: aws ssm get-parameters-by-path --path /${SERVICE}/${ENV} | jq -c -r '.Parameters[] | .Name' gt; $@ .PHONY: params-get params-get: .params-list @for param in $(cat .params-list); do aws ssm get-parameter --name ${param} --with-decryption | jq -c -r .Parameter.Value; done;
Комментарии:
1. Это действительно работает. Однако можно ли создать какую-то целевую композицию с помощью цикла? В основном для того, чтобы я мог повторно использовать цели в другом месте.
2. Да, вы можете сделать это, введя файл в одном рецепте, а затем импортировав файл в другом рецепте. Я также отредактирую ответ с помощью этого решения.