Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate licenses summary #188

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
"lib/cbindings",
"lib/node",
"lib/web",
"licenses"
]

default-members = [
Expand Down
1 change: 1 addition & 0 deletions lib/cbindings/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[package]
name = "didkit-cbindings"
version = "0.1.0"
license = "Apache-2.0"
authors = ["Spruce Systems, Inc."]
edition = "2018"
publish = false
Expand Down
2 changes: 2 additions & 0 deletions licenses/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
licenses.txt
didkit.tree
12 changes: 12 additions & 0 deletions licenses/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "didkit-licenses"
version = "0.1.0"
authors = ["Spruce Systems, Inc."]
edition = "2018"
license = "Apache-2.0"
description = "Gather license info for didkit"
publish = false

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
62 changes: 62 additions & 0 deletions licenses/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# DIDKit Licenses

This crate produces a report showing the software and document packages and
licenses used by DIDKit and its dependencies. This report is intended for
informational purposes, and to assist compliance with license terms that
require distribution of covered software and/or documents to include the
license text, attribution, copyright notices, and/or other notices.

## Usage

Building this package produces a text file containing the license and packages
info: `licenses.txt`. This file can then be included in binary distributions of
DIDKit, i.e. as a file in a tarball alongside the binary executable/library,
and/or as an output of an interactive command or screen as part of the
distributed program.

When making a binary build of DIDKit for distribution,

## Updating

This package builds a license report using two input files from this directory:
`std.tree` and `didkit.tree`.

### DIDKit dependencies: `didkit.tree`

`didkit.tree` in this directory contains info about DIDKit's crate dependency
tree.

Run `./tree-didkit.sh` from this directory to build the `didkit.tree` file.

`didkit.tree` it is not checked into this repo, as it is expected to change often.

### Standard library dependencies: `std.tree`

`std.tree` in this directory contains info about the crate dependency tree of
the Rust runtime.

Run `./tree-std.sh` from this directory to rebuild the `std.tree` file.

`std.tree` is checked into this repo as it is expected to change relatively
slowly.

Rebuilding `std.tree` requires the [Rust](https://github.com/rust-lang/rust/)
repo cloned alongside DIDKit's repo, i.e. at `../../rust` relative to this
directory.

### Licenses

This package matches license identifiers against known license SPDX identifiers.
The license identifiers are mapped to license text files, e.g. in the `text/` directory. Some manual overrides are done in `build.rs`, e.g. for specific crates that do not have a license field in their package metadata.

## Updating

Before publishing a new binary release, run `./tree-didkit.sh` in this
directory to rebuild `didkit.tree`. Then build `licenses.txt` using `cargo
build` (`cargo build -p didkit-licenses` from the repo root).

`std.tree` in this directory should be updated (using `./tree-std.sh`) to
correspond to the Rust compiler/runtime version used to build DIDKit.

If this package's build script encounters new license strings, it will fail,
and `build.rs` must then be updated to handle those license strings.
173 changes: 173 additions & 0 deletions licenses/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::{BufRead, Read, Write};

#[derive(Debug)]
struct Pkg {
pub name: String,
pub version: String,
pub license: String,
pub path: Option<String>,
pub url: Option<String>,
}

fn normalize_license(license: String) -> Result<String, String> {
Ok(match &license[..] {
"Apache-2.0" => license,
"MIT" => license,
"ISC" => license,
"CC0-1.0" => license,
"BSD-2-Clause" => license,
"BSD-3-Clause" => license,
"MIT/Apache-2.0" | "Apache-2.0 / MIT" | "Apache-2.0/MIT" | "MIT / Apache-2.0"
| "Apache-2.0 OR MIT" | "MIT OR Apache-2.0" => "MIT OR Apache-2.0".to_string(),
"MIT OR Zlib OR Apache-2.0" | "Zlib OR Apache-2.0 OR MIT" | "MIT OR Apache-2.0 OR Zlib" => {
"MIT OR Apache-2.0 OR Zlib".to_string()
}
"Apache-2.0 OR BSL-1.0" => license,
"Unlicense/MIT" | "Unlicense OR MIT" => "Unlicense OR MIT".to_string(),
"Apache-2.0 AND W3C-20150513 AND CC-BY-SA-3.0" => license,
"MIT OR Apache-2.0 OR BSD-2-Clause" => license,
"0BSD OR MIT OR Apache-2.0" => license,
"MPL-2.0" => license,
"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT" => license,
"Ring" => license,
_ => Err(license)?,
})
}

fn fix_license(name: &str, version: &str) -> Option<&'static str> {
match (name, version) {
("sshkeys", "v0.3.1") => Some("BSD-2-Clause"),
("ring", "v0.16.20") => Some("Ring"),
("fuchsia-cprng", "v0.1.1") => Some("BSD-3-Clause"),
_ => None,
}
}

fn main() -> std::io::Result<()> {
let mut out = File::create("licenses.txt")?;
// https://doc.rust-lang.org/cargo/reference/build-scripts.html#rerun-if-changed
println!("cargo:rerun-if-changed=didkit.tree");
println!("cargo:rerun-if-changed=std.tree");
println!("cargo:rerun-if-changed=text/");

let mut seen = HashSet::new();
let mut pkgs = Vec::new();
let mut fail = false;
let didkit_tree_file = File::open("didkit.tree")?;
let std_tree_file = File::open("std.tree")?;
let trees = didkit_tree_file.chain(std_tree_file);
let reader = std::io::BufReader::new(trees);
for line in reader.lines() {
let line = line?;
if seen.contains(&line) {
continue;
}
seen.insert(line.to_string());
let mut words = line.split(" ");
let name = words.next().unwrap().to_string();
let version = words.next().unwrap().to_string();
let next = words.next().unwrap();
let (path, url) = if next.chars().nth(0) == Some('(') {
let path = next[1..(next.len() - 1)].to_string();
let next = words.next().unwrap().to_string();
(Some(path), next)
} else {
(None, next.to_string())
};
let url = if url == "" { None } else { Some(url) };
let mut license = words.collect::<Vec<&str>>().join(" ");
if license == "" {
if let Some(l) = fix_license(&name, &version) {
license = l.to_string();
} else {
eprintln!("Missing license for pkg: {} {}", name, version);
fail = true;
continue;
}
}
let license = match normalize_license(license) {
Ok(license) => license,
Err(license) => {
eprintln!("Unrecognized license string: {}", license);
fail = true;
continue;
}
};
let pkg = Pkg {
name,
version,
license,
path,
url,
};
pkgs.push(pkg);
}
if fail {
std::process::exit(1);
}
let mut licenses = HashSet::new();
let mut pkgs_by_license = HashMap::new();
for pkg in pkgs {
let license = pkg.license.to_string();
for license_option in license.split(" OR ") {
for license in license_option.split(" AND ") {
if !licenses.contains(license) {
licenses.insert(license.to_string());
}
}
if !licenses.contains(license_option) {
licenses.insert(license_option.to_string());
}
}
pkgs_by_license
.entry(license)
.or_insert_with(HashMap::new)
.insert(pkg.name.to_string(), pkg);
}
writeln!(&mut out, "# DIDKit Licenses")?;
writeln!(&mut out, "## Packages by license")?;
let mut licenses_vec = pkgs_by_license.keys().collect::<Vec<_>>();
licenses_vec.sort();
for license in licenses_vec {
let pkgs = pkgs_by_license.get(license).unwrap();
let mut pkg_names = pkgs.keys().collect::<Vec<_>>();
pkg_names.sort();
writeln!(&mut out, "- {}", license)?;
for pkg_name in pkg_names {
let pkg = pkgs.get(pkg_name).unwrap();
writeln!(&mut out, " - {} {}", pkg.name, pkg.version)?;
}
}
writeln!(&mut out, "")?;
writeln!(&mut out, "## Licenses")?;
writeln!(&mut out, "")?;
let mut licenses_vec = licenses.into_iter().collect::<Vec<_>>();
licenses_vec.sort();
for license in licenses_vec {
writeln!(&mut out, "### {}", license)?;
writeln!(&mut out, "```")?;
let license_filename = match &license[..] {
"Apache-2.0 AND W3C-20150513 AND CC-BY-SA-3.0" => {
writeln!(&mut out, include_str!("../../ssi/contexts/LICENSES.md"))?;
continue;
}
"Apache-2.0 WITH LLVM-exception" => {
writeln!(&mut out, include_str!("text/LLVM-exception.txt"))?;
continue;
}
"Apache-2.0" => {
writeln!(&mut out, include_str!("../LICENSE"))?;
continue;
}
_ => format!("text/{}.txt", license),
};
let mut file = File::open(license_filename)?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
out.write_all(&buf)?;
write!(&mut out, "```\n\n")?;
}
Ok(())
}
3 changes: 3 additions & 0 deletions licenses/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
print!(include_str!("../licenses.txt"));
}
17 changes: 17 additions & 0 deletions licenses/std.tree
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
alloc v0.0.0 https://github.com/rust-lang/rust.git MIT OR Apache-2.0
cfg-if v0.1.10 https://github.com/alexcrichton/cfg-if MIT/Apache-2.0
compiler_builtins v0.1.70 https://github.com/rust-lang/compiler-builtins MIT/Apache-2.0
core v0.0.0 https://github.com/rust-lang/rust.git MIT OR Apache-2.0
dlmalloc v0.2.3 https://github.com/alexcrichton/dlmalloc-rs MIT/Apache-2.0
fortanix-sgx-abi v0.3.3 https://github.com/fortanix/rust-sgx MPL-2.0
hashbrown v0.12.0 https://github.com/rust-lang/hashbrown Apache-2.0/MIT
hermit-abi v0.1.19 https://github.com/hermitcore/libhermit-rs MIT/Apache-2.0
libc v0.2.116 https://github.com/rust-lang/libc MIT OR Apache-2.0
panic_abort v0.0.0 https://github.com/rust-lang/rust.git MIT OR Apache-2.0
rustc-demangle v0.1.21 https://github.com/alexcrichton/rustc-demangle MIT/Apache-2.0
rustc-std-workspace-alloc v1.99.0 MIT OR Apache-2.0
rustc-std-workspace-core v1.99.0 MIT OR Apache-2.0
std v0.0.0 https://github.com/rust-lang/rust.git MIT OR Apache-2.0
std_detect v0.1.5 https://github.com/rust-lang/stdarch MIT/Apache-2.0
unwind v0.0.0 https://github.com/rust-lang/rust.git MIT OR Apache-2.0
wasi v0.11.0+wasi-snapshot-preview1 https://github.com/bytecodealliance/wasi Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
12 changes: 12 additions & 0 deletions licenses/text/0BSD.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Copyright (C) <year> <copyright holders>

Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 changes: 24 additions & 0 deletions licenses/text/BSD-2-Clause.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Copyright (c) <year> <copyright holders>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer
in this position and unchanged.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 changes: 28 additions & 0 deletions licenses/text/BSD-3-Clause.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Copyright (c) <year> <copyright holders>. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 changes: 23 additions & 0 deletions licenses/text/BSL-1.0.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.