Use anyhow more idiomatically (#31052)

https://github.com/zed-industries/zed/issues/30972 brought up another
case where our context is not enough to track the actual source of the
issue: we get a general top-level error without inner error.

The reason for this was `.ok_or_else(|| anyhow!("failed to read HEAD
SHA"))?; ` on the top level.

The PR finally reworks the way we use anyhow to reduce such issues (or
at least make it simpler to bubble them up later in a fix).
On top of that, uses a few more anyhow methods for better readability.

* `.ok_or_else(|| anyhow!("..."))`, `map_err` and other similar error
conversion/option reporting cases are replaced with `context` and
`with_context` calls
* in addition to that, various `anyhow!("failed to do ...")` are
stripped with `.context("Doing ...")` messages instead to remove the
parasitic `failed to` text
* `anyhow::ensure!` is used instead of `if ... { return Err(...); }`
calls
* `anyhow::bail!` is used instead of `return Err(anyhow!(...));`

Release Notes:

- N/A
This commit is contained in:
Kirill Bulatov 2025-05-21 02:06:07 +03:00 committed by GitHub
parent 1e51a7ac44
commit 16366cf9f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
294 changed files with 2037 additions and 2610 deletions

View file

@ -711,9 +711,10 @@ impl Client {
let id = (TypeId::of::<T>(), remote_id);
let mut state = self.handler_set.lock();
if state.entities_by_type_and_remote_id.contains_key(&id) {
return Err(anyhow!("already subscribed to entity"));
}
anyhow::ensure!(
!state.entities_by_type_and_remote_id.contains_key(&id),
"already subscribed to entity"
);
state
.entities_by_type_and_remote_id
@ -962,10 +963,7 @@ impl Client {
hello_message_type_name
)
})?;
let peer_id = hello
.payload
.peer_id
.ok_or_else(|| anyhow!("invalid peer id"))?;
let peer_id = hello.payload.peer_id.context("invalid peer id")?;
Ok(peer_id)
};
@ -1075,22 +1073,19 @@ impl Client {
}
let response = http.get(&url, Default::default(), false).await?;
let collab_url = if response.status().is_redirection() {
response
.headers()
.get("Location")
.ok_or_else(|| anyhow!("missing location header in /rpc response"))?
.to_str()
.map_err(EstablishConnectionError::other)?
.to_string()
} else {
Err(anyhow!(
"unexpected /rpc response status {}",
response.status()
))?
};
Url::parse(&collab_url).context("invalid rpc url")
anyhow::ensure!(
response.status().is_redirection(),
"unexpected /rpc response status {}",
response.status()
);
let collab_url = response
.headers()
.get("Location")
.context("missing location header in /rpc response")?
.to_str()
.map_err(EstablishConnectionError::other)?
.to_string();
Url::parse(&collab_url).with_context(|| format!("parsing colab rpc url {collab_url}"))
}
}
@ -1132,7 +1127,7 @@ impl Client {
let rpc_host = rpc_url
.host_str()
.zip(rpc_url.port_or_known_default())
.ok_or_else(|| anyhow!("missing host in rpc url"))?;
.context("missing host in rpc url")?;
let stream = {
let handle = cx.update(|cx| gpui_tokio::Tokio::handle(cx)).ok().unwrap();
@ -1287,16 +1282,13 @@ impl Client {
)
.context("failed to respond to login http request")?;
return Ok((
user_id
.ok_or_else(|| anyhow!("missing user_id parameter"))?,
access_token.ok_or_else(|| {
anyhow!("missing access_token parameter")
})?,
user_id.context("missing user_id parameter")?,
access_token.context("missing access_token parameter")?,
));
}
}
Err(anyhow!("didn't receive login redirect"))
anyhow::bail!("didn't receive login redirect");
})
.await?;
@ -1414,13 +1406,12 @@ impl Client {
let mut response = http.send(request).await?;
let mut body = String::new();
response.body_mut().read_to_string(&mut body).await?;
if !response.status().is_success() {
Err(anyhow!(
"admin user request failed {} - {}",
response.status().as_u16(),
body,
))?;
}
anyhow::ensure!(
response.status().is_success(),
"admin user request failed {} - {}",
response.status().as_u16(),
body,
);
let response: AuthenticatedUserResponse = serde_json::from_str(&body)?;
// Use the admin API token to authenticate as the impersonated user.
@ -1457,7 +1448,7 @@ impl Client {
if let Status::Connected { connection_id, .. } = *self.status().borrow() {
Ok(connection_id)
} else {
Err(anyhow!("not connected"))
anyhow::bail!("not connected");
}
}

View file

@ -1,5 +1,5 @@
//! socks proxy
use anyhow::{Context, Result, anyhow};
use anyhow::{Context as _, Result};
use http_client::Url;
use tokio_socks::tcp::{Socks4Stream, Socks5Stream};
@ -31,7 +31,7 @@ pub(crate) async fn connect_socks_proxy_stream(
// If parsing the proxy URL fails, we must avoid falling back to an insecure connection.
// SOCKS proxies are often used in contexts where security and privacy are critical,
// so any fallback could expose users to significant risks.
return Err(anyhow!("Parsing proxy url failed"));
anyhow::bail!("Parsing proxy url failed");
};
// Connect to proxy and wrap protocol later

View file

@ -1,5 +1,5 @@
use crate::{Client, Connection, Credentials, EstablishConnectionError, UserStore};
use anyhow::{Result, anyhow};
use anyhow::{Context as _, Result, anyhow};
use chrono::Duration;
use futures::{StreamExt, stream::BoxStream};
use gpui::{AppContext as _, BackgroundExecutor, Entity, TestAppContext};
@ -45,7 +45,7 @@ impl FakeServer {
move |cx| {
let state = state.clone();
cx.spawn(async move |_| {
let state = state.upgrade().ok_or_else(|| anyhow!("server dropped"))?;
let state = state.upgrade().context("server dropped")?;
let mut state = state.lock();
state.auth_count += 1;
let access_token = state.access_token.to_string();
@ -64,8 +64,8 @@ impl FakeServer {
let state = state.clone();
let credentials = credentials.clone();
cx.spawn(async move |cx| {
let state = state.upgrade().ok_or_else(|| anyhow!("server dropped"))?;
let peer = peer.upgrade().ok_or_else(|| anyhow!("server dropped"))?;
let state = state.upgrade().context("server dropped")?;
let peer = peer.upgrade().context("server dropped")?;
if state.lock().forbid_connections {
Err(EstablishConnectionError::Other(anyhow!(
"server is forbidding connections"
@ -155,7 +155,7 @@ impl FakeServer {
.expect("not connected")
.next()
.await
.ok_or_else(|| anyhow!("other half hung up"))?;
.context("other half hung up")?;
self.executor.finish_waiting();
let type_name = message.payload_type_name();
let message = message.into_any();

View file

@ -388,9 +388,7 @@ impl UserStore {
// Users are fetched in parallel above and cached in call to get_users
// No need to parallelize here
let mut updated_contacts = Vec::new();
let this = this
.upgrade()
.ok_or_else(|| anyhow!("can't upgrade user store handle"))?;
let this = this.upgrade().context("can't upgrade user store handle")?;
for contact in message.contacts {
updated_contacts
.push(Arc::new(Contact::from_proto(contact, &this, cx).await?));
@ -574,7 +572,7 @@ impl UserStore {
let client = self.client.upgrade();
cx.spawn(async move |_, _| {
client
.ok_or_else(|| anyhow!("can't upgrade client reference"))?
.context("can't upgrade client reference")?
.request(proto::RespondToContactRequest {
requester_id,
response: proto::ContactRequestResponse::Dismiss as i32,
@ -596,7 +594,7 @@ impl UserStore {
cx.spawn(async move |this, cx| {
let response = client
.ok_or_else(|| anyhow!("can't upgrade client reference"))?
.context("can't upgrade client reference")?
.request(request)
.await;
this.update(cx, |this, cx| {
@ -663,7 +661,7 @@ impl UserStore {
this.users
.get(user_id)
.cloned()
.ok_or_else(|| anyhow!("user {} not found", user_id))
.with_context(|| format!("user {user_id} not found"))
})
.collect()
})?
@ -703,7 +701,7 @@ impl UserStore {
this.users
.get(&user_id)
.cloned()
.ok_or_else(|| anyhow!("server responded with no users"))
.context("server responded with no users")
})?
})
}
@ -765,20 +763,17 @@ impl UserStore {
};
let client = self.client.clone();
cx.spawn(async move |this, cx| {
if let Some(client) = client.upgrade() {
let response = client
.request(proto::AcceptTermsOfService {})
.await
.context("error accepting tos")?;
this.update(cx, |this, cx| {
this.set_current_user_accepted_tos_at(Some(response.accepted_tos_at));
cx.emit(Event::PrivateUserInfoUpdated);
})
} else {
Err(anyhow!("client not found"))
}
cx.spawn(async move |this, cx| -> anyhow::Result<()> {
let client = client.upgrade().context("client not found")?;
let response = client
.request(proto::AcceptTermsOfService {})
.await
.context("error accepting tos")?;
this.update(cx, |this, cx| {
this.set_current_user_accepted_tos_at(Some(response.accepted_tos_at));
cx.emit(Event::PrivateUserInfoUpdated);
})?;
Ok(())
})
}
@ -897,7 +892,7 @@ impl Contact {
impl Collaborator {
pub fn from_proto(message: proto::Collaborator) -> Result<Self> {
Ok(Self {
peer_id: message.peer_id.ok_or_else(|| anyhow!("invalid peer id"))?,
peer_id: message.peer_id.context("invalid peer id")?,
replica_id: message.replica_id as ReplicaId,
user_id: message.user_id as UserId,
is_host: message.is_host,