Elixir 脱机生成十六进制注册表文件
调整Elixir及其生态系统中的所有工具以与不同的构建系统协同工作 在这个系统中,包和它们的依赖项是分开管理的,Hex在脱机模式下工作。(抓住柏油球) 它有一个警告:每次我导入一个新包时,我还需要从hexpm导入最新的注册表文件,并且我不能使用未通过hex发布的包,除非它们位于deps链的顶层 给定一堆tarball(并假设它们之间的依赖关系得到满足),如何构建一个与它们一起工作的十六进制注册表文件 到目前为止,我所拥有的:Elixir 脱机生成十六进制注册表文件,elixir,elixir-mix,hex-pm,Elixir,Elixir Mix,Hex Pm,调整Elixir及其生态系统中的所有工具以与不同的构建系统协同工作 在这个系统中,包和它们的依赖项是分开管理的,Hex在脱机模式下工作。(抓住柏油球) 它有一个警告:每次我导入一个新包时,我还需要从hexpm导入最新的注册表文件,并且我不能使用未通过hex发布的包,除非它们位于deps链的顶层 给定一堆tarball(并假设它们之间的依赖关系得到满足),如何构建一个与它们一起工作的十六进制注册表文件 到目前为止,我所拥有的: 查看注册表文件格式,发现它是ets文件。可以加载并检查它;现在我需要
- 查看注册表文件格式,发现它是ets文件。可以加载并检查它;现在我需要生成
- 查看了网站如何构建注册表文件,但对于我的需求来说,它非常复杂
- 我很难理解为什么需要注册表文件(如果需要,为什么每个包都不能在元数据中包含所需的信息,从而使对中央注册表的需求过时)
无论如何,如果有人玩Hex,并且能够提供一些指导,我将不胜感激。如果没有关于您的用例的更多信息,就很难给出好的信息和建议。您能详细说明一下您正在做什么以及为什么要做吗?不过我会尽力回答这个问题 以下是注册表格式的规范: 格式相当简单,自己构建ETS文件不需要太多代码 我很难理解为什么需要注册表文件(如果需要,为什么每个包都不能在元数据中包含所需的信息,从而使对中央注册表的需求过时) 十六进制客户端中的依赖项解析需要注册表。如果客户端必须获取每个包版本以查看它是否解析了大量无用的HTTP请求,则解析程序可以尝试许多不同版本的包。注册表是作为一种优化而存在的,因此我们只需要获取一个文件进行完整解析
我认为您可能希望直接依赖于本地包tarballs,因为您暗示您自己进行依赖项解析。对吗?我在客户端上打开了一个问题来支持这一点:对于最终出现在这里的后代,这里有一个工作注册表生成器:
defp string_files(files) do
Enum.into(files, %{}, fn {name, binary} ->
{List.to_string(name), binary}
end)
end
defp decode(string) when is_binary(string) do
string = String.to_char_list(string)
case :safe_erl_term.string(string) do
{:ok, tokens, _line} ->
try do
terms = :safe_erl_term.terms(tokens)
result = Enum.into(terms, %{})
{:ok, result}
rescue
FunctionClauseError ->
{:error, "invalid terms"}
ArgumentError ->
{:error, "not in key-value format"}
end
{:error, reason} ->
{:error, inspect reason}
end
end
def build_registry(hex_home) do
# find the tars
tars = Path.wildcard(Path.join(hex_home,"packages/*.tar"))
# initialize the ets table used to build the registry
:ets.new(:myr, [:named_table])
:ets.insert(:myr, {:"$$version$$", 4})
# go through the tars, extract the info needed and populate
# the registry
Enum.each(tars, fn filename ->
{:ok, files} = :erl_tar.extract(String.to_char_list(filename), [:memory])
files = string_files(files)
{:ok, metadata} = decode(files["metadata.config"])
name = metadata["app"]
version = metadata["version"]
build_tools = metadata["build_tools"]
checksum = files["CHECKSUM"]
deps = []
if metadata["requirements"], do: deps = metadata["requirements"]
reg_deps = Enum.map(deps, fn
{name, depa} ->
depa = Enum.into(depa, %{})
[name, depa["requirement"], depa["optional"], depa["app"]]
depa ->
depa = Enum.into(depa, %{})
[depa["name"], depa["requirement"], depa["optional"], depa["app"]]
end)
IO.puts "adding dependency"
IO.inspect {name, [[version]]}
IO.inspect {{name, version}, [reg_deps, checksum, build_tools]}
:ets.insert(:myr, {name, [[version]]})
:ets.insert(:myr, {{name, version}, [reg_deps, checksum, build_tools]})
end)
# persist the registry to disk and remove the table
registry_file = Path.join(hex_home, "registry.ets")
IO.puts "Writing registry to: #{registry_file}"
:ets.tab2file(:myr, String.to_char_list(registry_file))
:ets.delete(:myr)
registry_file_gzip = registry_file <> ".gz"
IO.puts "Gzipping registry to: #{registry_file_gzip}"
gzipped_content = File.read!(registry_file) |> :zlib.gzip
File.write!(registry_file_gzip, gzipped_content)
end
defp string_文件(文件)执行
into(文件,%{},fn{name,binary}->
{List.to_字符串(名称),二进制}
(完)
结束
defp解码(字符串)何时为二进制(字符串)do
字符串=字符串。到字符列表(字符串)
大小写:safe_erl_term.string(string)do
{:好的,代币,{u line}->
试着做
术语=:安全术语。术语(令牌)
结果=Enum.into(术语,%{})
{:好的,结果}
营救
函数子句错误->
{:错误,“无效术语”}
ArgumentError->
{:错误,“不是键值格式”}
结束
{:错误,原因}->
{:错误,检查原因}
结束
结束
def build_注册表(hex_home)do
#找到焦油
tars=Path.wildcard(Path.join(hex_home,“packages/*.tar”))
#初始化用于构建注册表的ets表
:ets.new(:myr,[:named_table])
:ets.insert(:myr,{:$$version$$,4})
#检查TAR,提取所需信息并填充
#登记处
每个(TAR、fn文件名->
{:好的,files}=:erl_tar.extract(String.to_char_list(文件名),[:memory])
文件=字符串文件(文件)
{:ok,metadata}=decode(文件[“metadata.config”])
名称=元数据[“应用”]
版本=元数据[“版本”]
构建工具=元数据[“构建工具”]
校验和=文件[“校验和”]
deps=[]
如果元数据[“需求”],do:deps=元数据[“需求”]
reg_deps=枚举映射(deps,fn
{name,depa}->
depa=Enum.into(depa,%{})
[名称、depa[“要求”]、depa[“可选”]、depa[“应用”]]
德帕->
depa=Enum.into(depa,%{})
[depa[“名称”]、depa[“要求”]、depa[“可选”]、depa[“应用”]]
(完)
IO.puts“添加依赖项”
IO.inspect{name,[[version]]}
IO.inspect{{name,version},[reg\u deps,checksum,build\u tools]}
:ets.insert(:myr,{name,[[version]]})
:ets.insert(:myr,{{name,version},[reg\u deps,checksum,build\u tools]})
(完)
#将注册表持久化到磁盘并删除表
registry\u file=Path.join(hex\u home,“registry.ets”)
IO.puts“将注册表写入:#{registry_file}”
:ets.tab2文件(:myr,String.to_char_列表(注册表文件))
:ets.delete(:myr)
registry\u file\u gzip=registry\u file“.gz”
IO.puts“将注册表压缩到:#{registry_file_gzip}”
gzip_content=File.read!(注册表_文件)|>:zlib.gzip
File.write!(注册表文件、压缩内容)
结束
有关更多上下文:
- 注册表是一个ETS表。请参阅:
- 注册表格式概述如下:
- 本模块中的private fn灵感来自:
- safe_erl_term.xrl(需要在src/下)借用自:
- xrl是leex的输入。请参见此处(获取规范,生成erlang代码):