# SPDX-FileCopyrightText: 2021 Rosa Richter
#
# SPDX-License-Identifier: MIT
defmodule Mix.Tasks.Licenses.Explain do
@moduledoc """
Prints all dependencies with unrecognized or non-OSI-approved licenses.
It is not mandatory for a package's `:licenses` value to contain only SPDX license identifiers, it is only recommended.
Therefore, some problems reported by `mix licenses` may be false alarms.
For example, a project may specify its license as `MIT License` rather than the SPDX identifier `MIT`.
## Command line options
* `--osi` - additionally check if all licenses are approved by the [Open Source Initiative](https://opensource.org/licenses)
* `--update` - pull down a fresh copy of the SPDX license list instead of using the version checked in with this tool.
"""
use Mix.Task
@shortdoc "Prints all dependencies with unrecognized or non-OSI-approved licenses."
def run(args) do
check_osi_approved = "--osi" in args
allowed_statuses =
if check_osi_approved do
[:osi_approved]
else
[:osi_approved, :not_approved]
end
license_list =
if "--update" in args do
HexLicenses.SPDX.fetch_licenses()
|> HexLicenses.SPDX.parse_licenses()
else
HexLicenses.SPDX.licenses()
end
unsafe_deps =
license_list
|> HexLicenses.license_check()
|> Enum.reject(fn {_deps, licenses} -> licenses == :not_in_hex end)
|> Enum.filter(fn {_dep, licenses} ->
Enum.any?(licenses, fn {_license, status} ->
status not in allowed_statuses
end)
end)
Enum.sort_by(unsafe_deps, fn {dep, _licenses} -> to_string(dep) end)
|> Enum.each(fn {dep, licenses} ->
unsafe_licenses =
Enum.filter(licenses, fn {_license, status} -> status not in allowed_statuses end)
Mix.shell().info("#{dep} has #{Enum.count(unsafe_licenses)} unsafe licenses:")
Enum.each(licenses, fn {license, status} ->
Mix.shell().info(status_line(license, status))
end)
end)
if Enum.empty?(unsafe_deps) do
if check_osi_approved do
Mix.shell().info("All dependencies have OSI-approved licenses.")
else
Mix.shell().info("All dependencies have recognized licenses.")
end
else
exit({:shutdown, 1})
end
end
defp status_line(license, :not_approved) do
" - \"#{license}\" is not OSI-approved."
end
defp status_line(license, :not_recognized) do
" - \"#{license}\" is not an SPDX ID."
end
defp status_line(license, :deprecated) do
" - \"#{license}\" is deprecated."
end
end