#![allow(unused_imports)]
use std::collections::BTreeMap;
use std::fs;
use std::io::Write;
use std::path::Path;
use serde::{Deserialize, Serialize};
use crate::project::Project;
pub const MANIFEST_FILE: &str = "manifest.json";
pub const MANIFEST_VERSION: &str = "0.1.0";
#[derive(Serialize, Deserialize)]
pub struct Manifest {
pub projects: BTreeMap<String, Project>,
pub version: String,
}
impl Manifest {
pub fn new() -> Self {
Manifest {
projects: BTreeMap::new(),
version: MANIFEST_VERSION.to_string(),
}
}
pub fn read_file<P: AsRef<Path>>(path: P) -> anyhow::Result<Manifest> {
let json = fs::read_to_string(&path)?;
let json: Manifest = serde_json::from_str(&json)?;
Ok(json)
}
pub fn write_file<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
let json = serde_json::to_string_pretty(&self)?;
let mut file = fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&path)?;
file.write_all(json.as_ref())?;
Ok(())
}
pub fn find_project<P: AsRef<Path>>(&self, path: P) -> Option<Project> {
let path = path.as_ref().to_str().unwrap();
self.projects.get(path).cloned()
}
pub fn add_project<P: AsRef<Path>>(&mut self, path: P, project: Project) -> anyhow::Result<()> {
let path = path.as_ref().to_str().unwrap();
if self.projects.contains_key(path) {
return Err(anyhow::anyhow!(format!(
"Project already exist at {}",
path
)));
}
self.projects.insert(path.to_string(), project);
Ok(())
}
pub fn remove_project<P: AsRef<Path>>(&mut self, path: P) -> anyhow::Result<()> {
let path = path.as_ref().to_str().unwrap();
if !self.projects.contains_key(path) {
return Err(anyhow::anyhow!(format!("No project found at {}", path)));
}
self.projects.remove(path);
Ok(())
}
pub fn update_project<P: AsRef<Path>>(
&mut self,
path: P,
project: Project,
) -> anyhow::Result<()> {
self.remove_project(&path)?;
self.add_project(&path, project)?;
Ok(())
}
pub fn move_project<A: AsRef<Path>, B: AsRef<Path>>(
&mut self,
src: A,
dst: B,
) -> anyhow::Result<()> {
let project = self.find_project(&src).ok_or_else(|| {
anyhow::anyhow!(format!("No project found at {}", src.as_ref().display()))
})?;
if self.projects.contains_key(dst.as_ref().to_str().unwrap()) {
return Err(anyhow::anyhow!(format!(
"Project already exist at {}",
dst.as_ref().display()
)));
}
self.remove_project(&src)?;
self.add_project(&dst, project)?;
Ok(())
}
}
impl Default for Manifest {
fn default() -> Self {
Manifest::new()
}
}
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use std::path::Path;
use crate::manifest::{Manifest, MANIFEST_VERSION};
use crate::project::Project;
#[test]
fn test_new() {
let manifest = Manifest::new();
assert_eq!(manifest.version, MANIFEST_VERSION.to_string());
assert_eq!(manifest.projects.len(), 0);
}
#[test]
fn test_add_project() {
let mut manifest = Manifest::new();
let project = Project::new("", "", BTreeMap::new(), BTreeMap::new());
let res = manifest.add_project("test/test", project.clone());
assert!(res.is_ok());
let res = manifest.add_project("test/test", project);
assert!(res.is_err());
}
#[test]
fn test_find_project() {
let mut manifest = Manifest::new();
let project = Project::new("a", "b", BTreeMap::new(), BTreeMap::new());
manifest.add_project("test/test", project.clone()).unwrap();
let project = manifest.find_project("test/test");
assert!(&project.is_some());
let project = project.unwrap();
assert_eq!(project.remote, "a");
assert_eq!(project.branch, "b");
let project = manifest.find_project("not-exist");
assert!(project.is_none());
}
#[test]
fn test_remove_project() {
let mut manifest = Manifest::new();
let project = Project::new("", "", BTreeMap::new(), BTreeMap::new());
manifest.add_project("test/test", project.clone()).unwrap();
let res = manifest.remove_project("test/test");
assert!(res.is_ok());
let res = manifest.remove_project("test/test");
assert!(res.is_err());
}
#[test]
fn test_update_project() {
let mut manifest = Manifest::new();
let mut project = Project::new("a", "b", BTreeMap::new(), BTreeMap::new());
manifest.add_project("test/test", project.clone()).unwrap();
project.remote = "c".to_string();
project.branch = "d".to_string();
let res = manifest.update_project("test/test", project);
assert!(res.is_ok());
let project = manifest.find_project("test/test");
assert!(project.is_some());
let project = project.unwrap();
assert_eq!(project.remote, "c");
assert_eq!(project.branch, "d");
}
#[test]
fn test_move_project() {
let mut manifest = Manifest::new();
let project = Project::new("", "", BTreeMap::new(), BTreeMap::new());
manifest.add_project("test/test", project.clone()).unwrap();
let res = manifest.move_project("test/test", "test/test-2");
assert!(res.is_ok());
let project = manifest.find_project("test/test");
assert!(project.is_none());
let project = manifest.find_project("test/test-2");
assert!(project.is_some());
}
}