cargo_user/
lib.rs

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}