feat(core): create /usr/local/bin folder on macOS if it doesn't exist when adding espanso to the path. Fix #814

This commit is contained in:
Federico Terzi 2021-11-01 17:36:45 +01:00
parent 665790e8f5
commit 30de95adef

View File

@ -17,11 +17,11 @@
* along with espanso. If not, see <https://www.gnu.org/licenses/>. * along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/ */
use std::io::ErrorKind; use std::path::{Path, PathBuf};
use std::path::PathBuf; use std::{fs::create_dir_all, io::ErrorKind};
use thiserror::Error; use thiserror::Error;
use anyhow::Result; use anyhow::{Context, Result};
use log::{error, warn}; use log::{error, warn};
pub fn is_espanso_in_path() -> bool { pub fn is_espanso_in_path() -> bool {
@ -32,18 +32,44 @@ pub fn add_espanso_to_path(prompt_when_necessary: bool) -> Result<()> {
let target_link_dir = PathBuf::from("/usr/local/bin"); let target_link_dir = PathBuf::from("/usr/local/bin");
let exec_path = std::env::current_exe()?; let exec_path = std::env::current_exe()?;
if !target_link_dir.is_dir() {
return Err(PathError::UsrLocalBinDirDoesNotExist.into());
}
let target_link_path = target_link_dir.join("espanso"); let target_link_path = target_link_dir.join("espanso");
if !target_link_dir.is_dir() {
warn!("/usr/local/bin folder does not exist, attempting to create one...");
if let Err(error) = create_dir_all(&target_link_dir) {
match error.kind() {
ErrorKind::PermissionDenied if prompt_when_necessary => {
warn!("target link file can't be accessed with current permissions, requesting elevated ones through AppleScript.");
create_link_with_applescript(&exec_path, &target_link_path)
.context("unable to create link with AppleScript")?;
}
_other_error => {
return Err(PathError::SymlinkError(error).into());
}
}
}
}
if let Err(error) = std::os::unix::fs::symlink(&exec_path, &target_link_path) { if let Err(error) = std::os::unix::fs::symlink(&exec_path, &target_link_path) {
match error.kind() { match error.kind() {
ErrorKind::PermissionDenied => { ErrorKind::PermissionDenied if prompt_when_necessary => {
if prompt_when_necessary {
warn!("target link file can't be accessed with current permissions, requesting elevated ones through AppleScript."); warn!("target link file can't be accessed with current permissions, requesting elevated ones through AppleScript.");
create_link_with_applescript(&exec_path, &target_link_path)
.context("unable to create link with AppleScript")?;
}
_other_error => {
return Err(PathError::SymlinkError(error).into());
}
}
}
Ok(())
}
fn create_link_with_applescript(exec_path: &Path, target_link_path: &Path) -> Result<()> {
let params = format!( let params = format!(
r##"do shell script "mkdir -p /usr/local/bin && ln -sf '{}' '{}'" with administrator privileges"##, r##"do shell script "mkdir -p /usr/local/bin && ln -sf '{}' '{}'" with administrator privileges"##,
exec_path.to_string_lossy(), exec_path.to_string_lossy(),
@ -55,18 +81,10 @@ pub fn add_espanso_to_path(prompt_when_necessary: bool) -> Result<()> {
.spawn()?; .spawn()?;
let result = child.wait()?; let result = child.wait()?;
if !result.success() { if !result.success() {
return Err(PathError::ElevationRequestFailure.into()); return Err(PathError::ElevationRequestFailure.into());
} }
} else {
return Err(PathError::SymlinkError(error).into());
}
}
_other_error => {
return Err(PathError::SymlinkError(error).into());
}
}
}
Ok(()) Ok(())
} }
@ -112,9 +130,6 @@ pub fn remove_espanso_from_path(prompt_when_necessary: bool) -> Result<()> {
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum PathError { pub enum PathError {
#[error("/usr/local/bin directory doesn't exist")]
UsrLocalBinDirDoesNotExist,
#[error("symlink error: `{0}`")] #[error("symlink error: `{0}`")]
SymlinkError(std::io::Error), SymlinkError(std::io::Error),