From 0a9ed9273a6283ff79e93cef87b6bca3b1c344e1 Mon Sep 17 00:00:00 2001 From: figsoda Date: Fri, 16 Jun 2023 21:38:57 -0400 Subject: [PATCH 1/9] refactor: rewrite command-not-found.sh in rust --- src/bin/nix-locate.rs | 229 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 228 insertions(+), 1 deletion(-) diff --git a/src/bin/nix-locate.rs b/src/bin/nix-locate.rs index 760d398..3beaa53 100644 --- a/src/bin/nix-locate.rs +++ b/src/bin/nix-locate.rs @@ -1,8 +1,15 @@ //! Tool for searching for files in nixpkgs packages use std::collections::HashSet; +use std::env::var_os; use std::ffi::OsStr; +use std::fs::File; +use std::io::stdout; +use std::io::BufRead; +use std::io::BufReader; +use std::io::IsTerminal; use std::path::PathBuf; use std::process; +use std::process::Command; use std::result; use std::str; use std::str::FromStr; @@ -149,6 +156,204 @@ fn locate(args: &Args) -> Result<()> { Ok(()) } +fn has_env(env: &str) -> bool { + var_os(env).map_or(false, |var| !var.is_empty()) +} + +fn has_flakes() -> bool { + // TODO: user config + let mut files = vec![PathBuf::from("/etc/nix/nix.conf")]; + + while let Some(file) = files.pop() { + let Ok(file) = File::open(file) else { + continue; + }; + + for line in BufReader::new(file).lines() { + let Ok(line) = line else { + break; + }; + + let mut tokens = line.split_whitespace(); + let Some(name) = tokens.next() else { + continue; + }; + + match name { + "experimental-features" => { + if tokens.any(|feat| feat == "flakes") { + return true; + } + } + "include" | "!include" => { + if let Some(file) = tokens.next() { + files.push(file.into()); + } + } + _ => {} + } + } + } + + false +} + +fn command_not_found(args: Vec, database: PathBuf) -> Result<()> { + let mut args = args.into_iter(); + let cmd = args.next().expect("there should be a command"); + + // TODO: use "command not found" gettext translations + + // taken from http://www.linuxjournal.com/content/bash-command-not-found + // - do not run when inside Midnight Commander or within a Pipe + if has_env("MC_SID") || !stdout().is_terminal() { + eprintln!("{cmd}: command not found"); + process::exit(127); + } + + // Build the regular expression matcher + let pattern = format!("^/bin/{}$", cmd); + let regex = Regex::new(&pattern).chain_err(|| ErrorKind::Grep(pattern.clone()))?; + + // Open the database + let index_file = database.join("files"); + let db = database::Reader::open(&index_file) + .chain_err(|| ErrorKind::ReadDatabase(index_file.clone()))?; + + let results = db + .query(®ex) + .run() + .chain_err(|| ErrorKind::Grep(pattern.clone()))? + .filter(|v| { + v.as_ref().ok().map_or(true, |(store_path, entry)| { + store_path.origin().toplevel + && entry.node.get_type() == FileType::Regular { executable: true } + }) + }); + + let mut attrs = HashSet::new(); + for v in results { + let (store_path, _) = v.chain_err(|| ErrorKind::ReadDatabase(index_file.clone()))?; + + attrs.insert(format!( + "{}.{}", + store_path.origin().attr, + store_path.origin().output, + )); + } + + let mut it = attrs.iter(); + if let Some(attr) = it.next() { + if it.next().is_some() { + eprintln!("The program '{cmd}' is currently not installed. It is provided by"); + eprintln!("several packages. You can install it by typing one of the following:"); + + let has_flakes = has_flakes(); + + for attr in &attrs { + if has_flakes { + eprintln!(" nix profile install nixpkgs#{attr}"); + } else { + eprintln!(" nix-env -iA nixpkgs.{attr}"); + } + } + + eprintln!("\nOr run it once with:"); + + for attr in attrs { + if has_flakes { + eprintln!(" nix shell nixpkgs#{attr} -c {cmd} ..."); + } else { + eprintln!(" nix-shell -p {attr} --run '{cmd} ...'"); + } + } + } else if has_env("NIX_AUTO_INSTALL") { + eprintln!("The program '{cmd}' is currently not installed. It is provided by"); + eprintln!("the package 'nixpkgs.{attr}', which I will now install for you."); + + let res = if has_flakes() { + Command::new("nix") + .arg("profile") + .arg("install") + .arg(format!("nixpkgs#{attr}")) + .status() + } else { + Command::new("nix-env") + .arg("-iA") + .arg(format!("nixpkgs.{attr}")) + .status() + }; + + if res.is_ok_and(|status| status.success()) { + let res = Command::new(cmd).args(args).status(); + if let Ok(status) = res { + if let Some(code) = status.code() { + process::exit(code); + } + } + } else { + eprintln!("Failed to install nixpkgs.{attr}"); + eprintln!("{cmd}: command not found"); + } + } else if has_env("NIX_AUTO_RUN") { + let res = Command::new("nix-build") + .arg("--no-out-link") + .arg("-A") + .arg(attr) + .arg("") + .status(); + + if res.is_ok_and(|status| status.success()) { + // TODO: escape or find and alternative + let mut cmd = cmd; + for arg in args { + cmd.push(' '); + cmd.push_str(&arg); + } + + let res = Command::new("nix-shell") + .arg("-p") + .arg(attr) + .arg("--run") + .arg(cmd) + .status(); + + if let Ok(status) = res { + if let Some(code) = status.code() { + process::exit(code); + } + } + } else { + eprintln!("Failed to install nixpkgs.{attr}"); + eprintln!("{cmd}: command not found"); + } + } else { + let has_flakes = has_flakes(); + + eprintln!("The program '{cmd}' is currently not installed. You can install it"); + eprintln!("by typing:"); + + if has_flakes { + eprintln!(" nix profile install nixpkgs#{attr}"); + } else { + eprintln!(" nix-env -iA nixpkgs.{attr}"); + } + + eprintln!("\nOr run it once with:"); + + if has_flakes { + eprintln!(" nix shell nixpkgs#{attr} -c {cmd} ..."); + } else { + eprintln!(" nix-shell -p {attr} --run '{cmd} ...'"); + } + } + } else { + eprintln!("{cmd}: command not found"); + } + + Ok(()) +} + /// Extract the parsed arguments for clap's arg matches. /// /// Handles parsing the values of more complex arguments. @@ -236,7 +441,11 @@ fn cache_dir() -> &'static OsStr { #[clap(author, about, version, after_help = LONG_USAGE)] struct Opts { /// Pattern for which to search - // #[clap(name = "PATTERN")] + #[arg( + required_unless_present = "command_not_found", + default_value_t, // placeholder, will not be accessed + hide_default_value = true + )] pattern: String, /// Directory where the index is stored @@ -293,6 +502,9 @@ struct Opts { /// store path are omitted. This is useful for scripts that use the output of nix-locate. #[clap(long)] minimal: bool, + + #[clap(long, num_args = 1..)] + command_not_found: Option>, } #[derive(clap::ValueEnum, Clone, Copy, Debug)] @@ -318,6 +530,21 @@ impl FromStr for Color { fn main() { let args = Opts::parse(); + if let Some(cmd) = args.command_not_found { + if let Err(e) = command_not_found(cmd, args.database) { + eprintln!("error: {e}"); + + for e in e.iter().skip(1) { + eprintln!("caused by: {e}"); + } + + if let Some(backtrace) = e.backtrace() { + eprintln!("backtrace: {backtrace:?}"); + } + } + process::exit(127); + } + let args = process_args(args).unwrap_or_else(|e| e.exit()); if let Err(e) = locate(&args) { From c9f352ae54aaea3a1810fac9eabe2f3ca138c8f6 Mon Sep 17 00:00:00 2001 From: figsoda Date: Sat, 17 Jun 2023 09:08:55 -0400 Subject: [PATCH 2/9] fix(cnf): escape command --- src/bin/nix-locate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/nix-locate.rs b/src/bin/nix-locate.rs index 3beaa53..7d17011 100644 --- a/src/bin/nix-locate.rs +++ b/src/bin/nix-locate.rs @@ -212,7 +212,7 @@ fn command_not_found(args: Vec, database: PathBuf) -> Result<()> { } // Build the regular expression matcher - let pattern = format!("^/bin/{}$", cmd); + let pattern = format!("^/bin/{}$", regex::escape(&cmd)); let regex = Regex::new(&pattern).chain_err(|| ErrorKind::Grep(pattern.clone()))?; // Open the database From 2030741bf37aa5bb4ec84cf78bb428dc4d489d50 Mon Sep 17 00:00:00 2001 From: figsoda Date: Sat, 17 Jun 2023 09:32:13 -0400 Subject: [PATCH 3/9] fix(nix-locate): compatibility with rust 1.69 --- Cargo.lock | 1 + Cargo.toml | 1 + src/bin/nix-locate.rs | 7 ++++--- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4677aae..ac5004e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1110,6 +1110,7 @@ dependencies = [ "hyper", "hyper-proxy", "indexmap", + "is-terminal", "memchr", "num_cpus", "owo-colors", diff --git a/Cargo.toml b/Cargo.toml index 9dd5e87..d809958 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ grep = "0.2.12" headers = "0.3.8" http = "0.2.9" hyper-proxy = "0.9.1" +is-terminal = "0.4.7" atty = "0.2.14" memchr = "2.5.0" num_cpus = "1.15.0" diff --git a/src/bin/nix-locate.rs b/src/bin/nix-locate.rs index 7d17011..e257fd5 100644 --- a/src/bin/nix-locate.rs +++ b/src/bin/nix-locate.rs @@ -6,7 +6,7 @@ use std::fs::File; use std::io::stdout; use std::io::BufRead; use std::io::BufReader; -use std::io::IsTerminal; +// use std::io::IsTerminal; use std::path::PathBuf; use std::process; use std::process::Command; @@ -16,6 +16,7 @@ use std::str::FromStr; use clap::{value_parser, Parser}; use error_chain::error_chain; +use is_terminal::IsTerminal; use nix_index::database; use nix_index::files::{self, FileTreeEntry, FileType}; use owo_colors::{OwoColorize, Stream}; @@ -284,7 +285,7 @@ fn command_not_found(args: Vec, database: PathBuf) -> Result<()> { .status() }; - if res.is_ok_and(|status| status.success()) { + if matches!(res, Ok(status) if status.success()) { let res = Command::new(cmd).args(args).status(); if let Ok(status) = res { if let Some(code) = status.code() { @@ -303,7 +304,7 @@ fn command_not_found(args: Vec, database: PathBuf) -> Result<()> { .arg("") .status(); - if res.is_ok_and(|status| status.success()) { + if matches!(res, Ok(status) if status.success()) { // TODO: escape or find and alternative let mut cmd = cmd; for arg in args { From 96f18b082bcda1da9b398a3ffbc3f0e53b338605 Mon Sep 17 00:00:00 2001 From: figsoda Date: Sat, 17 Jun 2023 09:25:44 -0400 Subject: [PATCH 4/9] refactor: replace command-not-found.sh with `nix-locate --command-not-found` --- command-not-found.sh | 135 ------------------------------------- etc/command-not-found.bash | 3 + etc/command-not-found.fish | 3 + etc/command-not-found.zsh | 3 + flake.nix | 7 +- 5 files changed, 12 insertions(+), 139 deletions(-) delete mode 100755 command-not-found.sh create mode 100644 etc/command-not-found.bash create mode 100644 etc/command-not-found.fish create mode 100644 etc/command-not-found.zsh diff --git a/command-not-found.sh b/command-not-found.sh deleted file mode 100755 index 5f30bad..0000000 --- a/command-not-found.sh +++ /dev/null @@ -1,135 +0,0 @@ -#!/bin/sh - -# for bash 4 -# this will be called when a command is entered -# but not found in the user’s path + environment -command_not_found_handle () { - - # TODO: use "command not found" gettext translations - - # taken from http://www.linuxjournal.com/content/bash-command-not-found - # - do not run when inside Midnight Commander or within a Pipe - if [ -n "${MC_SID-}" ] || ! [ -t 1 ]; then - >&2 echo "$1: command not found" - return 127 - fi - - toplevel=nixpkgs # nixpkgs should always be available even in NixOS - cmd=$1 - attrs=$(@out@/bin/nix-locate --minimal --no-group --type x --type s --top-level --whole-name --at-root "/bin/$cmd") - len=$(echo -n "$attrs" | grep -c "^") - - case $len in - 0) - >&2 echo "$cmd: command not found" - ;; - 1) - # if only 1 package provides this, then we can invoke it - # without asking the users if they have opted in with one - # of 2 environment variables - - # they are based on the ones found in - # command-not-found.sh: - - # NIX_AUTO_INSTALL : install the missing command into the - # user’s environment - # NIX_AUTO_RUN : run the command transparently inside of - # nix shell - - # these will not return 127 if they worked correctly - - if ! [ -z "${NIX_AUTO_INSTALL-}" ]; then - >&2 cat <&2 cat <" - if [ "$?" -eq 0 ]; then - # how nix-shell handles commands is weird - # $(echo $@) is need to handle this - nix-shell -p $attrs --run "$(echo $@)" - return $? - else - >&2 cat <&2 cat <&2 cat <&2 cat <&2 echo " nix profile install $toplevel#$attr" - else - >&2 echo " nix-env -iA $toplevel.$attr" - fi - done <<< "$attrs" - - >&2 cat <&2 echo " nix shell $toplevel#$attr -c $cmd ..." - else - >&2 echo " nix-shell -p $attr --run '$cmd ...'" - fi - done <<< "$attrs" - ;; - esac - - return 127 # command not found should always exit with 127 -} - -# for zsh... -# we just pass it to the bash handler above -# apparently they work identically -command_not_found_handler () { - command_not_found_handle $@ - return $? -} diff --git a/etc/command-not-found.bash b/etc/command-not-found.bash new file mode 100644 index 0000000..ef4f71e --- /dev/null +++ b/etc/command-not-found.bash @@ -0,0 +1,3 @@ +command_not_found_handle() { + @out@/bin/nix-locate --command-not-found "$@" +} diff --git a/etc/command-not-found.fish b/etc/command-not-found.fish new file mode 100644 index 0000000..5536eda --- /dev/null +++ b/etc/command-not-found.fish @@ -0,0 +1,3 @@ +function fish_command_not_found + target/debug/nix-locate --command-not-found $argv +end diff --git a/etc/command-not-found.zsh b/etc/command-not-found.zsh new file mode 100644 index 0000000..3cc2583 --- /dev/null +++ b/etc/command-not-found.zsh @@ -0,0 +1,3 @@ +command_not_found_handler() { + @out@/bin/nix-locate --command-not-found "$@" +} diff --git a/flake.nix b/flake.nix index 084149e..6f5091b 100644 --- a/flake.nix +++ b/flake.nix @@ -23,9 +23,8 @@ inherit ((lib.importTOML ./Cargo.toml).package) version; src = lib.sourceByRegex self [ - "(examples|src)(/.*)?" + "(etc|examples|src)(/.*)?" ''Cargo\.(toml|lock)'' - ''command-not-found\.sh'' ]; cargoLock = { @@ -37,9 +36,9 @@ ++ lib.optionals stdenv.isDarwin [ darwin.apple_sdk.frameworks.Security ]; postInstall = '' - substituteInPlace command-not-found.sh \ + substituteInPlace etc/command-not-found.* \ --subst-var out - install -Dm555 command-not-found.sh -t $out/etc/profile.d + install -Dm444 etc/command-not-found.* -t $out/etc/profile.d ''; meta = with lib; { From 309c9d2f06e9e3c1cc9b2c3b4861a903c7e08edb Mon Sep 17 00:00:00 2001 From: figsoda Date: Sat, 17 Jun 2023 09:41:48 -0400 Subject: [PATCH 5/9] fix(cnf): typo --- etc/command-not-found.fish | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/command-not-found.fish b/etc/command-not-found.fish index 5536eda..449ae5e 100644 --- a/etc/command-not-found.fish +++ b/etc/command-not-found.fish @@ -1,3 +1,3 @@ function fish_command_not_found - target/debug/nix-locate --command-not-found $argv + @out@/bin/nix-locate --command-not-found $argv end From ebe9c99e477c389d901dffc3a3992841d5f0d793 Mon Sep 17 00:00:00 2001 From: figsoda Date: Sat, 17 Jun 2023 10:44:11 -0400 Subject: [PATCH 6/9] fix(cnf): gracefully handle flags --- src/bin/nix-locate.rs | 53 ++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/src/bin/nix-locate.rs b/src/bin/nix-locate.rs index e257fd5..412dabf 100644 --- a/src/bin/nix-locate.rs +++ b/src/bin/nix-locate.rs @@ -1,7 +1,9 @@ //! Tool for searching for files in nixpkgs packages use std::collections::HashSet; +use std::env::args_os; use std::env::var_os; use std::ffi::OsStr; +use std::ffi::OsString; use std::fs::File; use std::io::stdout; use std::io::BufRead; @@ -199,21 +201,23 @@ fn has_flakes() -> bool { false } -fn command_not_found(args: Vec, database: PathBuf) -> Result<()> { - let mut args = args.into_iter(); +fn command_not_found(args: Vec) -> Result<()> { + let mut args = args.into_iter().skip(2); let cmd = args.next().expect("there should be a command"); + let cmd_str = cmd.to_string_lossy(); + let database = var_os("NIX_INDEX_DATABASE").map_or_else(|| cache_dir().into(), PathBuf::from); // TODO: use "command not found" gettext translations // taken from http://www.linuxjournal.com/content/bash-command-not-found // - do not run when inside Midnight Commander or within a Pipe if has_env("MC_SID") || !stdout().is_terminal() { - eprintln!("{cmd}: command not found"); + eprintln!("{cmd_str}: command not found"); process::exit(127); } // Build the regular expression matcher - let pattern = format!("^/bin/{}$", regex::escape(&cmd)); + let pattern = format!("^/bin/{}$", regex::escape(&cmd_str)); let regex = Regex::new(&pattern).chain_err(|| ErrorKind::Grep(pattern.clone()))?; // Open the database @@ -246,7 +250,7 @@ fn command_not_found(args: Vec, database: PathBuf) -> Result<()> { let mut it = attrs.iter(); if let Some(attr) = it.next() { if it.next().is_some() { - eprintln!("The program '{cmd}' is currently not installed. It is provided by"); + eprintln!("The program '{cmd_str}' is currently not installed. It is provided by"); eprintln!("several packages. You can install it by typing one of the following:"); let has_flakes = has_flakes(); @@ -263,13 +267,13 @@ fn command_not_found(args: Vec, database: PathBuf) -> Result<()> { for attr in attrs { if has_flakes { - eprintln!(" nix shell nixpkgs#{attr} -c {cmd} ..."); + eprintln!(" nix shell nixpkgs#{attr} -c {cmd_str} ..."); } else { - eprintln!(" nix-shell -p {attr} --run '{cmd} ...'"); + eprintln!(" nix-shell -p {attr} --run '{cmd_str} ...'"); } } } else if has_env("NIX_AUTO_INSTALL") { - eprintln!("The program '{cmd}' is currently not installed. It is provided by"); + eprintln!("The program '{cmd_str}' is currently not installed. It is provided by"); eprintln!("the package 'nixpkgs.{attr}', which I will now install for you."); let res = if has_flakes() { @@ -294,7 +298,7 @@ fn command_not_found(args: Vec, database: PathBuf) -> Result<()> { } } else { eprintln!("Failed to install nixpkgs.{attr}"); - eprintln!("{cmd}: command not found"); + eprintln!("{cmd_str}: command not found"); } } else if has_env("NIX_AUTO_RUN") { let res = Command::new("nix-build") @@ -308,8 +312,8 @@ fn command_not_found(args: Vec, database: PathBuf) -> Result<()> { // TODO: escape or find and alternative let mut cmd = cmd; for arg in args { - cmd.push(' '); - cmd.push_str(&arg); + cmd.push(" "); + cmd.push(&arg); } let res = Command::new("nix-shell") @@ -326,12 +330,12 @@ fn command_not_found(args: Vec, database: PathBuf) -> Result<()> { } } else { eprintln!("Failed to install nixpkgs.{attr}"); - eprintln!("{cmd}: command not found"); + eprintln!("{cmd_str}: command not found"); } } else { let has_flakes = has_flakes(); - eprintln!("The program '{cmd}' is currently not installed. You can install it"); + eprintln!("The program '{cmd_str}' is currently not installed. You can install it"); eprintln!("by typing:"); if has_flakes { @@ -343,13 +347,13 @@ fn command_not_found(args: Vec, database: PathBuf) -> Result<()> { eprintln!("\nOr run it once with:"); if has_flakes { - eprintln!(" nix shell nixpkgs#{attr} -c {cmd} ..."); + eprintln!(" nix shell nixpkgs#{attr} -c {cmd_str} ..."); } else { - eprintln!(" nix-shell -p {attr} --run '{cmd} ...'"); + eprintln!(" nix-shell -p {attr} --run '{cmd_str} ...'"); } } } else { - eprintln!("{cmd}: command not found"); + eprintln!("{cmd_str}: command not found"); } Ok(()) @@ -442,11 +446,7 @@ fn cache_dir() -> &'static OsStr { #[clap(author, about, version, after_help = LONG_USAGE)] struct Opts { /// Pattern for which to search - #[arg( - required_unless_present = "command_not_found", - default_value_t, // placeholder, will not be accessed - hide_default_value = true - )] + // #[clap(name = "PATTERN")] pattern: String, /// Directory where the index is stored @@ -503,9 +503,6 @@ struct Opts { /// store path are omitted. This is useful for scripts that use the output of nix-locate. #[clap(long)] minimal: bool, - - #[clap(long, num_args = 1..)] - command_not_found: Option>, } #[derive(clap::ValueEnum, Clone, Copy, Debug)] @@ -529,10 +526,9 @@ impl FromStr for Color { } fn main() { - let args = Opts::parse(); - - if let Some(cmd) = args.command_not_found { - if let Err(e) = command_not_found(cmd, args.database) { + let args: Vec<_> = args_os().collect(); + if matches!(args.get(1), Some(arg) if arg == "--command-not-found") { + if let Err(e) = command_not_found(args) { eprintln!("error: {e}"); for e in e.iter().skip(1) { @@ -546,6 +542,7 @@ fn main() { process::exit(127); } + let args = Opts::parse_from(args); let args = process_args(args).unwrap_or_else(|e| e.exit()); if let Err(e) = locate(&args) { From b625cbbcd1f840d0c13b343ddc6b6034633bce98 Mon Sep 17 00:00:00 2001 From: figsoda Date: Thu, 22 Jun 2023 20:34:03 -0400 Subject: [PATCH 7/9] flake.lock: Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:NixOS/nixpkgs/75a5ebf473cd60148ba9aec0d219f72e5cf52519' (2023-06-11) → 'github:NixOS/nixpkgs/e603dc5f061ca1d8a19b3ede6a8cf9c9fcba6cdc' (2023-06-22) --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index f6fadf1..19ffa81 100644 --- a/flake.lock +++ b/flake.lock @@ -18,11 +18,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1686501370, - "narHash": "sha256-G0WuM9fqTPRc2URKP9Lgi5nhZMqsfHGrdEbrLvAPJcg=", + "lastModified": 1687412861, + "narHash": "sha256-Z/g0wbL68C+mSGerYS2quv9FXQ1RRP082cAC0Bh4vcs=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "75a5ebf473cd60148ba9aec0d219f72e5cf52519", + "rev": "e603dc5f061ca1d8a19b3ede6a8cf9c9fcba6cdc", "type": "github" }, "original": { From b2205e3a96b9362783a702c49e6a9d86868fd369 Mon Sep 17 00:00:00 2001 From: figsoda Date: Thu, 22 Jun 2023 20:34:22 -0400 Subject: [PATCH 8/9] Revert "fix(nix-locate): compatibility with rust 1.69" This reverts commit 2030741bf37aa5bb4ec84cf78bb428dc4d489d50. --- Cargo.lock | 1 - Cargo.toml | 1 - src/bin/nix-locate.rs | 7 +++---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac5004e..4677aae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1110,7 +1110,6 @@ dependencies = [ "hyper", "hyper-proxy", "indexmap", - "is-terminal", "memchr", "num_cpus", "owo-colors", diff --git a/Cargo.toml b/Cargo.toml index d809958..9dd5e87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,6 @@ grep = "0.2.12" headers = "0.3.8" http = "0.2.9" hyper-proxy = "0.9.1" -is-terminal = "0.4.7" atty = "0.2.14" memchr = "2.5.0" num_cpus = "1.15.0" diff --git a/src/bin/nix-locate.rs b/src/bin/nix-locate.rs index 412dabf..4a13354 100644 --- a/src/bin/nix-locate.rs +++ b/src/bin/nix-locate.rs @@ -8,7 +8,7 @@ use std::fs::File; use std::io::stdout; use std::io::BufRead; use std::io::BufReader; -// use std::io::IsTerminal; +use std::io::IsTerminal; use std::path::PathBuf; use std::process; use std::process::Command; @@ -18,7 +18,6 @@ use std::str::FromStr; use clap::{value_parser, Parser}; use error_chain::error_chain; -use is_terminal::IsTerminal; use nix_index::database; use nix_index::files::{self, FileTreeEntry, FileType}; use owo_colors::{OwoColorize, Stream}; @@ -289,7 +288,7 @@ fn command_not_found(args: Vec) -> Result<()> { .status() }; - if matches!(res, Ok(status) if status.success()) { + if res.is_ok_and(|status| status.success()) { let res = Command::new(cmd).args(args).status(); if let Ok(status) = res { if let Some(code) = status.code() { @@ -308,7 +307,7 @@ fn command_not_found(args: Vec) -> Result<()> { .arg("") .status(); - if matches!(res, Ok(status) if status.success()) { + if res.is_ok_and(|status| status.success()) { // TODO: escape or find and alternative let mut cmd = cmd; for arg in args { From d98abafdf65423cc664d153e980524178fa54b33 Mon Sep 17 00:00:00 2001 From: figsoda Date: Thu, 22 Jun 2023 21:01:20 -0400 Subject: [PATCH 9/9] feat(cnf): reduce stderr locking --- Cargo.lock | 7 +++++ Cargo.toml | 1 + src/bin/nix-locate.rs | 63 ++++++++++++++++++++++++++++--------------- 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4677aae..b02eff8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -917,6 +917,12 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "indoc" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f2cb48b81b1dc9f39676bf99f5499babfec7cd8fe14307f7b3d747208fb5690" + [[package]] name = "instant" version = "0.1.12" @@ -1110,6 +1116,7 @@ dependencies = [ "hyper", "hyper-proxy", "indexmap", + "indoc", "memchr", "num_cpus", "owo-colors", diff --git a/Cargo.toml b/Cargo.toml index 9dd5e87..c0c86ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ grep = "0.2.12" headers = "0.3.8" http = "0.2.9" hyper-proxy = "0.9.1" +indoc = "2.0.1" atty = "0.2.14" memchr = "2.5.0" num_cpus = "1.15.0" diff --git a/src/bin/nix-locate.rs b/src/bin/nix-locate.rs index 4a13354..7599029 100644 --- a/src/bin/nix-locate.rs +++ b/src/bin/nix-locate.rs @@ -5,10 +5,12 @@ use std::env::var_os; use std::ffi::OsStr; use std::ffi::OsString; use std::fs::File; +use std::io::stderr; use std::io::stdout; use std::io::BufRead; use std::io::BufReader; use std::io::IsTerminal; +use std::io::Write; use std::path::PathBuf; use std::process; use std::process::Command; @@ -18,6 +20,7 @@ use std::str::FromStr; use clap::{value_parser, Parser}; use error_chain::error_chain; +use indoc::writedoc; use nix_index::database; use nix_index::files::{self, FileTreeEntry, FileType}; use owo_colors::{OwoColorize, Stream}; @@ -205,13 +208,14 @@ fn command_not_found(args: Vec) -> Result<()> { let cmd = args.next().expect("there should be a command"); let cmd_str = cmd.to_string_lossy(); let database = var_os("NIX_INDEX_DATABASE").map_or_else(|| cache_dir().into(), PathBuf::from); + let mut err = stderr().lock(); // TODO: use "command not found" gettext translations // taken from http://www.linuxjournal.com/content/bash-command-not-found // - do not run when inside Midnight Commander or within a Pipe if has_env("MC_SID") || !stdout().is_terminal() { - eprintln!("{cmd_str}: command not found"); + let _ = writeln!(err, "{cmd_str}: command not found"); process::exit(127); } @@ -249,31 +253,37 @@ fn command_not_found(args: Vec) -> Result<()> { let mut it = attrs.iter(); if let Some(attr) = it.next() { if it.next().is_some() { - eprintln!("The program '{cmd_str}' is currently not installed. It is provided by"); - eprintln!("several packages. You can install it by typing one of the following:"); + writedoc! {err, " + The program '{cmd_str}' is currently not installed. It is provided by; + several packages. You can install it by typing one of the following: + "} + .unwrap(); let has_flakes = has_flakes(); for attr in &attrs { if has_flakes { - eprintln!(" nix profile install nixpkgs#{attr}"); + writeln!(err, " nix profile install nixpkgs#{attr}").unwrap(); } else { - eprintln!(" nix-env -iA nixpkgs.{attr}"); + writeln!(err, " nix-env -iA nixpkgs.{attr}").unwrap(); } } - eprintln!("\nOr run it once with:"); + writeln!(err, "\nOr run it once with:").unwrap(); for attr in attrs { if has_flakes { - eprintln!(" nix shell nixpkgs#{attr} -c {cmd_str} ..."); + writeln!(err, " nix shell nixpkgs#{attr} -c {cmd_str} ...").unwrap(); } else { - eprintln!(" nix-shell -p {attr} --run '{cmd_str} ...'"); + writeln!(err, " nix-shell -p {attr} --run '{cmd_str} ...'").unwrap(); } } } else if has_env("NIX_AUTO_INSTALL") { - eprintln!("The program '{cmd_str}' is currently not installed. It is provided by"); - eprintln!("the package 'nixpkgs.{attr}', which I will now install for you."); + writedoc! {err, " + The program '{cmd_str}' is currently not installed. It is provided by + the package 'nixpkgs.{attr}', which I will now install for you. + "} + .unwrap(); let res = if has_flakes() { Command::new("nix") @@ -296,8 +306,11 @@ fn command_not_found(args: Vec) -> Result<()> { } } } else { - eprintln!("Failed to install nixpkgs.{attr}"); - eprintln!("{cmd_str}: command not found"); + writedoc! {err, " + Failed to install nixpkgs.{attr} + {cmd_str}: command not found + "} + .unwrap(); } } else if has_env("NIX_AUTO_RUN") { let res = Command::new("nix-build") @@ -328,31 +341,37 @@ fn command_not_found(args: Vec) -> Result<()> { } } } else { - eprintln!("Failed to install nixpkgs.{attr}"); - eprintln!("{cmd_str}: command not found"); + writedoc! {err, " + Failed to install nixpkgs.{attr} + {cmd_str}: command not found + "} + .unwrap(); } } else { let has_flakes = has_flakes(); - eprintln!("The program '{cmd_str}' is currently not installed. You can install it"); - eprintln!("by typing:"); + writedoc! {err, " + The program '{cmd_str}' is currently not installed. You can install it + by typing: + "} + .unwrap(); if has_flakes { - eprintln!(" nix profile install nixpkgs#{attr}"); + writeln!(err, " nix profile install nixpkgs#{attr}").unwrap(); } else { - eprintln!(" nix-env -iA nixpkgs.{attr}"); + writeln!(err, " nix-env -iA nixpkgs.{attr}").unwrap(); } - eprintln!("\nOr run it once with:"); + writeln!(err, "\nOr run it once with:").unwrap(); if has_flakes { - eprintln!(" nix shell nixpkgs#{attr} -c {cmd_str} ..."); + writeln!(err, " nix shell nixpkgs#{attr} -c {cmd_str} ...").unwrap(); } else { - eprintln!(" nix-shell -p {attr} --run '{cmd_str} ...'"); + writeln!(err, " nix-shell -p {attr} --run '{cmd_str} ...'").unwrap(); } } } else { - eprintln!("{cmd_str}: command not found"); + writeln!(err, "{cmd_str}: command not found").unwrap(); } Ok(())