# licenses

[![crates.io](https://img.shields.io/crates/v/licenses)](https://crates.io/crates/licenses)
[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/lhalf/licenses/on_commit.yml)](https://github.com/lhalf/licenses/actions/workflows/on_commit.yml)
[![MIT](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)

Cargo subcommand for collecting licenses.

## Install

```bash
$ cargo install licenses
```

## Usage

```
$ cargo licenses --help
Usage: cargo licenses [OPTIONS] <COMMAND>

Commands:
  collect  Collects all licenses into a folder
  summary  Provides a summary of all licenses
  check    Checks all licenses for inconsistencies
  diff     Diff between the current licenses folder and the licenses that would be collected

Options:
  -d, --dev                  Include dev dependencies [default: excluded]
  -b, --build                Include build dependencies [default: excluded]
  -D, --depth <DEPTH>        The depth of dependencies to include [default: all sub dependencies]
  -e, --exclude <WORKSPACE>  Exclude specified workspace [default: all included]
  -i, --ignore <CRATE>       Ignore specified crate [default: all included]
  -c, --config <PATH>        Path to configuration file
  -h, --help                 Print help
```

## Commands

### Collect

Collects all licenses into a folder. 

The output folder path can be specified with `--path`, defaults to `licenses`. 

Prints a warning:
- If the crate had no declared license on crates.io (none declared)
- If no licenses were found for a crate (empty)
- If there were fewer licenses found for a crate than declared by the author on crates.io (too few)
- If there were more licenses found for a crate than declared by the author on crates.io (additional)
- If the content of the found licenses did not match the expected content for those licenses (mismatch)

```bash
$ cargo licenses collect --depth 1
```

```
licenses
├── anyhow-LICENSE-APACHE
├── anyhow-LICENSE-MIT
├── cargo_metadata-LICENSE-MIT
├── clap-LICENSE-APACHE
├── clap-LICENSE-MIT
├── colored-LICENSE
├── indicatif-LICENSE
├── itertools-LICENSE-APACHE
├── itertools-LICENSE-MIT
├── once_cell-LICENSE-APACHE
├── once_cell-LICENSE-MIT
├── serde-LICENSE-APACHE
├── serde-LICENSE-MIT
├── serde_json-LICENSE-APACHE
├── serde_json-LICENSE-MIT
├── spdx-LICENSE-APACHE
├── spdx-LICENSE-MIT
├── strsim-LICENSE
├── toml-LICENSE-APACHE
└── toml-LICENSE-MIT
```

### Summary

Summarises the declared licenses. 

The declared license is what the author declares the license as on crates.io, it is not necessarily the same
as the actual licenses. The warnings generated by the `collect` and `check` commands will highlight discrepancies between the
declared licenses and the actual licenses.

The summary can be formatted as JSON or TOML with `--json` or `--toml` respectively.

```
$ cargo licenses summary --depth 1
MIT - cargo_metadata,indicatif,strsim
MIT OR Apache-2.0 - anyhow,clap,itertools,once_cell,serde,serde_json,spdx,toml
MPL-2.0 - colored
```

### Check

Checks all licenses for inconsistencies.

Returns a non-zero exit code:
- If the crate had no declared license on crates.io (none declared)
- If no licenses were found for a crate (empty)
- If there were fewer licenses found for a crate than declared by the author on crates.io (too few)
- If there were more licenses found for a crate than declared by the author on crates.io (additional)
- If the content of the found licenses did not match the expected content for those licenses (mismatch)

```
$ cargo licenses check
warning: additional - found all declared licenses, but found additional licenses for:
        memchr - COPYING
        unicode_xid - COPYRIGHT
        utf8_iter - COPYRIGHT
warning: mismatch - found license(s) whose content was not similar to declared licenses for:
        portable_atomic - LICENSE-APACHE
```

### Diff

Compares the current collected licenses folder against the licenses that would be collected. 

Current licenses folder path can be specified with `--path`, defaults to `licenses`.

Returns a non-zero exit code if there is a difference between the licenses that would be collected and the current collected licenses folder.

```
$ cargo licenses diff
```

## Configuration

A [TOML](https://toml.io/en/) configuration file can be used to store all passed flags, as well as enabling options
on a per-crate basis. If both a config and a flag set the same option, the flag will take precedence.

```
$ cargo licenses <COMMAND> --config licenses.toml
```

### Skipping licenses

The configuration file allows the selective skipping of licenses found by the various subcommands.
It is recommended to provide a comment per skipped license to indicate why it is deemed okay to skip, for instance it might be
erroneously detected as a license because of the filename.

```toml
[crates]
example_crate = { skip = ["FILE"] } # comment on why the files are skipped
```

### Allowing warnings

Warnings generated by the `collect` or `check` command can be allowed in the configuration file, this allows erroneous 
warnings to be selectively silenced. It is recommended to provide a comment on why a warning is being allowed. The warnings
that can be allowed are included in the warning message, these are:
- `too few`
- `empty`
- `none declared`
- `{ additional = ["file1", "file2"] }`
- `{ mismatch = ["file1", "file2"] }`

```toml
[crates]
example_crate = { allow = "too few" }
```

### Include licenses

Additional licenses can be included for a specific crate via the configuration file.

```toml
[crates]
example_crate = { include = [{ name = "LICENSE", text = "custom license text" }] }
```

### Example

The below is an example of a TOML configuration file that could be used via the `--config` flag.

```toml
[global]
dev = true
build = true
depth = 1
exclude = ["workspace"]
ignore = ["crate"]

[crates]
crate_one = { skip = ["COPYING"] } # not a license, statement of which licenses the crate falls under
crate_two = { allow = { mismatch = ["LICENSE"] } } # erroneous license content mismatch
crate_three = { allow = "too few" } # only one license provided
```

## Usage patterns

This tool is designed to help collect required licenses when shipping software with open-source dependencies. The intended pattern of use would look as follows:

- `summary` provides a quick way to see if any dependencies are using stricter licenses that might not be suitable, copy-left for instance
- `collect` to collect all licenses into an output folder, this would be done manually and the license folder commited as part of the repository
- the previous command might have raised warnings about licenses found, or not found, these can be manually assessed then skipped or allowed in the configuration file
- as part of a continuous integration system, or as a pre-commit hook, a `diff` should be run to check the licenses folder hasn't missed any licenses added by new dependencies or removed by removing dependencies
- as part of a continuous integration system a `check` should be run to confirm all license inconsistencies have been handled in the configuration

## Legal disclaimer

This is provided as a convenience to help with collecting and reviewing open-source licenses. **It does not guarantee compliance with all legal licensing requirements.** It is
the user's responsibility to ensure that all applicable licenses are collected, reviewed and adhered to. The authors and contributors of this tool accept no liability for missing,
incomplete or inaccurate licenses files, or for any consequences arising from its use.
