读取依赖树的正确方法是什么?

时间:2016-09-01 10:49:58

标签: elixir

我想解析app deps树并生成一张地图 我目前正在阅读顶级代表:

top_level_deps = Mix.Dep.loaded([]) |> Enum.filter(& &1.top_level)

我在 top_level_deps 的递归方法中使用 Enum.reduce ,然后在 dep.deps 中使用。 一切都很好,直到第四级没有代表...
例如:
App A要求B需要需要D的C - 我在检查C deps时看到空列表(这里也没有十六进制包) 当我修改app A或B以要求D和C不需要D时,我会在地图中看到所有deps 读取依赖关系树的正确方法是什么?

重现步骤:
1为应用创建tmp目录
2转到tmp目录并创建4个应用程序,例如:

mix new a
mix new b
mix new c
mix new d

3为a,b和c应用添加deps,例如:

defp deps do
    [{:b, path: "../b"}] # deps for A app
end

4将此任务添加到 lib / mix / tasks / A 项目:

defmodule Mix.Tasks.Reproduce do
    use Mix.Task
    def run(_) do
        app_atom = Mix.Project.config[:app]
        top_level_deps = Mix.Dep.loaded([]) |> Enum.filter(& &1.top_level)
        result = reproduce top_level_deps, app_atom
        IO.inspect Map.put_new result, app_atom, Atom.to_string(app_atom)
    end

    defp reproduce deps, prefix, result \\ Map.new do
        Enum.reduce deps, result, fn(dep, result) ->
            if dep.scm != Hex.SCM do # filter Hex packages here
                new_prefix = "#{prefix}_#{dep.app}"
                new_result = reproduce dep.deps, new_prefix, result
                if dep.app == :c do
                    IO.puts "No deps here !!!"
                    IO.inspect dep.deps
                end
                Map.put_new new_result, dep.app, new_prefix
            else
                result
            end
        end
    end
end

5运行混合再现
目前的结果:

%{a: "a", b: "a_b", c: "a_b_c"}

预期结果:

%{a: "a", b: "a_b", c: "a_b_c", d: "a_b_c_d"}

1 个答案:

答案 0 :(得分:1)

我不知道为什么Mix.Dep.loaded([])在某个级别之后不包含嵌套的deps,但由于所有递归依赖 直接存在于该列表中,我们可以构建我们的自己的查找地图并使用它。这是一个返回预期输出的实现:

defmodule Mix.Tasks.Deps.Map do
  use Mix.Task

  def run(_) do
    app = Mix.Project.config[:app]
    deps = for %{app: app, deps: deps} <- Mix.Dep.loaded([]), into: %{} do
      {app, deps}
    end |> Map.put(app, Enum.filter(Mix.Dep.loaded([]), &(&1.top_level)))
    recur(deps, app, "") |> Map.put(app, "#{app}") |> IO.inspect
  end

  def recur(deps, app, prefix, result \\ Map.new) do
    Enum.reduce(deps[app], result, fn(dep, result) ->
      if dep.scm != Hex.SCM do
        recur(deps, dep.app, "#{prefix}#{app}_", result)
        |> Map.put_new(dep.app, "#{prefix}#{app}_#{dep.app}")
      else
        result
      end
    end)
  end
end

输出4个包,abcd

%{a: "a", b: "a_b", c: "a_b_c", d: "a_b_c_d"}

使用以上内容输出以及e所依赖的新包d

%{a: "a", b: "a_b", c: "a_b_c", d: "a_b_c_d", e: "a_b_c_d_e"}