use super::resources::project::{Project, ProjectSettings};
use super::resources::script::Scripts;
use crate::common;
use crate::constants::{PROJECT_FILE, THOT_DIR};
use crate::result::{Error, ProjectError, Result};
use crate::system::collections::projects::Projects;
use crate::system::projects;
use crate::system::resources::project::Project as SystemProject;
use settings_manager::local_settings::{LocalSettings, LockSettingsFile};
use settings_manager::system_settings::SystemSettings;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use thot_core::result::{Error as CoreError, ProjectError as CoreProjectError, ResourceError};
use thot_core::types::ResourceId;
pub fn init(root: &Path) -> Result<ResourceId> {
if path_is_resource(root) {
let prj = project_registration(root)?;
return Ok(prj.rid);
}
let thot_dir = root.join(THOT_DIR);
fs::create_dir(&thot_dir)?;
let name = match root.file_name() {
None => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput, "file name could not be extracted from path",
)
.into());
}
Some(f_name) => {
match f_name.to_str() {
None => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput, "file name could not be converted to string",
)
.into());
}
Some(f_str) => String::from(f_str),
}
}
};
let mut project = Project::new(name.as_str())?;
project.set_base_path(root.to_path_buf())?;
project.acquire_lock()?;
project.save()?;
let mut settings = ProjectSettings::new();
settings.set_base_path(root.to_path_buf())?;
settings.acquire_lock()?;
settings.save()?;
let mut scripts = Scripts::new();
scripts.set_base_path(root.to_path_buf())?;
scripts.acquire_lock()?;
scripts.save()?;
let prj = SystemProject::new(project.properties.rid.clone(), PathBuf::from(root));
projects::register_project(prj)?;
Ok(project.properties.rid)
}
pub fn new(root: &Path) -> Result<ResourceId> {
if root.exists() {
return Err(io::Error::new(io::ErrorKind::IsADirectory, "folder already exists").into());
}
fs::create_dir_all(root)?;
init(root)
}
pub fn mv(rid: &ResourceId, to: &Path) -> Result {
let mut changed = 0;
let mut o_path = None; let mut prjs = load_projects()?;
prjs.projects = prjs
.projects
.iter()
.map(|p| {
let mut n = p.clone();
if &p.rid == rid {
o_path = Some(p.path.clone());
n.path = PathBuf::from(to);
changed += 1;
}
n
})
.collect();
if changed == 0 {
return Err(Error::CoreError(CoreError::ResourceError(
ResourceError::DoesNotExist(format!("project with id `{}` does not exist.", rid.id)),
)));
} else if changed > 1 {
return Err(Error::CoreError(CoreError::ResourceError(
ResourceError::DuplicateId(rid.clone()),
)));
}
let o_path = o_path.unwrap();
if let Err(err) = fs::rename(o_path, to) {
return Err(err.into());
}
prjs.save()?;
Ok(())
}
pub fn path_is_resource(path: &Path) -> bool {
let path = common::thot_dir_of(path);
path.exists()
}
pub fn path_is_project_root(path: &Path) -> bool {
let path = common::project_file_of(path);
path.exists()
}
pub fn project_root_path(path: &Path) -> Result<PathBuf> {
let o_path = PathBuf::from(path);
let mut path = path.join("tmp"); while path.pop() {
if !path_is_project_root(&path) {
continue;
}
let prj = Project::load(&path)?;
if prj.properties.meta_level == 0 {
return common::canonicalize_path(path);
}
}
Err(Error::ProjectError(ProjectError::PathNotInProject(o_path)))
}
pub fn project_resource_root_path(path: &Path) -> Result<PathBuf> {
if !path_is_resource(path) {
return Err(Error::ProjectError(ProjectError::PathNotInProject(
PathBuf::from(path),
)));
}
let mut path = path.join("tmp"); while path.pop() {
let prj_file = common::project_file_of(&path);
if !prj_file.exists() {
continue;
}
let prj_json = match fs::read_to_string(prj_file) {
Ok(json) => json,
Err(err) => return Err(err.into()),
};
let prj: Project = match serde_json::from_str(prj_json.as_str()) {
Ok(prj) => prj,
Err(err) => return Err(err.into()),
};
if prj.properties.meta_level == 0 {
return common::canonicalize_path(path);
}
}
Err(
CoreError::ProjectError(CoreProjectError::Misconfigured(String::from(
"project has no root.",
)))
.into(),
)
}
pub fn project_registration(path: &Path) -> Result<SystemProject> {
let root = project_resource_root_path(path)?;
let reg = projects::project_by_path(root.as_path())?;
if reg == None {
let rid = None; return Err(
CoreError::ProjectError(CoreProjectError::NotRegistered(rid, Some(root))).into(),
);
}
Ok(reg.unwrap())
}
pub fn load_project(path: &Path) -> Result<Project> {
let thot_dir = PathBuf::from(path).join(THOT_DIR);
if !thot_dir.exists() {
return Err(Error::ProjectError(ProjectError::PathNotInProject(
PathBuf::from(path),
)));
}
let prj_file = thot_dir.join(PROJECT_FILE);
if !prj_file.exists() {
return Err(Error::ProjectError(ProjectError::PathNotAProjectRoot(
PathBuf::from(path),
)));
}
let prj_json = match fs::read_to_string(prj_file) {
Ok(json) => json,
Err(err) => return Err(err.into()),
};
let prj: Project = match serde_json::from_str(prj_json.as_str()) {
Ok(prj) => prj,
Err(err) => return Err(err.into()),
};
Ok(prj)
}
fn load_projects() -> Result<Projects> {
match Projects::load() {
Ok(prjs) => Ok(prjs),
Err(err) => return Err(Error::SettingsError(err)),
}
}
#[cfg(test)]
#[path = "./project_test.rs"]
mod project_test;