Skip to content

Commit

Permalink
Launch correct fzf binary on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
ajeetdsouza committed Dec 24, 2021
1 parent 339a789 commit fd088b4
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Parse error on Cygwin/MSYS due to CRLF line endings.
- Fzf: handle spaces correctly in preview window.
- Bash: avoid initializing completions on older versions.
- Fzf: avoid launching binary from current directory on Windows.

## [0.7.9] - 2021-11-02

Expand Down
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ glob = "0.3.0"
ordered-float = "2.0.0"
serde = { version = "1.0.116", features = ["derive"] }
tempfile = "3.1.0"
thiserror = "1.0.30"

[target.'cfg(windows)'.dependencies]
rand = { version = "0.8.4", features = [
Expand Down
12 changes: 6 additions & 6 deletions src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ impl<'file> Database<'file> {
}
}

#[cfg(unix)]
fn persist<P: AsRef<Path>>(file: NamedTempFile, path: P) -> Result<(), PersistError> {
file.persist(path)?;
Ok(())
}

#[cfg(windows)]
fn persist<P: AsRef<Path>>(mut file: NamedTempFile, path: P) -> Result<(), PersistError> {
use std::thread;
Expand Down Expand Up @@ -152,12 +158,6 @@ fn persist<P: AsRef<Path>>(mut file: NamedTempFile, path: P) -> Result<(), Persi
Ok(())
}

#[cfg(unix)]
fn persist<P: AsRef<Path>>(file: NamedTempFile, path: P) -> Result<(), PersistError> {
file.persist(path)?;
Ok(())
}

pub struct DatabaseFile {
buffer: Vec<u8>,
data_dir: PathBuf,
Expand Down
15 changes: 7 additions & 8 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
use std::fmt::{self, Display, Formatter};
use std::io;

use anyhow::{bail, Context, Result};
use thiserror::Error;

#[derive(Debug, Error)]
#[error("could not find fzf, is it installed?")]
pub struct FzfNotFound;

/// Custom error type for early exit.
#[derive(Debug)]
#[derive(Debug, Error)]
#[error("")]
pub struct SilentExit {
pub code: i32,
}

impl Display for SilentExit {
fn fmt(&self, _: &mut Formatter) -> fmt::Result {
Ok(())
}
}

pub trait BrokenPipeHandler {
fn pipe_exit(self, device: &str) -> Result<()>;
}
Expand Down
13 changes: 6 additions & 7 deletions src/fzf.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
use std::io::{self, Read};
use std::mem;
use std::process::{Child, ChildStdin, Command, Stdio};
use std::process::{Child, ChildStdin, Stdio};

use anyhow::{bail, Context, Result};

use crate::config;
use crate::error::SilentExit;
use crate::error::{FzfNotFound, SilentExit};
use crate::{config, util};

pub struct Fzf {
child: Child,
}

impl Fzf {
pub fn new(multiple: bool) -> Result<Self> {
let mut command = Command::new("fzf");
let bin = if cfg!(windows) { "fzf.exe" } else { "fzf" };
let mut command = util::get_command(bin).map_err(|_| FzfNotFound)?;
if multiple {
command.arg("-m");
}
Expand All @@ -37,9 +38,7 @@ impl Fzf {

let child = match command.spawn() {
Ok(child) => child,
Err(e) if e.kind() == io::ErrorKind::NotFound => {
bail!("could not find fzf, is it installed?")
}
Err(e) if e.kind() == io::ErrorKind::NotFound => bail!(FzfNotFound),
Err(e) => Err(e).context("could not launch fzf")?,
};

Expand Down
30 changes: 30 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::env;
use std::path::{Component, Path, PathBuf};
use std::process::Command;
use std::time::SystemTime;

use anyhow::{bail, Context, Result};
Expand All @@ -21,6 +22,35 @@ pub fn current_time() -> Result<Epoch> {
Ok(current_time)
}

/// Constructs a new [`Command`] for launching the program with the name
/// `program`.
///
/// On Windows, CreateProcess implicitly searches the current working directory
/// for the executable, which is a potential security issue. Instead, we resolve
/// the path to the executable and then pass it to CreateProcess.
///
/// On other platforms, this is a no-op.
///
pub fn get_command<P: AsRef<Path>>(program: P) -> Result<Command> {
let program = program.as_ref();
if !cfg!(windows) {
return Ok(Command::new(program));
}

let paths = env::var_os("PATH").context("PATH environment variable not set")?;
for path in env::split_paths(&paths) {
if path.as_os_str().is_empty() {
continue;
}
let path = path.join(program);
if path.metadata().map_or(false, |m| !m.is_dir()) {
return Ok(Command::new(path));
}
}

bail!("executable not found in PATH: {}", program.display());
}

pub fn path_to_str<P: AsRef<Path>>(path: &P) -> Result<&str> {
let path = path.as_ref();
path.to_str().with_context(|| format!("invalid unicode in path: {}", path.display()))
Expand Down

0 comments on commit fd088b4

Please sign in to comment.