2016-07-16 79 views
2

調整Elixir及其生態系統中的所有工具以使用不同的構建系統。脫機構建十六進制註冊表文件

在這個系統中,軟件包及其依賴關係分別管理,十六進制工作在離線模式下。 (抓住tarballs)

它正在處理一個警告:每次我導入一個新的包時,我還需要從hexpm導入最新的註冊表文件,我不能使用未通過hex發佈的包,除非它們位於頂部級別在deps鏈。

鑑於一堆壓縮包的(並假設它們之間的依賴關係得到滿足,如何將一個着手建立與他們工作的十六進制的註冊表文件

我至今:

  • 看着註冊表文件格式,看到這是一個ETS文件可以加載並檢查它。現在我需要產生
  • 看了一下網站,如何建立註冊表文件,但它是超級複雜,我的需要
  • 我掙扎AB它理解爲什麼有必要爲一個註冊表文件(如果有,爲什麼不能每個包包含元數據所需要的信息,從而不再需要中央登記過時)

無論如何,如果任何與Hex玩過的人都可以提供一些關於如何做到這一點的指導,我將不勝感激。

回答

2

如果沒有關於用例的更多信息,提供良好的信息和建議有點難。你能詳細說明你在做什麼以及你爲什麼這麼做嗎?儘管如此,我會盡力回答這個問題。

以下是註冊表格式的規範:https://github.com/hexpm/specifications/blob/master/registry.md

格式非常簡單,它不需要太多代碼來自己構建ETS文件。

我掙扎了一下,以瞭解爲什麼有必要爲一個註冊表文件(如果有,爲什麼不能每個包包含元數據所需要的信息,從而爲中央登記過時的需要)

十六進制客戶端中的依賴性解析需要註冊表。解析器可以嘗試許多不同版本的軟件包,如果客戶端必須獲取每個軟件包版本以查看它是否解決了大量無用的HTTP請求。註冊表是作爲一個優化,所以我們只需要獲取一個文件來完成全分辨率。

我想你可能想要的是直接依賴本地包tarballs,因爲你暗示你自己做依賴關係解析。那是對的嗎?我已在客戶端支持這個上開設了一個問題:https://github.com/hexpm/hex/issues/261

+0

是的。已經有了一個可以理解包和依賴性解析的構建系統(並且導入的十六進制包可以在這個系統中工作)。我將其設置爲使所有包都以〜/ hex dir結尾,當我擁有註冊表的新版本並且不使用任何未發佈爲十六進制的軟件包時,所有軟件包都可以正常工作。 – Mircea

+0

當我有一個我自己構建並試圖依賴它的軟件包時,它會崩潰,或者導入一個新軟件包而不更新註冊表。 – Mircea

+0

可以理解關於註冊表是一種優化的觀點,但如果它在離線模式下沒有使用並且/或者在程序包級別將其分解,那將會很好。我相信你已經打開的問題涵蓋了這個:) – Mircea

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 

欲瞭解更多背景: