Current section

Files

Jump to
licensir lib licensir scanner.ex
Raw

lib/licensir/scanner.ex

defmodule Licensir.Scanner do
@moduledoc """
Scans the project's dependencies for their license information.
"""
alias Licensir.{License, FileAnalyzer, Guesser}
@human_names %{
apache2: "Apache 2",
bsd: "BSD",
cc0: "CC0-1.0",
gpl_v2: "GPLv2",
gpl_v3: "GPLv3",
isc: "ISC",
lgpl: "LGPL",
mit: "MIT",
mpl2: "MPL2",
licensir_mock_license: "Licensir Mock License",
unrecognized_license_file: "Unrecognized license file content"
}
@doc """
Scans all dependencies, formats into a list, and print out the result.
"""
@spec scan(keyword()) :: list(License.t())
def scan(opts) do
# Make sure the dependencies are loaded
Mix.Project.get!()
deps()
|> to_struct()
|> filter_top_level(opts)
|> search_hex_metadata()
|> search_file()
|> Guesser.guess()
end
@spec deps() :: list(Mix.Dep.t())
defp deps() do
func = loaded_deps_func_name()
apply(Mix.Dep, func, [[]])
end
defp loaded_deps_func_name() do
if Keyword.has_key?(Mix.Dep.__info__(:functions), :load_on_environment) do
:load_on_environment
else
:loaded
end
end
defp to_struct(deps) when is_list(deps), do: Enum.map(deps, &to_struct/1)
defp to_struct(%Mix.Dep{} = dep) do
%License{
app: dep.app,
name: Atom.to_string(dep.app),
version: get_version(dep),
dep: dep
}
end
defp filter_top_level(deps, opts) do
if Keyword.get(opts, :top_level_only) do
Enum.filter(deps, &(&1.dep.top_level))
else
deps
end
end
defp get_version(%Mix.Dep{status: {:ok, version}}), do: version
defp get_version(_), do: nil
#
# Search in hex_metadata.config
#
defp search_hex_metadata(licenses) when is_list(licenses), do: Enum.map(licenses, &search_hex_metadata/1)
defp search_hex_metadata(%License{} = license) do
Map.put(license, :hex_metadata, search_hex_metadata(license.dep))
end
defp search_hex_metadata(%Mix.Dep{} = dep) do
Mix.Dep.in_dependency(dep, fn _ ->
"hex_metadata.config"
|> :file.consult()
|> case do
{:ok, metadata} -> metadata
{:error, _} -> []
end
|> List.keyfind("licenses", 0)
|> case do
{_, licenses} -> licenses
_ -> nil
end
end)
end
#
# Search in LICENSE file
#
defp search_file(licenses) when is_list(licenses), do: Enum.map(licenses, &search_file/1)
defp search_file(%License{} = license) do
Map.put(license, :file, search_file(license.dep))
end
defp search_file(%Mix.Dep{} = dep) do
license_atom =
Mix.Dep.in_dependency(dep, fn _ ->
case File.cwd() do
{:ok, dir_path} -> FileAnalyzer.analyze(dir_path)
_ -> nil
end
end)
Map.get(@human_names, license_atom)
end
end