diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 30be905..0000000 --- a/.editorconfig +++ /dev/null @@ -1,24 +0,0 @@ -root = true - -[*] -charset = utf-8 -end_of_line = lf -indent_style = space -indent_size = 2 -insert_final_newline = true -tab_width = 2 -trim_trailing_whitespace = true - -[*.md] -indent_style = space -indent_size = 2 -trim_trailing_whitespace = false - -[*.{lock,diff,patch}] -indent_style = unset -indent_size = unset -insert_final_newline = unset -trim_trailing_whitespace = unset -end_of_line = unset - - diff --git a/Cargo.lock b/Cargo.lock index 562e139..d295e00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,12 +11,56 @@ dependencies = [ "memchr", ] +[[package]] +name = "anstream" +version = "0.6.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + [[package]] name = "anstyle" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + [[package]] name = "cfg-if" version = "1.0.1" @@ -39,17 +83,10 @@ version = "4.5.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" dependencies = [ + "anstream", "anstyle", "clap_lex", -] - -[[package]] -name = "clap_complete" -version = "4.5.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5abde44486daf70c5be8b8f8f1b66c49f86236edf6fa2abadb4d961c4c6229a" -dependencies = [ - "clap", + "strsim", ] [[package]] @@ -70,9 +107,15 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + [[package]] name = "eh" -version = "0.1.1" +version = "0.1.0" dependencies = [ "clap", "regex", @@ -87,6 +130,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "lazy_static" version = "1.5.0" @@ -121,6 +170,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + [[package]] name = "overload" version = "0.1.1" @@ -195,6 +250,12 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.104" @@ -278,6 +339,12 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "valuable" version = "0.1.1" @@ -306,13 +373,84 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "xtask" -version = "0.1.1" +version = "0.1.0" dependencies = [ "clap", - "clap_complete", - "eh", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 38fd81f..116535e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,19 +9,11 @@ edition = "2024" license = "MPL-2.0" readme = true rust-version = "1.85" -version = "0.1.1" +version = "0.1.0" [workspace.dependencies] -clap = { default-features = false, features = [ "std", "help", "derive" ], version = "4.5" } -clap_complete = "4.5" -regex = "1.11" +clap = { features = [ "derive" ], version = "4.5" } +regex = "1.0" tracing = "0.1" tracing-subscriber = "0.3" yansi = "1.0" - -[profile.release] -codegen-units = 1 -lto = true -opt-level = "z" -panic = "abort" -strip = true diff --git a/eh/Cargo.toml b/eh/Cargo.toml index 8da1e92..db2736d 100644 --- a/eh/Cargo.toml +++ b/eh/Cargo.toml @@ -6,10 +6,6 @@ edition.workspace = true authors.workspace = true rust-version.workspace = true -[lib] -name = "eh" -crate-type = ["lib"] - [dependencies] clap.workspace = true regex.workspace = true diff --git a/eh/src/command.rs b/eh/src/command.rs index 75e6970..f94623e 100644 --- a/eh/src/command.rs +++ b/eh/src/command.rs @@ -98,7 +98,6 @@ impl NixCommand { if self.interactive { cmd.stdout(Stdio::inherit()); cmd.stderr(Stdio::inherit()); - cmd.stdin(Stdio::inherit()); return cmd.status(); } @@ -168,7 +167,6 @@ impl NixCommand { if self.interactive { cmd.stdout(Stdio::inherit()); cmd.stderr(Stdio::inherit()); - cmd.stdin(Stdio::inherit()); } else { cmd.stdout(Stdio::piped()); cmd.stderr(Stdio::piped()); diff --git a/eh/src/lib.rs b/eh/src/lib.rs deleted file mode 100644 index df062fa..0000000 --- a/eh/src/lib.rs +++ /dev/null @@ -1,34 +0,0 @@ -pub mod build; -pub mod command; -pub mod run; -pub mod shell; -pub mod util; - -pub use clap::{CommandFactory, Parser, Subcommand}; - -#[derive(Parser)] -#[command(name = "eh")] -#[command(about = "Ergonomic Nix helper", long_about = None)] -pub struct Cli { - #[command(subcommand)] - pub command: Option, -} - -#[derive(Subcommand)] -pub enum Command { - /// Run a Nix derivation - Run { - #[arg(trailing_var_arg = true)] - args: Vec, - }, - /// Enter a Nix shell - Shell { - #[arg(trailing_var_arg = true)] - args: Vec, - }, - /// Build a Nix derivation - Build { - #[arg(trailing_var_arg = true)] - args: Vec, - }, -} diff --git a/eh/src/main.rs b/eh/src/main.rs index 4aab85f..c7aad53 100644 --- a/eh/src/main.rs +++ b/eh/src/main.rs @@ -1,4 +1,4 @@ -use eh::{Cli, Command, CommandFactory, Parser}; +use clap::{CommandFactory, Parser, Subcommand}; use std::env; use std::path::Path; @@ -8,6 +8,33 @@ mod run; mod shell; mod util; +#[derive(Parser)] +#[command(name = "eh")] +#[command(about = "Ergonomic Nix helper", long_about = None)] +struct Cli { + #[command(subcommand)] + command: Option, +} + +#[derive(Subcommand)] +enum Command { + /// Run a Nix derivation + Run { + #[arg(trailing_var_arg = true)] + args: Vec, + }, + /// Enter a Nix shell + Shell { + #[arg(trailing_var_arg = true)] + args: Vec, + }, + /// Build a Nix derivation + Build { + #[arg(trailing_var_arg = true)] + args: Vec, + }, +} + fn main() { let format = tracing_subscriber::fmt::format() .with_level(true) // don't include levels in formatted output diff --git a/eh/src/run.rs b/eh/src/run.rs index 0fa322c..dc1b1e7 100644 --- a/eh/src/run.rs +++ b/eh/src/run.rs @@ -6,5 +6,5 @@ pub fn handle_nix_run( fixer: &dyn NixFileFixer, classifier: &dyn NixErrorClassifier, ) { - handle_nix_with_retry("run", args, hash_extractor, fixer, classifier, true); + handle_nix_with_retry("run", args, hash_extractor, fixer, classifier, false); } diff --git a/eh/src/util.rs b/eh/src/util.rs index 46dbb38..fc1f9ca 100644 --- a/eh/src/util.rs +++ b/eh/src/util.rs @@ -15,9 +15,9 @@ pub struct RegexHashExtractor; impl HashExtractor for RegexHashExtractor { fn extract_hash(&self, stderr: &str) -> Option { let patterns = [ - r"got:\s+(sha256-[a-zA-Z0-9+/=]+)", - r"actual:\s+(sha256-[a-zA-Z0-9+/=]+)", - r"have:\s+(sha256-[a-zA-Z0-9+/=]+)", + r"got:\s+([a-zA-Z0-9+/=]+)", + r"actual:\s+([a-zA-Z0-9+/=]+)", + r"have:\s+([a-zA-Z0-9+/=]+)", ]; for pattern in &patterns { if let Ok(re) = Regex::new(pattern) { @@ -110,43 +110,6 @@ pub trait NixErrorClassifier { fn should_retry(&self, stderr: &str) -> bool; } -/// Pre-evaluate expression to catch errors early -fn pre_evaluate(_subcommand: &str, args: &[String]) -> bool { - // Find flake references or expressions to evaluate - // Only take the first non-flag argument (the package/expression) - let eval_arg = args.iter().find(|arg| !arg.starts_with('-')); - - let Some(eval_arg) = eval_arg else { - return true; // No expression to evaluate - }; - - let eval_cmd = NixCommand::new("eval").arg(eval_arg).arg("--raw"); - - let output = match eval_cmd.output() { - Ok(output) => output, - Err(_) => return false, - }; - - if output.status.success() { - return true; - } - - let stderr = String::from_utf8_lossy(&output.stderr); - - // If eval fails due to unfree/insecure/broken, don't fail pre-evaluation - // Let the main command handle it with retry logic - if stderr.contains("has an unfree license") - || stderr.contains("refusing to evaluate") - || stderr.contains("has been marked as insecure") - || stderr.contains("has been marked as broken") - { - return true; - } - - // For other eval failures, fail early - false -} - /// Shared retry logic for nix commands (build/run/shell). pub fn handle_nix_with_retry( subcommand: &str, @@ -156,36 +119,29 @@ pub fn handle_nix_with_retry( classifier: &dyn NixErrorClassifier, interactive: bool, ) -> ! { - // Pre-evaluate for build commands to catch errors early - if !pre_evaluate(subcommand, args) { - eprintln!("Error: Expression evaluation failed"); - std::process::exit(1); + 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); } - // For run commands, try interactive first to avoid breaking terminal - if subcommand == "run" && interactive { - let mut cmd = NixCommand::new(subcommand) - .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 command"); - if status.success() { - std::process::exit(0); - } - } - - // First, always capture output to check for errors that need retry - let output_cmd = NixCommand::new(subcommand) + 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); - // Check if we need to retry with special flags 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...")); @@ -201,7 +157,7 @@ pub fn handle_nix_with_retry( } if classifier.should_retry(&stderr) { - if stderr.contains("has an unfree license") && stderr.contains("refusing") { + if stderr.contains("unfree") { warn!( "{}", Paint::yellow("⚠ Unfree package detected, retrying with NIXPKGS_ALLOW_UNFREE=1...") @@ -217,7 +173,7 @@ pub fn handle_nix_with_retry( let retry_status = retry_cmd.run_with_logs(StdIoInterceptor).unwrap(); std::process::exit(retry_status.code().unwrap_or(1)); } - if stderr.contains("has been marked as insecure") && stderr.contains("refusing") { + if stderr.contains("insecure") { warn!( "{}", Paint::yellow( @@ -235,7 +191,7 @@ pub fn handle_nix_with_retry( let retry_status = retry_cmd.run_with_logs(StdIoInterceptor).unwrap(); std::process::exit(retry_status.code().unwrap_or(1)); } - if stderr.contains("has been marked as broken") && stderr.contains("refusing") { + if stderr.contains("broken") { warn!( "{}", Paint::yellow("⚠ Broken package detected, retrying with NIXPKGS_ALLOW_BROKEN=1...") @@ -253,22 +209,16 @@ pub fn handle_nix_with_retry( } } - // If the first attempt succeeded, we're done - if output.status.success() { - std::process::exit(0); - } - - // Otherwise, show the error and exit std::io::stderr().write_all(output.stderr.as_ref()).unwrap(); - std::process::exit(output.status.code().unwrap_or(1)); + std::process::exit(status.code().unwrap_or(1)); } 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("unfree") && stderr.contains("refusing")) + || (stderr.contains("insecure") && stderr.contains("refusing")) + || (stderr.contains("broken") && stderr.contains("refusing")) } } diff --git a/eh/tests/basic.rs b/eh/tests/basic.rs deleted file mode 100644 index 4b69805..0000000 --- a/eh/tests/basic.rs +++ /dev/null @@ -1,178 +0,0 @@ -//! I hate writing tests, and I hate writing integration tests. This is the best -//! that you are getting, deal with it. -use std::process::{Command, Stdio}; - -#[test] -fn nix_eval_validation() { - // Test that invalid expressions are caught early for all commands - let commands = ["build", "run", "shell"]; - - for cmd in &commands { - let output = Command::new("timeout") - .args([ - "10", - "cargo", - "run", - "--bin", - "eh", - "--", - cmd, - "invalid-flake-ref", - ]) - .output() - .expect("Failed to execute command"); - - // Should fail fast with eval error - let stderr = String::from_utf8_lossy(&output.stderr); - assert!(stderr.contains("Error: Expression evaluation failed") || !output.status.success()); - } -} - -#[test] -fn unfree_package_handling() { - // Test that unfree packages are detected and handled correctly - let output = Command::new("timeout") - .args([ - "30", - "cargo", - "run", - "--bin", - "eh", - "--", - "build", - "nixpkgs#discord", - ]) - .output() - .expect("Failed to execute command"); - - let stderr = String::from_utf8_lossy(&output.stderr); - let stdout = String::from_utf8_lossy(&output.stdout); - let combined = format!("{}{}", stdout, stderr); - - // Should detect unfree package and show appropriate message - assert!( - combined.contains("has an unfree license") - || combined.contains("NIXPKGS_ALLOW_UNFREE") - || combined.contains("⚠ Unfree package detected") - ); -} - -#[test] -fn insecure_package_handling() { - // Test that error classification works for insecure packages - use eh::util::{DefaultNixErrorClassifier, NixErrorClassifier}; - - let classifier = DefaultNixErrorClassifier; - let stderr_insecure = - "Package 'example-1.0' has been marked as insecure, refusing to evaluate."; - - assert!(classifier.should_retry(stderr_insecure)); -} - -#[test] -fn broken_package_handling() { - // Test that error classification works for broken packages - use eh::util::{DefaultNixErrorClassifier, NixErrorClassifier}; - - let classifier = DefaultNixErrorClassifier; - let stderr_broken = "Package 'example-1.0' has been marked as broken, refusing to evaluate."; - - assert!(classifier.should_retry(stderr_broken)); -} - -#[test] -fn multicall_binary_dispatch() { - // Test that nb/nr/ns dispatch correctly based on binary name - let commands = [("nb", "build"), ("nr", "run"), ("ns", "shell")]; - - for (binary_name, _expected_cmd) in &commands { - let output = Command::new("timeout") - .args(["10", "cargo", "run", "--bin", "eh"]) - .env("CARGO_BIN_NAME", binary_name) - .arg("nixpkgs#hello") - .arg("--help") // Use help to avoid actually building - .output() - .expect("Failed to execute command"); - - // Should execute without panicking (status code may vary) - assert!(output.status.code().is_some()); - } -} - -#[test] -fn interactive_mode_inheritance() { - // Test that run commands inherit stdio properly - let mut child = Command::new("timeout") - .args([ - "10", - "cargo", - "run", - "--bin", - "eh", - "--", - "run", - "nixpkgs#echo", - "test", - ]) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .expect("Failed to spawn command"); - - let status = child.wait().expect("Failed to wait for child"); - - // Should complete without hanging - assert!(status.code().is_some()); -} - -#[test] -fn hash_extraction() { - use eh::util::{HashExtractor, RegexHashExtractor}; - - let extractor = RegexHashExtractor; - let stderr = "error: hash mismatch in fixed-output derivation '/nix/store/...': - specified: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= - got: sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB="; - - let hash = extractor.extract_hash(stderr); - assert!(hash.is_some()); - assert_eq!( - hash.unwrap(), - "sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=" - ); -} - -#[test] -fn error_classification() { - use eh::util::{DefaultNixErrorClassifier, NixErrorClassifier}; - - let classifier = DefaultNixErrorClassifier; - - assert!(classifier.should_retry("has an unfree license ('unfree'), refusing to evaluate")); - assert!(classifier.should_retry("has been marked as insecure, refusing to evaluate")); - assert!(classifier.should_retry("has been marked as broken, refusing to evaluate")); - assert!(!classifier.should_retry("random build error")); -} - -#[test] -fn hash_mismatch_auto_fix() { - // Test that hash mismatches are automatically detected and fixed - // This is harder to test without creating actual files, so we test the regex - // for the time being. Alternatively I could do this inside a temporary directory - // but cba for now. - use eh::util::{HashExtractor, RegexHashExtractor}; - - let extractor = RegexHashExtractor; - let stderr_with_mismatch = r#" -error: hash mismatch in fixed-output derivation - specified: sha256-oldhashaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa= - got: sha256-newhashbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb= -"#; - - let extracted = extractor.extract_hash(stderr_with_mismatch); - assert_eq!( - extracted, - Some("sha256-newhashbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=".to_string()) - ); -} diff --git a/flake.nix b/flake.nix index 58ffdf5..18bd6fa 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,6 @@ { - inputs.nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable"; + description = "Rust Project Template"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; outputs = { self, @@ -7,11 +8,11 @@ }: let systems = ["x86_64-linux" "aarch64-linux"]; forEachSystem = nixpkgs.lib.genAttrs systems; + pkgsForEach = nixpkgs.legacyPackages; in { packages = forEachSystem (system: { - eh = pkgsForEach.${system}.callPackage ./nix/package.nix {}; - default = self.packages.${system}.eh; + default = pkgsForEach.${system}.callPackage ./nix/package.nix {}; }); devShells = forEachSystem (system: { @@ -19,6 +20,5 @@ }); hydraJobs = self.packages; - checks = self.packages // self.devShells; }; } diff --git a/nix/package.nix b/nix/package.nix index afa39dc..7a91195 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -1,7 +1,6 @@ { lib, rustPlatform, - stdenv, }: rustPlatform.buildRustPackage (finalAttrs: { pname = "eh"; @@ -22,28 +21,11 @@ rustPlatform.buildRustPackage (finalAttrs: { ]); }; - # xtask doesn't support passing --targe - # but nix hooks expect the folder structure from when it's set - env.CARGO_BUILD_TARGET = stdenv.hostPlatform.rust.cargoShortTarget; cargoLock.lockFile = "${finalAttrs.src}/Cargo.lock"; enableParallelBuilding = true; - postInstall = '' - # Install required files with the 'dist' task - $out/bin/xtask multicall \ - --bin-dir $out/bin \ - --main-binary $out/bin/eh - - # The xtask output has been built as a part of the build phase. If - # we don't remove it, it'll be linked in $out/bin alongside the actual - # binary and populate $PATH with a dedicated 'xtask' command. Remove. - rm -rf $out/bin/xtask - ''; - meta = { description = "Ergonomic Nix CLI helper"; maintainers = with lib.licenses; [NotAShelf]; - license = lib.licenses.mpl20; - mainProgram = "eh"; }; }) diff --git a/nix/shell.nix b/nix/shell.nix index fcda3a5..965a0eb 100644 --- a/nix/shell.nix +++ b/nix/shell.nix @@ -4,7 +4,6 @@ rustfmt, clippy, cargo, - taplo, rustPlatform, }: mkShell { @@ -14,8 +13,6 @@ mkShell { rustfmt clippy cargo - - taplo ]; RUST_SRC_PATH = "${rustPlatform.rustLibSrc}"; diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 54657fb..a8d8f20 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -10,5 +10,3 @@ publish = false [dependencies] clap.workspace = true -clap_complete.workspace = true -eh = { path = "../eh" } diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 4d92b6a..6a2d7b7 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -4,8 +4,7 @@ use std::{ process, }; -use clap::{CommandFactory, Parser}; -use clap_complete::{Shell, generate}; +use clap::Parser; #[derive(clap::Parser)] struct Cli { @@ -25,15 +24,6 @@ enum Command { #[arg(long, default_value = "target/release/eh")] main_binary: PathBuf, }, - /// Generate shell completion scripts - Completions { - /// Shell to generate completions for - #[arg(value_enum)] - shell: Shell, - /// Directory to output completion files - #[arg(long, default_value = "completions")] - output_dir: PathBuf, - }, } #[derive(Debug, Clone, Copy)] @@ -66,12 +56,6 @@ fn main() { 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); - } - } } } @@ -133,43 +117,3 @@ fn create_multicall_binaries( Ok(()) } - -fn generate_completions(shell: Shell, output_dir: &Path) -> Result<(), Box> { - println!("generating {} completions...", shell); - - fs::create_dir_all(output_dir)?; - - let mut cmd = eh::Cli::command(); - let bin_name = "eh"; - - let completion_file = output_dir.join(format!("{}.{}", bin_name, shell)); - let mut file = fs::File::create(&completion_file)?; - - generate(shell, &mut cmd, bin_name, &mut file); - - println!("completion file generated: {}", completion_file.display()); - - // Create symlinks for multicall binaries - let multicall_names = ["nb", "nr", "ns"]; - for name in &multicall_names { - let symlink_path = output_dir.join(format!("{}.{}", name, shell)); - if symlink_path.exists() { - fs::remove_file(&symlink_path)?; - } - - #[cfg(unix)] - { - std::os::unix::fs::symlink(&completion_file, &symlink_path)?; - println!("completion symlink created: {}", symlink_path.display()); - } - - #[cfg(not(unix))] - { - fs::copy(&completion_file, &symlink_path)?; - println!("completion copy created: {}", symlink_path.display()); - } - } - - println!("completions generated successfully!"); - Ok(()) -}