1extern crate dirs_sys;
2
3use std::env;
4use std::path::PathBuf;
5
6use BaseDirs;
7use UserDirs;
8use ProjectDirs;
9
10pub fn base_dirs() -> Option<BaseDirs> {
11 if let Some(home_dir) = dirs_sys::home_dir() {
12 let cache_dir = env::var_os("XDG_CACHE_HOME") .and_then(dirs_sys::is_absolute_path).unwrap_or_else(|| home_dir.join(".cache"));
13 let config_dir = env::var_os("XDG_CONFIG_HOME").and_then(dirs_sys::is_absolute_path).unwrap_or_else(|| home_dir.join(".config"));
14 let config_local_dir = config_dir.clone();
15 let data_dir = env::var_os("XDG_DATA_HOME") .and_then(dirs_sys::is_absolute_path).unwrap_or_else(|| home_dir.join(".local/share"));
16 let data_local_dir = data_dir.clone();
17 let preference_dir = config_dir.clone();
18 let runtime_dir = env::var_os("XDG_RUNTIME_DIR").and_then(dirs_sys::is_absolute_path);
19 let state_dir = env::var_os("XDG_STATE_HOME") .and_then(dirs_sys::is_absolute_path).unwrap_or_else(|| home_dir.join(".local/state"));
20 let executable_dir = env::var_os("XDG_BIN_HOME") .and_then(dirs_sys::is_absolute_path).unwrap_or_else(|| home_dir.join(".local/bin"));
21
22 let base_dirs = BaseDirs {
23 home_dir: home_dir,
24 cache_dir: cache_dir,
25 config_dir: config_dir,
26 config_local_dir: config_local_dir,
27 data_dir: data_dir,
28 data_local_dir: data_local_dir,
29 executable_dir: Some(executable_dir),
30 preference_dir: preference_dir,
31 runtime_dir: runtime_dir,
32 state_dir: Some(state_dir)
33 };
34 Some(base_dirs)
35 } else {
36 None
37 }
38}
39
40pub fn user_dirs() -> Option<UserDirs> {
41 if let Some(home_dir: PathBuf) = dirs_sys::home_dir() {
42 let data_dir: PathBuf = env::var_os(key:"XDG_DATA_HOME").and_then(dirs_sys::is_absolute_path).unwrap_or_else(|| home_dir.join(path:".local/share"));
43 let font_dir: PathBuf = data_dir.join(path:"fonts");
44 let mut user_dirs_map: HashMap = dirs_sys::user_dirs(&home_dir);
45
46 let user_dirs: UserDirs = UserDirs {
47 home_dir: home_dir,
48 audio_dir: user_dirs_map.remove("MUSIC"),
49 desktop_dir: user_dirs_map.remove("DESKTOP"),
50 document_dir: user_dirs_map.remove("DOCUMENTS"),
51 download_dir: user_dirs_map.remove("DOWNLOAD"),
52 font_dir: Some(font_dir),
53 picture_dir: user_dirs_map.remove("PICTURES"),
54 public_dir: user_dirs_map.remove("PUBLICSHARE"),
55 template_dir: user_dirs_map.remove("TEMPLATES"),
56 video_dir: user_dirs_map.remove("VIDEOS")
57 };
58 Some(user_dirs)
59 } else {
60 None
61 }
62}
63
64pub fn project_dirs_from_path(project_path: PathBuf) -> Option<ProjectDirs> {
65 if let Some(home_dir) = dirs_sys::home_dir() {
66 let cache_dir = env::var_os("XDG_CACHE_HOME") .and_then(dirs_sys::is_absolute_path).unwrap_or_else(|| home_dir.join(".cache")).join(&project_path);
67 let config_dir = env::var_os("XDG_CONFIG_HOME").and_then(dirs_sys::is_absolute_path).unwrap_or_else(|| home_dir.join(".config")).join(&project_path);
68 let config_local_dir = config_dir.clone();
69 let data_dir = env::var_os("XDG_DATA_HOME") .and_then(dirs_sys::is_absolute_path).unwrap_or_else(|| home_dir.join(".local/share")).join(&project_path);
70 let data_local_dir = data_dir.clone();
71 let preference_dir = config_dir.clone();
72 let runtime_dir = env::var_os("XDG_RUNTIME_DIR").and_then(dirs_sys::is_absolute_path).map(|o| o.join(&project_path));
73 let state_dir = env::var_os("XDG_STATE_HOME") .and_then(dirs_sys::is_absolute_path).unwrap_or_else(|| home_dir.join(".local/state")).join(&project_path);
74
75 let project_dirs = ProjectDirs {
76 project_path: project_path,
77 cache_dir: cache_dir,
78 config_dir: config_dir,
79 config_local_dir: config_local_dir,
80 data_dir: data_dir,
81 data_local_dir: data_local_dir,
82 preference_dir: preference_dir,
83 runtime_dir: runtime_dir,
84 state_dir: Some(state_dir)
85 };
86 Some(project_dirs)
87 } else {
88 None
89 }
90}
91
92pub fn project_dirs_from(_qualifier: &str, _organization: &str, application: &str) -> Option<ProjectDirs> {
93 ProjectDirs::from_path(project_path:PathBuf::from(&trim_and_lowercase_then_replace_spaces(name:application, replacement:"")))
94}
95
96fn trim_and_lowercase_then_replace_spaces(name: &str, replacement: &str) -> String {
97 let mut buf: String = String::with_capacity(name.len());
98 let mut parts: SplitWhitespace<'_> = name.split_whitespace();
99 let mut current_part: Option<&str> = parts.next();
100 let replace: bool = !replacement.is_empty();
101 while current_part.is_some() {
102 let value: String = current_part.unwrap().to_lowercase();
103 buf.push_str(&value);
104 current_part = parts.next();
105 if replace && current_part.is_some() {
106 buf.push_str(string:replacement);
107 }
108 }
109 buf
110}
111
112#[cfg(test)]
113mod tests {
114 use lin::trim_and_lowercase_then_replace_spaces;
115
116 #[test]
117 fn test_trim_and_lowercase_then_replace_spaces() {
118 let input1 = "Bar App";
119 let actual1 = trim_and_lowercase_then_replace_spaces(input1, "-");
120 let expected1 = "bar-app";
121 assert_eq!(expected1, actual1);
122
123 let input2 = "BarApp-Foo";
124 let actual2 = trim_and_lowercase_then_replace_spaces(input2, "-");
125 let expected2 = "barapp-foo";
126 assert_eq!(expected2, actual2);
127
128 let input3 = " Bar App ";
129 let actual3 = trim_and_lowercase_then_replace_spaces(input3, "-");
130 let expected3 = "bar-app";
131 assert_eq!(expected3, actual3);
132
133 let input4 = " Bar App ";
134 let actual4 = trim_and_lowercase_then_replace_spaces(input4, "-");
135 let expected4 = "bar-app";
136 assert_eq!(expected4, actual4);
137 }
138
139 #[test]
140 fn test_file_user_dirs_exists() {
141 let base_dirs = ::BaseDirs::new();
142 let user_dirs_file = base_dirs.unwrap().config_dir().join("user-dirs.dirs");
143 println!("{:?} exists: {:?}", user_dirs_file, user_dirs_file.exists());
144 }
145}
146