В последнем посте мы видели, как использовать подстановочные знаки Makefile для записи таких целей:

migrate-to-%:
    @bundle exec rake migrate[$(*)] 
guard-%:
    @if [ -z '${${*}}' ]; then echo 'ERROR: variable $* not set' && exit 1; fi
logs: guard-STACK
    @awslogs get -w /ecs/$(STACK)_MyService

Чтобы мы могли создавать CLI следующим образом:

$ make migrate-to-50
Migrating to version 50...
$ make logs
ERROR: variable STACK not set
$ STACK=qa make logs
...

(Обратите внимание на префикс @ в командах в Makefile, он позволяет избежать вывода строки на стандартный вывод)

Это удобно, но хорошо работает только для пользовательских значений, таких как "50". Бывают случаи, когда мы хотим, чтобы пользователь предоставил аргумент, но не значение. Скажем, например, пользователи хотят указать «производство» для «постановки», но мы не хотим, чтобы они запоминали URL-адрес сервера.

Мы можем использовать подстановочные знаки для динамического выбора переменной Make:

staging_url:=https://staging-api.lithic.tech
production_url:=https://api.lithic.tech
ping-%:
    curl "$($(*)_url)"

И мы можем использовать его так:

$ make ping-staging
curl "https://staging-api.lithic.tech"

Хорошо, этот пример не очень полезен. Но для некоторых клиентов у нас есть несколько развернутых версий одного и того же приложения, и мы можем использовать эти переменные, чтобы не помнить, где развернуты приложения.

Например, предположим, что у нас есть 3 версии кодовой базы, развернутой в Heroku: одна промежуточная и две продакшн-приложения. Во фрагменте кода Make ниже каждая переменная _app относится к имени приложения Heroku. Мы можем использовать это имя приложения, чтобы получить строку базы данных с помощью интерфейса командной строки Heroku и передать ее в psql (интерфейс командной строки Postgres).

staging_app:=lithic-api-staging
production-pdx_app:=lithic-api-production
production-nyc_app:=lithic-api-production-nyc
psql-%:
    psql `heroku config:get DATABASE_URL --app=$($(*)_app)`

Теперь, чтобы подключиться к staging, это так же просто, как:

$ make psql-staging

Если мы используем приложения для обзора Heroku, мы также должны поддерживать версии этих команд, зависящие от среды, поскольку имена приложений эфемерны. Вместо подстановочного знака нам потребуется установить переменную окружения APP:

psql-app: guard-APP
    psql `heroku config:get DATABASE_URL --app=${APP}`

Собираем все вместе

В приведенном выше примере есть пара небольших ошибок, которые могут сбить пользователей с толку: если psql или heroku не находятся на PATH, команда выдаст какую-то загадочную ошибку:

$ make psql-staging
psql `heroku config:get DATABASE_URL --app=lithic-api-staging`
/bin/sh: heroku: command not found
could not connect to server: No such file or directory

Фу! Можем ли мы использовать что-то вроде нашей прекрасной цели guard-% для объявления наших исполняемых зависимостей?

Спорим, мы можем!

cmd-exists-%:
    @hash $(*) > /dev/null 2>&1 || \
        (echo "ERROR: '$(*)' must be installed and available on your PATH."; exit 1)
guard-%:
    @if [ -z '${${*}}' ]; then echo 'ERROR: environment variable $* not set' && exit 1; fi
psql-%: cmd-exists-heroku cmd-exists-psql
    psql `heroku config:get DATABASE_URL --app=$($(*)_app)`
psql-app: guard-APP cmd-exists-heroku cmd-exists-psql
    psql `heroku config:get DATABASE_URL --app=${APP}`

Теперь, если вам не хватает heroku или psql, вы получите приятное сообщение:

$ make psql-staging
ERROR: 'heroku' must be installed and available on your PATH.

Кто знал, что Make может быть таким забавным в использовании?

С Make еще не покончено

На следующей неделе у нас будет еще одна запись в блоге, посвященная Make, вместе с кучей полезных помощников Makefile. Быть в курсе!