From 612782a33d0ca4c4d1d215e3e9627a63a6510b7f Mon Sep 17 00:00:00 2001 From: Myrddin Dundragon Date: Tue, 24 Jun 2025 22:07:32 -0400 Subject: [PATCH] A quick cargo and git to add license headers. This was a quickly written tool to add the SPDX license header to all the *.rs files. It just checks if the license is at the top. If it isn't it stamps the file. If it is it ignores it. --- Cargo.lock | 7 ++ Cargo.toml | 15 ++- LICENSE.md | 219 ++++++++++++++++++++++++++++++----------- README.md | 21 +++- src/cargo_magistamp.rs | 85 ++++++++++++++++ src/magistamp.rs | 35 +++++++ src/main.rs | 20 ---- src/project.rs | 8 ++ src/stamper.rs | 65 ++++++++++++ 9 files changed, 393 insertions(+), 82 deletions(-) create mode 100644 Cargo.lock create mode 100644 src/cargo_magistamp.rs create mode 100644 src/magistamp.rs delete mode 100644 src/main.rs create mode 100644 src/stamper.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..d2c2f76 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "magistamp" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 804d1b0..d78c288 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,22 @@ [package] name = "magistamp" -version = "0.0.0" +version = "0.1.0" edition = "2021" -description = "🪄 Magistamp: A Rust tool to magically seal your source files with SPDX license headers." +description = "A Rust tool to magically seal your source files with SPDX license headers." repository = "/CyberMages/magistamp" authors = ["CyberMages LLC ", "Jason Travis Smith "] readme = "README.md" -license-file = "LICENSE.md" +license = "Apache-2.0" +[[bin]] +name = "magistamp" +path = "src/magistamp.rs" + +[[bin]] +name = "cargo-magistamp" +path = "src/cargo_magistamp.rs" + + [dependencies] diff --git a/LICENSE.md b/LICENSE.md index 0a2e8d7..cad616a 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,69 +1,174 @@ -Copyright (c) <2025> CyberMages LLC +# Apache License +Version 2.0, January 2004 + -Redistribution and use in source and binary forms, with or -without modification, are permitted provided that the -following conditions are met: +## TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -1. Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. +### 1. Definitions. -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. +**"License"** shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. -Subject to the terms and conditions of this license, each -copyright holder and contributor hereby grants to those -receiving rights under this license a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, -irrevocable (except for failure to satisfy the conditions -of this license) patent license to make, have made, use, -offer to sell, sell, import, and otherwise transfer this -software, where such license applies only to those patent -claims, already acquired or hereafter acquired, licensable -by such copyright holder or contributor that are -necessarily infringed by: +**"Licensor"** shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. - (a) their Contribution(s) (the licensed copyrights of - copyright holders and non-copyrightable additions - of contributors, in source or binary form) alone; +**"Legal Entity"** shall mean the union of the acting entity and all +other entities that control, are controlled by, or are under common +control with that entity. For the purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. - -- or -- +**"You" (or "Your")** shall mean an individual or Legal Entity exercising +permissions granted by this License. - (b) combination of their Contribution(s) with the work - of authorship to which such Contribution(s) was - added by such copyright holder or contributor, if, - at the time the Contribution is added, such - addition causes such combination to be necessarily - infringed. The patent license shall not apply to - any other combinations which include the - Contribution. +**"Source" form** shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, +and configuration files. -Except as expressly stated above, no rights or licenses -from any copyright holder or contributor is granted under -this license, whether expressly, by implication, estoppel -or otherwise. +**"Object" form** shall mean any form resulting from mechanical +transformation or translation of a Source form, including but not +limited to compiled object code, generated documentation, and +conversions to other media types. +**"Work"** shall mean the work of authorship, whether in Source or +Object form, made available under the License, as indicated by a +copyright notice that is included in or attached to the work +(an example is provided in the Appendix below). -DISCLAIMER +**"Derivative Works"** shall mean any work, whether in Source or Object +form, that is based on (or derived from) the Work and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. For the purposes +of this License, Derivative Works shall not include works that remain +separable from, or merely link (or bind by name) to the interfaces of, +the Work and Derivative Works thereof. -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 -HOLDERS 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. +**"Contribution"** shall mean any work of authorship, including the +original version of the Work and any modifications or additions to that +Work or Derivative Works thereof, that is intentionally submitted to +the Licensor for inclusion in the Work by the copyright owner or by an +individual or Legal Entity authorized to submit on behalf of the +copyright owner. -YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT DESIGNED, -LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, -OPERATION OR MAINTENANCE OF ANY MILITARY FACILITY OR -RELIGIOUS INSTITUTION. +**"Contributor"** shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +### 2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor +hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable copyright license to reproduce, prepare +Derivative Works of, publicly display, publicly perform, sublicense, +and distribute the Work and such Derivative Works in Source or Object +form. + +### 3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor +hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable (except as stated in this section) patent +license to make, have made, use, offer to sell, sell, import, and +otherwise transfer the Work, where such license applies only to those +patent claims licensable by such Contributor that are necessarily +infringed by their Contribution(s) alone or by combination of their +Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that +the Work or a Contribution incorporated within the Work constitutes +direct or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate as of +the date such litigation is filed. + +### 4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works +thereof in any medium, with or without modifications, and in Source or +Object form, provided that You meet the following conditions: + +1. You must give any other recipients of the Work or Derivative Works a + copy of this License; and + +2. You must cause any modified files to carry prominent notices stating + that You changed the files; and + +3. You must retain, in the Source form of any Derivative Works that You + distribute, all copyright, patent, trademark, and attribution notices + from the Source form of the Work, excluding those notices that do not + pertain to any part of the Derivative Works; and + +4. If the Work includes a "NOTICE" text file as part of its distribution, + then any Derivative Works that You distribute must include a readable + copy of the attribution notices contained within such NOTICE file, + excluding those notices that do not pertain to any part of the + Derivative Works, in at least one of the following places: within a + NOTICE text file distributed as part of the Derivative Works; within + the Source form or documentation, if provided along with the Derivative + Works; or, within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents of the + NOTICE file are for informational purposes only and do not modify the + License. You may add Your own attribution notices within Derivative + Works that You distribute, alongside or as an addendum to the NOTICE + text from the Work, provided that such additional attribution notices + cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may +provide additional or different license terms and conditions for use, +reproduction, or distribution of Your modifications, or for any such +Derivative Works as a whole, provided Your use, reproduction, and +distribution of the Work otherwise complies with the conditions stated +in this License. + +### 5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally +submitted for inclusion in the Work by You to the Licensor shall be +under the terms and conditions of this License, without any additional +terms or conditions. Notwithstanding the above, nothing herein shall +supersede or modify the terms of any separate license agreement you +may have executed with Licensor regarding such Contributions. + +### 6. Trademarks. + +This License does not grant permission to use the trade names, +trademarks, service marks, or product names of the Licensor, except as +required for describing the origin of the Work and reproducing the +content of the NOTICE file. + +### 7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor +provides the Work (and each Contributor provides its Contributions) on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +express or implied, including, without limitation, any warranties or +conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR +A PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +### 8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including +negligence), contract, or otherwise, unless required by applicable law +(such as deliberate and grossly negligent acts) or agreed to in writing, +shall any Contributor be liable to You for damages, including any direct, +indirect, special, incidental, or consequential damages of any character +arising as a result of this License or out of the use or inability to use +the Work (including but not limited to damages for loss of goodwill, work +stoppage, computer failure or malfunction, or any and all other commercial +damages or losses), even if such Contributor has been advised of the +possibility of such damages. + +### 9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose +to offer, and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this License. +However, in accepting such obligations, You may act only on Your own behalf +and on Your sole responsibility, not on behalf of any other Contributor, +and only if You agree to indemnify, defend, and hold each Contributor +harmless for any liability incurred by, or claims asserted against, such +Contributor by reason of your accepting any such warranty or additional +liability. diff --git a/README.md b/README.md index cae555e..ab2dc8c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,20 @@ -# magistamp +# Magistamp -🪄 Magistamp: A Rust tool to magically seal your source files with SPDX license headers. +A Rust tool to magically seal your source files with SPDX license headers. + + + +--- + +## Copyright & License + +Copyright 2015 CyberMages LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this library except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS diff --git a/src/cargo_magistamp.rs b/src/cargo_magistamp.rs new file mode 100644 index 0000000..48664e5 --- /dev/null +++ b/src/cargo_magistamp.rs @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: Apache-2.0 +// Sealed with Magistamp. + +//! A Rust tool to magically seal your source files with SPDX license headers. + +mod project; +mod stamper; + + + +use std::path::PathBuf; +use std::process::Command; +use std::io; + +use crate::stamper::*; + + + +/// Print the version of the project. +#[allow(dead_code)] +fn print_version() +{ + println!("{} v{}", project::get_name(), project::get_version()); +} + + +fn get_workspace_root() -> io::Result { + let output = Command::new("cargo") + .args(&["metadata", "--no-deps", "--format-version", "1"]) + .output()?; + + if !output.status.success() { + return Err(io::Error::new(io::ErrorKind::Other, "cargo metadata failed")); + } + + let metadata_json = String::from_utf8(output.stdout) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + + let workspace_root = parse_workspace_root(&metadata_json)?; + Ok(workspace_root) +} + +fn parse_workspace_root(json: &str) -> io::Result { + + match json.find("\"workspace_root\"") + { + None => {} + + Some(index) => + { + let sub = &json[index+17..]; + let mut start = 0; + let mut one_more = false; + + for (i, c) in sub.chars().enumerate() + { + if c == '"' + { + if !one_more + { + start = i+1; + one_more = true; + } + else + { + return Ok(PathBuf::from(sub[start..i].to_owned())); + } + } + } + } + } + + Err(io::Error::new(io::ErrorKind::Other, "workspace_root not found")) +} + + +fn main() -> io::Result<()> +{ + let path = get_workspace_root()?; + + println!("workspace root: {}", path.display()); + Stamper::visit_dirs(&path)?; + + Ok(()) +} diff --git a/src/magistamp.rs b/src/magistamp.rs new file mode 100644 index 0000000..cada582 --- /dev/null +++ b/src/magistamp.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: Apache-2.0 +// Sealed with Magistamp. + +//! A Rust tool to magically seal your source files with SPDX license headers. + +mod project; +mod stamper; + + + +use std::path::Path; +use std::{env, io}; + +use crate::stamper::*; + + + +/// Print the version of the project. +#[allow(dead_code)] +fn print_version() +{ + println!("{} v{}", project::get_name(), project::get_version()); +} + + + +fn main() -> io::Result<()> +{ + let dir = env::args().nth(1).unwrap_or_else(|| ".".to_string()); + let path = Path::new(&dir); + + Stamper::visit_dirs(path)?; + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index b13b727..0000000 --- a/src/main.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! 🪄 Magistamp: A Rust tool to magically seal your source files with SPDX license headers. - - - -mod project; - - - -/// Print the version of the project. -fn print_version() -{ - println!("{} v{}", project::get_name(), project::get_version()); -} - - -/// The usual starting point of your project. -fn main() -{ - print_version(); -} diff --git a/src/project.rs b/src/project.rs index a977e1c..a79718b 100644 --- a/src/project.rs +++ b/src/project.rs @@ -1,14 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 +// Sealed with Magistamp. + //! This is where the Projects build information can be retreived from. /// The environment variable defined by Cargo for the name. +#[allow(dead_code)] const NAME: Option<&str> = option_env!("CARGO_PKG_NAME"); /// The environment variable defined by Cargo for the version. +#[allow(dead_code)] const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION"); /// The string to display if a value is not defined during compile time. +#[allow(dead_code)] const NOT_DEFINED: &'static str = "UNDEFINED"; @@ -17,6 +23,7 @@ const NOT_DEFINED: &'static str = "UNDEFINED"; /// set at compile time and comes from the Cargo.toml file. /// /// If a value is not found, then it will return the not defined value. +#[allow(dead_code)] pub fn get_name() -> &'static str { NAME.unwrap_or(NOT_DEFINED) @@ -27,6 +34,7 @@ pub fn get_name() -> &'static str /// set at compile time and comes from the Cargo.toml file. /// /// If a value is not found, then it will return the not defined value. +#[allow(dead_code)] pub fn get_version() -> &'static str { VERSION.unwrap_or(NOT_DEFINED) diff --git a/src/stamper.rs b/src/stamper.rs new file mode 100644 index 0000000..c7b8e6e --- /dev/null +++ b/src/stamper.rs @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: Apache-2.0 +// Sealed with Magistamp. + +use std::fs::{read_to_string, write}; +use std::path::Path; +use std::{fs, io}; + + + +const SPDX_HEADER: &str = "\ +// SPDX-License-Identifier: Apache-2.0 +// Sealed with Magistamp. + +"; + + + +pub enum Stamper {} + + + +impl Stamper +{ + pub fn visit_dirs(dir: &Path) -> io::Result<()> + { + if dir.is_dir() + { + for entry in fs::read_dir(dir)? + { + let entry = entry?; + let path = entry.path(); + if path.is_dir() + { + Stamper::visit_dirs(&path)?; + } + else if path.extension().and_then(|s| s.to_str()) == Some("rs") + { + Stamper::process_file(&path); + } + } + } + + Ok(()) + } + + fn process_file(path: &Path) + { + if let Ok(content) = read_to_string(path) + { + if content.starts_with("// SPDX-License-Identifier:") + { + return; // Already has a header + } + + println!("🪄 Magistamp: sealing {} with SPDX protection...", + path.display()); + + let new_content = format!("{SPDX_HEADER}{content}"); + if let Err(e) = write(path, new_content) + { + eprintln!("Failed to write to {}: {}", path.display(), e); + } + } + } +}