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
//! # Standard Paths //! //! A Rust library providing methods for accessing standard paths //! on the local filesystem (config, cache, user directories and etc.). //! //! It's a port of [QStandardPaths](https://doc.qt.io/qt-5/qstandardpaths.html) //! class of the Qt framework. //! //! ### Usage //! ``` //! extern crate standard_paths; //! //! use standard_paths::*; //! use standard_paths::LocationType::*; //! //! fn main() { //! let sp = StandardPaths::new_with_names("app", "org"); //! println!("{:?}", sp.writable_location(AppLocalDataLocation)); //! } //! ``` #[cfg(target_os = "linux")] mod linux; #[cfg(target_os = "linux")] use linux::*; #[cfg(windows)] mod windows; #[cfg(windows)] use windows::*; use std::env; use std::path::{Path, PathBuf}; use std::io::{Error, ErrorKind}; /// Enumerates the standard location type. /// /// Is used to call /// [StandardPaths::writable location](struct.StandardPaths.html#method.writable_location) and /// [StandardPaths::find_executable_in_paths](struct.StandardPaths.html#method.find_executable_in_paths). /// /// Some of the values are used to acquire user-specific paths, /// some are application-specific and some are system-wide. #[derive(Debug, Clone, PartialEq)] pub enum LocationType { /// The user's home directory. /// /// * On Linux systems it's equal to the `$HOME` environment variable. /// * On the last Windows operating systems it's equal to the `%HomePath%` /// environment variable. HomeLocation, /// The user's desktop directory. DesktopLocation, /// The user's documents directory. DocumentsLocation, /// The directory for the user's downloaded files. /// /// This is a generic value. On Windows if no such directory exists, /// the directory for storing user documents is returned. DownloadLocation, /// The user's movies and videos directory. MoviesLocation, /// The user's music, recordings and other audio files directory. MusicLocation, /// The user's pictures, photos and screenshots directory. PicturesLocation, /// The user's applications directory. /// /// It might contain either executables, desktop files, or shortcuts. /// /// It's a platform-specific value. ApplicationsLocation, /// The user's fonts directory. FontsLocation, /// The directory for the runtime communication files (like Unix local sockets). /// /// This is a generic value. It could returns /// [None](https://doc.rust-lang.org/std/option/enum.Option.html#variant.None) /// on some systems. RuntimeLocation, /// A directory for storing temporary files. /// /// It might be application-specific, user-specific or system-wide. TempLocation, /// The directory for the persistent data shared across applications. /// /// This is a generic value. GenericDataLocation, /// The persistent application data directory. /// /// This is an application-specific directory. /// On the Windows operating system, this returns the roaming path. AppDataLocation, /// The local settings directory. /// /// This is a Windows-specific value. /// On all other platforms, it returns the same value as /// [AppDataLocation](enum.LocationType.html#variant.AppDataLocation). AppLocalDataLocation, /// The directory for the user-specific cached data shared across applications. /// /// This is a generic value. It could returns /// [None](https://doc.rust-lang.org/std/option/enum.Option.html#variant.None) /// from the appropriate methods if the system has no concept of shared cache. GenericCacheLocation, /// The user-specific cached data directory. /// /// This is an application-specific directory. AppCacheLocation, /// The user-specific configuration files directory. /// /// This may be either a generic value or application-specific. ConfigLocation, /// The user-specific configuration files directory. /// shared between multiple applications. /// /// This is a generic value. GenericConfigLocation, /// The user-specific configuration files directory. /// /// This is an application-specific value. AppConfigLocation } /// Enumerates the locate option type. /// /// Is used to call /// [StandardPaths::locate location](struct.StandardPaths.html#method.locate) and /// [StandardPaths::locate_all](struct.StandardPaths.html#method.locate_all). #[derive(Debug, Clone, PartialEq)] pub enum LocateOption { /// Locate both files and directories (traversing symbolic links). LocateBoth, /// Locate only files. LocateFile, /// Locate only directories. LocateDirectory } /// Stores application and organization names and provides all the crate methods. pub struct StandardPaths { /// Application name. app_name: String, /// organization name. org_name: String } impl StandardPaths { /// Constructs a new `StandardPaths` with the application name /// derived from the `CARGO_PKG_NAME` variable. pub fn new() -> StandardPaths { StandardPaths { app_name: match env::var("CARGO_PKG_NAME") { Ok(name) => name, _ => String::new() }, org_name: String::new() } } /// Constructs a new `StandardPaths` with the provided `app` and `organization` names. pub fn new_with_names<S>(app: S, organization: S) -> StandardPaths where S: Into<String> { StandardPaths { app_name: app.into(), org_name: organization.into() } } /// Append application suffix to the `path`. /// /// For example `~/.config` -> `~/.config/org/app`. /// /// # Arguments /// * `path` - a mutable `PathBuf` to which the app suffix should be appended. fn append_organization_and_app(&self, path: &mut PathBuf) { if !self.org_name.is_empty() { path.push(&self.org_name); } if !self.app_name.is_empty() { path.push(&self.app_name); } } /// Returns the directory where files of type `location` should be written to. /// /// Note: the returned path can be a directory that does not exist. /// /// Returns [Error](https://doc.rust-lang.org/std/io/struct.Error.html) /// if the location cannot be determined. /// /// # Arguments /// * `location` - location type. pub fn writable_location(&self, location: LocationType) -> Result<PathBuf, Error> { self.writable_location_impl(location) } /// Returns all the directories of type `location`. /// /// The vector of locations is sorted by priority, starting with /// [self.writable location](struct.StandardPaths.html#method.writable_location) /// if it can be determined. /// /// Returns [Error](https://doc.rust-lang.org/std/io/struct.Error.html) /// if the locations cannot be determined or an empty vector if no locations /// for the provided type are defined. /// /// # Arguments /// * `location` - location type. pub fn standard_locations(&self, location: LocationType) -> Result<Vec<PathBuf>, Error> { self.standard_locations_impl(location) } /// Returns the absolute file path to the executable with `name` in the system path. /// /// It also could be used to check a path to be an executable. /// /// Internally it calls the /// [self.find_executable_in_paths](struct.StandardPaths.html#method.find_executable_in_paths) /// method with the system path as the `paths` argument. On most operating systems /// the system path is determined by the `PATH` environment variable. /// /// Note: on Windows the executable extensions from the `PATHEXT` environment variable /// are automatically appended to the `name` if it doesn't contain any extension. /// /// Returns [None](https://doc.rust-lang.org/std/option/enum.Option.html#variant.None) /// if no executables are found or if the provided path is not executable. /// /// # Arguments /// * `name` - the name of the searched executable or an absolute path /// which should be checked to be executable. pub fn find_executable<S>(name: S) -> Option<Vec<PathBuf>> where S: Into<String> { // Read system paths let path_var = match env::var("PATH") { Ok(var) => var, _ => return None }; let paths: Vec<PathBuf> = env::split_paths(&path_var).collect(); StandardPaths::find_executable_in_paths(name, paths) } /// Returns the absolute file path to the executable with `name` in the provided `paths`. /// /// Note: on Windows the executable extensions from the `PATHEXT` environment variable /// are automatically appended to the `name` if it doesn't contain any extension. /// /// Returns [None](https://doc.rust-lang.org/std/option/enum.Option.html#variant.None) /// if no executables are found or if the provided path is not executable. /// /// # Arguments /// * `name` - the name of the searched executable or an absolute path /// which should be checked to be executable. /// * `paths` - the directories where to search for the executable. pub fn find_executable_in_paths<S, P>(name: S, paths: P) -> Option<Vec<PathBuf>> where S: Into<String>, P: AsRef<Vec<PathBuf>> { find_executable_in_paths_impl(name, &paths) } /// Search for a file or directory called 'name' in the standard locations. /// /// Returns a full path to the first file or directory found. /// /// Returns [Error](https://doc.rust-lang.org/std/io/struct.Error.html) /// if accessing the `location` failed or /// [None](https://doc.rust-lang.org/std/option/enum.Option.html#variant.None) /// if no such file or directory can be found. /// /// # Arguments /// * `location` - the location type where to search. /// * `name` - the name of the file or directory to search. /// * `option` - the type of entry to search. pub fn locate<P>(&self, location: LocationType, name: P, option: LocateOption) -> Result<Option<PathBuf>, Error> where P: AsRef<Path> { let paths = self.standard_locations(location)?; for mut path in paths { path.push(&name); match &option { &LocateOption::LocateBoth => if path.exists() { return Ok(Some(path)) }, &LocateOption::LocateFile => if path.is_file() { return Ok(Some(path)) }, &LocateOption::LocateDirectory => if path.is_dir() { return Ok(Some(path)) } } } Ok(None) } /// Search for all files or directories called 'name' in the standard locations. /// /// Returns a vector of full paths to the all files or directories found. /// /// Returns [Error](https://doc.rust-lang.org/std/io/struct.Error.html) /// if accessing the `location` failed or /// [None](https://doc.rust-lang.org/std/option/enum.Option.html#variant.None) /// if no such files or directories can be found. /// /// # Arguments /// * `location` - the location type where to search. /// * `name` - the name of the files or directories to search. /// * `option` - the type of entries to search. pub fn locate_all<P>(&self, location: LocationType, name: P, option: LocateOption) -> Result<Option<Vec<PathBuf>>, Error> where P: AsRef<Path> { let paths = self.standard_locations(location)?; let mut res = Vec::new(); for mut path in paths { path.push(&name); match &option { &LocateOption::LocateBoth => if path.exists() { res.push(path); }, &LocateOption::LocateFile => if path.is_file() { res.push(path); }, &LocateOption::LocateDirectory => if path.is_dir() { res.push(path); } } } if res.is_empty() { Ok(None) } else { Ok(Some(res)) } } #[inline] fn home_dir_err() -> Error { Error::new(ErrorKind::Other, "Error getting HOME directory") } }