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:
parent
665790e8f5
commit
30de95adef
|
@ -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,35 +32,33 @@ 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.");
|
|
||||||
|
|
||||||
let params = format!(
|
create_link_with_applescript(&exec_path, &target_link_path)
|
||||||
r##"do shell script "mkdir -p /usr/local/bin && ln -sf '{}' '{}'" with administrator privileges"##,
|
.context("unable to create link with AppleScript")?;
|
||||||
exec_path.to_string_lossy(),
|
|
||||||
target_link_path.to_string_lossy(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut child = std::process::Command::new("osascript")
|
|
||||||
.args(&["-e", ¶ms])
|
|
||||||
.spawn()?;
|
|
||||||
|
|
||||||
let result = child.wait()?;
|
|
||||||
if !result.success() {
|
|
||||||
return Err(PathError::ElevationRequestFailure.into());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(PathError::SymlinkError(error).into());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_other_error => {
|
_other_error => {
|
||||||
return Err(PathError::SymlinkError(error).into());
|
return Err(PathError::SymlinkError(error).into());
|
||||||
|
@ -71,6 +69,26 @@ pub fn add_espanso_to_path(prompt_when_necessary: bool) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_link_with_applescript(exec_path: &Path, target_link_path: &Path) -> Result<()> {
|
||||||
|
let params = format!(
|
||||||
|
r##"do shell script "mkdir -p /usr/local/bin && ln -sf '{}' '{}'" with administrator privileges"##,
|
||||||
|
exec_path.to_string_lossy(),
|
||||||
|
target_link_path.to_string_lossy(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut child = std::process::Command::new("osascript")
|
||||||
|
.args(&["-e", ¶ms])
|
||||||
|
.spawn()?;
|
||||||
|
|
||||||
|
let result = child.wait()?;
|
||||||
|
|
||||||
|
if !result.success() {
|
||||||
|
return Err(PathError::ElevationRequestFailure.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn remove_espanso_from_path(prompt_when_necessary: bool) -> Result<()> {
|
pub fn remove_espanso_from_path(prompt_when_necessary: bool) -> Result<()> {
|
||||||
let target_link_path = PathBuf::from("/usr/local/bin/espanso");
|
let target_link_path = PathBuf::from("/usr/local/bin/espanso");
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user