use crate::commands::init::{find_rivets_root, RivetsConfig, CONFIG_FILE_NAME, RIVETS_DIR_NAME};
use crate::error::{Error, Result};
use crate::storage::{create_storage, IssueStorage};
use std::path::{Path, PathBuf};
pub struct App {
storage: Box<dyn IssueStorage>,
rivets_dir: PathBuf,
prefix: String,
}
impl std::fmt::Debug for App {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("App")
.field("rivets_dir", &self.rivets_dir)
.field("prefix", &self.prefix)
.field("storage", &"<dyn IssueStorage>")
.finish()
}
}
impl App {
pub async fn from_directory(working_dir: &Path) -> Result<Self> {
let root_dir = find_rivets_root(working_dir).ok_or_else(|| {
Error::Config(
"Not a rivets repository (or any of the parent directories). \
Run 'rivets init' to create a new repository."
.to_string(),
)
})?;
let rivets_dir = root_dir.join(RIVETS_DIR_NAME);
let config_path = rivets_dir.join(CONFIG_FILE_NAME);
let config = RivetsConfig::load(&config_path).await?;
let backend = config.storage.to_backend(&root_dir)?;
let storage = create_storage(backend, config.issue_prefix.clone()).await?;
Ok(Self {
storage,
rivets_dir,
prefix: config.issue_prefix,
})
}
pub fn storage_mut(&mut self) -> &mut dyn IssueStorage {
self.storage.as_mut()
}
pub fn storage(&self) -> &dyn IssueStorage {
self.storage.as_ref()
}
pub fn prefix(&self) -> &str {
&self.prefix
}
pub fn rivets_dir(&self) -> &Path {
&self.rivets_dir
}
pub async fn save(&self) -> Result<()> {
self.storage.save().await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::commands::init;
use tempfile::TempDir;
#[tokio::test]
async fn test_app_from_initialized_directory() {
let temp_dir = TempDir::new().unwrap();
init::init(temp_dir.path(), Some("test")).await.unwrap();
let app = App::from_directory(temp_dir.path()).await.unwrap();
assert_eq!(app.prefix(), "test");
assert!(app.rivets_dir().ends_with(".rivets"));
}
#[tokio::test]
async fn test_app_from_subdirectory() {
let temp_dir = TempDir::new().unwrap();
init::init(temp_dir.path(), Some("proj")).await.unwrap();
let sub_dir = temp_dir.path().join("src").join("lib");
std::fs::create_dir_all(&sub_dir).unwrap();
let app = App::from_directory(&sub_dir).await.unwrap();
assert_eq!(app.prefix(), "proj");
}
#[tokio::test]
async fn test_app_from_uninitialized_directory() {
let temp_dir = TempDir::new().unwrap();
let result = App::from_directory(temp_dir.path()).await;
assert!(result.is_err());
let err = result.unwrap_err().to_string();
assert!(err.contains("Not a rivets repository"));
}
}