Skip to content

Commit

Permalink
Script license header check and update in rust
Browse files Browse the repository at this point in the history
The previous license header update, implemented in bash, would duplicate
the headers if run. The rules defined in that script also seem to have
been inconsistently applied. Having said that it is not clear what the
desired license header rule for this repo is.

The changes here implement the license check and update in rust. It runs
far faster, is more maintainable, does not duplicate the license header
if already present and would add it if it is missing.

The rules programmed in the rust implementation are specifically picked
to reduce the churn in code, and hopefully by the grace of reviewers,
learn what the intended rules for this repo should be.
  • Loading branch information
masih committed Oct 21, 2024
1 parent 4cb7342 commit 41b7798
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 50 deletions.
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ members = [
"testing/test_actors",
"testing/test_actors/actors/*",
"tools/fvm-bench",
"scripts/check-license",
]

[workspace.package]
Expand Down Expand Up @@ -45,7 +46,7 @@ futures = "0.3.28"
# IPLD/Encoding
cid = { version = "0.10.1", default-features = false }
multihash = { version = "0.18.1", default-features = false }
libipld = { version = "0.16.0", features = ["serde-codec"] }
libipld = { version = "0.16.0", features = ["serde-codec"] }
libipld-core = { version = "0.16.0", features = ["serde-codec"] }

# crypto
Expand All @@ -54,7 +55,7 @@ libsecp256k1 = { version = "0.7.1" }
bls-signatures = { version = "0.15", default-features = false }

# wasmtime
wasmtime = {version = "25.0.2", default-features = false, features = ["cranelift", "pooling-allocator", "parallel-compilation", "runtime"] }
wasmtime = { version = "25.0.2", default-features = false, features = ["cranelift", "pooling-allocator", "parallel-compilation", "runtime"] }
wasmtime-environ = "25.0.2"

# misc
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ build:

clean:
cargo clean
.PHONY: clean

lint:
cargo fmt --all --check
cargo clippy --all --all-targets -- -D warnings
.PHONY: lint

license:
./scripts/add_license.sh
cargo run --bin check-license -- .
.PHONY: license
3 changes: 1 addition & 2 deletions ipld/blockstore/src/block.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::fmt;

// Copyright 2021-2023 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT
use std::fmt;
use cid::multihash::{self, MultihashDigest};
use cid::Cid;

Expand Down
3 changes: 1 addition & 2 deletions ipld/encoding/src/ipld_block.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::fmt::{Debug, Formatter};

// Copyright 2021-2023 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT
use serde::de::value;
use std::fmt::{Debug, Formatter};
use {serde, serde_ipld_dagcbor};

use crate::{CodecProtocol, Error, RawBytes, CBOR, DAG_CBOR, IPLD_RAW};
Expand Down
41 changes: 0 additions & 41 deletions scripts/add_license.sh

This file was deleted.

12 changes: 12 additions & 0 deletions scripts/check-license/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "check-license"
version.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
authors.workspace = true

[dependencies]
walkdir = "2.5.0"
regex = "1.11.0"
lazy_static = "1.5.0"
105 changes: 105 additions & 0 deletions scripts/check-license/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// SPDX-License-Identifier: Apache-2.0, MIT
use regex::Regex;
use std::collections::HashSet;
use std::fs::{self, OpenOptions};
use std::io::{self, BufRead, BufReader, Write};
use std::path::{Path, PathBuf};
use walkdir::WalkDir;

const HEADER_LINES_TO_CHECK: usize = 3;

lazy_static::lazy_static! {
static ref PL_LICENSE: Regex = Regex::new(r"// Copyright \\d{4}-\\d{4} Protocol Labs").unwrap();
static ref CS_LICENSE: Regex = Regex::new(r"// Copyright \\d{4}-\\d{4} ChainSafe Systems").unwrap();
static ref SPDX_LICENSE: Regex = Regex::new(r"// SPDX-License-Identifier: Apache-2.0, MIT").unwrap();

/// LICENSE_CHECKS is a static vector containing tuples that define license validation rules.
/// Each tuple consists of:
/// - a regular expression to detect a license pattern,
/// - a boolean indicating whether the license is mandatory, and
/// - the text to add to file if license is not found.
static ref LICENSE_CHECKS: Vec<(&'static Regex, bool, &'static str)> = vec![
(&PL_LICENSE, false, "// Copyright 2021-2024 Protocol Labs"),
(&CS_LICENSE, false, "// Copyright 2019-2024 ChainSafe Systems"),
(&SPDX_LICENSE, true, "// SPDX-License-Identifier: Apache-2.0, MIT"),
];

/// IGNORED_DIRECTORIES is a static set containing directories to ignore during the license check.
static ref IGNORED_DIRECTORIES: HashSet<PathBuf> = {
let mut set = HashSet::new();
set.insert(PathBuf::from("./target/"));
set
};
}

/// This program expects the target directory as the first command-line argument. It recursively
/// checks all `.rs` files within the specified directory, skipping any directories that are listed
/// in the `IGNORED_DIRECTORIES` set. If a required license is missing, it is automatically added
/// to the beginning of the file.
fn main() {
let target_directory = std::env::args()
.nth(1)
.expect("Please provide the target directory as the first argument.");

check_and_add_license(&target_directory).expect("Error while checking files.");
}

fn check_and_add_license(directory: &str) -> io::Result<()> {
for entry in WalkDir::new(directory) {
let entry = entry?;
let path = entry.path();

if IGNORED_DIRECTORIES
.iter()
.any(|ignored_dir| path.starts_with(ignored_dir))
{
continue;
}

if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("rs") {
check_and_add_license_to_file(path)?;
}
}
Ok(())
}

fn check_and_add_license_to_file(path: &Path) -> io::Result<()> {
let file = fs::File::open(path)?;
let reader = BufReader::new(file);
let lines: Vec<String> = reader
.lines()
.take(HEADER_LINES_TO_CHECK)
.filter_map(Result::ok)
.collect();

let mut missing_licenses: Vec<&str> = Vec::new();
for (regex, is_required, text_to_add) in LICENSE_CHECKS.iter() {
let mut found_match = false;
for line in &lines {
if regex.is_match(line) {
found_match = true;
break;
}
}

if !found_match && *is_required {
missing_licenses.push(text_to_add);
}
}

if !missing_licenses.is_empty() {
println!("Adding license header to: {}", path.display());

let file_content = fs::read_to_string(path)?;
let mut file = OpenOptions::new().write(true).truncate(true).open(path)?;

for license in missing_licenses {
file.write_all(license.as_bytes())?;
file.write_all(b"\n")?;
}

file.write_all(file_content.as_bytes())?;
}

Ok(())
}
2 changes: 0 additions & 2 deletions scripts/copyright.txt

This file was deleted.

0 comments on commit 41b7798

Please sign in to comment.