1use std::collections::hash_map::DefaultHasher;
2use std::fs;
3use std::hash::{Hash, Hasher};
4use std::io::{stdin, stdout, Write};
5use std::path::Path;
6
7pub const DEFAULT_FLATPAK_BUILDER_CACHE_DIR: &str = ".flatpak-builder/";
8pub const DEFAULT_FLATPAK_BUILDER_OUTPUT_DIR: &str = ".flatpak-builder-out/";
9pub const DEFAULT_GIT_CACHE_DIR: &str = ".git/";
10
11pub fn get_module_hash(module: &flatpak_rs::module::FlatpakModule) -> String {
12 let mut s = DefaultHasher::new();
14 module.hash(&mut s);
15 s.finish().to_string()
16}
17
18pub fn get_all_paths(dir: &Path) -> Result<Vec<std::path::PathBuf>, String> {
19 let mut all_paths: Vec<std::path::PathBuf> = vec![];
20
21 let dir_entries = match fs::read_dir(dir) {
22 Ok(entries) => entries,
23 Err(err) => {
24 return Err(format!(
25 "Could not read dir {}: {}",
26 dir.to_str().unwrap(),
27 err.to_string()
28 ))
29 }
30 };
31 for entry in dir_entries {
32 let entry_path = entry.unwrap().path();
33 let entry_path_str = match entry_path.to_str() {
34 Some(p) => p,
35 None => continue,
36 };
37 if entry_path_str.contains(DEFAULT_GIT_CACHE_DIR) {
38 continue;
39 }
40 if entry_path_str.contains(DEFAULT_FLATPAK_BUILDER_CACHE_DIR) {
41 continue;
42 }
43 if entry_path_str.contains(DEFAULT_FLATPAK_BUILDER_OUTPUT_DIR) {
44 continue;
45 }
46
47 if entry_path.is_dir() {
48 let mut dir_paths: Vec<std::path::PathBuf> = get_all_paths(&entry_path)?;
49 all_paths.append(&mut dir_paths);
50 } else {
51 all_paths.push(entry_path);
52 }
53 }
54
55 Ok(all_paths)
56}
57
58pub fn get_build_system(file_path: String) -> Option<String> {
59 if file_path.ends_with("CMakeLists.txt") {
60 return Some("cmake".to_string());
61 }
62 if file_path.ends_with("autogen.sh") || file_path.ends_with("autogen") {
63 return Some("autotools".to_string());
64 }
65 if file_path.ends_with("bootstrap.sh") || file_path.ends_with("bootstrap") {
66 return Some("autotools".to_string());
67 }
68 if file_path.ends_with(".pro") {
69 return Some("qmake".to_string());
70 }
71 if file_path.ends_with("meson.build") || file_path.ends_with("meson_options.txt") {
72 return Some("meson".to_string());
73 }
74 if file_path.ends_with("Cargo.toml") || file_path.ends_with("Cargo.lock") {
75 return Some("cargo".to_string());
76 }
77 if file_path.ends_with("pom.xml") {
78 return Some("maven".to_string());
79 }
80 if file_path.ends_with("debian/control") {
81 return Some("debian".to_string());
82 }
83 if file_path.ends_with("snapcraft.yml") || file_path.ends_with("snapcraft.yaml") {
84 return Some("snap".to_string());
85 }
86 if file_path.ends_with("go.mod") || file_path.ends_with("go.sum") {
87 return Some("go".to_string());
88 }
89 if file_path.ends_with("package.json") || file_path.ends_with("package-lock.json") {
90 return Some("npm".to_string());
91 }
92 if file_path.ends_with("pyproject.toml") {
93 return Some("pip".to_string());
94 }
95 if file_path.ends_with("vcpkg.json") {
96 return Some("vcpkg".to_string());
97 }
98
99 None
100}
101
102pub fn format_bytes(bytes: usize) -> String {
115 let sizes: Vec<&str> = vec!["B", "KB", "MB", "GB", "TB"];
116
117 let mut i = 0;
118 let mut approximated_bytes = bytes as f64;
119 while i < 5 && approximated_bytes >= 1024.0 {
120 i += 1;
121 approximated_bytes = approximated_bytes / 1024.0;
122 }
123 return format!("{:.2} {}", approximated_bytes, sizes[i]);
124}
125
126pub fn ask_yes_no_question(question: String) -> bool {
127 let mut answer = String::new();
128 print!("{}? [Y/n]: ", question);
129 let _ = stdout().flush();
130 stdin()
131 .read_line(&mut answer)
132 .expect("Error while reading answer for question.");
133 if let Some('\n') = answer.chars().next_back() {
134 answer.pop();
135 }
136 if let Some('\r') = answer.chars().next_back() {
137 answer.pop();
138 }
139 if answer == "Y" || answer == "y" {
140 return true;
141 }
142 return false;
143}