-
Notifications
You must be signed in to change notification settings - Fork 928
/
Copy patherrors.rs
222 lines (207 loc) · 8.87 KB
/
errors.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#![allow(clippy::large_enum_variant)]
use std::borrow::Cow;
use std::ffi::OsString;
use std::fmt::Debug;
use std::io::{self, Write};
use std::path::PathBuf;
use thiserror::Error as ThisError;
use url::Url;
use crate::currentprocess::process;
use crate::dist::manifest::{Component, Manifest};
use crate::utils::ownership::OwnershipError;
const TOOLSTATE_MSG: &str =
"If you require these components, please install and use the latest successful build version,\n\
which you can find at <https://rust-lang.github.io/rustup-components-history>.\n\nAfter determining \
the correct date, install it with a command such as:\n\n \
rustup toolchain install nightly-2018-12-27\n\n\
Then you can use the toolchain with commands such as:\n\n \
cargo +nightly-2018-12-27 build";
/// A type erasing thunk for the retry crate to permit use with anyhow. See <https://github.com/dtolnay/anyhow/issues/149>
#[derive(Debug, ThisError)]
#[error(transparent)]
pub struct OperationError(pub anyhow::Error);
#[derive(ThisError, Debug)]
pub enum RustupError {
#[error("partially downloaded file may have been damaged and was removed, please try again")]
BrokenPartialFile,
#[error("component download failed for {0}")]
ComponentDownloadFailed(String),
#[error("failure removing component '{name}', directory does not exist: '{}'", .path.display())]
ComponentMissingDir { name: String, path: PathBuf },
#[error("failure removing component '{name}', directory does not exist: '{}'", .path.display())]
ComponentMissingFile { name: String, path: PathBuf },
#[error("could not create {name} directory: '{}'", .path.display())]
CreatingDirectory { name: &'static str, path: PathBuf },
#[error("unable to read the PGP key '{}'", .path.display())]
InvalidPgpKey {
path: PathBuf,
source: anyhow::Error,
},
#[error("invalid toolchain name: '{0}'")]
InvalidToolchainName(String),
#[error("could not create link from '{}' to '{}'", .src.display(), .dest.display())]
LinkingFile { src: PathBuf, dest: PathBuf },
#[error("Unable to proceed. Could not locate working directory.")]
LocatingWorkingDir,
#[error("failed to set permissions for '{}'", .p.display())]
SettingPermissions { p: PathBuf, source: io::Error },
#[error("checksum failed for '{url}', expected: '{expected}', calculated: '{calculated}'")]
ChecksumFailed {
url: String,
expected: String,
calculated: String,
},
#[error("failed to install component: '{name}', detected conflict: '{}'", .path.display())]
ComponentConflict { name: String, path: PathBuf },
#[error("toolchain '{0}' does not support components")]
ComponentsUnsupported(String),
#[error("component manifest for '{0}' is corrupt")]
CorruptComponent(String),
#[error("could not download file from '{url}' to '{}'", .path.display())]
DownloadingFile { url: Url, path: PathBuf },
#[error("could not download file from '{url}' to '{}'", .path.display())]
DownloadNotExists { url: Url, path: PathBuf },
#[error("Missing manifest in toolchain '{}'", .name)]
MissingManifest { name: String },
#[error("server sent a broken manifest: missing package for component {0}")]
MissingPackageForComponent(String),
#[error("could not read {name} directory: '{}'", .path.display())]
ReadingDirectory { name: &'static str, path: PathBuf },
#[error("could not read {name} file: '{}'", .path.display())]
ReadingFile { name: &'static str, path: PathBuf },
#[error("could not remove '{}' directory: '{}'", .name, .path.display())]
RemovingDirectory { name: &'static str, path: PathBuf },
#[error("could not remove '{name}' file: '{}'", .path.display())]
RemovingFile { name: &'static str, path: PathBuf },
#[error("{}", component_unavailable_msg(.components, .manifest, .toolchain))]
RequestedComponentsUnavailable {
components: Vec<Component>,
manifest: Manifest,
toolchain: String,
},
#[error("command failed: '{}'", PathBuf::from(.name).display())]
RunningCommand { name: OsString },
#[error("toolchain '{0}' is not installable")]
ToolchainNotInstallable(String),
#[error("toolchain '{0}' is not installed")]
ToolchainNotInstalled(String),
#[error(
"rustup could not choose a version of {} to run, because one wasn't specified explicitly, and no default is configured.\n{}",
process().name().unwrap_or_else(|| "Rust".into()),
"help: run 'rustup default stable' to download the latest stable release of Rust and set it as your default toolchain."
)]
ToolchainNotSelected,
#[error("toolchain '{}' does not contain component {}{}{}", .name, .component, if let Some(suggestion) = .suggestion {
format!("; did you mean '{}'?", suggestion)
} else {
"".to_string()
}, if .component.contains("rust-std") {
format!("\nnote: not all platforms have the standard library pre-compiled: https://doc.rust-lang.org/nightly/rustc/platform-support.html{}",
if name.contains("nightly") { "\nhelp: consider using `cargo build -Z build-std` instead" } else { "" }
)
} else { "".to_string() })]
UnknownComponent {
name: String,
component: String,
suggestion: Option<String>,
},
#[error("unknown metadata version: '{0}'")]
UnknownMetadataVersion(String),
#[error("manifest version '{0}' is not supported")]
UnsupportedVersion(String),
#[error("could not write {name} file: '{}'", .path.display())]
WritingFile { name: &'static str, path: PathBuf },
#[error("{}", ownership_error_msg(.0))]
Ownership(OwnershipError),
}
fn remove_component_msg(cs: &Component, manifest: &Manifest, toolchain: &str) -> String {
if cs.short_name_in_manifest() == "rust-std" {
// We special-case rust-std as it's the stdlib so really you want to do
// rustup target remove
format!(
" rustup target remove --toolchain {} {}",
toolchain,
cs.target.as_deref().unwrap_or(toolchain)
)
} else {
format!(
" rustup component remove --toolchain {}{} {}",
toolchain,
if let Some(target) = cs.target.as_ref() {
format!(" --target {}", target)
} else {
String::default()
},
cs.short_name(manifest)
)
}
}
fn component_unavailable_msg(cs: &[Component], manifest: &Manifest, toolchain: &str) -> String {
assert!(!cs.is_empty());
let mut buf = vec![];
if cs.len() == 1 {
let _ = writeln!(
buf,
"component {} is unavailable for download for channel '{}'",
&cs[0].description(manifest),
toolchain,
);
if toolchain.starts_with("nightly") {
let _ = write!(
buf,
"Sometimes not all components are available in any given nightly. "
);
}
let _ = write!(
buf,
"If you don't need the component, you can remove it with:\n\n{}",
remove_component_msg(&cs[0], manifest, toolchain)
);
} else {
// More than one component
let same_target = cs
.iter()
.all(|c| c.target == cs[0].target || c.target.is_none());
let cs_str = if same_target {
cs.iter()
.map(|c| format!("'{}'", c.short_name(manifest)))
.collect::<Vec<_>>()
.join(", ")
} else {
cs.iter()
.map(|c| c.description(manifest))
.collect::<Vec<_>>()
.join(", ")
};
let remove_msg = cs
.iter()
.map(|c| remove_component_msg(c, manifest, toolchain))
.collect::<Vec<_>>()
.join("\n");
let _ = write!(
buf,
"some components unavailable for download for channel '{}': {}\n\
If you don't need the components, you can remove them with:\n\n{}\n\n{}",
toolchain, cs_str, remove_msg, TOOLSTATE_MSG,
);
}
String::from_utf8(buf).unwrap()
}
fn ownership_error_msg(err: &OwnershipError) -> String {
// rust-toolchain or rust-toolchain.toml
let what = err.path.file_name().unwrap().to_string_lossy();
let to_add = err.path.parent().unwrap();
let escaped = shell_escape::escape(Cow::Borrowed(to_add.to_str().expect("utf-8 path")));
format!(
"`{}` is owned by a different user\n \
For safety reasons, Rustup does not allow opening `{what}` files owned by\n \
a different user, unless explicitly approved.\n\
\n \
To approve this directory, run\n\
\n \
rustup set safe-directories add {escaped}\n\
\n \
See https://rust-lang.github.io/rustup/safe-directories.html for more information.",
err.path.display(),
)
}