使Elixir及其生态系统中的所有工具适应不同的构建系统。
在此系统中,程序包及其依赖项是单独管理的,而Hex可以在脱机模式下运行。 (抓住tarball)
它正在处理一个警告:每次我导入一个新包时,我还需要从hexpm导入最新的注册表文件,我不能使用不通过十六进制发布的包,除非它们位于顶层deps chain。
鉴于一堆tarball(并假设它们之间的依赖关系得到满足,如何构建一个与它们一起使用的十六进制注册表文件。
到目前为止我所拥有的:
无论如何,如果有人玩过Hex并且可以就如何做到这一点提供一些指导,我将不胜感激。
答案 0 :(得分:2)
如果没有关于您的用例的更多信息,提供良好的信息和建议有点困难。你能详细说明你在做什么以及为什么这样做?我会尽力回答这个问题。
以下是注册表格式的规范:https://github.com/hexpm/specifications/blob/master/registry.md。
格式非常简单,自己构建ETS文件不需要太多代码。
我有点难以理解为什么需要一个注册表文件(如果存在,为什么每个包都不能包含元数据中所需的信息,这使得中央注册表需要过时)
Hex客户端中的依赖项解析需要注册表。解析器可以尝试许多不同版本的包,如果客户端必须获取每个包版本以查看它是否已解决,则必须进行大量无用的HTTP请求。注册表作为优化存在,因此我们只需要获取单个文件来执行完整分辨率。
我认为你可能想要的是直接依赖本地包tarball,因为你暗示你自己做了依赖解析。那是对的吗?我在客户端上打开了一个问题来支持此问题:https://github.com/hexpm/hex/issues/261
答案 1 :(得分:0)
对于最终来到这里的后代,这里有一个工作的注册表构建器:
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
更多背景信息: