forked from open-telemetry/weaver
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlib.rs
More file actions
331 lines (293 loc) · 9.23 KB
/
lib.rs
File metadata and controls
331 lines (293 loc) · 9.23 KB
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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
// SPDX-License-Identifier: Apache-2.0
#![doc = include_str!("../README.md")]
pub mod diagnostic;
pub mod error;
pub mod ordered_float;
pub mod result;
#[cfg(test)]
pub mod test;
pub mod vdir;
use crate::diagnostic::{DiagnosticMessage, DiagnosticMessages};
use crate::error::{format_errors, WeaverError};
use crate::Error::CompoundError;
use miette::Diagnostic;
use paris::formatter::colorize_string;
use serde::Serialize;
use std::io::Write;
use std::path::Path;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
/// All the errors emitted by this crate.
#[derive(thiserror::Error, Debug, Clone, PartialEq, Serialize, Diagnostic)]
#[non_exhaustive]
pub enum Error {
/// Home directory not found.
#[error("Home directory not found")]
HomeDirNotFound,
/// Cache directory not created.
#[error("Cache directory not created: {message}")]
CacheDirNotCreated {
/// The error message
message: String,
},
/// Git repo not created.
#[error("Git repo `{repo_url}` not created: {message}")]
GitRepoNotCreated {
/// The git repo URL
repo_url: String,
/// The error message
message: String,
},
/// A git error occurred.
#[error("Git error occurred while cloning `{repo_url}`: {message}")]
GitError {
/// The git repo URL
repo_url: String,
/// The error message
message: String,
},
/// An invalid registry path.
#[error("The registry path `{path}` is invalid: {error}")]
InvalidRegistryPath {
/// The registry path
path: String,
/// The error message
error: String,
},
/// A virtual directory error.
#[error("Virtual directory `{path}` is invalid: {error}")]
InvalidVirtualDirectory {
/// The virtual directory path
path: String,
/// The error message
error: String,
},
/// An invalid registry archive.
#[error("The registry archive `{archive}` is invalid: {error}")]
InvalidRegistryArchive {
/// The registry archive path
archive: String,
/// The error message
error: String,
},
/// An invalid registry archive.
#[error("This archive `{archive}` is not supported. Supported formats are: .tar.gz, .zip")]
UnsupportedRegistryArchive {
/// The registry archive path
archive: String,
},
/// A container for multiple errors.
#[error("{:?}", format_errors(.0))]
CompoundError(#[related] Vec<Error>),
}
impl WeaverError<Error> for Error {
fn compound(errors: Vec<Error>) -> Error {
CompoundError(
errors
.into_iter()
.flat_map(|e| match e {
CompoundError(errors) => errors,
e => vec![e],
})
.collect(),
)
}
}
impl From<Error> for DiagnosticMessages {
fn from(error: Error) -> Self {
DiagnosticMessages::new(match error {
CompoundError(errors) => errors
.into_iter()
.flat_map(|e| {
let diag_msgs: DiagnosticMessages = e.into();
diag_msgs.into_inner()
})
.collect(),
_ => vec![DiagnosticMessage::new(error)],
})
}
}
/// A logger implementation for the standard Rust `log` crate that can be used in tests.
/// This logger tracks warning and error counts and is thread-safe.
#[derive(Default, Clone)]
pub struct TestLog {
warn_count: Arc<AtomicUsize>,
error_count: Arc<AtomicUsize>,
}
impl TestLog {
/// Creates a new test logger.
#[must_use]
pub fn new() -> Self {
let testlog = TestLog {
warn_count: Arc::new(AtomicUsize::new(0)),
error_count: Arc::new(AtomicUsize::new(0)),
};
log::set_max_level(log::LevelFilter::Info);
log::set_boxed_logger(Box::new(testlog.clone())).expect("Failed to set logger");
testlog
}
/// Returns the number of warning messages logged.
#[must_use]
pub fn warn_count(&self) -> usize {
self.warn_count.load(Ordering::Relaxed)
}
/// Returns the number of error messages logged.
#[must_use]
pub fn error_count(&self) -> usize {
self.error_count.load(Ordering::Relaxed)
}
}
impl log::Log for TestLog {
fn enabled(&self, _metadata: &log::Metadata<'_>) -> bool {
true
}
fn log(&self, record: &log::Record<'_>) {
match record.level() {
log::Level::Warn => {
_ = self.warn_count.fetch_add(1, Ordering::Relaxed);
}
log::Level::Error => {
_ = self.error_count.fetch_add(1, Ordering::Relaxed);
}
_ => {}
}
// Print the log message to stderr
std::io::stderr()
.write_fmt(format_args!("{} - {}\n", record.level(), record.args()))
.expect("Failed to write log message");
}
fn flush(&self) {}
}
/// A stored log record with all relevant information
#[derive(Debug, Clone)]
pub struct StoredRecord {
/// The level of the log record
pub level: log::Level,
/// The target of the log record
pub target: String,
/// The message of the log record
pub message: String,
}
/// A logger implementation for the standard Rust `log` crate that stores records in memory.
/// This logger keeps all logs in a vector for later inspection and is thread-safe.
#[derive(Default, Clone)]
pub struct MemLog {
records: Arc<Mutex<Vec<StoredRecord>>>,
}
impl MemLog {
/// Creates a new memory logger.
#[must_use]
pub fn new() -> Self {
let memlog = MemLog {
records: Arc::new(Mutex::new(Vec::new())),
};
log::set_max_level(log::LevelFilter::Info);
log::set_boxed_logger(Box::new(memlog.clone())).expect("Failed to set logger");
memlog
}
/// Returns all stored log records.
#[must_use]
pub fn records(&self) -> Vec<StoredRecord> {
self.records.lock().expect("Failed to lock records").clone()
}
/// Returns the number of warning messages logged.
#[must_use]
pub fn warn_count(&self) -> usize {
self.records
.lock()
.expect("Failed to lock records")
.iter()
.filter(|record| record.level == log::Level::Warn)
.count()
}
/// Returns the number of error messages logged.
#[must_use]
pub fn error_count(&self) -> usize {
self.records
.lock()
.expect("Failed to lock records")
.iter()
.filter(|record| record.level == log::Level::Error)
.count()
}
}
impl log::Log for MemLog {
fn enabled(&self, _metadata: &log::Metadata<'_>) -> bool {
true
}
fn log(&self, record: &log::Record<'_>) {
let stored_record = StoredRecord {
level: record.level(),
target: record.target().to_owned(),
message: record.args().to_string(),
};
self.records
.lock()
.expect("Failed to lock records")
.push(stored_record);
}
fn flush(&self) {}
}
/// Adds some success flare to text
pub fn success_flare<T: std::fmt::Display>(message: T) -> String {
colorize_string(format!("<green><tick></> {message}"))
}
/// Logs a success message as info
pub fn log_success<T: std::fmt::Display>(message: T) {
log::info!("{}", success_flare(message));
}
/// Adds some error flare to text
pub fn error_flare<T: std::fmt::Display>(message: T) -> String {
colorize_string(format!("<red><cross></> {message}"))
}
/// Logs an error message as error
pub fn log_error<T: std::fmt::Display>(message: T) {
log::error!("{}", error_flare(message));
}
/// Adds some info flare to text
pub fn info_flare<T: std::fmt::Display>(message: T) -> String {
colorize_string(format!("<cyan><info></> {message}"))
}
/// Logs an info message as info
pub fn log_info<T: std::fmt::Display>(message: T) {
log::info!("{}", info_flare(message));
}
/// Adds some warning flare to text
pub fn warn_flare<T: std::fmt::Display>(message: T) -> String {
colorize_string(format!("<yellow><warn></> {message}"))
}
/// Logs a warning message as warn
pub fn log_warn<T: std::fmt::Display>(message: T) {
log::warn!("{}", warn_flare(message));
}
/// Types of path strings we can support.
pub enum PathType {
/// A URL path, like http://server/
URL,
/// A relative path, like ../some-file
RelativePath,
/// An absolute path, like /my/file/location
AbsolutePath,
/// Weaver-special. A reference to a file
/// in a git repo or other.
WeaverPath,
}
/// Returns the type of path we're dealing with.
#[must_use]
pub fn get_path_type(input: &str) -> PathType {
match url::Url::parse(input) {
Ok(_) => PathType::URL,
Err(url::ParseError::RelativeUrlWithoutBase) => {
let test_path = Path::new(input);
if test_path.is_absolute() {
PathType::AbsolutePath
} else {
PathType::RelativePath
}
}
// TODO - we can learn more from error, we may be able
// to determine if this is a git-relative path or
// in-archive file reference.
Err(_) => PathType::WeaverPath,
}
}