【问题标题】:What is the correct way to read dependency tree?阅读依赖树的正确方法是什么?
【发布时间】:2016-09-01 23:00:17
【问题描述】:

我想解析 app deps 树并生成地图。
我目前正在阅读顶级部门,例如:

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

我在 top_level_depsdep.deps 的递归方法中使用 Enum.reduce
一切都很好,直到没有部门的第 4 级...
例如:
应用程序 A 需要 B 需要 C 需要 D - 检查 C deps 时我看到空列表(这里也没有十六进制包)。
当我将应用程序 A 或 B 修改为需要 D 而 C 不需要 D 时,我会在我的地图中看到所有部门。
读取依赖树的正确方法是什么?

复制步骤:
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"}

【问题讨论】:

  • 不确定为什么返回的列表不包含嵌套依赖项,但我正在尝试一种不同的方法来获得您的预期结果,并且有一个问题:如果 b 也取决于您期望什么输出在d 上(如果依赖项是a -> bb -> cb -> dc -> d)。
  • @Dogbert:我将捕获碰撞并执行以下操作之一:第一个结果、最后一个结果(覆盖上一个)或后备,例如:“a_multi_d” - 取决于配置。
  • 我需要添加一个免责声明,即 Mix.Dep 不是公共 API。您不应该调用它,并且不能保证该模块或该函数将在未来的 Elixir 版本中存在。 :)

标签: elixir


【解决方案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"}

【讨论】:

  • 为了完全完成这个主题,我想知道为什么我的代码不能按预期工作。无论如何,谢谢你的帮助。现在它工作得非常好。
猜你喜欢
  • 2022-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-30
  • 1970-01-01
  • 1970-01-01
  • 2010-10-10
  • 2012-11-17
相关资源
最近更新 更多