如何在 Makefile 目标中实现 $(<some-file) ?
How can I achieve $(<some-file) inside a Makefile target?
我正在尝试从 https://docs.gitlab.com/ee/api/lint.html#use-jq-to-create-and-process-yaml--json-payloads 执行 jq
管道 curl
命令,但在 make 文件上下文中。
我花了好几个小时尝试转义和尝试替代命令的每一个排列,但我无法让等效的工作。我在 makefile 之外没有问题。
我尝试用 "$$(<foo.yml)"
或 $(shell cat foo.yml)
甚至 cat foo.yml | ... @-
替换 "$(<foo.yml)"
但没有成功。 shell cat
是我得到的最接近的,但是 cat 删除了 \n 字符,这使得我传递给 GitLab 的结果 JSON 返回时出现令人困惑的错误:
{"valid":false,"errors":["(\u003cunknown\u003e): 在第 1 行第 12 列的上下文中不允许块序列条目"],"warnings":[],"status":"无效"}
我将字符串与 Makefile 上下文之外的工作原始版本进行了比较,唯一不同的是缺少 \n 字符。
请帮忙!谢谢。
编辑
根据要求,这里是 URL.
的额外详细信息
这是我试图移动到 Makefile 上下文中的命令。此命令直接从我的 bash 终端运行正常。
jq --null-input --arg yaml "$(<.gitlab-ci.yml)" '.content=$yaml' | curl "https://gitlab.com/api/v4/ci/lint?" --header "Content-Type: application/json" --header "PRIVATE-TOKEN: $GITLAB_PERSONAL_ACCESS_TOKEN" --data @-
回复如下:
{"valid":true,"errors":[],"warnings":[],"status":"valid"}
这是我的 Makefile 版本:
.PHONY: lint
make lint:
jq --null-input '.content="$(shell cat "$(GITLAB_CI_FILE_PATH)")"' | curl --header "Content-Type: application/json" --header "PRIVATE-TOKEN: $(GITLAB_PERSONAL_ACCESS_TOKEN)" --data @- "https://gitlab.com/api/v4/ci/lint"
回复如下:
{"valid":false,"errors":["(\u003cunknown\u003e): block sequence entries are not allowed in this context at line 1 column 12"],"warnings":[],"status":"invalid"}
我知道这是因为我的 makefile 版本不包含换行符。
这是输入的 YAML 文件:
include:
- project: adamcunnington.info/MLG/common
file: /cicd/.gitlab-ci-python.yml
如果您提供您要编写的完整规则,那将非常有帮助。
在 make 配方中使用 $(<foo.yml)
无效,因为 make 将以 $
开头的所有内容都视为 make 变量,并在 运行 和 shell 之前扩展它.您需要转义您希望 shell 看到的所有 $
,如 $$
.
使用 $$(<foo.yml)
在某些系统上有效,但在其他系统上无效:POSIX 标准未定义该语法,因此 shell 提供 POSIX features 不会用它做任何事情。这是 bash shell 的增强语法。默认情况下,Make 总是运行 /bin/sh
,所以如果你的 /bin/sh
真的是 bash,它可能会起作用。没有就没有。
使用 $(shell cat foo.yml)
无法工作,因为 make 的 shell 函数会在替换之前从输出中删除所有换行符。
由于我们看不到您的实际规则,因此无法真正建议最佳替代方案。有什么原因你不能使用简单的标准:
jq < foo.yml
?
预计到达时间
如前所述,您的 shell 是 bash。 Make always 默认使用 /bin/sh
作为 shell(想象一下如果 make 总是使用调用它的人正在使用的任何 shell 可移植性问题)。
如果您不知道如何重写您的 makefile 配方以使用标准 POSIX 语法,而是想使用 bash 特定的语法,您可以告诉 make 使用 bash 作为其 shell:
SHELL := /bin/bash
现在所有 bash 特有的魔法都将在您的食谱中发挥作用。当然,您的 makefile 将无法在没有 /bin/bash
.
的系统上运行
jq
部分的更简单和更便携的重新表述将是
jq --null-input --rawfile yaml .gitlab-ci.yml '.content=$yaml'
在一个 Makefile
里面,显然是美元符号的两倍。
一个细微差别是 --rawfile
文件中的最后一个换行符也包含在内。
--rawfile
选项是在 jq
1.6 中引入的。
我正在尝试从 https://docs.gitlab.com/ee/api/lint.html#use-jq-to-create-and-process-yaml--json-payloads 执行 jq
管道 curl
命令,但在 make 文件上下文中。
我花了好几个小时尝试转义和尝试替代命令的每一个排列,但我无法让等效的工作。我在 makefile 之外没有问题。
我尝试用 "$$(<foo.yml)"
或 $(shell cat foo.yml)
甚至 cat foo.yml | ... @-
替换 "$(<foo.yml)"
但没有成功。 shell cat
是我得到的最接近的,但是 cat 删除了 \n 字符,这使得我传递给 GitLab 的结果 JSON 返回时出现令人困惑的错误:
{"valid":false,"errors":["(\u003cunknown\u003e): 在第 1 行第 12 列的上下文中不允许块序列条目"],"warnings":[],"status":"无效"}
我将字符串与 Makefile 上下文之外的工作原始版本进行了比较,唯一不同的是缺少 \n 字符。
请帮忙!谢谢。
编辑 根据要求,这里是 URL.
的额外详细信息这是我试图移动到 Makefile 上下文中的命令。此命令直接从我的 bash 终端运行正常。
jq --null-input --arg yaml "$(<.gitlab-ci.yml)" '.content=$yaml' | curl "https://gitlab.com/api/v4/ci/lint?" --header "Content-Type: application/json" --header "PRIVATE-TOKEN: $GITLAB_PERSONAL_ACCESS_TOKEN" --data @-
回复如下:
{"valid":true,"errors":[],"warnings":[],"status":"valid"}
这是我的 Makefile 版本:
.PHONY: lint
make lint:
jq --null-input '.content="$(shell cat "$(GITLAB_CI_FILE_PATH)")"' | curl --header "Content-Type: application/json" --header "PRIVATE-TOKEN: $(GITLAB_PERSONAL_ACCESS_TOKEN)" --data @- "https://gitlab.com/api/v4/ci/lint"
回复如下:
{"valid":false,"errors":["(\u003cunknown\u003e): block sequence entries are not allowed in this context at line 1 column 12"],"warnings":[],"status":"invalid"}
我知道这是因为我的 makefile 版本不包含换行符。
这是输入的 YAML 文件:
include:
- project: adamcunnington.info/MLG/common
file: /cicd/.gitlab-ci-python.yml
如果您提供您要编写的完整规则,那将非常有帮助。
在 make 配方中使用 $(<foo.yml)
无效,因为 make 将以 $
开头的所有内容都视为 make 变量,并在 运行 和 shell 之前扩展它.您需要转义您希望 shell 看到的所有 $
,如 $$
.
使用 $$(<foo.yml)
在某些系统上有效,但在其他系统上无效:POSIX 标准未定义该语法,因此 shell 提供 POSIX features 不会用它做任何事情。这是 bash shell 的增强语法。默认情况下,Make 总是运行 /bin/sh
,所以如果你的 /bin/sh
真的是 bash,它可能会起作用。没有就没有。
使用 $(shell cat foo.yml)
无法工作,因为 make 的 shell 函数会在替换之前从输出中删除所有换行符。
由于我们看不到您的实际规则,因此无法真正建议最佳替代方案。有什么原因你不能使用简单的标准:
jq < foo.yml
?
预计到达时间
如前所述,您的 shell 是 bash。 Make always 默认使用 /bin/sh
作为 shell(想象一下如果 make 总是使用调用它的人正在使用的任何 shell 可移植性问题)。
如果您不知道如何重写您的 makefile 配方以使用标准 POSIX 语法,而是想使用 bash 特定的语法,您可以告诉 make 使用 bash 作为其 shell:
SHELL := /bin/bash
现在所有 bash 特有的魔法都将在您的食谱中发挥作用。当然,您的 makefile 将无法在没有 /bin/bash
.
jq
部分的更简单和更便携的重新表述将是
jq --null-input --rawfile yaml .gitlab-ci.yml '.content=$yaml'
在一个 Makefile
里面,显然是美元符号的两倍。
一个细微差别是 --rawfile
文件中的最后一个换行符也包含在内。
--rawfile
选项是在 jq
1.6 中引入的。