Elixir 脱机生成十六进制注册表文件

Elixir 脱机生成十六进制注册表文件,elixir,elixir-mix,hex-pm,Elixir,Elixir Mix,Hex Pm,调整Elixir及其生态系统中的所有工具以与不同的构建系统协同工作 在这个系统中,包和它们的依赖项是分开管理的,Hex在脱机模式下工作。(抓住柏油球) 它有一个警告:每次我导入一个新包时,我还需要从hexpm导入最新的注册表文件,并且我不能使用未通过hex发布的包,除非它们位于deps链的顶层 给定一堆tarball(并假设它们之间的依赖关系得到满足),如何构建一个与它们一起工作的十六进制注册表文件 到目前为止,我所拥有的: 查看注册表文件格式,发现它是ets文件。可以加载并检查它;现在我需要

调整Elixir及其生态系统中的所有工具以与不同的构建系统协同工作

在这个系统中,包和它们的依赖项是分开管理的,Hex在脱机模式下工作。(抓住柏油球)

它有一个警告:每次我导入一个新包时,我还需要从hexpm导入最新的注册表文件,并且我不能使用未通过hex发布的包,除非它们位于deps链的顶层

给定一堆tarball(并假设它们之间的依赖关系得到满足),如何构建一个与它们一起工作的十六进制注册表文件

到目前为止,我所拥有的:

  • 查看注册表文件格式,发现它是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代码):

是。已经有一个构建系统能够理解包和依赖项解析(并且十六进制的包被导入到该系统中工作)。我将其设置为所有包都在~/hex目录中,当我有一个新版本的注册表并且不使用任何未发布到hex的包时,一切正常。当我有一个我自己构建的包并试图依赖它时,它会崩溃,或者在不更新注册表的情况下导入一个新包关于注册表是一个优化,但如果它能在脱机模式下工作,并且/或者在包级别将其分解,那就太好了