/ build.rs
build.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm library.
  3  //
  4  // Alpha Chain | Delta Chain Protocol
  5  // International Monetary Graphite.
  6  //
  7  // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com).
  8  // They built world-class ZK infrastructure. We installed the EASY button.
  9  // Their cryptography: elegant. Our modifications: bureaucracy-compatible.
 10  // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours.
 11  //
 12  // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
 13  // All modifications and new work: CC0 1.0 Universal Public Domain Dedication.
 14  // No rights reserved. No permission required. No warranty. No refunds.
 15  //
 16  // https://creativecommons.org/publicdomain/zero/1.0/
 17  // SPDX-License-Identifier: CC0-1.0
 18  
 19  use std::{
 20      ffi::OsStr,
 21      fs::{self, File},
 22      io::Read,
 23      path::Path,
 24  };
 25  
 26  use walkdir::WalkDir;
 27  
 28  // The following license text that should be present at the beginning of every source file.
 29  const EXPECTED_LICENSE_TEXT: &[u8] = include_bytes!(".license_header");
 30  
 31  // The following directories will be excluded from the license scan.
 32  const DIRS_TO_SKIP: [&str; 5] = [".cargo", ".circleci", ".git", ".github", "target"];
 33  
 34  #[derive(Clone, Copy, PartialEq, Eq)]
 35  enum ImportOfInterest {
 36      Locktick,
 37      ParkingLot,
 38      Tokio,
 39  }
 40  
 41  fn check_locktick_imports<P: AsRef<Path>>(path: P) {
 42      let mut iter = WalkDir::new(path).into_iter();
 43      while let Some(entry) = iter.next() {
 44          let entry = entry.unwrap();
 45          let entry_type = entry.file_type();
 46  
 47          // Skip the specified directories.
 48          if entry_type.is_dir() && DIRS_TO_SKIP.contains(&entry.file_name().to_str().unwrap_or("")) {
 49              iter.skip_current_dir();
 50  
 51              continue;
 52          }
 53  
 54          let path = entry.path();
 55  
 56          // Ignore non-rs
 57          if path.extension() != Some(OsStr::new("rs")) {
 58              continue;
 59          }
 60  
 61          // Read the entire file.
 62          let file = fs::read_to_string(path).unwrap();
 63  
 64          // Prepare a filtered line iterator.
 65          let lines = file
 66              .lines()
 67              .filter(|l| !l.is_empty()) // Ignore empty lines.
 68              .skip_while(|l| !l.starts_with("use")) // Skip the license etc.
 69              .take_while(|l| { // Process the section containing import statements.
 70                  l.starts_with("use")
 71                      || l.starts_with("#[cfg")
 72                      || l.starts_with("//")
 73                      || *l == "};"
 74                      || l.starts_with(|c: char| c.is_ascii_whitespace())
 75              });
 76  
 77          // The currently processed import of interest.
 78          let mut import_of_interest: Option<ImportOfInterest> = None;
 79          // This value not being zero at the end of the imports suggests a missing locktick import.
 80          let mut lock_balance: i8 = 0;
 81  
 82          // Process the filtered lines.
 83          for line in lines {
 84              // Check if this is a lock-related import.
 85              if import_of_interest.is_none() {
 86                  if line.starts_with("use locktick::") {
 87                      import_of_interest = Some(ImportOfInterest::Locktick);
 88                  } else if line.starts_with("use parking_lot::") {
 89                      import_of_interest = Some(ImportOfInterest::ParkingLot);
 90                  } else if line.starts_with("use tokio::") {
 91                      import_of_interest = Some(ImportOfInterest::Tokio);
 92                  }
 93              }
 94  
 95              // Skip irrelevant imports.
 96              let Some(ioi) = import_of_interest else {
 97                  continue;
 98              };
 99  
100              // Modify the lock balance based on the type of the relevant import.
101              if [ImportOfInterest::ParkingLot, ImportOfInterest::Tokio].contains(&ioi) {
102                  if line.contains("Mutex") {
103                      lock_balance += 1;
104                  }
105                  if line.contains("RwLock") {
106                      lock_balance += 1;
107                  }
108              } else if ioi == ImportOfInterest::Locktick {
109                  // Use `matches` instead of just `contains` here, as more than a single
110                  // lock type entry is possible in a locktick import.
111                  for _hit in line.matches("Mutex") {
112                      lock_balance -= 1;
113                  }
114                  for _hit in line.matches("RwLock") {
115                      lock_balance -= 1;
116                  }
117                  // A correction in case of the `use tokio::Mutex as TMutex` convention.
118                  if line.contains("TMutex") {
119                      lock_balance += 1;
120                  }
121              }
122  
123              // Register the end of an import statement.
124              if line.ends_with(";") {
125                  import_of_interest = None;
126              }
127          }
128  
129          // If the file has a lock import "imbalance", print it out and increment the counter.
130          assert!(
131              lock_balance == 0,
132              "The locks in \"{}\" don't seem to have `locktick` counterparts!",
133              entry.path().display()
134          );
135      }
136  }
137  
138  fn check_file_licenses<P: AsRef<Path>>(path: P) {
139      let path = path.as_ref();
140  
141      let mut iter = WalkDir::new(path).into_iter();
142      while let Some(entry) = iter.next() {
143          let entry = entry.unwrap();
144          let entry_type = entry.file_type();
145  
146          // Skip the specified directories.
147          if entry_type.is_dir() && DIRS_TO_SKIP.contains(&entry.file_name().to_str().unwrap_or("")) {
148              iter.skip_current_dir();
149  
150              continue;
151          }
152  
153          // Check all files with the ".rs" extension.
154          if entry_type.is_file() && entry.file_name().to_str().unwrap_or("").ends_with(".rs") {
155              let file = File::open(entry.path()).unwrap();
156              let mut contents = Vec::with_capacity(EXPECTED_LICENSE_TEXT.len());
157              file.take(EXPECTED_LICENSE_TEXT.len() as u64).read_to_end(&mut contents).unwrap();
158  
159              assert!(
160                  contents == EXPECTED_LICENSE_TEXT,
161                  "The license in \"{}\" is either missing or it doesn't match the expected string!",
162                  entry.path().display()
163              );
164          }
165      }
166  }
167  
168  // The build script; it currently only checks the licenses.
169  fn main() {
170      // Check licenses in the current folder.
171      check_file_licenses(".");
172      // Ensure that lock imports have locktick counterparts.
173      check_locktick_imports(".");
174  }