From c913f49e310db2e729ffda11e7bf74f7cff16050 Mon Sep 17 00:00:00 2001 From: Piotr Siuszko Date: Mon, 26 Sep 2022 17:50:15 +0200 Subject: [PATCH] Init work on macos support --- .github/workflows/rust.yml | 6 +- egui_client/Cargo.lock | 111 ++++++++++++++++++++++++++++- egui_client/Cargo.toml | 2 +- egui_client/build.rs | 3 +- egui_client/icon.png | 0 egui_client/src/hub_client.rs | 10 +-- rusty_hub/Cargo.lock | 124 +++++++++++++++++++++++++++++++++ rusty_hub/Cargo.toml | 3 +- rusty_hub/src/config.rs | 60 ++++++++-------- rusty_hub/src/consts.rs | 6 ++ rusty_hub/src/hub.rs | 54 +++++++------- rusty_hub/src/lib.rs | 1 + rusty_hub/src/unity_editor.rs | 8 ++- rusty_hub/src/unity_project.rs | 20 ++++-- 14 files changed, 335 insertions(+), 73 deletions(-) create mode 100644 egui_client/icon.png create mode 100644 rusty_hub/src/consts.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 975b061..e6e342a 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -46,4 +46,8 @@ jobs: cache-on-failure: "" - uses: actions/checkout@v2 - name: Build - run: cd egui_client && cargo build --verbose \ No newline at end of file + run: cd egui_client && cargo build --verbose + - uses: actions/upload-artifact@v3 + with: + name: upload executable + path: egui_client/target/release/rusty_hub_egui \ No newline at end of file diff --git a/egui_client/Cargo.lock b/egui_client/Cargo.lock index ce59b49..4804cf1 100644 --- a/egui_client/Cargo.lock +++ b/egui_client/Cargo.lock @@ -387,6 +387,75 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "crossbeam" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "crossbeam-utils", + "memoffset", + "once_cell", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", +] + [[package]] name = "crossfont" version = "0.5.0" @@ -502,6 +571,15 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "dpc-pariter" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a6f60e0061d01135c7e9b77486a7f5a8e63ba14acbdbca73e42007cfd8a1c91" +dependencies = [ + "pariter", +] + [[package]] name = "dwrote" version = "0.11.0" @@ -949,6 +1027,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hex" version = "0.4.3" @@ -1323,6 +1410,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "num_enum" version = "0.5.7" @@ -1415,6 +1512,17 @@ dependencies = [ "system-deps", ] +[[package]] +name = "pariter" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "324a62b9e7b5f270c0acc92a2040f8028bb643f959f9c068f11a7864f327e3d9" +dependencies = [ + "crossbeam", + "crossbeam-channel", + "num_cpus", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -1596,6 +1704,7 @@ dependencies = [ name = "rusty_hub" version = "0.1.0" dependencies = [ + "dpc-pariter", "exe", "registry", "serde", @@ -1605,7 +1714,7 @@ dependencies = [ [[package]] name = "rusty_hub_egui" -version = "0.1.0" +version = "0.2.0" dependencies = [ "confy", "eframe", diff --git a/egui_client/Cargo.toml b/egui_client/Cargo.toml index 775c2e2..1a631c1 100644 --- a/egui_client/Cargo.toml +++ b/egui_client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rusty_hub_egui" -version = "0.1.0" +version = "0.2.0" edition = "2021" homepage = "https://github.com/Leinnan/rusty_hub" build = "build.rs" diff --git a/egui_client/build.rs b/egui_client/build.rs index 50a6b58..342e745 100644 --- a/egui_client/build.rs +++ b/egui_client/build.rs @@ -9,5 +9,4 @@ fn main() { } #[cfg(unix)] -fn main() { -} \ No newline at end of file +fn main() {} diff --git a/egui_client/icon.png b/egui_client/icon.png new file mode 100644 index 0000000..e69de29 diff --git a/egui_client/src/hub_client.rs b/egui_client/src/hub_client.rs index a40e134..3688e1b 100644 --- a/egui_client/src/hub_client.rs +++ b/egui_client/src/hub_client.rs @@ -21,21 +21,23 @@ impl HubClient { let hub_option = confy::load("lwa_unity_hub", "config"); let hub = if hub_option.is_ok() { - hub_option.unwrap() + let mut h: Hub = hub_option.unwrap(); + h.update_projects_info(); + h } else { Hub::default() }; - let mut client = Self { + let client = Self { hub, current_tab: WindowTab::Projects, }; - client.save_config(true); + client } fn save_config(&mut self, rebuild: bool) { if rebuild { - self.hub.update_info(); + self.hub.update_data(); } let _ = confy::store("lwa_unity_hub", "config", &self.hub); } diff --git a/rusty_hub/Cargo.lock b/rusty_hub/Cargo.lock index 9c11174..2d54fd6 100644 --- a/rusty_hub/Cargo.lock +++ b/rusty_hub/Cargo.lock @@ -80,6 +80,75 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "once_cell", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "digest" version = "0.9.0" @@ -89,6 +158,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "dpc-pariter" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a6f60e0061d01135c7e9b77486a7f5a8e63ba14acbdbca73e42007cfd8a1c91" +dependencies = [ + "pariter", +] + [[package]] name = "exe" version = "0.5.4" @@ -117,6 +195,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hex" version = "0.4.3" @@ -171,6 +258,15 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -190,6 +286,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "once_cell" version = "1.15.0" @@ -202,6 +308,17 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "pariter" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "324a62b9e7b5f270c0acc92a2040f8028bb643f959f9c068f11a7864f327e3d9" +dependencies = [ + "crossbeam", + "crossbeam-channel", + "num_cpus", +] + [[package]] name = "pkbuffer" version = "0.4.1" @@ -257,6 +374,7 @@ dependencies = [ name = "rusty_hub" version = "0.1.0" dependencies = [ + "dpc-pariter", "exe", "registry", "serde", @@ -273,6 +391,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "serde" version = "1.0.145" diff --git a/rusty_hub/Cargo.toml b/rusty_hub/Cargo.toml index e6dc475..4a756b8 100644 --- a/rusty_hub/Cargo.toml +++ b/rusty_hub/Cargo.toml @@ -18,4 +18,5 @@ serde = "^1.0" serde_derive = "^1.0" walkdir = "^2.3.2" exe = "^0.5.4" -registry = "1.2.2" \ No newline at end of file +registry = "1.2.2" +dpc-pariter = "0.5.1" diff --git a/rusty_hub/src/config.rs b/rusty_hub/src/config.rs index 01247ea..64cde5c 100644 --- a/rusty_hub/src/config.rs +++ b/rusty_hub/src/config.rs @@ -1,7 +1,8 @@ +use crate::{consts, unity_editor::UnityEditor}; +use dpc_pariter::IteratorExt; +use std::collections::HashSet; use walkdir::{DirEntry, WalkDir}; -use crate::unity_editor::UnityEditor; - #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Configuration { pub unity_search_paths: Vec, @@ -10,18 +11,13 @@ pub struct Configuration { impl Configuration { pub fn rebuild(&mut self) { - self.editors_configurations = Vec::new(); let paths = self.get_unity_paths(); - for path in &paths { - let editor = UnityEditor::new(&path); - if editor.is_none() { - continue; - } - let editor = editor.unwrap(); - if !self.editors_configurations.contains(&editor) { - self.editors_configurations.push(editor); - } - } + self.editors_configurations = paths + .into_iter() + .parallel_map(|path| UnityEditor::new(&path)) + .parallel_filter(|editor| editor.is_some()) + .parallel_map(|editor| editor.unwrap()) + .collect(); } pub fn get_unity_paths(&self) -> Vec { let mut paths = Vec::new(); @@ -34,8 +30,11 @@ impl Configuration { } fn is_unity_dir(entry: &DirEntry) -> bool { + #[cfg(windows)] let uninstall_exists = entry.path().clone().join("Uninstall.exe").exists(); - let unity_exe_exists = entry.path().clone().join("Unity.exe").exists(); + #[cfg(unix)] + let uninstall_exists = true; // just check that on windows only + let unity_exe_exists = entry.path().clone().join(consts::UNITY_EXE_NAME).exists(); uninstall_exists && unity_exe_exists } @@ -45,29 +44,32 @@ impl Configuration { if !path_exists { return Vec::new(); } - let mut result_paths: Vec = Vec::new(); - for entry in WalkDir::new(path) - .max_depth(5) + let hashset: HashSet = WalkDir::new(path) + .max_depth(2) .into_iter() - .filter_entry(|_| true) - { - if entry.is_ok() { - let entry_unwraped = entry.unwrap(); - let success = Configuration::is_unity_dir(&entry_unwraped); - if success { - result_paths.push(entry_unwraped.path().to_string_lossy().into()); - } - } - } - result_paths + .parallel_filter(|entry| entry.is_ok()) + .parallel_map(|entry| entry.unwrap()) + .parallel_filter(|entry| Configuration::is_unity_dir(&entry)) + .parallel_map(|entry| entry.path().to_string_lossy().into()) + .collect(); + + Vec::from_iter(hashset) } } impl Default for Configuration { fn default() -> Self { let mut default = Self { - unity_search_paths: vec!["C:\\Program Files\\Unity\\Hub".to_string()], + #[cfg(windows)] + unity_search_paths: vec!["C:\\Program Files\\Unity\\Hub\\Editor".to_string()], + #[cfg(target_os = "macos")] + unity_search_paths: vec![ + "/Applications/Unity/Hub/Editor".to_string(), + "/Applications/Unity/".to_string(), + ], + #[cfg(target_os = "linux")] + unity_search_paths: vec!["~/Unity/Hub/Editor".to_string()], editors_configurations: Vec::new(), }; default.rebuild(); diff --git a/rusty_hub/src/consts.rs b/rusty_hub/src/consts.rs new file mode 100644 index 0000000..142a860 --- /dev/null +++ b/rusty_hub/src/consts.rs @@ -0,0 +1,6 @@ +#[cfg(windows)] +pub const UNITY_EXE_NAME: &str = "Unity.exe"; +#[cfg(target_os = "macos")] +pub const UNITY_EXE_NAME: &str = "Unity.app/Contents/MacOS/Unity"; +#[cfg(target_os = "linux")] +pub const UNITY_EXE_NAME: &str = "Unity"; diff --git a/rusty_hub/src/hub.rs b/rusty_hub/src/hub.rs index f349e7c..968f95d 100644 --- a/rusty_hub/src/hub.rs +++ b/rusty_hub/src/hub.rs @@ -1,8 +1,7 @@ -use std::{path::PathBuf, process::Command}; - -use walkdir::WalkDir; - use crate::{config::Configuration, unity_editor::UnityEditor, unity_project::UnityProject}; +use dpc_pariter::IteratorExt; +use std::{path::PathBuf, process::Command}; +use walkdir::WalkDir; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Hub { @@ -15,11 +14,16 @@ impl Hub { Self { config, projects } } - pub fn update_info(&mut self) { + pub fn update_data(&mut self) { self.config.rebuild(); - for project in self.projects.iter_mut() { + self.update_projects_info(); + } + + pub fn update_projects_info(&mut self) { + self.projects.iter_mut().for_each(|project| { project.update_info(); - } + }); + self.projects.sort_by(|a, b| b.edit_time.cmp(&a.edit_time)); } pub fn run_project_nr(&self, nr: usize) { @@ -52,30 +56,28 @@ impl Hub { pub fn search_for_projects_at_path(&mut self, path: &PathBuf) -> usize { let path_exists = std::fs::metadata(path).is_ok(); - let mut result = 0; if !path_exists { - return result; + return 0; } - for entry in WalkDir::new(path) + let projects = self.projects.clone(); + let new_projects: Vec = WalkDir::new(path) .max_depth(3) .into_iter() - .filter_entry(|_| true) - { - let projects = self.projects.clone(); - if entry.is_err() { - continue; - } + .parallel_filter(|entry| entry.is_ok()) + .parallel_map(|entry| { + UnityProject::try_get_project_at_path( + &entry.unwrap().path().as_os_str().to_str().unwrap(), + ) + }) + .parallel_filter(|project| project.is_some()) + .parallel_map(|project| project.unwrap()) + .parallel_filter(move |p| !projects.contains(p)) + .collect(); - let entry_unwraped = entry.unwrap(); - let path_string = entry_unwraped.path().as_os_str().to_str(); - if let Some(project) = UnityProject::try_get_project_at_path(&path_string.unwrap()) { - if !projects.contains(&project) { - self.projects.push(project); - result = result + 1; - } - } - } - result + let len = new_projects.len(); + self.projects.extend(new_projects); + + len } } impl Default for Hub { diff --git a/rusty_hub/src/lib.rs b/rusty_hub/src/lib.rs index 3ea922f..a1833c3 100644 --- a/rusty_hub/src/lib.rs +++ b/rusty_hub/src/lib.rs @@ -2,6 +2,7 @@ extern crate serde_derive; pub mod config; +pub mod consts; pub mod hub; pub mod unity_editor; pub mod unity_project; diff --git a/rusty_hub/src/unity_editor.rs b/rusty_hub/src/unity_editor.rs index 04c116c..ca42a46 100644 --- a/rusty_hub/src/unity_editor.rs +++ b/rusty_hub/src/unity_editor.rs @@ -4,7 +4,9 @@ use std::borrow::Borrow; use std::collections::HashMap; use std::path::Path; -#[derive(Debug, Serialize, Deserialize, Clone)] +use crate::consts; + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, Hash)] pub struct UnityEditor { pub version: String, pub exe_path: String, @@ -21,12 +23,12 @@ impl PartialEq for UnityEditor { impl UnityEditor { pub fn new(path: &str) -> Option { let base_path = Path::new(path); - let exe_path = base_path.join("Unity.exe"); + let exe_path = base_path.join(consts::UNITY_EXE_NAME); if !std::fs::metadata(&exe_path).is_ok() { return None; } - let image = VecPE::from_disk_file(base_path.join("Unity.exe")).unwrap(); + let image = VecPE::from_disk_file(&exe_path).unwrap(); let vs_version_check = VSVersionInfo::parse(&image); if vs_version_check.is_err() { return None; diff --git a/rusty_hub/src/unity_project.rs b/rusty_hub/src/unity_project.rs index 342f8bd..5f678e4 100644 --- a/rusty_hub/src/unity_project.rs +++ b/rusty_hub/src/unity_project.rs @@ -1,4 +1,4 @@ -use std::{path::Path, str}; +use std::{ops::Sub, path::Path, str}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct UnityProject { @@ -7,6 +7,7 @@ pub struct UnityProject { pub version: String, pub branch: String, pub is_valid: bool, + pub edit_time: std::time::SystemTime, } impl PartialEq for UnityProject { @@ -31,7 +32,6 @@ impl UnityProject { Security::Read, ) .unwrap(); - println!("{}", key.to_string()); for value in key.values() { if value.is_err() { @@ -48,7 +48,6 @@ impl UnityProject { if let Some(result) = UnityProject::try_get_project_at_path(&project_path) { projects.push(result); } - println!("\t{}: {}", unwraped_name, project_path); } } projects @@ -76,13 +75,19 @@ impl UnityProject { iter.next(); let project_version = iter.next().unwrap().to_string(); - Some(UnityProject { + let mut project = UnityProject { path: path.to_string(), title: path.split("\\").last().unwrap().to_string(), version: project_version, branch: String::new(), is_valid: true, - }) + edit_time: std::time::SystemTime::now() + .sub(std::time::Duration::new(60 * 60 * 24 * 365 * 30, 0)), + }; + + project.update_info(); + + Some(project) } pub fn update_info(&mut self) { @@ -109,5 +114,10 @@ impl UnityProject { self.branch = head_content.replace(HEAD_PREFIX, "").trim().to_string(); } } + if let Ok(meta) = std::fs::metadata(&self.path) { + if let Ok(data) = meta.modified() { + self.edit_time = data; + } + } } }