1pub mod dirs;
2pub mod errors;
3pub mod profile;
4
5use std::{fs::create_dir_all, io::Read, path::{Path, PathBuf}};
6use dirs::{path_dir_storage, path_file_credentials};
7pub use errors::{Error, ErrorStorage, Success};
8pub use profile::Profile;
9
10
11fn read(path: impl AsRef<Path>) -> std::io::Result<Vec<u8>> {
12 let mut data = Vec::new();
13 let mut file = std::fs::File::open(path)?;
14 file.read_to_end(&mut data)?;
15
16 Ok(data)
17}
18
19
20pub fn ensure_storage() -> Result<PathBuf, ErrorStorage> {
21 let path_dir = path_dir_storage().ok_or(ErrorStorage::NoPath)?;
22
23 if path_dir.exists() {
24 if path_dir.is_dir() {
25 Ok(path_dir)
26 } else {
27 Err(ErrorStorage::NotDir)
28 }
29 } else {
30 match create_dir_all(&path_dir) {
31 Ok(()) => Ok(path_dir),
32 Err(e) => Err(ErrorStorage::CannotCreate(e)),
33 }
34 }
35}
36
37
38pub fn profile_clear() -> Result<Success, Error> {
39 match path_file_credentials() {
40 Some(path_cred) => match std::fs::remove_file(path_cred) {
41 Ok(()) => Ok(Success::Cleared),
42 Err(e) => Err(Error::CredentialsCannotRemove(e)),
43 }
44 None => Err(Error::CredentialsNoPath),
45 }
46}
47
48
49pub fn profile_list() -> Result<Success, Error> {
50 let dir_profile = ensure_storage()?;
51 let mut profiles = Vec::new();
52
53 if let Ok(dir) = dir_profile.read_dir() {
54 for entry in dir {
55 if let Ok(sub) = entry {
56 if let Some(profile) = Profile::from_path(sub.path()) {
57 profiles.push(profile);
58 }
59 }
60 }
61 }
62
63 Ok(Success::List(profiles))
64}
65
66
67pub fn profile_current() -> Result<Success, Error> {
68 match path_file_credentials() {
69 None => Err(Error::CredentialsNoPath),
70 Some(path) if !path.is_file() => Ok(Success::CurrentNone),
71
72 Some(path) => {
73 let mut current = Vec::new();
74
75 if let Ok(dir) = ensure_storage()?.read_dir() {
76 let creds = read(path).map_err(Error::CredentialsCannotRead)?;
77
78 for entry in dir.filter_map(Result::ok) {
79 let path = entry.path();
80
81 if let Some(profile) = Profile::from_path(&path) {
82 match read(&path) {
83 Ok(data) => if data == creds {
84 current.push(profile);
85 }
86 Err(err) => {
87 return Err(Error::ProfileCannotRead(profile, err));
88 }
89 }
90 }
91 }
92 }
93
94 Ok(Success::Current(current))
95 }
96 }
97}
98
99
100pub fn profile_find(name_opt: Option<String>) -> Result<Success, Error> {
101 let found: Result<PathBuf, ErrorStorage> = match name_opt {
102 Some(name) => Profile::new(name).path().ok_or(ErrorStorage::NoPath),
103 None => ensure_storage(),
104 };
105
106 Ok(Success::Found(found?))
107}
108
109
110pub fn profile_save(name: String, clobber: bool) -> Result<Success, Error> {
111 let mut path_dst = ensure_storage()?;
112 let profile = Profile::new(name);
113 path_dst.push(profile.filename());
114
115 if !clobber && path_dst.exists() {
116 Err(Error::ProfileExists(profile))
117 } else {
118 match path_file_credentials() {
119 Some(path) if !path.is_file() => Err(Error::CredentialsNotFound),
120
121 Some(path_src) => match std::fs::copy(path_src, path_dst) {
122 Ok(..) => Ok(Success::Saved(profile)),
123 Err(e) => Err(Error::CannotSave(profile, e)),
124 }
125
126 None => Err(Error::CredentialsNoPath),
127 }
128 }
129}
130
131
132pub fn profile_load(name: String) -> Result<Success, Error> {
133 let mut path_src = ensure_storage()?;
134 let profile = Profile::new(name);
135 path_src.push(profile.filename());
136
137 match path_file_credentials() {
138 Some(path_dst) => match std::fs::copy(path_src, path_dst) {
139 Ok(..) => Ok(Success::Loaded(profile)),
140 Err(e) => Err(Error::CannotLoad(profile, e)),
141 }
142 None => Err(Error::CredentialsNoPath),
143 }
144}
145
146
147pub fn profile_rename(
148 name_old: String,
149 name_new: String,
150 clobber: bool,
151) -> Result<Success, Error> {
152 let mut path_src = ensure_storage()?;
153 let mut path_dst = path_src.clone();
154
155 let old = Profile::new(name_old);
156 path_src.push(old.filename());
157
158 let new = Profile::new(name_new);
159 path_dst.push(new.filename());
160
161 if !clobber && path_dst.exists() {
162 Err(Error::ProfileExists(new))
163 } else {
164 match std::fs::rename(path_src, path_dst) {
165 Ok(..) => Ok(Success::Renamed(old, new)),
166 Err(e) => Err(Error::ProfileCannotRename(old, new, e)),
167 }
168 }
169}
170
171
172pub fn profile_remove(names: Vec<String>) -> Result<Success, Error> {
173 let dir_profile = ensure_storage()?;
174 let mut vec_del = Vec::with_capacity(names.len());
175 let mut vec_err = Vec::with_capacity(names.len());
176
177 for name in names {
178 let profile = Profile::new(name);
179
180 let mut path = dir_profile.clone();
181 path.push(profile.filename());
182
183 if path.is_file() {
184 match std::fs::remove_file(&path) {
185 Ok(()) => vec_del.push(profile),
186 Err(e) => vec_err.push(Error::ProfileCannotRemove(profile, e)),
187 }
188 } else {
189 vec_err.push(Error::ProfileNotFound(profile));
190 }
191 }
192
193 Ok(Success::Removed { removed: vec_del, errors: vec_err })
194}