-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Change generate-copyright to generate HTML, with cargo dependencies included #128353
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
Merged
bors
merged 10 commits into
rust-lang:master
from
ferrocene:jonathanpallant/add-dependencies-to-copyright-file
Aug 7, 2024
Merged
Changes from 8 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
ba0d6c9
Update generate-copyright
jonathanpallant 204e3ea
generate-copyright: Produce HTML, not Markdown
jonathanpallant 56f8479
generate-copyright: Fix typo
jonathanpallant dbab595
generate-copyright: use cargo-metadata
jonathanpallant f7e6bf6
generate-copyright: use rinja to format the output
jonathanpallant 37ab090
REUSE.toml: Copyright text isn't parsed as Markdown.
jonathanpallant 30ac7c9
generate-copyright: Render Node with rinja too.
jonathanpallant 5277b67
generate-copyright: gather files inside interesting folders
jonathanpallant 4e24e9b
Update to rinja 0.3
jonathanpallant 99579f3
Apparently library/std is now part of a workspace at library/
jonathanpallant File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
//! Gets metadata about a workspace from Cargo | ||
|
||
use std::collections::BTreeMap; | ||
use std::ffi::OsStr; | ||
use std::path::{Path, PathBuf}; | ||
|
||
/// Describes how this module can fail | ||
#[derive(Debug, thiserror::Error)] | ||
pub enum Error { | ||
#[error("I/O Error: {0:?}")] | ||
Io(#[from] std::io::Error), | ||
#[error("Failed get output from cargo-metadata: {0:?}")] | ||
GettingMetadata(#[from] cargo_metadata::Error), | ||
#[error("Failed to run cargo vendor: {0:?}")] | ||
LaunchingVendor(std::io::Error), | ||
#[error("Failed to complete cargo vendor")] | ||
RunningVendor, | ||
#[error("Bad path {0:?} whilst scraping files")] | ||
Scraping(PathBuf), | ||
} | ||
|
||
/// Uniquely describes a package on crates.io | ||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||
pub struct Package { | ||
/// The name of the package | ||
pub name: String, | ||
/// The version number | ||
pub version: String, | ||
} | ||
|
||
/// Extra data about a package | ||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||
pub struct PackageMetadata { | ||
/// The license it is under | ||
pub license: String, | ||
/// The list of authors from the package metadata | ||
pub authors: Vec<String>, | ||
/// A list of important files from the package, with their contents. | ||
/// | ||
/// This includes *COPYRIGHT*, *NOTICE*, *AUTHOR*, *LICENSE*, and *LICENCE* files, case-insensitive. | ||
pub notices: BTreeMap<String, String>, | ||
/// If this is true, this dep is in the Rust Standard Library | ||
pub is_in_libstd: Option<bool>, | ||
} | ||
|
||
/// Use `cargo metadata` and `cargo vendor` to get a list of dependencies and their license data. | ||
/// | ||
/// This will involve running `cargo vendor` into `${BUILD}/vendor` so we can | ||
/// grab the license files. | ||
/// | ||
/// Any dependency with a path beginning with `root_path` is ignored, as we | ||
/// assume `reuse` has covered it already. | ||
pub fn get_metadata_and_notices( | ||
cargo: &Path, | ||
dest: &Path, | ||
root_path: &Path, | ||
manifest_paths: &[&Path], | ||
) -> Result<BTreeMap<Package, PackageMetadata>, Error> { | ||
let mut output = get_metadata(cargo, root_path, manifest_paths)?; | ||
|
||
// Now do a cargo-vendor and grab everything | ||
let vendor_path = dest.join("vendor"); | ||
println!("Vendoring deps into {}...", vendor_path.display()); | ||
run_cargo_vendor(cargo, &vendor_path, manifest_paths)?; | ||
|
||
// Now for each dependency we found, go and grab any important looking files | ||
for (package, metadata) in output.iter_mut() { | ||
load_important_files(package, metadata, &vendor_path)?; | ||
} | ||
|
||
Ok(output) | ||
} | ||
|
||
/// Use `cargo metadata` to get a list of dependencies and their license data. | ||
/// | ||
/// Any dependency with a path beginning with `root_path` is ignored, as we | ||
/// assume `reuse` has covered it already. | ||
pub fn get_metadata( | ||
cargo: &Path, | ||
root_path: &Path, | ||
manifest_paths: &[&Path], | ||
) -> Result<BTreeMap<Package, PackageMetadata>, Error> { | ||
let mut output = BTreeMap::new(); | ||
// Look at the metadata for each manifest | ||
for manifest_path in manifest_paths { | ||
if manifest_path.file_name() != Some(OsStr::new("Cargo.toml")) { | ||
panic!("cargo_manifest::get requires a path to a Cargo.toml file"); | ||
} | ||
let metadata = cargo_metadata::MetadataCommand::new() | ||
.cargo_path(cargo) | ||
.env("RUSTC_BOOTSTRAP", "1") | ||
.manifest_path(manifest_path) | ||
.exec()?; | ||
for package in metadata.packages { | ||
let manifest_path = package.manifest_path.as_path(); | ||
if manifest_path.starts_with(root_path) { | ||
// it's an in-tree dependency and reuse covers it | ||
continue; | ||
} | ||
// otherwise it's an out-of-tree dependency | ||
let package_id = Package { name: package.name, version: package.version.to_string() }; | ||
output.insert( | ||
package_id, | ||
PackageMetadata { | ||
license: package.license.unwrap_or_else(|| String::from("Unspecified")), | ||
authors: package.authors, | ||
notices: BTreeMap::new(), | ||
is_in_libstd: None, | ||
}, | ||
); | ||
} | ||
} | ||
|
||
Ok(output) | ||
} | ||
|
||
/// Run cargo-vendor, fetching into the given dir | ||
fn run_cargo_vendor(cargo: &Path, dest: &Path, manifest_paths: &[&Path]) -> Result<(), Error> { | ||
let mut vendor_command = std::process::Command::new(cargo); | ||
vendor_command.env("RUSTC_BOOTSTRAP", "1"); | ||
vendor_command.arg("vendor"); | ||
vendor_command.arg("--quiet"); | ||
vendor_command.arg("--versioned-dirs"); | ||
for manifest_path in manifest_paths { | ||
vendor_command.arg("-s"); | ||
vendor_command.arg(manifest_path); | ||
} | ||
vendor_command.arg(dest); | ||
|
||
let vendor_status = vendor_command.status().map_err(Error::LaunchingVendor)?; | ||
|
||
if !vendor_status.success() { | ||
return Err(Error::RunningVendor); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Add important files off disk into this dependency. | ||
/// | ||
/// Maybe one-day Cargo.toml will contain enough information that we don't need | ||
/// to do this manual scraping. | ||
fn load_important_files( | ||
package: &Package, | ||
dep: &mut PackageMetadata, | ||
vendor_root: &Path, | ||
) -> Result<(), Error> { | ||
let name_version = format!("{}-{}", package.name, package.version); | ||
println!("Scraping notices for {}...", name_version); | ||
let dep_vendor_path = vendor_root.join(name_version); | ||
for entry in std::fs::read_dir(dep_vendor_path)? { | ||
let entry = entry?; | ||
let metadata = entry.metadata()?; | ||
let path = entry.path(); | ||
let Some(filename) = path.file_name() else { | ||
return Err(Error::Scraping(path)); | ||
}; | ||
let lc_filename = filename.to_ascii_lowercase(); | ||
let lc_filename_str = lc_filename.to_string_lossy(); | ||
let mut keep = false; | ||
for m in ["copyright", "licence", "license", "author", "notice"] { | ||
if lc_filename_str.contains(m) { | ||
keep = true; | ||
break; | ||
} | ||
} | ||
if keep { | ||
if metadata.is_dir() { | ||
for inner_entry in std::fs::read_dir(entry.path())? { | ||
let inner_entry = inner_entry?; | ||
if inner_entry.metadata()?.is_file() { | ||
let inner_filename = inner_entry.file_name(); | ||
let inner_filename_str = inner_filename.to_string_lossy(); | ||
let qualified_filename = | ||
format!("{}/{}", lc_filename_str, inner_filename_str); | ||
println!("Scraping {}", qualified_filename); | ||
dep.notices.insert( | ||
qualified_filename.to_string(), | ||
std::fs::read_to_string(inner_entry.path())?, | ||
); | ||
} | ||
} | ||
} else if metadata.is_file() { | ||
let filename = filename.to_string_lossy(); | ||
println!("Scraping {}", filename); | ||
dep.notices.insert(filename.to_string(), std::fs::read_to_string(path)?); | ||
} | ||
} | ||
} | ||
Ok(()) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.