1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
use std::path::{Path, PathBuf};
use crate::error::{Error as AppError, Result};
/// Gets config path from environment variables, or infer one.
///
/// 1. If the environment variable indexed by `env_for_file`'s value is
/// present, that environment variable's value is returned as the config file
/// path.
///
/// # Example
///
/// ```
/// # use dt_core::utils::default_config_path;
/// # use std::path::PathBuf;
/// # use std::str::FromStr;
/// std::env::set_var("DT_CLI_CONFIG_PATH", "/tmp/dt/configuration.toml");
/// assert_eq!(
/// default_config_path::<&str>("DT_CLI_CONFIG_PATH", "", &[]),
/// Ok(PathBuf::from_str("/tmp/dt/configuration.toml").unwrap()),
/// );
/// ```
///
/// 2. Otherwise, if the environment variable indexed by `env_for_dir`'s value
/// is present, that environment variable's value is considered the parent
/// directory of the returned config path, filenames within `search_list` will
/// be checked in order and the first existing file's path will be returned.
/// If none of the `search_list` exists, a fallback filename `config.toml`
/// will be used.
///
/// # Example
///
/// ```
/// # use dt_core::utils::default_config_path;
/// # use std::path::PathBuf;
/// # use std::str::FromStr;
/// std::env::set_var("DT_CONFIG_DIR", "/tmp/d/t");
/// assert_eq!(
/// default_config_path::<&str>(
/// "some_non_existing_var",
/// "DT_CONFIG_DIR",
/// &[],
/// ),
/// Ok(PathBuf::from_str("/tmp/d/t/config.toml").unwrap()),
/// );
/// ```
///
/// 3. When neither of `env_for_file`'s and `env_for_dir`'s corresponding
/// environment variable exists, the parent directory of returned path is
/// inferred as `$XDG_CONFIG_HOME/dt`, or `$HOME/.config/dt` if
/// XDG_CONFIG_HOME is not set in the runtime environment.
///
/// # Example
///
/// ```
/// # use dt_core::utils::default_config_path;
/// # use std::path::PathBuf;
/// # use std::str::FromStr;
/// std::env::set_var("XDG_CONFIG_HOME", "/tmp/confighome");
/// assert_eq!(
/// default_config_path::<&str>(
/// "some_non_existing_var",
/// "some_other_non_existing_var",
/// &[],
/// ),
/// Ok(PathBuf::from_str("/tmp/confighome/dt/config.toml").unwrap()),
/// );
///
/// std::env::remove_var("XDG_CONFIG_HOME");
/// std::env::set_var("HOME", "/tmp/home");
/// assert_eq!(
/// default_config_path::<&str>(
/// "some_non_existing_var",
/// "some_other_non_existing_var",
/// &[],
/// ),
/// Ok(PathBuf::from_str("/tmp/home/.config/dt/config.toml").unwrap()),
/// );
/// ```
pub fn default_config_path<P: AsRef<Path>>(
env_for_file: &str,
env_for_dir: &str,
search_list: &[P],
) -> Result<PathBuf> {
if let Ok(file_path) = std::env::var(env_for_file) {
log::debug!(
"Using config file '{}' (from environment variable `{}`)",
file_path,
env_for_file,
);
Ok(file_path.into())
} else {
let dir_path = match std::env::var(env_for_dir) {
Ok(dir_path) => {
log::debug!(
"Using config directory '{}' (from environment variable `{}`)",
dir_path,
env_for_dir,
);
dir_path.into()
}
_ => {
if let Some(dir_path) = dirs::config_dir() {
log::debug!(
"Using config directory '{}' (inferred)",
dir_path.display(),
);
dir_path.join("dt")
} else {
return Err(AppError::ConfigError(
"Could not infer directory to config file".to_owned(),
));
}
}
};
let mut file_path = dir_path.join("config.toml");
for p in search_list {
let candidate = dir_path.join(p);
if candidate.exists() {
file_path = candidate;
break;
}
}
log::debug!("Using config file '{}' (inferred)", file_path.display());
Ok(file_path)
}
}
/// Gets the host-specific suffix, according to given [`hostname_sep`] and
/// current machine's hostname.
///
/// [`hostname_sep`]: crate::config::GlobalConfig::hostname_sep
pub fn host_specific_suffix(hostname_sep: &str) -> String {
hostname_sep.to_owned()
+ gethostname::gethostname()
.to_str()
.expect("Failed getting hostname")
}
#[cfg(test)]
pub(crate) mod testing {
use std::{
fs::Permissions, os::unix::prelude::PermissionsExt, path::PathBuf,
};
use color_eyre::Report;
const TESTROOT: &str = "/tmp/dt-testing/syncing";
pub fn get_testroot() -> PathBuf {
TESTROOT.into()
}
pub fn prepare_directory(
abspath: PathBuf,
mode: u32,
) -> Result<PathBuf, Report> {
std::fs::create_dir_all(&abspath)?;
std::fs::set_permissions(&abspath, Permissions::from_mode(mode))?;
Ok(abspath)
}
pub fn prepare_file(
abspath: PathBuf,
mode: u32,
) -> Result<PathBuf, Report> {
if let Some(parent) = abspath.parent() {
std::fs::create_dir_all(parent)?;
}
std::fs::write(
&abspath,
"Created by: `dt_core::syncing::tests::prepare_file`\n",
)?;
std::fs::set_permissions(&abspath, Permissions::from_mode(mode))?;
Ok(abspath)
}
}
// Author: Blurgy <gy@blurgy.xyz>
// Date: Oct 03 2021, 02:54 [CST]