如何管理jq中的模块依赖
How to manage module dependencies in jq
从 1.5 版开始 jq data processing language has a library module system。一个模块由可选的元数据和一组函数组成。例如
module { name: "util", version: "1.0.0" };
def digitsum: tostring|split("")|map(tonumber)|add;
存储为文件 util.jq
可以这样使用:
$ echo '789' | jq -L. 'include "util"; digitsum'
24
模块可以使用其他模块并且依赖关系由modulemeta
指令跟踪但是如何表达和检查模块号的最小版本?例如:
module {
name: "math",
version: "0.1.0",
};
include "util"; # TODO: require at least version 1.0.0!
def digitroot:
(.|digitsum) as $sum |
if $sum<10 then $sum else $sum|digitroot end;
jq 中对模块的支持目前(2019 年 6 月)仍然非常少,尽管在 github 上有一个 jq 的模块管理系统:https://github.com/joelpurra/jqnpm
不使用这样的外部模块管理系统,jq本身能做什么?扩展给定的示例,下面说明了一种支持版本要求的方法。请注意 math
模块的元数据中名为 dependencies
的附加键。 (目前,此密钥无法命名为 deps
,因为 jq 会覆盖它。)
文件
dependencies.jq
# Recursively check specified version constraints
module { name: "dependencies", version: "0.0.2" };
# parents of a module as defined by its .deps
def parents:
. as $in
| if type == "array" then map(parents) | add
else modulemeta | .deps | map(.relpath)
end ;
# ancestors of a single module or an array of modules.
# The array of "ancestors" of a module includes itself.
def ancestors:
# input and $visited should be arrays of strings
def ancestors($visited):
. as $in
| ($in - $visited) as $new
| if $new == [] then $visited
else $new | parents | ancestors($visited + $new | unique)
end;
if type == "array" then . else [.] end
| ancestors([]) ;
def versionsort:
def parse:
sub("(?<a>(alpha|beta|gamma))"; "\(.a).")
| [splits("[-.]")]
| map(tonumber? // .) ;
sort_by(parse);
# Input: a module name
# Emit empty if the constraints for the given module are satisfied, otherwise raise an error
def dependencies($version):
def le($y): (. == $y) or ([.,$y] | . == versionsort);
modulemeta
| .version as $mv
| if (($mv == null) or ($version | le($mv))) then empty
else ("module \(.name) dependencies version \($version) vs \($mv)" | error)
end ;
# Input: a module name or array of module names
# Check the module-version dependencies in .dependencies, proceeding up the chain as defined by .deps
def dependencies:
def check:
modulemeta
| select(has("dependencies"))
| all( .dependencies | to_entries[];
.key as $m | .value as $v | ($m | dependencies($v) ))
| empty;
ancestors[] | check;
util.jq
module { name: "util", version: "1.0.0" };
def digitsum: tostring|split("")|map(tonumber)|add;
math.jq
module {
name: "math",
version: "0.1.0",
dependencies: {"util": "1.0.0"} };
include "util" ;
def digitroot:
digitsum as $sum
| if $sum<10 then $sum
else $sum|digitroot
end;
调用
jq -n -L . '
include "dependencies";
include "math";
"math" | dependencies,
(123|digitroot) '
从 1.5 版开始 jq data processing language has a library module system。一个模块由可选的元数据和一组函数组成。例如
module { name: "util", version: "1.0.0" };
def digitsum: tostring|split("")|map(tonumber)|add;
存储为文件 util.jq
可以这样使用:
$ echo '789' | jq -L. 'include "util"; digitsum'
24
模块可以使用其他模块并且依赖关系由modulemeta
指令跟踪但是如何表达和检查模块号的最小版本?例如:
module {
name: "math",
version: "0.1.0",
};
include "util"; # TODO: require at least version 1.0.0!
def digitroot:
(.|digitsum) as $sum |
if $sum<10 then $sum else $sum|digitroot end;
jq 中对模块的支持目前(2019 年 6 月)仍然非常少,尽管在 github 上有一个 jq 的模块管理系统:https://github.com/joelpurra/jqnpm
不使用这样的外部模块管理系统,jq本身能做什么?扩展给定的示例,下面说明了一种支持版本要求的方法。请注意 math
模块的元数据中名为 dependencies
的附加键。 (目前,此密钥无法命名为 deps
,因为 jq 会覆盖它。)
文件
dependencies.jq
# Recursively check specified version constraints
module { name: "dependencies", version: "0.0.2" };
# parents of a module as defined by its .deps
def parents:
. as $in
| if type == "array" then map(parents) | add
else modulemeta | .deps | map(.relpath)
end ;
# ancestors of a single module or an array of modules.
# The array of "ancestors" of a module includes itself.
def ancestors:
# input and $visited should be arrays of strings
def ancestors($visited):
. as $in
| ($in - $visited) as $new
| if $new == [] then $visited
else $new | parents | ancestors($visited + $new | unique)
end;
if type == "array" then . else [.] end
| ancestors([]) ;
def versionsort:
def parse:
sub("(?<a>(alpha|beta|gamma))"; "\(.a).")
| [splits("[-.]")]
| map(tonumber? // .) ;
sort_by(parse);
# Input: a module name
# Emit empty if the constraints for the given module are satisfied, otherwise raise an error
def dependencies($version):
def le($y): (. == $y) or ([.,$y] | . == versionsort);
modulemeta
| .version as $mv
| if (($mv == null) or ($version | le($mv))) then empty
else ("module \(.name) dependencies version \($version) vs \($mv)" | error)
end ;
# Input: a module name or array of module names
# Check the module-version dependencies in .dependencies, proceeding up the chain as defined by .deps
def dependencies:
def check:
modulemeta
| select(has("dependencies"))
| all( .dependencies | to_entries[];
.key as $m | .value as $v | ($m | dependencies($v) ))
| empty;
ancestors[] | check;
util.jq
module { name: "util", version: "1.0.0" };
def digitsum: tostring|split("")|map(tonumber)|add;
math.jq
module {
name: "math",
version: "0.1.0",
dependencies: {"util": "1.0.0"} };
include "util" ;
def digitroot:
digitsum as $sum
| if $sum<10 then $sum
else $sum|digitroot
end;
调用
jq -n -L . '
include "dependencies";
include "math";
"math" | dependencies,
(123|digitroot) '