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::util::{HashExtractor, NixErrorClassifier, NixFileFixer, handle_nix_with_retry};
use crate::{
error::Result,
util::{
HashExtractor,
NixErrorClassifier,
NixFileFixer,
handle_nix_with_retry,
},
};
pub fn handle_nix_build(
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 std::collections::VecDeque;
use std::io::{self, Read, Write};
use std::process::{Command, ExitStatus, Output, Stdio};
/// Trait for log interception and output handling.
pub trait LogInterceptor: Send {
@ -60,7 +63,11 @@ impl NixCommand {
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
}
@ -91,7 +98,9 @@ impl NixCommand {
let mut cmd = Command::new("nix");
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");
}
if self.impure {
@ -113,11 +122,15 @@ impl NixCommand {
cmd.stderr(Stdio::piped());
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),
}
})?;
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),
}
})?;
let mut stdout = child_stdout;
let mut stderr = child_stderr;
@ -132,24 +145,24 @@ impl NixCommand {
let mut did_something = false;
match stdout.read(&mut out_buf) {
Ok(0) => {}
Ok(0) => {},
Ok(n) => {
interceptor.on_stdout(&out_buf[..n]);
out_queue.push_back(Vec::from(&out_buf[..n]));
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)),
}
match stderr.read(&mut err_buf) {
Ok(0) => {}
Ok(0) => {},
Ok(n) => {
interceptor.on_stderr(&err_buf[..n]);
err_queue.push_back(Vec::from(&err_buf[..n]));
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)),
}
@ -167,7 +180,9 @@ impl NixCommand {
let mut cmd = Command::new("nix");
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");
}
if self.impure {

View file

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

View file

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

View file

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

View file

@ -1,13 +1,19 @@
use crate::command::{NixCommand, StdIoInterceptor};
use crate::error::{EhError, Result};
use std::{
fs,
io::Write,
path::{Path, PathBuf},
};
use regex::Regex;
use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use tracing::{info, warn};
use walkdir::WalkDir;
use yansi::Paint;
use crate::{
command::{NixCommand, StdIoInterceptor},
error::{EhError, Result},
};
pub trait HashExtractor {
fn extract_hash(&self, stderr: &str) -> Option<String>;
}
@ -100,8 +106,10 @@ impl NixFileFixer for DefaultNixFileFixer {
}
}
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(),
}
})?;
Ok(true)
} else {
@ -198,20 +206,21 @@ pub fn handle_nix_with_retry(
}
let retry_status = retry_cmd.run_with_logs(StdIoInterceptor)?;
return Ok(retry_status.code().unwrap_or(1));
}
},
Ok(false) => {
// No files were fixed, continue with normal error handling
}
},
Err(EhError::NoNixFilesFound) => {
warn!("No .nix files found to fix hash in");
// Continue with normal error handling
}
},
Err(e) => {
return Err(e);
}
},
}
} 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);
}
@ -219,7 +228,9 @@ pub fn handle_nix_with_retry(
if stderr.contains("has an unfree license") && stderr.contains("refusing") {
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)
.print_build_logs(true)
@ -232,11 +243,14 @@ pub fn handle_nix_with_retry(
let retry_status = retry_cmd.run_with_logs(StdIoInterceptor)?;
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!(
"{}",
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)
@ -250,10 +264,14 @@ pub fn handle_nix_with_retry(
let retry_status = retry_cmd.run_with_logs(StdIoInterceptor)?;
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!(
"{}",
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)
.print_build_logs(true)
@ -286,8 +304,11 @@ pub struct DefaultNixErrorClassifier;
impl NixErrorClassifier for DefaultNixErrorClassifier {
fn should_retry(&self, stderr: &str) -> bool {
RegexHashExtractor.extract_hash(stderr).is_some()
|| (stderr.contains("has an unfree license") && stderr.contains("refusing"))
|| (stderr.contains("has been marked as insecure") && stderr.contains("refusing"))
|| (stderr.contains("has been marked as broken") && stderr.contains("refusing"))
|| (stderr.contains("has an unfree license")
&& 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::{
DefaultNixErrorClassifier, DefaultNixFileFixer, HashExtractor, NixErrorClassifier,
NixFileFixer, RegexHashExtractor,
DefaultNixErrorClassifier,
DefaultNixFileFixer,
HashExtractor,
NixErrorClassifier,
NixFileFixer,
RegexHashExtractor,
};
use std::fs;
use std::process::Command;
use tempfile::TempDir;
#[test]
@ -38,8 +42,10 @@ fn test_error_classification_for_retry_logic() {
// These should trigger retries
let retry_cases = [
"Package 'discord-1.0.0' has an unfree license ('unfree'), refusing to evaluate.",
"Package 'openssl-1.1.1' has been marked as insecure, refusing to evaluate.",
"Package 'discord-1.0.0' has an unfree license ('unfree'), refusing to \
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.",
"hash mismatch in fixed-output derivation\ngot: sha256-newhash",
];
@ -100,7 +106,8 @@ stdenv.mkDerivation {
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
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
let stderr = String::from_utf8_lossy(&output.stderr);
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",
binary_name
);
@ -177,7 +186,9 @@ fn test_invalid_expression_handling() {
let stderr = String::from_utf8_lossy(&output.stderr);
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 '{}': {}",
invalid_ref,
stderr
@ -192,7 +203,8 @@ fn test_nix_file_discovery() {
let fixer = DefaultNixFileFixer;
// 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 = [
("test.nix", "stdenv.mkDerivation { name = \"test\"; }"),
@ -202,12 +214,15 @@ fn test_nix_file_discovery() {
];
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
let original_dir = std::env::current_dir().expect("Failed to get current dir");
std::env::set_current_dir(temp_dir.path()).expect("Failed to change directory");
let original_dir =
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");

View file

@ -1,5 +1,6 @@
use std::{
error, fs,
error,
fs,
path::{Path, PathBuf},
process,
};
@ -65,13 +66,13 @@ fn main() {
eprintln!("error creating multicall binaries: {error}");
process::exit(1);
}
}
},
Command::Completions { shell, output_dir } => {
if let Err(error) = generate_completions(shell, &output_dir) {
eprintln!("error generating completions: {error}");
process::exit(1);
}
}
},
}
}
@ -84,7 +85,9 @@ fn create_multicall_binaries(
fs::create_dir_all(bin_dir)?;
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];
@ -131,7 +134,10 @@ fn create_multicall_binaries(
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...");
fs::create_dir_all(output_dir)?;