создание шестнадцатеричного файла реестра в автономном режиме

Адаптация Elixir и всех инструментов в его экосистеме для работы с другой системой сборки.

В этой системе пакеты и их зависимости управляются отдельно, а шестнадцатеричный код работает в автономном режиме. (возьмите архивы)

Он работает с одной оговоркой: каждый раз, когда я импортирую новый пакет, мне нужно также импортировать последний файл реестра из hexpm, и я не могу использовать пакеты, которые не публикуются через шестнадцатеричный код, если они не находятся на верхнем уровне в цепочке deps.

Учитывая кучу tar-архивов (и предполагая, что зависимости между ними удовлетворены, как можно было бы создать шестнадцатеричный файл реестра, который будет работать с ними.

Что у меня есть на данный момент:

  • посмотрел формат файла реестра и увидел, что это файл ets. Можно загрузить и осмотреть; теперь мне нужно сгенерировать
  • посмотрел, как сайт строит файл реестра, но это очень сложно для моих нужд
  • Мне немного сложно понять, почему нужен файл реестра (и если он есть, почему каждый пакет не может содержать необходимую информацию в метаданных, что делает необходимость в центральном реестре устаревшей)

В любом случае, если кто-нибудь играл с Hex и может дать какие-то рекомендации, как это сделать, я был бы признателен.


person Mircea    schedule 16.07.2016    source источник


Ответы (2)


Немного сложно дать хорошую информацию и совет без дополнительной информации о вашем варианте использования. Не могли бы вы подробнее рассказать о том, что вы делаете и почему вы это делаете? Тем не менее, я постараюсь ответить на этот вопрос.

Вот спецификация формата реестра: https://github.com/hexpm/specifications/blob/master/registry.md.

Формат довольно прост, и для самостоятельного создания файла ETS не потребуется слишком много кода.

Мне немного сложно понять, почему нужен файл реестра (и если он есть, почему каждый пакет не может содержать необходимую информацию в метаданных, что делает необходимость в центральном реестре устаревшей)

Реестр необходим для разрешения зависимостей в шестнадцатеричном клиенте. Сопоставитель может попробовать много разных версий пакетов, если клиенту нужно будет получить каждую версию пакета, чтобы увидеть, разрешил ли он много бесполезных HTTP-запросов. Реестр предназначен для оптимизации, поэтому нам нужно получить только один файл, чтобы получить полное разрешение.

Я думаю, что вы, возможно, захотите напрямую зависеть от локальных архивов пакетов, поскольку вы подразумеваете, что сами выполняете разрешение зависимостей. Это правильно? Я открыл проблему на клиенте, чтобы поддержать это: https://github.com/hexpm/hex/issues/261

person Eric Meadows-Jönsson    schedule 16.07.2016
comment
да. уже существует система сборки, которая понимает пакеты и разрешение зависимостей (и пакеты в шестнадцатеричном формате импортируются для работы в этой системе). Я настроил его так, чтобы все пакеты попадали в каталог ~ / hex, и все работало, когда у меня есть новая версия реестра и я не использую какие-либо пакеты, которые не опубликованы в шестнадцатеричном формате. - person Mircea; 16.07.2016
comment
он выходит из строя, когда у меня есть пакет, который я создаю сам, и я пытаюсь полагаться на него или импортировать новый пакет без обновления реестра. - person Mircea; 16.07.2016
comment
вроде как понять суть того, что реестр является оптимизацией, но было бы здорово, если бы он работал без него в автономном режиме и / или разбивал его на уровне пакета. Я считаю, что проблема, которую вы открыли, охватывает это :) - person Mircea; 16.07.2016
comment
Elixir 1.3.2 также добавил env var MIX_NO_DEPS=1, чтобы пользователь мог обрабатывать всю загрузку зависимостей. С этой опцией Mix не будет загружать какие-либо зависимости, поэтому ему не нужен реестр. Вам нужно будет самостоятельно добавить зависимости в путь загрузки с помощью флага -pz. github.com/elixir-lang/elixir/blob/master/ bin / elixir # L11 - person Eric Meadows-Jönsson; 17.07.2016
comment
опубликовал собственный ответ с кодом, который я взломал вместе. был бы признателен за руководство, если с ним что-то не так (я тестировал его, и реестр, который он создает, работает с шестнадцатеричным - ограниченное тестирование, конечно) - person Mircea; 19.07.2016

Для будущих поколений, которые оказались здесь, вот работающий конструктор реестра:

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

Для получения дополнительной информации:

person Mircea    schedule 19.07.2016