Convert a remote error to a CLI error. Maps the various remote error types to appropriate CLI error types with user-friendly messages and suggestions. # Arguments `err` - The remote error to convert `url` - The remote URL (for context in error messages) # Returns A `CliError` that can be displayed to the user.
(err: RemoteError, url: &str)
| 396 | /// |
| 397 | /// A `CliError` that can be displayed to the user. |
| 398 | pub fn convert_remote_error(err: RemoteError, url: &str) -> CliError { |
| 399 | match err { |
| 400 | RemoteError::ConnectionFailed { .. } => CliError::RemoteError { |
| 401 | message: format!("Failed to connect: {}", err), |
| 402 | url: Some(url.to_string()), |
| 403 | }, |
| 404 | RemoteError::AuthenticationFailed { .. } => CliError::AuthenticationFailed { |
| 405 | remote: url.to_string(), |
| 406 | }, |
| 407 | // A 404 on a push is ambiguous. Private projects are deliberately |
| 408 | // masked: the server returns "not found" to anyone who isn't |
| 409 | // authenticated/authorized, so a missing project and a private one we |
| 410 | // can't see are indistinguishable on the wire. A push is a *write* that |
| 411 | // always requires auth, so the most likely cause is missing/expired |
| 412 | // credentials — not a genuinely-absent project/view. Say so, and point |
| 413 | // at the remedy, instead of the misleading "view not found". |
| 414 | RemoteError::RepositoryNotFound { .. } => CliError::RemoteError { |
| 415 | message: not_found_push_message("the project"), |
| 416 | url: Some(url.to_string()), |
| 417 | }, |
| 418 | RemoteError::ViewNotFound { view } => CliError::RemoteError { |
| 419 | message: not_found_push_message(&format!("project/view '{}'", view)), |
| 420 | url: Some(url.to_string()), |
| 421 | }, |
| 422 | RemoteError::ChangeNotFound { hash } => CliError::ChangeNotFound { hash }, |
| 423 | RemoteError::MissingDependencies { |
| 424 | count, |
| 425 | missing_hashes, |
| 426 | } => CliError::MissingDependency { |
| 427 | change: "uploaded change".to_string(), |
| 428 | dependency: if missing_hashes.is_empty() { |
| 429 | format!("{} dependencies", count) |
| 430 | } else { |
| 431 | missing_hashes.join(", ") |
| 432 | }, |
| 433 | }, |
| 434 | RemoteError::StateMismatch { |
| 435 | remote_state, |
| 436 | requested_state, |
| 437 | } => CliError::Conflict { |
| 438 | description: format!( |
| 439 | "State mismatch: remote is at {}, requested {}", |
| 440 | remote_state, requested_state |
| 441 | ), |
| 442 | }, |
| 443 | RemoteError::Timeout { seconds } => CliError::RemoteError { |
| 444 | message: format!("Request timed out after {} seconds", seconds), |
| 445 | url: Some(url.to_string()), |
| 446 | }, |
| 447 | RemoteError::HttpError { status: 413, .. } => CliError::RemoteError { |
| 448 | message: "Change too large for server (413 Payload Too Large). \ |
| 449 | The server's body size limit is too small. \ |
| 450 | Ask the server admin to increase MAX_BODY_SIZE_MB." |
| 451 | .to_string(), |
| 452 | url: Some(url.to_string()), |
| 453 | }, |
| 454 | _ => CliError::RemoteError { |
| 455 | message: err.to_string(), |