rusty_hub/unity_hub_lib/src/unity_project.rs

129 lines
3.9 KiB
Rust

use std::{ops::Sub, path::Path, str};
use crate::consts;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct UnityProject {
pub path: String,
pub title: String,
pub version: String,
pub branch: String,
pub is_valid: bool,
pub edit_time: std::time::SystemTime,
}
impl PartialEq for UnityProject {
fn eq(&self, other: &Self) -> bool {
self.path == other.path
}
}
impl UnityProject {
#[cfg(not(target_os = "windows"))]
pub fn get_projects_from_registry() -> Vec<UnityProject> {
Vec::new()
}
#[cfg(target_os = "windows")]
pub fn get_projects_from_registry() -> Vec<UnityProject> {
use registry::{Hive, Security};
let mut projects = Vec::new();
let key = Hive::CurrentUser
.open(
r"SOFTWARE\Unity Technologies\Unity Editor 5.x",
Security::Read,
)
.unwrap();
for value in key.values() {
if value.is_err() {
continue;
}
let val = value.unwrap();
let unwraped_name = val.name().to_string().unwrap();
if !unwraped_name.contains("RecentlyUsedProjectPaths-") {
continue;
}
if let registry::value::Data::Binary(data) = &val.data() {
let project_path = str::from_utf8(&data).unwrap().to_string();
if let Some(result) = UnityProject::try_get_project_at_path(&project_path) {
projects.push(result);
}
}
}
projects
}
fn is_project_at_path(path: &str) -> bool {
let one = Path::new(&path).join("ProjectSettings");
let two = one.join("ProjectVersion.txt");
std::fs::metadata(&one).is_ok() && std::fs::metadata(&two).is_ok()
}
pub fn try_get_project_at_path(path: &str) -> Option<UnityProject> {
#[cfg(windows)]
let path = path.trim_matches(char::from(0)).replace("/", "\\");
#[cfg(unix)]
let path = path.trim_matches(char::from(0));
if !UnityProject::is_project_at_path(&path) {
return None;
}
let project_version_file = std::fs::read_to_string(
Path::new(&path)
.join("ProjectSettings")
.join("ProjectVersion.txt"),
);
let project_version_file = project_version_file.unwrap();
let mut iter = project_version_file.split_whitespace();
iter.next();
let project_version = iter.next().unwrap().to_string();
let mut project = UnityProject {
path: path.to_string(),
title: path.split(consts::SLASH).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) {
const HEAD_PREFIX: &str = "ref: refs/heads/";
let is_project = UnityProject::is_project_at_path(&self.path);
self.is_valid = is_project;
if !is_project {
return;
}
let mut base_path = Path::new(&self.path);
while let Some(path) = base_path.parent() {
base_path = path;
let head_path = Path::new(&path).join(".git").join("HEAD");
if !head_path.exists() {
continue;
}
let head_content =
std::fs::read_to_string(&head_path).expect("Could not read HEAD file");
if head_content.contains(HEAD_PREFIX) {
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;
}
}
}
}