thot-local 0.10.0-intermediate

Local functionality for Thot data management and analysis software.
Documentation
//! High level functions associated to the projects list.
use super::collections::projects::Projects;
use super::resources::project::Project;
use crate::result::{Error, ProjectError, Result, SettingsValidationError};
use crate::system::settings::user_settings::UserSettings;
use settings_manager::prelude::SystemSettings;
use std::path::{Path, PathBuf};
use thot_core::result::{Error as CoreError, ResourceError};
use thot_core::types::ResourceId;

// *********************
// *** Projects ***
// *********************

/// Adds a project to the registry collection.
pub fn register_project(project: Project) -> Result {
    // check if project is already registered.
    if let Some(_) = project_by_id(&project.rid)? {
        return Err(Error::CoreError(CoreError::ResourceError(
            ResourceError::DuplicateId(project.rid),
        )));
    }

    let mut projects = load_projects()?;
    projects.projects.push(project);
    projects.save()?;

    Ok(())
}

/// Deregister a project.
pub fn deregister_project(id: &ResourceId) -> Result {
    let mut projects = load_projects()?;
    projects.projects.retain(|p| &p.rid != id);

    projects.save()?;
    Ok(())
}

/// Retrieves a project by its id.
/// Returns None if project is not found.
pub fn project_by_id(id: &ResourceId) -> Result<Option<Project>> {
    let projects = load_projects()?;
    let mut prjs = projects.projects;
    prjs.retain(|p| &p.rid == id);

    match prjs.len() {
        0 => Ok(None),
        1 => Ok(Some(prjs[0].clone())),
        _ => Err(Error::CoreError(CoreError::ResourceError(
            ResourceError::DuplicateId(id.clone()),
        ))),
    }
}

/// Returns a project by its path.
/// Returns None if project is not found.
pub fn project_by_path(path: &Path) -> Result<Option<Project>> {
    let projects = load_projects()?;
    let mut prjs = projects.projects;
    prjs.retain(|p| p.path == path);

    match prjs.len() {
        0 => Ok(None),
        1 => Ok(Some(prjs[0].clone())),
        _ => Err(Error::ProjectError(ProjectError::DuplicatePath(
            PathBuf::from(path),
        ))),
    }
}

/// Updates a project.
/// Replaces the project in the projects collection with the same id.
pub fn update_project(project: Project) -> Result {
    let mut projects = load_projects()?;
    projects.projects = projects
        .projects
        .iter()
        .map(|p| {
            if p.rid == project.rid {
                // project to be updated
                project.clone()
            } else {
                //do nothing
                p.clone()
            }
        })
        .collect();

    projects.save()?;
    Ok(())
}

pub fn set_active_project(id: &ResourceId) -> Result {
    // ensure valid project
    if !validate_project(id) {
        return Err(Error::SettingsValidationError(
            SettingsValidationError::InvalidSetting,
        ));
    };

    let mut settings = load_user_settings()?;

    settings.active_project = Some(id.clone());
    save_user_settings(settings)
}

pub fn set_active_project_by_path(path: &Path) -> Result {
    let project = match project_by_path(path)? {
        None => {
            return Err(Error::ProjectError(ProjectError::PathNotAProjectRoot(
                PathBuf::from(path),
            )))
        }
        Some(p) => p,
    };

    let mut settings = load_user_settings()?;
    settings.active_project = Some(project.rid);
    save_user_settings(settings)
}

pub fn unset_active_project() -> Result {
    let mut settings = load_user_settings()?;

    settings.active_project = None;
    save_user_settings(settings)
}

// *************************
// *** private functions ***
// *************************

fn load_projects() -> Result<Projects> {
    match Projects::load() {
        Ok(prjs) => Ok(prjs),
        Err(err) => Err(Error::SettingsError(err)),
    }
}

// @todo
fn validate_project(id: &ResourceId) -> bool {
    true
}

// @todo
fn validate_project_path(path: &Path) -> bool {
    true
}

fn load_user_settings() -> Result<UserSettings> {
    match UserSettings::load() {
        Ok(sets) => Ok(sets),
        Err(err) => Err(Error::SettingsError(err)),
    }
}

fn save_user_settings(settings: UserSettings) -> Result {
    match settings.save() {
        Ok(_) => Ok(()),
        Err(err) => Err(Error::SettingsError(err)),
    }
}

#[cfg(test)]
#[path = "./projects_test.rs"]
mod projects_test;