|
1 | 1 | #![allow(clippy::large_enum_variant)]
|
2 | 2 | #![allow(deprecated)] // because of `Error::description` deprecation in `error_chain`
|
3 | 3 |
|
4 |
| -use crate::dist::dist::Profile; |
5 |
| -use crate::dist::manifest::{Component, Manifest}; |
6 |
| -use crate::dist::temp; |
7 |
| -use crate::{component_for_bin, Toolchain}; |
8 |
| -use error_chain::error_chain; |
9 | 4 | use std::ffi::OsString;
|
| 5 | +use std::fmt::{self, Debug, Display}; |
10 | 6 | use std::io::{self, Write};
|
11 | 7 | use std::path::PathBuf;
|
| 8 | +use std::sync::{Arc, Mutex, MutexGuard, Weak}; |
| 9 | + |
| 10 | +use error_chain::error_chain; |
12 | 11 | use url::Url;
|
13 | 12 |
|
| 13 | +use crate::dist::dist::Profile; |
| 14 | +use crate::dist::manifest::{Component, Manifest}; |
| 15 | +use crate::dist::temp; |
| 16 | +use crate::{component_for_bin, Toolchain}; |
| 17 | + |
14 | 18 | pub const TOOLSTATE_MSG: &str =
|
15 | 19 | "If you require these components, please install and use the latest successful build version,\n\
|
16 | 20 | which you can find at <https://rust-lang.github.io/rustup-components-history>.\n\nAfter determining \
|
@@ -415,6 +419,137 @@ error_chain! {
|
415 | 419 | }
|
416 | 420 | }
|
417 | 421 |
|
| 422 | +/// Inspired by failure::SyncFailure, but not identical. |
| 423 | +/// |
| 424 | +/// SyncError does not grant full safety: it will panic when errors are used |
| 425 | +/// across threads (e.g. by threaded error logging libraries). This could be |
| 426 | +/// fixed, but as we don't do that within rustup, it is not needed. If using |
| 427 | +/// this code elsewhere, just hunt down and remove the unchecked unwraps. |
| 428 | +pub struct SyncError<T: 'static> { |
| 429 | + inner: Arc<Mutex<T>>, |
| 430 | + proxy: Option<CauseProxy<T>>, |
| 431 | +} |
| 432 | + |
| 433 | +impl<T: std::error::Error + 'static> SyncError<T> { |
| 434 | + pub fn new(err: T) -> Self { |
| 435 | + let arc = Arc::new(Mutex::new(err)); |
| 436 | + let proxy = match arc.lock().unwrap().source() { |
| 437 | + None => None, |
| 438 | + Some(source) => Some(CauseProxy::new(source, Arc::downgrade(&arc), 0)), |
| 439 | + }; |
| 440 | + |
| 441 | + SyncError { inner: arc, proxy } |
| 442 | + } |
| 443 | + |
| 444 | + pub fn maybe<R>(r: std::result::Result<R, T>) -> std::result::Result<R, Self> { |
| 445 | + match r { |
| 446 | + Ok(v) => Ok(v), |
| 447 | + Err(e) => Err(SyncError::new(e)), |
| 448 | + } |
| 449 | + } |
| 450 | + |
| 451 | + pub fn unwrap(self) -> T { |
| 452 | + Arc::try_unwrap(self.inner).unwrap().into_inner().unwrap() |
| 453 | + } |
| 454 | + |
| 455 | + pub fn as_ref(&self) -> MutexGuard<'_, T> { |
| 456 | + Arc::as_ref(&self.inner).lock().unwrap() |
| 457 | + } |
| 458 | +} |
| 459 | + |
| 460 | +impl<T: std::error::Error + 'static> std::error::Error for SyncError<T> { |
| 461 | + #[cfg(backtrace)] |
| 462 | + fn backtrace(&self) -> Option<&Backtrace> {} |
| 463 | + |
| 464 | + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { |
| 465 | + self.proxy.as_ref().map(|x| x as _) |
| 466 | + } |
| 467 | +} |
| 468 | + |
| 469 | +impl<T> Display for SyncError<T> |
| 470 | +where |
| 471 | + T: Display, |
| 472 | +{ |
| 473 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 474 | + self.inner.lock().unwrap().fmt(f) |
| 475 | + } |
| 476 | +} |
| 477 | + |
| 478 | +impl<T> Debug for SyncError<T> |
| 479 | +where |
| 480 | + T: Debug, |
| 481 | +{ |
| 482 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 483 | + self.inner.lock().unwrap().fmt(f) |
| 484 | + } |
| 485 | +} |
| 486 | + |
| 487 | +struct CauseProxy<T: 'static> { |
| 488 | + inner: Weak<Mutex<T>>, |
| 489 | + next: Option<Box<CauseProxy<T>>>, |
| 490 | + depth: u32, |
| 491 | +} |
| 492 | + |
| 493 | +impl<T: std::error::Error> CauseProxy<T> { |
| 494 | + fn new(err: &dyn std::error::Error, weak: Weak<Mutex<T>>, depth: u32) -> Self { |
| 495 | + // Can't allocate an object, or mutate the proxy safely during source(), |
| 496 | + // so we just take the hit at construction, recursively. We can't hold |
| 497 | + // references outside the mutex at all, so instead we remember how many |
| 498 | + // steps to get to this proxy. And if some error chain plays tricks, the |
| 499 | + // user gets both pieces. |
| 500 | + CauseProxy { |
| 501 | + inner: weak.clone(), |
| 502 | + depth, |
| 503 | + next: match err.source() { |
| 504 | + None => None, |
| 505 | + Some(source) => Some(Box::new(CauseProxy::new(source, weak, depth + 1))), |
| 506 | + }, |
| 507 | + } |
| 508 | + } |
| 509 | + |
| 510 | + fn with_instance<R, F>(&self, f: F) -> R |
| 511 | + where |
| 512 | + F: FnOnce(&(dyn std::error::Error + 'static)) -> R, |
| 513 | + { |
| 514 | + let arc = self.inner.upgrade().unwrap(); |
| 515 | + { |
| 516 | + let e = arc.lock().unwrap(); |
| 517 | + let mut source = e.source().unwrap(); |
| 518 | + for _ in 0..self.depth { |
| 519 | + source = source.source().unwrap(); |
| 520 | + } |
| 521 | + f(source) |
| 522 | + } |
| 523 | + } |
| 524 | +} |
| 525 | + |
| 526 | +impl<T: std::error::Error + 'static> std::error::Error for CauseProxy<T> { |
| 527 | + #[cfg(backtrace)] |
| 528 | + fn backtrace(&self) -> Option<&Backtrace> {} |
| 529 | + |
| 530 | + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { |
| 531 | + self.next.as_ref().map(|x| x as _) |
| 532 | + } |
| 533 | +} |
| 534 | + |
| 535 | +impl<T> Display for CauseProxy<T> |
| 536 | +where |
| 537 | + T: Display + std::error::Error, |
| 538 | +{ |
| 539 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 540 | + self.with_instance(|i| std::fmt::Display::fmt(&i, f)) |
| 541 | + } |
| 542 | +} |
| 543 | + |
| 544 | +impl<T> Debug for CauseProxy<T> |
| 545 | +where |
| 546 | + T: Debug + std::error::Error, |
| 547 | +{ |
| 548 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 549 | + self.with_instance(|i| std::fmt::Debug::fmt(&i, f)) |
| 550 | + } |
| 551 | +} |
| 552 | + |
418 | 553 | fn valid_profile_names() -> String {
|
419 | 554 | Profile::names()
|
420 | 555 | .iter()
|
|
0 commit comments