chore: use nightly rustfmt rules

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ia3745c82c92a78e8326d2e0e446f20d66a6a6964
This commit is contained in:
raf 2025-11-14 21:47:33 +03:00
commit c3321858c4
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
11 changed files with 912 additions and 799 deletions

View file

@ -1 +1,27 @@
condense_wildcard_suffixes = true
doc_comment_code_block_width = 80
edition = "2024" # Keep in sync with Cargo.toml.
enum_discrim_align_threshold = 60
force_explicit_abi = false
force_multiline_blocks = true
format_code_in_doc_comments = true
format_macro_matchers = true
format_strings = true
group_imports = "StdExternalCrate"
hex_literal_case = "Upper"
imports_granularity = "Crate"
imports_layout = "HorizontalVertical"
inline_attribute_width = 60
match_block_trailing_comma = true
max_width = 80
newline_style = "Unix"
normalize_comments = true
normalize_doc_attributes = true
overflow_delimited_expr = true
struct_field_align_threshold = 60
tab_spaces = 2
unstable_features = true
use_field_init_shorthand = true
use_try_shorthand = true
wrap_comments = true

View file

@ -1,5 +1,12 @@
use crate::error::Result; use crate::{
use crate::util::{HashExtractor, NixErrorClassifier, NixFileFixer, handle_nix_with_retry}; error::Result,
util::{
HashExtractor,
NixErrorClassifier,
NixFileFixer,
handle_nix_with_retry,
},
};
pub fn handle_nix_build( pub fn handle_nix_build(
args: &[String], args: &[String],

View file

@ -1,7 +1,10 @@
use std::{
collections::VecDeque,
io::{self, Read, Write},
process::{Command, ExitStatus, Output, Stdio},
};
use crate::error::{EhError, Result}; use crate::error::{EhError, Result};
use std::collections::VecDeque;
use std::io::{self, Read, Write};
use std::process::{Command, ExitStatus, Output, Stdio};
/// Trait for log interception and output handling. /// Trait for log interception and output handling.
pub trait LogInterceptor: Send { pub trait LogInterceptor: Send {
@ -60,7 +63,11 @@ impl NixCommand {
self self
} }
pub fn env<K: Into<String>, V: Into<String>>(mut self, key: K, value: V) -> Self { pub fn env<K: Into<String>, V: Into<String>>(
mut self,
key: K,
value: V,
) -> Self {
self.env.push((key.into(), value.into())); self.env.push((key.into(), value.into()));
self self
} }
@ -91,7 +98,9 @@ impl NixCommand {
let mut cmd = Command::new("nix"); let mut cmd = Command::new("nix");
cmd.arg(&self.subcommand); cmd.arg(&self.subcommand);
if self.print_build_logs && !self.args.iter().any(|a| a == "--no-build-output") { if self.print_build_logs
&& !self.args.iter().any(|a| a == "--no-build-output")
{
cmd.arg("--print-build-logs"); cmd.arg("--print-build-logs");
} }
if self.impure { if self.impure {
@ -113,11 +122,15 @@ impl NixCommand {
cmd.stderr(Stdio::piped()); cmd.stderr(Stdio::piped());
let mut child = cmd.spawn()?; let mut child = cmd.spawn()?;
let child_stdout = child.stdout.take().ok_or_else(|| EhError::CommandFailed { let child_stdout = child.stdout.take().ok_or_else(|| {
EhError::CommandFailed {
command: format!("nix {}", self.subcommand), command: format!("nix {}", self.subcommand),
}
})?; })?;
let child_stderr = child.stderr.take().ok_or_else(|| EhError::CommandFailed { let child_stderr = child.stderr.take().ok_or_else(|| {
EhError::CommandFailed {
command: format!("nix {}", self.subcommand), command: format!("nix {}", self.subcommand),
}
})?; })?;
let mut stdout = child_stdout; let mut stdout = child_stdout;
let mut stderr = child_stderr; let mut stderr = child_stderr;
@ -132,24 +145,24 @@ impl NixCommand {
let mut did_something = false; let mut did_something = false;
match stdout.read(&mut out_buf) { match stdout.read(&mut out_buf) {
Ok(0) => {} Ok(0) => {},
Ok(n) => { Ok(n) => {
interceptor.on_stdout(&out_buf[..n]); interceptor.on_stdout(&out_buf[..n]);
out_queue.push_back(Vec::from(&out_buf[..n])); out_queue.push_back(Vec::from(&out_buf[..n]));
did_something = true; did_something = true;
} },
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {} Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {},
Err(e) => return Err(EhError::Io(e)), Err(e) => return Err(EhError::Io(e)),
} }
match stderr.read(&mut err_buf) { match stderr.read(&mut err_buf) {
Ok(0) => {} Ok(0) => {},
Ok(n) => { Ok(n) => {
interceptor.on_stderr(&err_buf[..n]); interceptor.on_stderr(&err_buf[..n]);
err_queue.push_back(Vec::from(&err_buf[..n])); err_queue.push_back(Vec::from(&err_buf[..n]));
did_something = true; did_something = true;
} },
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {} Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {},
Err(e) => return Err(EhError::Io(e)), Err(e) => return Err(EhError::Io(e)),
} }
@ -167,7 +180,9 @@ impl NixCommand {
let mut cmd = Command::new("nix"); let mut cmd = Command::new("nix");
cmd.arg(&self.subcommand); cmd.arg(&self.subcommand);
if self.print_build_logs && !self.args.iter().any(|a| a == "--no-build-output") { if self.print_build_logs
&& !self.args.iter().any(|a| a == "--no-build-output")
{
cmd.arg("--print-build-logs"); cmd.arg("--print-build-logs");
} }
if self.impure { if self.impure {

View file

@ -1,7 +1,7 @@
use std::{env, path::Path};
use eh::{Cli, Command, CommandFactory, Parser}; use eh::{Cli, Command, CommandFactory, Parser};
use error::Result; use error::Result;
use std::env;
use std::path::Path;
mod build; mod build;
mod command; mod command;
@ -26,36 +26,45 @@ fn main() {
Err(e) => { Err(e) => {
eprintln!("Error: {e}"); eprintln!("Error: {e}");
std::process::exit(e.exit_code()); std::process::exit(e.exit_code());
} },
} }
} }
// Design partially taken from Stash // Design partially taken from Stash
fn dispatch_multicall(app_name: &str, args: std::env::Args) -> Option<Result<i32>> { fn dispatch_multicall(
app_name: &str,
args: std::env::Args,
) -> Option<Result<i32>> {
let rest: Vec<String> = args.collect(); let rest: Vec<String> = args.collect();
let hash_extractor = util::RegexHashExtractor; let hash_extractor = util::RegexHashExtractor;
let fixer = util::DefaultNixFileFixer; let fixer = util::DefaultNixFileFixer;
let classifier = util::DefaultNixErrorClassifier; let classifier = util::DefaultNixErrorClassifier;
match app_name { match app_name {
"nr" => Some(run::handle_nix_run( "nr" => {
Some(run::handle_nix_run(
&rest, &rest,
&hash_extractor, &hash_extractor,
&fixer, &fixer,
&classifier, &classifier,
)), ))
"ns" => Some(shell::handle_nix_shell( },
"ns" => {
Some(shell::handle_nix_shell(
&rest, &rest,
&hash_extractor, &hash_extractor,
&fixer, &fixer,
&classifier, &classifier,
)), ))
"nb" => Some(build::handle_nix_build( },
"nb" => {
Some(build::handle_nix_build(
&rest, &rest,
&hash_extractor, &hash_extractor,
&fixer, &fixer,
&classifier, &classifier,
)), ))
},
_ => None, _ => None,
} }
} }
@ -82,20 +91,20 @@ fn run_app() -> Result<i32> {
match cli.command { match cli.command {
Some(Command::Run { args }) => { Some(Command::Run { args }) => {
run::handle_nix_run(&args, &hash_extractor, &fixer, &classifier) run::handle_nix_run(&args, &hash_extractor, &fixer, &classifier)
} },
Some(Command::Shell { args }) => { Some(Command::Shell { args }) => {
shell::handle_nix_shell(&args, &hash_extractor, &fixer, &classifier) shell::handle_nix_shell(&args, &hash_extractor, &fixer, &classifier)
} },
Some(Command::Build { args }) => { Some(Command::Build { args }) => {
build::handle_nix_build(&args, &hash_extractor, &fixer, &classifier) build::handle_nix_build(&args, &hash_extractor, &fixer, &classifier)
} },
_ => { _ => {
Cli::command().print_help()?; Cli::command().print_help()?;
println!(); println!();
Ok(0) Ok(0)
} },
} }
} }

View file

@ -1,5 +1,12 @@
use crate::error::Result; use crate::{
use crate::util::{HashExtractor, NixErrorClassifier, NixFileFixer, handle_nix_with_retry}; error::Result,
util::{
HashExtractor,
NixErrorClassifier,
NixFileFixer,
handle_nix_with_retry,
},
};
pub fn handle_nix_run( pub fn handle_nix_run(
args: &[String], args: &[String],

View file

@ -1,5 +1,12 @@
use crate::error::Result; use crate::{
use crate::util::{HashExtractor, NixErrorClassifier, NixFileFixer, handle_nix_with_retry}; error::Result,
util::{
HashExtractor,
NixErrorClassifier,
NixFileFixer,
handle_nix_with_retry,
},
};
pub fn handle_nix_shell( pub fn handle_nix_shell(
args: &[String], args: &[String],

View file

@ -1,13 +1,19 @@
use crate::command::{NixCommand, StdIoInterceptor}; use std::{
use crate::error::{EhError, Result}; fs,
io::Write,
path::{Path, PathBuf},
};
use regex::Regex; use regex::Regex;
use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use tracing::{info, warn}; use tracing::{info, warn};
use walkdir::WalkDir; use walkdir::WalkDir;
use yansi::Paint; use yansi::Paint;
use crate::{
command::{NixCommand, StdIoInterceptor},
error::{EhError, Result},
};
pub trait HashExtractor { pub trait HashExtractor {
fn extract_hash(&self, stderr: &str) -> Option<String>; fn extract_hash(&self, stderr: &str) -> Option<String>;
} }
@ -100,8 +106,10 @@ impl NixFileFixer for DefaultNixFileFixer {
} }
} }
if replaced { if replaced {
fs::write(file_path, new_content).map_err(|_| EhError::HashFixFailed { fs::write(file_path, new_content).map_err(|_| {
EhError::HashFixFailed {
path: file_path.to_string_lossy().to_string(), path: file_path.to_string_lossy().to_string(),
}
})?; })?;
Ok(true) Ok(true)
} else { } else {
@ -198,20 +206,21 @@ pub fn handle_nix_with_retry(
} }
let retry_status = retry_cmd.run_with_logs(StdIoInterceptor)?; let retry_status = retry_cmd.run_with_logs(StdIoInterceptor)?;
return Ok(retry_status.code().unwrap_or(1)); return Ok(retry_status.code().unwrap_or(1));
} },
Ok(false) => { Ok(false) => {
// No files were fixed, continue with normal error handling // No files were fixed, continue with normal error handling
} },
Err(EhError::NoNixFilesFound) => { Err(EhError::NoNixFilesFound) => {
warn!("No .nix files found to fix hash in"); warn!("No .nix files found to fix hash in");
// Continue with normal error handling // Continue with normal error handling
} },
Err(e) => { Err(e) => {
return Err(e); return Err(e);
} },
} }
} else if stderr.contains("hash") || stderr.contains("sha256") { } else if stderr.contains("hash") || stderr.contains("sha256") {
// If there's a hash-related error but we couldn't extract it, that's a failure // If there's a hash-related error but we couldn't extract it, that's a
// failure
return Err(EhError::HashExtractionFailed); return Err(EhError::HashExtractionFailed);
} }
@ -219,7 +228,9 @@ pub fn handle_nix_with_retry(
if stderr.contains("has an unfree license") && stderr.contains("refusing") { if stderr.contains("has an unfree license") && stderr.contains("refusing") {
warn!( warn!(
"{}", "{}",
Paint::yellow("⚠ Unfree package detected, retrying with NIXPKGS_ALLOW_UNFREE=1...") Paint::yellow(
"⚠ Unfree package detected, retrying with NIXPKGS_ALLOW_UNFREE=1..."
)
); );
let mut retry_cmd = NixCommand::new(subcommand) let mut retry_cmd = NixCommand::new(subcommand)
.print_build_logs(true) .print_build_logs(true)
@ -232,11 +243,14 @@ pub fn handle_nix_with_retry(
let retry_status = retry_cmd.run_with_logs(StdIoInterceptor)?; let retry_status = retry_cmd.run_with_logs(StdIoInterceptor)?;
return Ok(retry_status.code().unwrap_or(1)); return Ok(retry_status.code().unwrap_or(1));
} }
if stderr.contains("has been marked as insecure") && stderr.contains("refusing") { if stderr.contains("has been marked as insecure")
&& stderr.contains("refusing")
{
warn!( warn!(
"{}", "{}",
Paint::yellow( Paint::yellow(
"⚠ Insecure package detected, retrying with NIXPKGS_ALLOW_INSECURE=1..." "⚠ Insecure package detected, retrying with \
NIXPKGS_ALLOW_INSECURE=1..."
) )
); );
let mut retry_cmd = NixCommand::new(subcommand) let mut retry_cmd = NixCommand::new(subcommand)
@ -250,10 +264,14 @@ pub fn handle_nix_with_retry(
let retry_status = retry_cmd.run_with_logs(StdIoInterceptor)?; let retry_status = retry_cmd.run_with_logs(StdIoInterceptor)?;
return Ok(retry_status.code().unwrap_or(1)); return Ok(retry_status.code().unwrap_or(1));
} }
if stderr.contains("has been marked as broken") && stderr.contains("refusing") { if stderr.contains("has been marked as broken")
&& stderr.contains("refusing")
{
warn!( warn!(
"{}", "{}",
Paint::yellow("⚠ Broken package detected, retrying with NIXPKGS_ALLOW_BROKEN=1...") Paint::yellow(
"⚠ Broken package detected, retrying with NIXPKGS_ALLOW_BROKEN=1..."
)
); );
let mut retry_cmd = NixCommand::new(subcommand) let mut retry_cmd = NixCommand::new(subcommand)
.print_build_logs(true) .print_build_logs(true)
@ -286,8 +304,11 @@ pub struct DefaultNixErrorClassifier;
impl NixErrorClassifier for DefaultNixErrorClassifier { impl NixErrorClassifier for DefaultNixErrorClassifier {
fn should_retry(&self, stderr: &str) -> bool { fn should_retry(&self, stderr: &str) -> bool {
RegexHashExtractor.extract_hash(stderr).is_some() RegexHashExtractor.extract_hash(stderr).is_some()
|| (stderr.contains("has an unfree license") && stderr.contains("refusing")) || (stderr.contains("has an unfree license")
|| (stderr.contains("has been marked as insecure") && stderr.contains("refusing")) && stderr.contains("refusing"))
|| (stderr.contains("has been marked as broken") && stderr.contains("refusing")) || (stderr.contains("has been marked as insecure")
&& stderr.contains("refusing"))
|| (stderr.contains("has been marked as broken")
&& stderr.contains("refusing"))
} }
} }

View file

@ -1,9 +1,13 @@
use std::{fs, process::Command};
use eh::util::{ use eh::util::{
DefaultNixErrorClassifier, DefaultNixFileFixer, HashExtractor, NixErrorClassifier, DefaultNixErrorClassifier,
NixFileFixer, RegexHashExtractor, DefaultNixFileFixer,
HashExtractor,
NixErrorClassifier,
NixFileFixer,
RegexHashExtractor,
}; };
use std::fs;
use std::process::Command;
use tempfile::TempDir; use tempfile::TempDir;
#[test] #[test]
@ -38,8 +42,10 @@ fn test_error_classification_for_retry_logic() {
// These should trigger retries // These should trigger retries
let retry_cases = [ let retry_cases = [
"Package 'discord-1.0.0' has an unfree license ('unfree'), refusing to evaluate.", "Package 'discord-1.0.0' has an unfree license ('unfree'), refusing to \
"Package 'openssl-1.1.1' has been marked as insecure, refusing to evaluate.", evaluate.",
"Package 'openssl-1.1.1' has been marked as insecure, refusing to \
evaluate.",
"Package 'broken-1.0' has been marked as broken, refusing to evaluate.", "Package 'broken-1.0' has been marked as broken, refusing to evaluate.",
"hash mismatch in fixed-output derivation\ngot: sha256-newhash", "hash mismatch in fixed-output derivation\ngot: sha256-newhash",
]; ];
@ -100,7 +106,8 @@ stdenv.mkDerivation {
assert!(was_fixed, "File should have been modified"); assert!(was_fixed, "File should have been modified");
let updated_content = fs::read_to_string(&file_path).expect("Failed to read updated file"); let updated_content =
fs::read_to_string(&file_path).expect("Failed to read updated file");
// All hash formats should be updated // All hash formats should be updated
assert!(updated_content.contains(&format!(r#"hash = "{}""#, new_hash))); assert!(updated_content.contains(&format!(r#"hash = "{}""#, new_hash)));
@ -137,7 +144,9 @@ fn test_multicall_binary_dispatch() {
// Should show an error message, not crash // Should show an error message, not crash
let stderr = String::from_utf8_lossy(&output.stderr); let stderr = String::from_utf8_lossy(&output.stderr);
assert!( assert!(
stderr.contains("Error:") || stderr.contains("error:") || stderr.contains("failed"), stderr.contains("Error:")
|| stderr.contains("error:")
|| stderr.contains("failed"),
"{} should show error for invalid package", "{} should show error for invalid package",
binary_name binary_name
); );
@ -177,7 +186,9 @@ fn test_invalid_expression_handling() {
let stderr = String::from_utf8_lossy(&output.stderr); let stderr = String::from_utf8_lossy(&output.stderr);
assert!( assert!(
stderr.contains("Error:") || stderr.contains("error:") || stderr.contains("failed"), stderr.contains("Error:")
|| stderr.contains("error:")
|| stderr.contains("failed"),
"Should show error message for invalid ref '{}': {}", "Should show error message for invalid ref '{}': {}",
invalid_ref, invalid_ref,
stderr stderr
@ -192,7 +203,8 @@ fn test_nix_file_discovery() {
let fixer = DefaultNixFileFixer; let fixer = DefaultNixFileFixer;
// Create directory structure with Nix files // Create directory structure with Nix files
fs::create_dir_all(temp_dir.path().join("subdir")).expect("Failed to create subdir"); fs::create_dir_all(temp_dir.path().join("subdir"))
.expect("Failed to create subdir");
let files = [ let files = [
("test.nix", "stdenv.mkDerivation { name = \"test\"; }"), ("test.nix", "stdenv.mkDerivation { name = \"test\"; }"),
@ -202,12 +214,15 @@ fn test_nix_file_discovery() {
]; ];
for (path, content) in files { for (path, content) in files {
fs::write(temp_dir.path().join(path), content).expect("Failed to write file"); fs::write(temp_dir.path().join(path), content)
.expect("Failed to write file");
} }
// Change to temp dir for file discovery // Change to temp dir for file discovery
let original_dir = std::env::current_dir().expect("Failed to get current dir"); let original_dir =
std::env::set_current_dir(temp_dir.path()).expect("Failed to change directory"); std::env::current_dir().expect("Failed to get current dir");
std::env::set_current_dir(temp_dir.path())
.expect("Failed to change directory");
let found_files = fixer.find_nix_files().expect("Failed to find Nix files"); let found_files = fixer.find_nix_files().expect("Failed to find Nix files");

View file

@ -1,5 +1,6 @@
use std::{ use std::{
error, fs, error,
fs,
path::{Path, PathBuf}, path::{Path, PathBuf},
process, process,
}; };
@ -65,13 +66,13 @@ fn main() {
eprintln!("error creating multicall binaries: {error}"); eprintln!("error creating multicall binaries: {error}");
process::exit(1); process::exit(1);
} }
} },
Command::Completions { shell, output_dir } => { Command::Completions { shell, output_dir } => {
if let Err(error) = generate_completions(shell, &output_dir) { if let Err(error) = generate_completions(shell, &output_dir) {
eprintln!("error generating completions: {error}"); eprintln!("error generating completions: {error}");
process::exit(1); process::exit(1);
} }
} },
} }
} }
@ -84,7 +85,9 @@ fn create_multicall_binaries(
fs::create_dir_all(bin_dir)?; fs::create_dir_all(bin_dir)?;
if !main_binary.exists() { if !main_binary.exists() {
return Err(format!("main binary not found at: {}", main_binary.display()).into()); return Err(
format!("main binary not found at: {}", main_binary.display()).into(),
);
} }
let multicall_binaries = [Binary::Nr, Binary::Ns, Binary::Nb]; let multicall_binaries = [Binary::Nr, Binary::Ns, Binary::Nb];
@ -131,7 +134,10 @@ fn create_multicall_binaries(
Ok(()) Ok(())
} }
fn generate_completions(shell: Shell, output_dir: &Path) -> Result<(), Box<dyn error::Error>> { fn generate_completions(
shell: Shell,
output_dir: &Path,
) -> Result<(), Box<dyn error::Error>> {
println!("generating {shell} completions..."); println!("generating {shell} completions...");
fs::create_dir_all(output_dir)?; fs::create_dir_all(output_dir)?;