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
use crate::path;
use crate::prelude::*;
use std::io;
use std::path::{Path, PathBuf};
#[derive(Debug, Error)]
pub enum VarError {
#[error("Environment variable not present.")]
NotPresent,
#[error("Environment variable contains non-Unicode characters.")]
NotUnicode,
}
#[derive(Debug, Error)]
pub enum WorkingPathError {
#[error("The current working directory was not found.")]
NotFound,
#[error("Permission denied reading the current working directory.")]
PermissionDenied,
#[error("The current working directory `{}` is not unicode.", .0.display())]
NotUnicode(PathBuf),
}
static EXE_PATH: Lazy<Result<(String, String), String>> = Lazy::new(|| {
let mut path: String = std::env::current_exe()
.map_err(|err| format!("IO error. {}.", err))?
.to_str()
.ok_or("non-unicode path name.")?
.into();
let file = path::pop(&mut path).unwrap_or_default();
Ok((path, file))
});
pub fn exe_name() -> &'static str {
&EXE_PATH.as_ref().expect("Failed to determine path to current executable").1
}
pub fn exe_path() -> &'static str {
&EXE_PATH.as_ref().expect("Failed to determine path to current executable").0
}
pub fn project_path() -> Option<&'static str> {
static PATH: Lazy<Option<&'static str>> = Lazy::new(|| {
let value = var("CARGO_MANIFEST_DIR").ok()?;
Some(Box::leak(value.into_boxed_str()))
});
*PATH
}
pub fn var(name: &str) -> Result<String, VarError> {
std::env::var(name).map_err(|err| match err {
std::env::VarError::NotPresent => VarError::NotPresent,
std::env::VarError::NotUnicode(_) => VarError::NotUnicode,
})
}
pub fn working_path() -> Result<String, WorkingPathError> {
let path = std::env::current_dir().map_err(|err| match err.kind() {
io::ErrorKind::NotFound => WorkingPathError::NotFound,
io::ErrorKind::PermissionDenied => WorkingPathError::PermissionDenied,
_ => panic!("{}", err),
})?;
Ok(path.to_str().map(String::from).ok_or(WorkingPathError::NotUnicode(path))?)
}
pub fn workspace_path() -> Option<&'static str> {
static PATH: Lazy<Option<&'static str>> = Lazy::new(|| {
let project_path = project_path()?;
let mut workspace_path: String = project_path.into();
loop {
path::append(&mut workspace_path, "Cargo.lock");
let found = AsRef::<Path>::as_ref(&workspace_path).exists();
path::pop(&mut workspace_path);
if found {
break;
}
if path::pop(&mut workspace_path).is_none() {
workspace_path.replace_range(.., project_path);
break;
}
}
Some(Box::leak(workspace_path.into_boxed_str()))
});
*PATH
}