| 1 | use std::{ |
| 2 | env, |
| 3 | io::{self, Read}, |
| 4 | process, |
| 5 | }; |
| 6 | use walkdir::WalkDir; |
| 7 | |
| 8 | fn dir_size_bytes(root: &str) -> io::Result<u64> { |
| 9 | let mut total: u64 = 0; |
| 10 | for entry in WalkDir::new(root).follow_links(false) { |
| 11 | let entry = entry.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?; |
| 12 | if entry.file_type().is_file() { |
| 13 | let md = entry.metadata()?; |
| 14 | total = total.saturating_add(md.len()); |
| 15 | } |
| 16 | } |
| 17 | Ok(total) |
| 18 | } |
| 19 | |
| 20 | fn main() { |
| 21 | // Consume stdin (pre-receive provides ref updates on stdin) |
| 22 | let mut _stdin = String::new(); |
| 23 | let _ = io::stdin().read_to_string(&mut _stdin); |
| 24 | |
| 25 | let max_bytes: u64 = env::var("MAX_REPO_BYTES") |
| 26 | .ok() |
| 27 | .and_then(|v| v.parse::<u64>().ok()) |
| 28 | .unwrap_or(50 * 1024 * 1024); |
| 29 | |
| 30 | let size = match dir_size_bytes(".") { |
| 31 | Ok(s) => s, |
| 32 | Err(e) => { |
| 33 | eprintln!("quota hook error: failed to compute repo size: {e}"); |
| 34 | process::exit(1); |
| 35 | } |
| 36 | }; |
| 37 | |
| 38 | if size > max_bytes { |
| 39 | eprintln!("Rejected: repo exceeds quota ({} bytes > {} bytes).", size, max_bytes); |
| 40 | process::exit(1); |
| 41 | } |
| 42 | |
| 43 | process::exit(0); |
| 44 | } |