/
project.ex
53 lines (44 loc) · 1.75 KB
/
project.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
defmodule MixAudit.Project do
def dependencies(path) do
Enum.flat_map(lockfiles(path), &map_lockfile_to_dependencies/1)
end
defp lockfiles(path) do
Path.wildcard(Path.join(path, "mix.lock")) ++ Path.wildcard(Path.join(path, "apps/**/mix.lock"))
end
defp map_lockfile_to_dependencies(lockfile) do
lockfile
|> read_lockfile()
|> Map.values()
|> Enum.map(&map_dependency(&1, lockfile))
|> Enum.reject(&is_nil/1)
end
defp read_lockfile(lockfile) do
# Backwards compatibility: suppressing warnings needs to be done with two different options:
# - emit_warnings: from Elixir v1.16 onwards
# - warn_on_unnecessary_quotes: up to Elixir v1.15
opts = [file: lockfile, emit_warnings: false, warn_on_unnecessary_quotes: false]
with {:ok, contents} <- File.read(lockfile),
assert_no_merge_conflicts_in_lockfile(lockfile, contents),
{:ok, quoted} <- Code.string_to_quoted(contents, opts),
{%{} = lock, _} <- Code.eval_quoted(quoted, [], opts) do
lock
else
_ -> %{}
end
end
defp map_dependency({:hex, package, version, _, _, _, _}, lockfile) do
do_map_dependency(package, version, lockfile)
end
defp map_dependency({:hex, package, version, _, _, _, _, _}, lockfile) do
do_map_dependency(package, version, lockfile)
end
defp map_dependency(_, _), do: nil
defp do_map_dependency(package, version, lockfile) do
%MixAudit.Dependency{package: to_string(package), version: version, lockfile: lockfile}
end
defp assert_no_merge_conflicts_in_lockfile(lockfile, info) do
if String.contains?(info, ~w(<<<<<<< ======= >>>>>>>)) do
Mix.raise("Your #{lockfile} contains merge conflicts. Please resolve the conflicts and run the command again")
end
end
end