mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-25 01:34:02 +00:00
Use more elaborate messages for permission denied errors on startup (#22368)
Also show all paths with issues, grouping them by the issue kind. Inspired by https://github.com/zed-industries/zed/issues/22365 , https://github.com/zed-industries/zed/issues/20162, https://github.com/zed-industries/zed/issues/13426, ... Attempts to provide example `chown` and `chmod` commands on this error, instead of encouraging to submit another issue. For now, uses a hardcoded command examples, but we might provide a better workflow later, e.g. try to automatically run those commands. I seem to be unable to select the size of the modal, but for something that's supposed to appear only once, it seems to be ok. ![regular](https://github.com/user-attachments/assets/484feb95-b9c5-445c-87f8-cd1db9337529) ![also_regular](https://github.com/user-attachments/assets/680ea95d-91fe-4b16-b3bc-e241ecd841d4) ![many_kinds](https://github.com/user-attachments/assets/7103161f-754d-413a-94df-62a44e353674) ![exaggerated](https://github.com/user-attachments/assets/b6e70be7-9ab4-4861-afae-5285a554fdba) Release Notes: - N/A
This commit is contained in:
parent
8ccc7b81c8
commit
5df409971c
1 changed files with 65 additions and 25 deletions
|
@ -10,6 +10,7 @@ use clap::{command, Parser};
|
|||
use cli::FORCE_CLI_MODE_ENV_VAR_NAME;
|
||||
use client::{parse_zed_link, Client, ProxySettings, UserStore};
|
||||
use collab_ui::channel_view::ChannelView;
|
||||
use collections::HashMap;
|
||||
use db::kvp::{GLOBAL_KEY_VALUE_STORE, KEY_VALUE_STORE};
|
||||
use editor::Editor;
|
||||
use env_logger::Builder;
|
||||
|
@ -40,7 +41,7 @@ use simplelog::ConfigBuilder;
|
|||
use std::{
|
||||
env,
|
||||
fs::OpenOptions,
|
||||
io::{IsTerminal, Write},
|
||||
io::{self, IsTerminal, Write},
|
||||
path::{Path, PathBuf},
|
||||
process,
|
||||
sync::Arc,
|
||||
|
@ -69,22 +70,59 @@ use util::load_shell_from_passwd;
|
|||
#[global_allocator]
|
||||
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
||||
|
||||
fn fail_to_launch(e: anyhow::Error) {
|
||||
eprintln!("Zed failed to launch: {e:?}");
|
||||
App::new().run(move |cx| {
|
||||
if let Ok(window) = cx.open_window(gpui::WindowOptions::default(), |cx| cx.new_view(|_| gpui::Empty)) {
|
||||
window.update(cx, |_, cx| {
|
||||
let response = cx.prompt(gpui::PromptLevel::Critical, "Zed failed to launch", Some(&format!("{e}\n\nFor help resolving this, please open an issue on https://github.com/zed-industries/zed")), &["Exit"]);
|
||||
fn files_not_createad_on_launch(errors: HashMap<io::ErrorKind, Vec<&Path>>) {
|
||||
let message = "Zed failed to launch";
|
||||
let error_details = errors
|
||||
.into_iter()
|
||||
.flat_map(|(kind, paths)| {
|
||||
#[allow(unused_mut)] // for non-unix platforms
|
||||
let mut error_kind_details = match paths.len() {
|
||||
0 => return None,
|
||||
1 => format!(
|
||||
"{kind} when creating directory {:?}",
|
||||
paths.first().expect("match arm checks for a single entry")
|
||||
),
|
||||
_many => format!("{kind} when creating directories {paths:?}"),
|
||||
};
|
||||
|
||||
cx.spawn(|_, mut cx| async move {
|
||||
response.await?;
|
||||
cx.update(|cx| {
|
||||
cx.quit()
|
||||
#[cfg(unix)]
|
||||
{
|
||||
match kind {
|
||||
io::ErrorKind::PermissionDenied => {
|
||||
error_kind_details.push_str("\n\nConsider using chown and chmod tools for altering the directories permissions if your user has corresponding rights.\
|
||||
\nFor example, `sudo chown $(whoami):staff ~/.config` and `chmod +uwrx ~/.config`");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Some(error_kind_details)
|
||||
})
|
||||
.collect::<Vec<_>>().join("\n\n");
|
||||
|
||||
eprintln!("{message}: {error_details}");
|
||||
App::new().run(move |cx| {
|
||||
if let Ok(window) = cx.open_window(gpui::WindowOptions::default(), |cx| {
|
||||
cx.new_view(|_| gpui::Empty)
|
||||
}) {
|
||||
window
|
||||
.update(cx, |_, cx| {
|
||||
let response = cx.prompt(
|
||||
gpui::PromptLevel::Critical,
|
||||
message,
|
||||
Some(&error_details),
|
||||
&["Exit"],
|
||||
);
|
||||
|
||||
cx.spawn(|_, mut cx| async move {
|
||||
response.await?;
|
||||
cx.update(|cx| cx.quit())
|
||||
})
|
||||
}).detach_and_log_err(cx);
|
||||
}).log_err();
|
||||
.detach_and_log_err(cx);
|
||||
})
|
||||
.log_err();
|
||||
} else {
|
||||
fail_to_open_window(e, cx)
|
||||
fail_to_open_window(anyhow::anyhow!("{message}: {error_details}"), cx)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -139,8 +177,9 @@ fn main() {
|
|||
menu::init();
|
||||
zed_actions::init();
|
||||
|
||||
if let Err(e) = init_paths() {
|
||||
fail_to_launch(e);
|
||||
let file_errors = init_paths();
|
||||
if !file_errors.is_empty() {
|
||||
files_not_createad_on_launch(file_errors);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -907,8 +946,8 @@ pub(crate) async fn restorable_workspace_locations(
|
|||
}
|
||||
}
|
||||
|
||||
fn init_paths() -> anyhow::Result<()> {
|
||||
for path in [
|
||||
fn init_paths() -> HashMap<io::ErrorKind, Vec<&'static Path>> {
|
||||
[
|
||||
paths::config_dir(),
|
||||
paths::extensions_dir(),
|
||||
paths::languages_dir(),
|
||||
|
@ -916,12 +955,13 @@ fn init_paths() -> anyhow::Result<()> {
|
|||
paths::logs_dir(),
|
||||
paths::temp_dir(),
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
std::fs::create_dir_all(path)
|
||||
.map_err(|e| anyhow!("Could not create directory {:?}: {}", path, e))?;
|
||||
}
|
||||
Ok(())
|
||||
.into_iter()
|
||||
.fold(HashMap::default(), |mut errors, path| {
|
||||
if let Err(e) = std::fs::create_dir_all(path) {
|
||||
errors.entry(e.kind()).or_insert_with(Vec::new).push(path);
|
||||
}
|
||||
errors
|
||||
})
|
||||
}
|
||||
|
||||
fn init_logger() {
|
||||
|
@ -1001,7 +1041,7 @@ fn init_stdout_logger() {
|
|||
}
|
||||
|
||||
fn stdout_is_a_pty() -> bool {
|
||||
std::env::var(FORCE_CLI_MODE_ENV_VAR_NAME).ok().is_none() && std::io::stdout().is_terminal()
|
||||
std::env::var(FORCE_CLI_MODE_ENV_VAR_NAME).ok().is_none() && io::stdout().is_terminal()
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
|
|
Loading…
Reference in a new issue