NBPR.Spdx (NBPR v0.2.1)

Copy Markdown View Source

SPDX licence-list cache and validation.

Hex requires package: [licenses: ...] entries to be SPDX identifiers. Buildroot's <NAME>_LICENSE strings are mostly SPDX-aligned but use a few non-SPDX forms (GPL-2.0+ rather than GPL-2.0-or-later, etc.) and occasionally lag behind the upstream list. The generator validates each BR-supplied identifier against the canonical SPDX list and offers Jaro-distance suggestions when one doesn't match.

Cache

The list (~100 KB) is fetched on first use to $NERVES_ARTIFACTS_DIR/nbpr/spdx_licenses.json (same base as the BR tarball cache; XDG_DATA_HOME-aware, falling back to ~/.local/share). Subsequent calls read the cached file. Refresh with refresh!/0 or rm the file.

No hardcoded BR-to-SPDX translation table — when BR says GPL-2.0+, the suggestions surface GPL-2.0-or-later and friends, and the user picks. This keeps maintenance to zero at the cost of one extra decision per non-canonical licence.

Summary

Functions

Returns the absolute path the SPDX list is (or will be) cached at.

Ensures the SPDX list is cached locally and returns its path. Fetches from https://spdx.org/licenses/licenses.json on first call.

Returns the canonical list of current SPDX licence IDs — deprecated identifiers (GPL-2.0+, GPL-2.0, etc.) are filtered out so they surface as suggestion candidates for their replacements rather than passing validation. Hex publish rejects deprecated IDs, so accepting them here would just push the failure later.

Forces a refresh of the cached SPDX list. Use after an SPDX release if validation rejects an identifier you know to be current.

Returns :ok when id is a valid SPDX licence identifier; otherwise {:error, suggestions} with up to n ranked suggestions (default 3).

Functions

cache_path()

@spec cache_path() :: Path.t()

Returns the absolute path the SPDX list is (or will be) cached at.

ensure_cached!()

@spec ensure_cached!() :: Path.t()

Ensures the SPDX list is cached locally and returns its path. Fetches from https://spdx.org/licenses/licenses.json on first call.

license_ids()

@spec license_ids() :: [String.t()]

Returns the canonical list of current SPDX licence IDs — deprecated identifiers (GPL-2.0+, GPL-2.0, etc.) are filtered out so they surface as suggestion candidates for their replacements rather than passing validation. Hex publish rejects deprecated IDs, so accepting them here would just push the failure later.

refresh!()

@spec refresh!() :: Path.t()

Forces a refresh of the cached SPDX list. Use after an SPDX release if validation rejects an identifier you know to be current.

validate(id, n \\ 3)

@spec validate(String.t(), pos_integer()) :: :ok | {:error, [String.t()]}

Returns :ok when id is a valid SPDX licence identifier; otherwise {:error, suggestions} with up to n ranked suggestions (default 3).

Ranking weights case-insensitive longest-common-prefix heavily, with Jaro distance as a tiebreaker. Prefix weighting matters because SPDX IDs cluster into families (GPL-2.0-only, GPL-2.0-or-later, LGPL-…) and users typing a non-canonical form (GPL-2.0+) almost always want a sibling within the same family — pure edit-distance metrics rank equal-length unrelated IDs (MPL-2.0) above the actual family members.