thot-local 0.10.0-intermediate

Local functionality for Thot data management and analysis software.
Documentation
use super::container;
use super::project::{path_is_project_root, project_root_path};
use super::resources::container::Container;
use super::resources::script::Scripts;
use crate::result::{ContainerError, Error, ProjectError, Result};
use settings_manager::list_setting::ListSetting;
use settings_manager::local_settings::LocalSettings;
use std::path::Path;
use thot_core::project::{Script, ScriptAssociation};
use thot_core::result::{Error as CoreError, ProjectError as CoreProjectError};
use thot_core::types::{ResourceId, ResourcePath};

// ***************
// *** Scripts ***
// ***************

/// Initialize a file as a Script for a Project.
///
/// If `project` is `None`, assumes the file is contained within the project.
pub fn init(path: &Path, project: Option<&Path>) -> Result<ResourceId> {
    let project = match project {
        None => project_root_path(path)?,
        Some(p) => {
            // check path is a project root
            if !path_is_project_root(p) {
                return Err(Error::ProjectError(ProjectError::PathNotAProjectRoot(
                    p.to_path_buf(),
                )));
            }

            p.to_path_buf()
        }
    };

    let s_rp = ResourcePath::new(path.to_path_buf())?;
    let mut scripts = Scripts::load(&project)?;

    // check if script is already registered
    for s in &scripts.scripts {
        if s.path == s_rp {
            return Ok(s.rid.clone());
        }
    }

    let script = Script::new(s_rp)?;
    let rid = script.rid.clone();
    scripts.push(script);
    scripts.save()?;

    Ok(rid)
}

/// Returns the id of the script associated with the path registered with the given project.
/// If project path is not given, searches in ancestors for project root.
/// Errors if the path is not registered.
pub fn id_by_path(path: &Path, project: Option<&Path>) -> Result<ResourceId> {
    // get project
    let project = match project {
        Some(p) => {
            if !path_is_project_root(p) {
                return Err(Error::ProjectError(ProjectError::PathNotAProjectRoot(
                    p.to_path_buf(),
                )));
            }
            p.to_path_buf()
        }
        None => {
            let p = project_root_path(path)?;
            p
        }
    };

    let scripts = Scripts::load(&project)?;
    let s_path = ResourcePath::new(path.to_path_buf())?;
    match scripts.by_path(&s_path) {
        None => Err(Error::CoreError(CoreError::ProjectError(
            CoreProjectError::NotRegistered(None, Some(path.to_path_buf())),
        ))),
        Some(script) => Ok(script.rid.clone()),
    }
}

/// Returns if the path is registered as a script with the given project.
/// If project path is not given, searches in ancestors for project root.
pub fn path_is_registered(path: &Path, project: Option<&Path>) -> Result<bool> {
    // get project
    let project = match project {
        Some(p) => {
            if !path_is_project_root(p) {
                return Err(Error::ProjectError(ProjectError::PathNotAProjectRoot(
                    p.to_path_buf(),
                )));
            }
            p.to_path_buf()
        }
        None => {
            let p = project_root_path(path)?;
            p
        }
    };

    // check if script is registered
    let scripts = Scripts::load(&project)?;
    let s_path = ResourcePath::new(path.to_path_buf())?;
    Ok(scripts.contains_path(&s_path))
}

// **************************
// *** Script Association ***
// **************************

/// Add an associaiton with the given script to the given container.
/// Returns the resource id of the script.
///
/// # Arguments
/// + `container`: Path of the `Container` to associate the script with.
///     Must be a in a [`Project`].
///
/// # Errors
/// + If `container` is not in a `Project`.
pub fn add_association(script: &Path, container: &Path) -> Result<ResourceId> {
    // check script and container are valid
    if !container::path_is_container(container) {
        return Err(Error::ContainerError(ContainerError::PathNotAContainer(
            container.to_path_buf(),
        )));
    }

    // get script
    let prj_path = project_root_path(container)?;
    let scripts = Scripts::load(&prj_path)?;
    let s_path = ResourcePath::new(script.to_path_buf())?;
    let script = match scripts.by_path(&s_path) {
        Some(s) => s,
        None => {
            return Err(Error::CoreError(CoreError::ProjectError(
                CoreProjectError::NotRegistered(None, Some(script.to_path_buf())),
            )))
        }
    };

    // add association
    let mut container = Container::load(container)?;
    let assoc = ScriptAssociation::new(script.rid.clone());
    container.add_script_association(assoc)?;
    container.save()?;

    Ok(script.rid.clone())
}

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