Current section
Files
Jump to
Current section
Files
lib/kudos.ex
defmodule Kudos do
@moduledoc """
Documentation for Kudos.
"""
@license_file_names ~w(LICENSE.txt LICENSE.md LICENSE license.txt license.md license LICENSE-2.0.txt)
@readme_file_names ~w(README.md README.markdown)
@doc """
Generates a licenses file in the root dir with the licenses of all deps.
## Examples
iex> Kudos.generate() |> String.length()
219
iex> Kudos.generate(false) |> String.length()
219
iex> Kudos.generate(true) |> String.length()
19050
"""
def generate(include_dev_deps \\ false) do
load_deps_meta_data(include_dev_deps)
|> Enum.reduce(header(), fn meta_data, resp ->
resp <> format(meta_data)
end)
|> String.trim()
end
defp header() do
"""
# Project Licenses
This file was generated by the kudos utility. It contains the name, version and checksum, description, links, maintainers and license information for every dependency in this project.
## Dependencies
"""
end
defp format(:umbrella) do
""
end
defp format(:dev) do
""
end
defp format(meta_data) do
"""
### #{meta_data.name} (Version #{meta_data.version} | Checksum: #{checksum(meta_data.checksum)})
#{meta_data.description}
Links: #{links(meta_data.links)}
Maintainers: #{maintainers(meta_data.maintainers)}
Licenses Used: #{meta_data.licenses}
#{meta_data.license_file}
"""
end
defp checksum(value) when is_list(value) do
value[:branch]
end
defp checksum(value) do
value
end
defp maintainers(values) when is_nil(values) do
""
end
defp maintainers(values) when is_map(values) do
Map.to_list(values)
|> maintainers()
end
defp maintainers(values) when is_list(values) do
Enum.join(values, ", ")
end
defp links(values) when is_nil(values) do
""
end
defp links(values) when is_map(values) do
Map.to_list(values)
|> Enum.map(&prepare_link(&1))
|> Enum.join(", ")
end
defp prepare_link(value) when is_tuple(value) do
"[#{elem(value, 0)}](#{elem(value, 1)})"
end
defp prepare_link({key, value}) do
"[#{key}](#{value})"
end
defp load_deps_meta_data(include_dev_deps) do
Mix.Dep.load_on_environment([])
|> Enum.map(fn dep ->
Mix.Dep.in_dependency(dep, fn _ ->
case is_umbrella?(dep) do
true ->
:umbrella
false ->
case include_dev_deps || is_prod?(dep) do
false ->
:dev
_ ->
%{
name: Atom.to_string(Mix.Project.config()[:app]),
version: Mix.Project.config()[:version],
checksum: elem(dep.opts[:lock], 3),
description: Mix.Project.config()[:description],
source_url: Mix.Project.config()[:source_url],
links: get_in(Mix.Project.config(), [:package, :links]),
maintainers: get_in(Mix.Project.config(), [:package, :maintainers]),
licenses: get_in(Mix.Project.config(), [:package, :licenses]),
license_file: get_license_file_content(dep.opts[:dest])
}
end
end
end)
end)
end
defp is_umbrella?(dep) do
case List.keyfind(dep.opts, :in_umbrella, 0, {:in_umbrella, false}) do
{:in_umbrella, true} -> true
{:in_umbrella, false} -> from_umbrella?(dep)
end
end
defp from_umbrella?(dep) do
case List.keyfind(dep.opts, :from_umbrella, 0, {:from_umbrella, false}) do
{:from_umbrella, true} -> true
{:from_umbrella, false} -> false
end
end
defp is_prod?(dep) do
only = List.keyfind(dep.opts, :only, 0, [])
case only do
[] -> true
_ -> false
end
end
defp get_license_file_content(path) do
(File.ls!(path) -- File.ls!(path) -- @license_file_names)
|> read_license_file(path)
end
defp read_license_file([], path) do
read_license_from_readme_file(path)
end
defp read_license_file([first_file_name | _], path) do
Path.join(path, first_file_name)
|> File.read!()
end
defp read_license_from_readme_file(path) do
files = File.ls!(path) -- File.ls!(path) -- @readme_file_names
read_license_from_readme_file(files, path)
end
defp read_license_from_readme_file([], _path) do
"Full license text not found in dependency source."
end
defp read_license_from_readme_file([first_file_name | _], path) do
readme_content =
Path.join(path, first_file_name)
|> File.read!()
case String.split(readme_content, "# License", parts: 2) do
[_, content] ->
content
_ ->
"Full license text not found in dependency source."
end
end
end