Files
ELY-Browser/crates/ely_app/src/services/download_files.rs
T

75 lines
2.0 KiB
Rust

use std::{
fs, io,
path::{Path, PathBuf},
process::{Command, ExitStatus},
};
use thiserror::Error;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DownloadFileAction {
Open,
Reveal,
}
#[derive(Debug, Error)]
pub enum DownloadFileError {
#[error("download file is unavailable: {path:?}")]
FileUnavailable { path: PathBuf },
#[error("failed to launch {action} for download file: {path:?}: {source}")]
LaunchFailed { action: &'static str, path: PathBuf, source: io::Error },
#[error("{action} failed for download file: {path:?} ({status})")]
CommandFailed { action: &'static str, path: PathBuf, status: ExitStatus },
}
impl DownloadFileAction {
pub fn run(self, path: &Path) -> Result<(), DownloadFileError> {
ensure_regular_file(path)?;
let status =
self.command(path).status().map_err(|source| DownloadFileError::LaunchFailed {
action: self.label(),
path: path.to_path_buf(),
source,
})?;
if status.success() {
return Ok(());
}
Err(DownloadFileError::CommandFailed {
action: self.label(),
path: path.to_path_buf(),
status,
})
}
fn command(self, path: &Path) -> Command {
let mut command = Command::new("/usr/bin/open");
match self {
Self::Open => {
command.arg(path);
}
Self::Reveal => {
command.arg("-R").arg(path);
}
}
command
}
pub fn label(self) -> &'static str {
match self {
Self::Open => "open",
Self::Reveal => "reveal",
}
}
}
fn ensure_regular_file(path: &Path) -> Result<(), DownloadFileError> {
match fs::metadata(path) {
Ok(metadata) if metadata.is_file() => Ok(()),
Ok(_) | Err(_) => Err(DownloadFileError::FileUnavailable { path: path.to_path_buf() }),
}
}