use crate::UP_BUNDLE_ID;
use crate::errors::UpError;
use camino::Utf8Path;
use camino::Utf8PathBuf;
use color_eyre::Result;
use color_eyre::eyre::Context;
use color_eyre::eyre::eyre;
use std::fs;
use std::fs::File;
use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use tracing::trace;
use tracing::warn;
const EMPTY_HOME_DIR: &str = "/var/empty";
pub fn home_dir() -> Result<Utf8PathBuf> {
let home_dir = dirs::home_dir()
.ok_or_else(|| eyre!("Expected to be able to calculate the user's home directory."))?;
let home_dir = Utf8PathBuf::try_from(home_dir)?;
if home_dir == EMPTY_HOME_DIR {
warn!(
"User home directory appears to be set to {EMPTY_HOME_DIR}. This is likely to cause \
issues with program execution."
);
}
Ok(home_dir)
}
pub fn log_dir() -> Result<Utf8PathBuf> {
Ok(home_dir()?.join("Library/Logs").join(UP_BUNDLE_ID))
}
pub(crate) fn parent(path: &Utf8Path) -> Result<&Utf8Path> {
path.parent()
.ok_or_else(|| eyre!("Didn't expect path {path} to be the root directory."))
}
pub fn to_utf8_path(path: &std::path::Path) -> Result<&Utf8Path> {
Utf8Path::from_path(path).ok_or_else(|| eyre!("Invalid UTF-8 in path {path:?}"))
}
pub fn remove_broken_symlink(path: &Utf8Path) -> Result<(), UpError> {
warn!(
"Removing existing broken symlink.\n Path: {path}\n Dest: {dest}",
dest = &path.read_link_utf8().map_err(|e| UpError::IoError {
path: path.to_owned(),
source: e
})?
);
fs::remove_file(path).map_err(|e| UpError::DeleteError {
path: path.to_owned(),
source: e,
})?;
Ok(())
}
pub fn create(file_path: &Utf8Path, mode: Option<u32>) -> Result<File> {
trace!("Ensuring file exists: {file_path}");
create_dir_all(parent(file_path)?)?;
let mode = mode.unwrap_or(0o666);
let file = OpenOptions::new()
.write(true)
.create(true)
.mode(mode)
.open(file_path)
.wrap_err_with(|| eyre!("Failed to create file at {file_path}"))?;
Ok(file)
}
pub fn create_dir_all(path: impl AsRef<Utf8Path>) -> Result<()> {
let path = path.as_ref();
trace!("Ensuring that directory path exists: {path}");
fs::create_dir_all(path).wrap_err_with(|| eyre!("Failed to create directory {path}"))
}
pub(crate) fn write(path: impl AsRef<Utf8Path>, contents: impl AsRef<[u8]>) -> Result<()> {
let path = path.as_ref();
trace!("Writing data to {path}");
fs::write(path, contents).wrap_err_with(|| eyre!("Failed to write to file {path}"))
}