Init work on macos support

This commit is contained in:
Piotr Siuszko 2022-09-26 17:50:15 +02:00
parent 2257948203
commit c913f49e31
14 changed files with 335 additions and 73 deletions

View File

@ -47,3 +47,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Build - name: Build
run: cd egui_client && cargo build --verbose run: cd egui_client && cargo build --verbose
- uses: actions/upload-artifact@v3
with:
name: upload executable
path: egui_client/target/release/rusty_hub_egui

111
egui_client/Cargo.lock generated
View File

@ -387,6 +387,75 @@ dependencies = [
"cfg-if 1.0.0", "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]] [[package]]
name = "crossfont" name = "crossfont"
version = "0.5.0" version = "0.5.0"
@ -502,6 +571,15 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" 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]] [[package]]
name = "dwrote" name = "dwrote"
version = "0.11.0" version = "0.11.0"
@ -949,6 +1027,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 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]] [[package]]
name = "hex" name = "hex"
version = "0.4.3" version = "0.4.3"
@ -1323,6 +1410,16 @@ dependencies = [
"autocfg", "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]] [[package]]
name = "num_enum" name = "num_enum"
version = "0.5.7" version = "0.5.7"
@ -1415,6 +1512,17 @@ dependencies = [
"system-deps", "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]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.1" version = "0.12.1"
@ -1596,6 +1704,7 @@ dependencies = [
name = "rusty_hub" name = "rusty_hub"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"dpc-pariter",
"exe", "exe",
"registry", "registry",
"serde", "serde",
@ -1605,7 +1714,7 @@ dependencies = [
[[package]] [[package]]
name = "rusty_hub_egui" name = "rusty_hub_egui"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"confy", "confy",
"eframe", "eframe",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "rusty_hub_egui" name = "rusty_hub_egui"
version = "0.1.0" version = "0.2.0"
edition = "2021" edition = "2021"
homepage = "https://github.com/Leinnan/rusty_hub" homepage = "https://github.com/Leinnan/rusty_hub"
build = "build.rs" build = "build.rs"

View File

@ -9,5 +9,4 @@ fn main() {
} }
#[cfg(unix)] #[cfg(unix)]
fn main() { fn main() {}
}

0
egui_client/icon.png Normal file
View File

View File

@ -21,21 +21,23 @@ impl HubClient {
let hub_option = confy::load("lwa_unity_hub", "config"); let hub_option = confy::load("lwa_unity_hub", "config");
let hub = if hub_option.is_ok() { let hub = if hub_option.is_ok() {
hub_option.unwrap() let mut h: Hub = hub_option.unwrap();
h.update_projects_info();
h
} else { } else {
Hub::default() Hub::default()
}; };
let mut client = Self { let client = Self {
hub, hub,
current_tab: WindowTab::Projects, current_tab: WindowTab::Projects,
}; };
client.save_config(true);
client client
} }
fn save_config(&mut self, rebuild: bool) { fn save_config(&mut self, rebuild: bool) {
if rebuild { if rebuild {
self.hub.update_info(); self.hub.update_data();
} }
let _ = confy::store("lwa_unity_hub", "config", &self.hub); let _ = confy::store("lwa_unity_hub", "config", &self.hub);
} }

124
rusty_hub/Cargo.lock generated
View File

@ -80,6 +80,75 @@ dependencies = [
"libc", "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]] [[package]]
name = "digest" name = "digest"
version = "0.9.0" version = "0.9.0"
@ -89,6 +158,15 @@ dependencies = [
"generic-array", "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]] [[package]]
name = "exe" name = "exe"
version = "0.5.4" version = "0.5.4"
@ -117,6 +195,15 @@ dependencies = [
"version_check", "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]] [[package]]
name = "hex" name = "hex"
version = "0.4.3" version = "0.4.3"
@ -171,6 +258,15 @@ dependencies = [
"opaque-debug", "opaque-debug",
] ]
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.45" version = "0.1.45"
@ -190,6 +286,16 @@ dependencies = [
"autocfg", "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]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.15.0" version = "1.15.0"
@ -202,6 +308,17 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 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]] [[package]]
name = "pkbuffer" name = "pkbuffer"
version = "0.4.1" version = "0.4.1"
@ -257,6 +374,7 @@ dependencies = [
name = "rusty_hub" name = "rusty_hub"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"dpc-pariter",
"exe", "exe",
"registry", "registry",
"serde", "serde",
@ -273,6 +391,12 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.145" version = "1.0.145"

View File

@ -19,3 +19,4 @@ serde_derive = "^1.0"
walkdir = "^2.3.2" walkdir = "^2.3.2"
exe = "^0.5.4" exe = "^0.5.4"
registry = "1.2.2" registry = "1.2.2"
dpc-pariter = "0.5.1"

View File

@ -1,7 +1,8 @@
use crate::{consts, unity_editor::UnityEditor};
use dpc_pariter::IteratorExt;
use std::collections::HashSet;
use walkdir::{DirEntry, WalkDir}; use walkdir::{DirEntry, WalkDir};
use crate::unity_editor::UnityEditor;
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Configuration { pub struct Configuration {
pub unity_search_paths: Vec<String>, pub unity_search_paths: Vec<String>,
@ -10,18 +11,13 @@ pub struct Configuration {
impl Configuration { impl Configuration {
pub fn rebuild(&mut self) { pub fn rebuild(&mut self) {
self.editors_configurations = Vec::new();
let paths = self.get_unity_paths(); let paths = self.get_unity_paths();
for path in &paths { self.editors_configurations = paths
let editor = UnityEditor::new(&path); .into_iter()
if editor.is_none() { .parallel_map(|path| UnityEditor::new(&path))
continue; .parallel_filter(|editor| editor.is_some())
} .parallel_map(|editor| editor.unwrap())
let editor = editor.unwrap(); .collect();
if !self.editors_configurations.contains(&editor) {
self.editors_configurations.push(editor);
}
}
} }
pub fn get_unity_paths(&self) -> Vec<String> { pub fn get_unity_paths(&self) -> Vec<String> {
let mut paths = Vec::new(); let mut paths = Vec::new();
@ -34,8 +30,11 @@ impl Configuration {
} }
fn is_unity_dir(entry: &DirEntry) -> bool { fn is_unity_dir(entry: &DirEntry) -> bool {
#[cfg(windows)]
let uninstall_exists = entry.path().clone().join("Uninstall.exe").exists(); 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 uninstall_exists && unity_exe_exists
} }
@ -45,29 +44,32 @@ impl Configuration {
if !path_exists { if !path_exists {
return Vec::new(); return Vec::new();
} }
let mut result_paths: Vec<String> = Vec::new();
for entry in WalkDir::new(path) let hashset: HashSet<String> = WalkDir::new(path)
.max_depth(5) .max_depth(2)
.into_iter() .into_iter()
.filter_entry(|_| true) .parallel_filter(|entry| entry.is_ok())
{ .parallel_map(|entry| entry.unwrap())
if entry.is_ok() { .parallel_filter(|entry| Configuration::is_unity_dir(&entry))
let entry_unwraped = entry.unwrap(); .parallel_map(|entry| entry.path().to_string_lossy().into())
let success = Configuration::is_unity_dir(&entry_unwraped); .collect();
if success {
result_paths.push(entry_unwraped.path().to_string_lossy().into()); Vec::from_iter(hashset)
}
}
}
result_paths
} }
} }
impl Default for Configuration { impl Default for Configuration {
fn default() -> Self { fn default() -> Self {
let mut 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(), editors_configurations: Vec::new(),
}; };
default.rebuild(); default.rebuild();

6
rusty_hub/src/consts.rs Normal file
View File

@ -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";

View File

@ -1,8 +1,7 @@
use std::{path::PathBuf, process::Command};
use walkdir::WalkDir;
use crate::{config::Configuration, unity_editor::UnityEditor, unity_project::UnityProject}; 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)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Hub { pub struct Hub {
@ -15,11 +14,16 @@ impl Hub {
Self { config, projects } Self { config, projects }
} }
pub fn update_info(&mut self) { pub fn update_data(&mut self) {
self.config.rebuild(); self.config.rebuild();
for project in self.projects.iter_mut() { self.update_projects_info();
project.update_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) { 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 { pub fn search_for_projects_at_path(&mut self, path: &PathBuf) -> usize {
let path_exists = std::fs::metadata(path).is_ok(); let path_exists = std::fs::metadata(path).is_ok();
let mut result = 0;
if !path_exists { if !path_exists {
return result; return 0;
} }
for entry in WalkDir::new(path) let projects = self.projects.clone();
let new_projects: Vec<UnityProject> = WalkDir::new(path)
.max_depth(3) .max_depth(3)
.into_iter() .into_iter()
.filter_entry(|_| true) .parallel_filter(|entry| entry.is_ok())
{ .parallel_map(|entry| {
let projects = self.projects.clone(); UnityProject::try_get_project_at_path(
if entry.is_err() { &entry.unwrap().path().as_os_str().to_str().unwrap(),
continue; )
} })
.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 len = new_projects.len();
let path_string = entry_unwraped.path().as_os_str().to_str(); self.projects.extend(new_projects);
if let Some(project) = UnityProject::try_get_project_at_path(&path_string.unwrap()) {
if !projects.contains(&project) { len
self.projects.push(project);
result = result + 1;
}
}
}
result
} }
} }
impl Default for Hub { impl Default for Hub {

View File

@ -2,6 +2,7 @@
extern crate serde_derive; extern crate serde_derive;
pub mod config; pub mod config;
pub mod consts;
pub mod hub; pub mod hub;
pub mod unity_editor; pub mod unity_editor;
pub mod unity_project; pub mod unity_project;

View File

@ -4,7 +4,9 @@ use std::borrow::Borrow;
use std::collections::HashMap; use std::collections::HashMap;
use std::path::Path; use std::path::Path;
#[derive(Debug, Serialize, Deserialize, Clone)] use crate::consts;
#[derive(Debug, Serialize, Deserialize, Clone, Eq, Hash)]
pub struct UnityEditor { pub struct UnityEditor {
pub version: String, pub version: String,
pub exe_path: String, pub exe_path: String,
@ -21,12 +23,12 @@ impl PartialEq for UnityEditor {
impl UnityEditor { impl UnityEditor {
pub fn new(path: &str) -> Option<Self> { pub fn new(path: &str) -> Option<Self> {
let base_path = Path::new(path); 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() { if !std::fs::metadata(&exe_path).is_ok() {
return None; 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); let vs_version_check = VSVersionInfo::parse(&image);
if vs_version_check.is_err() { if vs_version_check.is_err() {
return None; return None;

View File

@ -1,4 +1,4 @@
use std::{path::Path, str}; use std::{ops::Sub, path::Path, str};
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct UnityProject { pub struct UnityProject {
@ -7,6 +7,7 @@ pub struct UnityProject {
pub version: String, pub version: String,
pub branch: String, pub branch: String,
pub is_valid: bool, pub is_valid: bool,
pub edit_time: std::time::SystemTime,
} }
impl PartialEq for UnityProject { impl PartialEq for UnityProject {
@ -31,7 +32,6 @@ impl UnityProject {
Security::Read, Security::Read,
) )
.unwrap(); .unwrap();
println!("{}", key.to_string());
for value in key.values() { for value in key.values() {
if value.is_err() { if value.is_err() {
@ -48,7 +48,6 @@ impl UnityProject {
if let Some(result) = UnityProject::try_get_project_at_path(&project_path) { if let Some(result) = UnityProject::try_get_project_at_path(&project_path) {
projects.push(result); projects.push(result);
} }
println!("\t{}: {}", unwraped_name, project_path);
} }
} }
projects projects
@ -76,13 +75,19 @@ impl UnityProject {
iter.next(); iter.next();
let project_version = iter.next().unwrap().to_string(); let project_version = iter.next().unwrap().to_string();
Some(UnityProject { let mut project = UnityProject {
path: path.to_string(), path: path.to_string(),
title: path.split("\\").last().unwrap().to_string(), title: path.split("\\").last().unwrap().to_string(),
version: project_version, version: project_version,
branch: String::new(), branch: String::new(),
is_valid: true, 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) { pub fn update_info(&mut self) {
@ -109,5 +114,10 @@ impl UnityProject {
self.branch = head_content.replace(HEAD_PREFIX, "").trim().to_string(); 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;
}
}
} }
} }