refactor redundant code

This commit is contained in:
raf 2025-07-22 02:02:31 +03:00
commit bd9f759439
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
4 changed files with 112 additions and 259 deletions

View file

@ -1,8 +1,4 @@
use crate::command::{NixCommand, StdIoInterceptor};
use crate::util::{HashExtractor, NixErrorClassifier, NixFileFixer};
use std::io::Write;
use tracing::{info, warn};
use yansi::Paint;
use crate::util::{HashExtractor, NixErrorClassifier, NixFileFixer, handle_nix_with_retry};
pub fn handle_nix_build(
args: &[String],
@ -10,83 +6,5 @@ pub fn handle_nix_build(
fixer: &dyn NixFileFixer,
classifier: &dyn NixErrorClassifier,
) {
let mut cmd = NixCommand::new("build").print_build_logs(true);
for arg in args {
cmd = cmd.arg(arg);
}
let status = cmd
.run_with_logs(StdIoInterceptor)
.expect("failed to run nix build");
if status.success() {
return;
}
let output = NixCommand::new("build")
.print_build_logs(true)
.args(args.iter().cloned())
.output()
.expect("failed to capture output");
let stderr = String::from_utf8_lossy(&output.stderr);
if let Some(new_hash) = hash_extractor.extract_hash(&stderr) {
if fixer.fix_hash_in_files(&new_hash) {
info!("{}", Paint::green("✔ Fixed hash mismatch, retrying..."));
let retry_status = NixCommand::new("build")
.print_build_logs(true)
.args(args.iter().cloned())
.run_with_logs(StdIoInterceptor)
.unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
}
if classifier.should_retry(&stderr) {
if stderr.contains("unfree") {
warn!(
"{}",
Paint::yellow("⚠ Unfree package detected, retrying with NIXPKGS_ALLOW_UNFREE=1...")
);
let retry_status = NixCommand::new("build")
.print_build_logs(true)
.args(args.iter().cloned())
.env("NIXPKGS_ALLOW_UNFREE", "1")
.impure(true)
.run_with_logs(StdIoInterceptor)
.unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
if stderr.contains("insecure") {
warn!(
"{}",
Paint::yellow(
"⚠ Insecure package detected, retrying with NIXPKGS_ALLOW_INSECURE=1..."
)
);
let retry_status = NixCommand::new("build")
.print_build_logs(true)
.args(args.iter().cloned())
.env("NIXPKGS_ALLOW_INSECURE", "1")
.impure(true)
.run_with_logs(StdIoInterceptor)
.unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
if stderr.contains("broken") {
warn!(
"{}",
Paint::yellow("⚠ Broken package detected, retrying with NIXPKGS_ALLOW_BROKEN=1...")
);
let retry_status = NixCommand::new("build")
.print_build_logs(true)
.args(args.iter().cloned())
.env("NIXPKGS_ALLOW_BROKEN", "1")
.impure(true)
.run_with_logs(StdIoInterceptor)
.unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
}
std::io::stderr().write_all(output.stderr.as_ref()).unwrap();
std::process::exit(status.code().unwrap_or(1));
handle_nix_with_retry("build", args, hash_extractor, fixer, classifier, false);
}

View file

@ -1,8 +1,4 @@
use crate::command::{NixCommand, StdIoInterceptor};
use crate::util::{HashExtractor, NixErrorClassifier, NixFileFixer};
use std::io::Write;
use tracing::{info, warn};
use yansi::Paint;
use crate::util::{HashExtractor, NixErrorClassifier, NixFileFixer, handle_nix_with_retry};
pub fn handle_nix_run(
args: &[String],
@ -10,83 +6,5 @@ pub fn handle_nix_run(
fixer: &dyn NixFileFixer,
classifier: &dyn NixErrorClassifier,
) {
let mut cmd = NixCommand::new("run").print_build_logs(true);
for arg in args {
cmd = cmd.arg(arg);
}
let status = cmd
.run_with_logs(StdIoInterceptor)
.expect("failed to run nix run");
if status.success() {
return;
}
let output = NixCommand::new("run")
.print_build_logs(true)
.args(args.iter().cloned())
.output()
.expect("failed to capture output");
let stderr = String::from_utf8_lossy(&output.stderr);
if let Some(new_hash) = hash_extractor.extract_hash(&stderr) {
if fixer.fix_hash_in_files(&new_hash) {
info!("{}", Paint::green("✔ Fixed hash mismatch, retrying..."));
let retry_status = NixCommand::new("run")
.print_build_logs(true)
.args(args.iter().cloned())
.run_with_logs(StdIoInterceptor)
.unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
}
if classifier.should_retry(&stderr) {
if stderr.contains("unfree") {
warn!(
"{}",
Paint::yellow("⚠ Unfree package detected, retrying with NIXPKGS_ALLOW_UNFREE=1...")
);
let retry_status = NixCommand::new("run")
.print_build_logs(true)
.args(args.iter().cloned())
.env("NIXPKGS_ALLOW_UNFREE", "1")
.impure(true)
.run_with_logs(StdIoInterceptor)
.unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
if stderr.contains("insecure") {
warn!(
"{}",
Paint::yellow(
"⚠ Insecure package detected, retrying with NIXPKGS_ALLOW_INSECURE=1..."
)
);
let retry_status = NixCommand::new("run")
.print_build_logs(true)
.args(args.iter().cloned())
.env("NIXPKGS_ALLOW_INSECURE", "1")
.impure(true)
.run_with_logs(StdIoInterceptor)
.unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
if stderr.contains("broken") {
warn!(
"{}",
Paint::yellow("⚠ Broken package detected, retrying with NIXPKGS_ALLOW_BROKEN=1...")
);
let retry_status = NixCommand::new("run")
.print_build_logs(true)
.args(args.iter().cloned())
.env("NIXPKGS_ALLOW_BROKEN", "1")
.impure(true)
.run_with_logs(StdIoInterceptor)
.unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
}
std::io::stderr().write_all(output.stderr.as_ref()).unwrap();
std::process::exit(status.code().unwrap_or(1));
handle_nix_with_retry("run", args, hash_extractor, fixer, classifier, false);
}

View file

@ -1,8 +1,4 @@
use crate::command::{NixCommand, StdIoInterceptor};
use crate::util::{HashExtractor, NixErrorClassifier, NixFileFixer};
use std::io::Write;
use tracing::{info, warn};
use yansi::Paint;
use crate::util::{HashExtractor, NixErrorClassifier, NixFileFixer, handle_nix_with_retry};
pub fn handle_nix_shell(
args: &[String],
@ -10,90 +6,5 @@ pub fn handle_nix_shell(
fixer: &dyn NixFileFixer,
classifier: &dyn NixErrorClassifier,
) {
let mut cmd = NixCommand::new("shell")
.print_build_logs(true)
.interactive(true);
for arg in args {
cmd = cmd.arg(arg);
}
let status = cmd
.run_with_logs(StdIoInterceptor)
.expect("failed to run nix shell");
if status.success() {
std::process::exit(0);
}
// Try to capture error output for retry logic
let output = NixCommand::new("shell")
.print_build_logs(true)
.args(args.iter().cloned())
.output()
.expect("failed to capture output");
let stderr = String::from_utf8_lossy(&output.stderr);
if let Some(new_hash) = hash_extractor.extract_hash(&stderr) {
if fixer.fix_hash_in_files(&new_hash) {
info!("{}", Paint::green("✔ Fixed hash mismatch, retrying..."));
let retry_status = NixCommand::new("shell")
.print_build_logs(true)
.interactive(true)
.args(args.iter().cloned())
.run_with_logs(StdIoInterceptor)
.unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
}
if classifier.should_retry(&stderr) {
if stderr.contains("unfree") {
warn!(
"{}",
Paint::yellow("⚠ Unfree package detected, retrying with NIXPKGS_ALLOW_UNFREE=1...")
);
let retry_status = NixCommand::new("shell")
.print_build_logs(true)
.interactive(true)
.args(args.iter().cloned())
.env("NIXPKGS_ALLOW_UNFREE", "1")
.impure(true)
.run_with_logs(StdIoInterceptor)
.unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
if stderr.contains("insecure") {
warn!(
"{}",
Paint::yellow(
"⚠ Insecure package detected, retrying with NIXPKGS_ALLOW_INSECURE=1..."
)
);
let retry_status = NixCommand::new("shell")
.print_build_logs(true)
.interactive(true)
.args(args.iter().cloned())
.env("NIXPKGS_ALLOW_INSECURE", "1")
.impure(true)
.run_with_logs(StdIoInterceptor)
.unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
if stderr.contains("broken") {
warn!(
"{}",
Paint::yellow("⚠ Broken package detected, retrying with NIXPKGS_ALLOW_BROKEN=1...")
);
let retry_status = NixCommand::new("shell")
.print_build_logs(true)
.interactive(true)
.args(args.iter().cloned())
.env("NIXPKGS_ALLOW_BROKEN", "1")
.impure(true)
.run_with_logs(StdIoInterceptor)
.unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
}
std::io::stderr().write_all(output.stderr.as_ref()).unwrap();
std::process::exit(status.code().unwrap_or(1));
handle_nix_with_retry("shell", args, hash_extractor, fixer, classifier, true);
}

View file

@ -1,6 +1,10 @@
use crate::command::{NixCommand, StdIoInterceptor};
use regex::Regex;
use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use tracing::{info, warn};
use yansi::Paint;
pub trait HashExtractor {
fn extract_hash(&self, stderr: &str) -> Option<String>;
@ -111,6 +115,108 @@ pub trait NixErrorClassifier {
fn should_retry(&self, stderr: &str) -> bool;
}
/// Shared retry logic for nix commands (build/run/shell).
pub fn handle_nix_with_retry(
subcommand: &str,
args: &[String],
hash_extractor: &dyn HashExtractor,
fixer: &dyn NixFileFixer,
classifier: &dyn NixErrorClassifier,
interactive: bool,
) -> ! {
let mut cmd = NixCommand::new(subcommand).print_build_logs(true);
if interactive {
cmd = cmd.interactive(true);
}
for arg in args {
cmd = cmd.arg(arg);
}
let status = cmd
.run_with_logs(StdIoInterceptor)
.expect("failed to run nix command");
if status.success() {
std::process::exit(0);
}
let mut output_cmd = NixCommand::new(subcommand)
.print_build_logs(true)
.args(args.iter().cloned());
if interactive {
output_cmd = output_cmd.interactive(true);
}
let output = output_cmd.output().expect("failed to capture output");
let stderr = String::from_utf8_lossy(&output.stderr);
if let Some(new_hash) = hash_extractor.extract_hash(&stderr) {
if fixer.fix_hash_in_files(&new_hash) {
info!("{}", Paint::green("✔ Fixed hash mismatch, retrying..."));
let mut retry_cmd = NixCommand::new(subcommand)
.print_build_logs(true)
.args(args.iter().cloned());
if interactive {
retry_cmd = retry_cmd.interactive(true);
}
let retry_status = retry_cmd.run_with_logs(StdIoInterceptor).unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
}
if classifier.should_retry(&stderr) {
if stderr.contains("unfree") {
warn!(
"{}",
Paint::yellow("⚠ Unfree package detected, retrying with NIXPKGS_ALLOW_UNFREE=1...")
);
let mut retry_cmd = NixCommand::new(subcommand)
.print_build_logs(true)
.args(args.iter().cloned())
.env("NIXPKGS_ALLOW_UNFREE", "1")
.impure(true);
if interactive {
retry_cmd = retry_cmd.interactive(true);
}
let retry_status = retry_cmd.run_with_logs(StdIoInterceptor).unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
if stderr.contains("insecure") {
warn!(
"{}",
Paint::yellow(
"⚠ Insecure package detected, retrying with NIXPKGS_ALLOW_INSECURE=1..."
)
);
let mut retry_cmd = NixCommand::new(subcommand)
.print_build_logs(true)
.args(args.iter().cloned())
.env("NIXPKGS_ALLOW_INSECURE", "1")
.impure(true);
if interactive {
retry_cmd = retry_cmd.interactive(true);
}
let retry_status = retry_cmd.run_with_logs(StdIoInterceptor).unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
if stderr.contains("broken") {
warn!(
"{}",
Paint::yellow("⚠ Broken package detected, retrying with NIXPKGS_ALLOW_BROKEN=1...")
);
let mut retry_cmd = NixCommand::new(subcommand)
.print_build_logs(true)
.args(args.iter().cloned())
.env("NIXPKGS_ALLOW_BROKEN", "1")
.impure(true);
if interactive {
retry_cmd = retry_cmd.interactive(true);
}
let retry_status = retry_cmd.run_with_logs(StdIoInterceptor).unwrap();
std::process::exit(retry_status.code().unwrap_or(1));
}
}
std::io::stderr().write_all(output.stderr.as_ref()).unwrap();
std::process::exit(status.code().unwrap_or(1));
}
pub struct DefaultNixErrorClassifier;
impl NixErrorClassifier for DefaultNixErrorClassifier {