mirror of
https://github.com/fish-shell/fish-shell
synced 2024-11-14 00:47:30 +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();
|
||||
|
||||
// Complain about invalid config paths.
|
||||
path_emit_config_directory_errors(vars);
|
||||
|
||||
// Set up universal variables. The empty string means to use the default path.
|
||||
assert(s_universal_variables == NULL);
|
||||
s_universal_variables = new env_universal_t(L"");
|
||||
|
|
104
src/path.cpp
104
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.
|
||||
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,
|
||||
int saved_errno) {
|
||||
auto &vars = env_stack_t::globals();
|
||||
int saved_errno, env_stack_t &vars) {
|
||||
wcstring warning_var_name = L"_FISH_WARNED_" + which_dir;
|
||||
if (vars.get(warning_var_name, ENV_GLOBAL | ENV_EXPORT)) {
|
||||
return;
|
||||
|
@ -278,74 +277,77 @@ static void maybe_issue_path_warning(const wcstring &which_dir, const wcstring &
|
|||
ignore_result(write(STDERR_FILENO, "\n", 1));
|
||||
}
|
||||
|
||||
static void path_create(wcstring &path, const wcstring &xdg_var, const wcstring &which_dir,
|
||||
const wcstring &custom_error_msg) {
|
||||
bool path_done = false;
|
||||
bool using_xdg = false;
|
||||
int saved_errno = 0;
|
||||
/// The following type wraps up a user's "base" directories, corresponding (conceptually if not
|
||||
/// actually) to XDG spec.
|
||||
struct base_directory_t {
|
||||
wcstring path{}; /// the path where we attempted to create the directory.
|
||||
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
|
||||
// allowing that creates a lock inversion that deadlocks the shell since we're called before
|
||||
// uvars are available.
|
||||
const auto &vars = env_stack_t::globals();
|
||||
base_directory_t result{};
|
||||
const auto xdg_dir = vars.get(xdg_var, ENV_GLOBAL | ENV_EXPORT);
|
||||
if (!xdg_dir.missing_or_empty()) {
|
||||
using_xdg = true;
|
||||
path = xdg_dir->as_string() + L"/fish";
|
||||
if (create_directory(path) != -1) {
|
||||
path_done = true;
|
||||
} else {
|
||||
saved_errno = errno;
|
||||
}
|
||||
result.path = xdg_dir->as_string() + L"/fish";
|
||||
result.used_xdg = true;
|
||||
} else {
|
||||
const auto home = vars.get(L"HOME", ENV_GLOBAL | ENV_EXPORT);
|
||||
if (!home.missing_or_empty()) {
|
||||
path = home->as_string() +
|
||||
(which_dir == L"config" ? L"/.config/fish" : L"/.local/share/fish");
|
||||
if (create_directory(path) != -1) {
|
||||
path_done = true;
|
||||
} else {
|
||||
saved_errno = errno;
|
||||
}
|
||||
result.path = home->as_string() + non_xdg_homepath;
|
||||
}
|
||||
}
|
||||
|
||||
if (!path_done) {
|
||||
maybe_issue_path_warning(which_dir, custom_error_msg, using_xdg, xdg_var, path,
|
||||
saved_errno);
|
||||
path.clear();
|
||||
}
|
||||
|
||||
return;
|
||||
errno = 0;
|
||||
result.success = !result.path.empty() && create_directory(result.path) != -1;
|
||||
result.err = errno;
|
||||
return result;
|
||||
}
|
||||
|
||||
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) {
|
||||
static bool config_path_done = false;
|
||||
static wcstring config_path(L"");
|
||||
|
||||
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();
|
||||
const auto &dir = get_config_directory();
|
||||
path = dir.success ? dir.path : L"";
|
||||
return dir.success;
|
||||
}
|
||||
|
||||
/// Cache the data path.
|
||||
bool path_get_data(wcstring &path) {
|
||||
static bool data_path_done = false;
|
||||
static wcstring data_path(L"");
|
||||
|
||||
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();
|
||||
const auto &dir = get_data_directory();
|
||||
path = dir.success ? dir.path : L"";
|
||||
return dir.success;
|
||||
}
|
||||
|
||||
void path_make_canonical(wcstring &path) {
|
||||
|
|
|
@ -29,6 +29,11 @@ bool path_get_config(wcstring &path);
|
|||
/// \return whether the directory was returned successfully
|
||||
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.
|
||||
///
|
||||
/// Args:
|
||||
|
|
Loading…
Reference in a new issue