mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 12:53:13 +00:00
Simplify reporting of invalid config paths
Do this at a well defined point, instead of randomly the first time they're queried.
This commit is contained in:
parent
72e43a514b
commit
649d3ac101
3 changed files with 61 additions and 51 deletions
|
@ -730,6 +730,9 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
|
||||||
|
|
||||||
init_input();
|
init_input();
|
||||||
|
|
||||||
|
// Complain about invalid config paths.
|
||||||
|
path_emit_config_directory_errors(vars);
|
||||||
|
|
||||||
// Set up universal variables. The empty string means to use the default path.
|
// Set up universal variables. The empty string means to use the default path.
|
||||||
assert(s_universal_variables == NULL);
|
assert(s_universal_variables == NULL);
|
||||||
s_universal_variables = new env_universal_t(L"");
|
s_universal_variables = new env_universal_t(L"");
|
||||||
|
|
100
src/path.cpp
100
src/path.cpp
|
@ -255,8 +255,7 @@ wcstring path_apply_working_directory(const wcstring &path, const wcstring &work
|
||||||
/// a function) we don't want that subshell to issue the same warnings.
|
/// a function) we don't want that subshell to issue the same warnings.
|
||||||
static void maybe_issue_path_warning(const wcstring &which_dir, const wcstring &custom_error_msg,
|
static void maybe_issue_path_warning(const wcstring &which_dir, const wcstring &custom_error_msg,
|
||||||
bool using_xdg, const wcstring &xdg_var, const wcstring &path,
|
bool using_xdg, const wcstring &xdg_var, const wcstring &path,
|
||||||
int saved_errno) {
|
int saved_errno, env_stack_t &vars) {
|
||||||
auto &vars = env_stack_t::globals();
|
|
||||||
wcstring warning_var_name = L"_FISH_WARNED_" + which_dir;
|
wcstring warning_var_name = L"_FISH_WARNED_" + which_dir;
|
||||||
if (vars.get(warning_var_name, ENV_GLOBAL | ENV_EXPORT)) {
|
if (vars.get(warning_var_name, ENV_GLOBAL | ENV_EXPORT)) {
|
||||||
return;
|
return;
|
||||||
|
@ -278,74 +277,77 @@ static void maybe_issue_path_warning(const wcstring &which_dir, const wcstring &
|
||||||
ignore_result(write(STDERR_FILENO, "\n", 1));
|
ignore_result(write(STDERR_FILENO, "\n", 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void path_create(wcstring &path, const wcstring &xdg_var, const wcstring &which_dir,
|
/// The following type wraps up a user's "base" directories, corresponding (conceptually if not
|
||||||
const wcstring &custom_error_msg) {
|
/// actually) to XDG spec.
|
||||||
bool path_done = false;
|
struct base_directory_t {
|
||||||
bool using_xdg = false;
|
wcstring path{}; /// the path where we attempted to create the directory.
|
||||||
int saved_errno = 0;
|
bool success{false}; /// whether creating the directory succeeded.
|
||||||
|
int err{0}; /// the error code if creating the directory failed.
|
||||||
|
bool used_xdg{false}; /// whether an XDG variable was used in resolving the direcotry.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Attempt to get a base directory, creating it if necessary. If a variable named \p xdg_var is
|
||||||
|
/// set, use that directory; otherwise use the path \p non_xdg_homepath rooted in $HOME. \return the
|
||||||
|
/// result; see the base_directory_t fields.
|
||||||
|
static base_directory_t make_base_directory(const wcstring &xdg_var,
|
||||||
|
const wchar_t *non_xdg_homepath) {
|
||||||
// The vars we fetch must be exported. Allowing them to be universal doesn't make sense and
|
// The vars we fetch must be exported. Allowing them to be universal doesn't make sense and
|
||||||
// allowing that creates a lock inversion that deadlocks the shell since we're called before
|
// allowing that creates a lock inversion that deadlocks the shell since we're called before
|
||||||
// uvars are available.
|
// uvars are available.
|
||||||
const auto &vars = env_stack_t::globals();
|
const auto &vars = env_stack_t::globals();
|
||||||
|
base_directory_t result{};
|
||||||
const auto xdg_dir = vars.get(xdg_var, ENV_GLOBAL | ENV_EXPORT);
|
const auto xdg_dir = vars.get(xdg_var, ENV_GLOBAL | ENV_EXPORT);
|
||||||
if (!xdg_dir.missing_or_empty()) {
|
if (!xdg_dir.missing_or_empty()) {
|
||||||
using_xdg = true;
|
result.path = xdg_dir->as_string() + L"/fish";
|
||||||
path = xdg_dir->as_string() + L"/fish";
|
result.used_xdg = true;
|
||||||
if (create_directory(path) != -1) {
|
|
||||||
path_done = true;
|
|
||||||
} else {
|
|
||||||
saved_errno = errno;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const auto home = vars.get(L"HOME", ENV_GLOBAL | ENV_EXPORT);
|
const auto home = vars.get(L"HOME", ENV_GLOBAL | ENV_EXPORT);
|
||||||
if (!home.missing_or_empty()) {
|
if (!home.missing_or_empty()) {
|
||||||
path = home->as_string() +
|
result.path = home->as_string() + non_xdg_homepath;
|
||||||
(which_dir == L"config" ? L"/.config/fish" : L"/.local/share/fish");
|
|
||||||
if (create_directory(path) != -1) {
|
|
||||||
path_done = true;
|
|
||||||
} else {
|
|
||||||
saved_errno = errno;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!path_done) {
|
errno = 0;
|
||||||
maybe_issue_path_warning(which_dir, custom_error_msg, using_xdg, xdg_var, path,
|
result.success = !result.path.empty() && create_directory(result.path) != -1;
|
||||||
saved_errno);
|
result.err = errno;
|
||||||
path.clear();
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
static const base_directory_t &get_data_directory() {
|
||||||
|
static base_directory_t s_dir = make_base_directory(L"XDG_DATA_HOME", L"/.local/share/fish");
|
||||||
|
return s_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const base_directory_t &get_config_directory() {
|
||||||
|
static base_directory_t s_dir = make_base_directory(L"XDG_CONFIG_HOME", L"/.config/fish");
|
||||||
|
return s_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
void path_emit_config_directory_errors(env_stack_t &vars) {
|
||||||
|
const auto &data = get_data_directory();
|
||||||
|
if (!data.success) {
|
||||||
|
maybe_issue_path_warning(L"data", _(L"Your history will not be saved."), data.used_xdg,
|
||||||
|
L"XDG_DATA_HOME", data.path, data.err, vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &config = get_config_directory();
|
||||||
|
if (!config.success) {
|
||||||
|
maybe_issue_path_warning(L"config", _(L"Your personal settings will not be saved."),
|
||||||
|
config.used_xdg, L"XDG_CONFIG_HOME", config.path, config.err,
|
||||||
|
vars);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cache the config path.
|
|
||||||
bool path_get_config(wcstring &path) {
|
bool path_get_config(wcstring &path) {
|
||||||
static bool config_path_done = false;
|
const auto &dir = get_config_directory();
|
||||||
static wcstring config_path(L"");
|
path = dir.success ? dir.path : L"";
|
||||||
|
return dir.success;
|
||||||
if (!config_path_done) {
|
|
||||||
path_create(config_path, L"XDG_CONFIG_HOME", L"config",
|
|
||||||
_(L"Your personal settings will not be saved."));
|
|
||||||
config_path_done = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
path = config_path;
|
|
||||||
return !config_path.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cache the data path.
|
|
||||||
bool path_get_data(wcstring &path) {
|
bool path_get_data(wcstring &path) {
|
||||||
static bool data_path_done = false;
|
const auto &dir = get_data_directory();
|
||||||
static wcstring data_path(L"");
|
path = dir.success ? dir.path : L"";
|
||||||
|
return dir.success;
|
||||||
if (!data_path_done) {
|
|
||||||
data_path_done = true;
|
|
||||||
path_create(data_path, L"XDG_DATA_HOME", L"data", _(L"Your history will not be saved."));
|
|
||||||
}
|
|
||||||
|
|
||||||
path = data_path;
|
|
||||||
return !data_path.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void path_make_canonical(wcstring &path) {
|
void path_make_canonical(wcstring &path) {
|
||||||
|
|
|
@ -29,6 +29,11 @@ bool path_get_config(wcstring &path);
|
||||||
/// \return whether the directory was returned successfully
|
/// \return whether the directory was returned successfully
|
||||||
bool path_get_data(wcstring &path);
|
bool path_get_data(wcstring &path);
|
||||||
|
|
||||||
|
/// Emit any errors if config directories are missing.
|
||||||
|
/// Use the given environment stack to ensure this only occurs once.
|
||||||
|
class env_stack_t;
|
||||||
|
void path_emit_config_directory_errors(env_stack_t &vars);
|
||||||
|
|
||||||
/// Finds the full path of an executable.
|
/// Finds the full path of an executable.
|
||||||
///
|
///
|
||||||
/// Args:
|
/// Args:
|
||||||
|
|
Loading…
Reference in a new issue