diff --git a/coffee_cmd/src/coffee_term/command_show.rs b/coffee_cmd/src/coffee_term/command_show.rs index 819635ca..2363d7aa 100644 --- a/coffee_cmd/src/coffee_term/command_show.rs +++ b/coffee_cmd/src/coffee_term/command_show.rs @@ -102,10 +102,14 @@ pub fn show_nurse_result( NurseStatus::RepositoryLocallyRemoved(_) => { "Removed from local storage".to_string() } + NurseStatus::MovingGlobalRepostoryTo(_) => { + "Moving Global repository directory".to_string() + } }; let repos_str = match status { NurseStatus::RepositoryLocallyRestored(repos) | NurseStatus::RepositoryLocallyRemoved(repos) => repos.join(", "), + NurseStatus::MovingGlobalRepostoryTo(network) => network.to_owned(), }; table.push([ diff --git a/coffee_core/src/coffee.rs b/coffee_core/src/coffee.rs index c60244de..e311462c 100644 --- a/coffee_core/src/coffee.rs +++ b/coffee_core/src/coffee.rs @@ -1,8 +1,8 @@ //! Coffee mod implementation use std::collections::HashMap; use std::fmt::Debug; +use std::path::Path; use std::vec::Vec; -use tokio::fs; use async_trait::async_trait; use clightningrpc_common::client::Client; @@ -12,6 +12,7 @@ use log; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use serde_json::json; +use tokio::fs; use tokio::process::Command; use coffee_github::repository::Github; @@ -20,6 +21,7 @@ use coffee_lib::plugin_manager::PluginManager; use coffee_lib::repository::Repository; use coffee_lib::types::response::*; use coffee_lib::url::URL; +use coffee_lib::utils::{copy_dir_if_exist, rm_dir_if_exist}; use coffee_lib::{commit_id, error, get_repo_info, sh}; use coffee_storage::model::repository::{Kind, Repository as RepositoryInfo}; use coffee_storage::nosql_db::NoSQlStorage; @@ -497,6 +499,17 @@ impl PluginManager for CoffeeManager { let mut actions = self.patch_repository_locally_absent(repos.to_vec()).await?; nurse_actions.append(&mut actions); } + Defect::CoffeeGlobalrepoCleanup(networks) => { + let global_repo = format!("{}/repositories", self.config.root_path); + for (network, path) in networks { + if !Path::exists(Path::new(&path)) { + copy_dir_if_exist(&global_repo, path).await?; + } + nurse_actions + .push(NurseStatus::MovingGlobalRepostoryTo(network.to_owned())); + } + rm_dir_if_exist(&global_repo).await?; + } } } let mut nurse = CoffeeNurse { diff --git a/coffee_core/src/config.rs b/coffee_core/src/config.rs index bd43eb1e..5f9e2874 100644 --- a/coffee_core/src/config.rs +++ b/coffee_core/src/config.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use std::env; use crate::CoffeeOperation; -use coffee_lib::utils::{check_dir_or_make_if_missing, move_dir_if_exist}; +use coffee_lib::utils::{check_dir_or_make_if_missing, copy_dir_if_exist}; use coffee_lib::{errors::CoffeeError, plugin::Plugin}; use crate::CoffeeArgs; @@ -66,7 +66,9 @@ impl CoffeeConf { check_dir_or_make_if_missing(format!("{def_path}/{}", coffee.network)).await?; check_dir_or_make_if_missing(format!("{def_path}/{}/plugins", coffee.network)).await?; let repo_dir = format!("{def_path}/{}/repositories", coffee.network); - move_dir_if_exist(&format!("{def_path}/repositories"), &repo_dir).await?; + // older version of coffee has a repository inside the directory + copy_dir_if_exist(&format!("{def_path}/repositories"), &repo_dir).await?; + // FIXME: nurse should clean up the `{def_path}/repositories`. check_dir_or_make_if_missing(repo_dir).await?; // after we know all the information regarding // the configuration we try to see if there is diff --git a/coffee_core/src/nurse/chain.rs b/coffee_core/src/nurse/chain.rs index 921d3820..24437720 100644 --- a/coffee_core/src/nurse/chain.rs +++ b/coffee_core/src/nurse/chain.rs @@ -33,7 +33,7 @@ use async_trait::async_trait; use coffee_lib::errors::CoffeeError; use coffee_lib::types::response::{ChainOfResponsibilityStatus, Defect}; -use super::strategy::GitRepositoryLocallyAbsentStrategy; +use super::strategy::{CoffeeRepositoryDirCleanUp, GitRepositoryLocallyAbsentStrategy}; use crate::coffee::CoffeeManager; #[async_trait] @@ -52,7 +52,10 @@ impl RecoveryChainOfResponsibility { /// Create a new instance of the chain of responsibility pub async fn new() -> Result { Ok(Self { - handlers: vec![Arc::new(GitRepositoryLocallyAbsentStrategy)], + handlers: vec![ + Arc::new(GitRepositoryLocallyAbsentStrategy), + Arc::new(CoffeeRepositoryDirCleanUp), + ], }) } diff --git a/coffee_core/src/nurse/strategy.rs b/coffee_core/src/nurse/strategy.rs index a1e85d4d..fca65fec 100644 --- a/coffee_core/src/nurse/strategy.rs +++ b/coffee_core/src/nurse/strategy.rs @@ -74,3 +74,34 @@ impl Handler for GitRepositoryLocallyAbsentStrategy { } } } + +/// Stategy for migration of the repository global directory +/// to a local directory for each network, see [1] +/// +/// This is a strategy tht return the list of network that +/// needs to be migrated to to the new repository configuration. +/// +/// [1] https://github.com/coffee-tools/coffee/issues/234 +pub struct CoffeeRepositoryDirCleanUp; + +#[async_trait] +impl Handler for CoffeeRepositoryDirCleanUp { + async fn can_be_applied( + self: Arc, + coffee: &CoffeeManager, + ) -> Result, CoffeeError> { + let networks = ["testnet", "signet", "bitcoin", "liquid"]; + // Check whether there exists a network-specific repositories folder for each network. + let mut directory_moving = vec![]; + for network in networks { + let subpath_repo = format!("{}/{network}/repositories", coffee.config.root_path); + if !Path::exists(Path::new(&subpath_repo)) { + directory_moving.push((network.to_string(), subpath_repo)); + } + } + if directory_moving.is_empty() { + return Ok(None); + } + Ok(Some(Defect::CoffeeGlobalrepoCleanup(directory_moving))) + } +} diff --git a/coffee_lib/src/types/mod.rs b/coffee_lib/src/types/mod.rs index 794dc53a..d9df6d51 100644 --- a/coffee_lib/src/types/mod.rs +++ b/coffee_lib/src/types/mod.rs @@ -138,6 +138,8 @@ pub mod response { // A patch operation when a git repository is present in the coffee configuration // but is absent from the local storage. RepositoryLocallyAbsent(Vec), + /// (Affected network, path) + CoffeeGlobalrepoCleanup(Vec<(String, String)>), // TODO: Add more patch operations } @@ -166,6 +168,16 @@ pub mod response { write!(f, " {}", repo)?; } } + Defect::CoffeeGlobalrepoCleanup(networks) => { + writeln!( + f, + "Global repository migration completed for the networks: {}", + networks + .iter() + .map(|(network, _)| network.to_owned()) + .collect::() + )?; + } } } Ok(()) @@ -180,6 +192,7 @@ pub mod response { pub enum NurseStatus { RepositoryLocallyRestored(Vec), RepositoryLocallyRemoved(Vec), + MovingGlobalRepostoryTo(String), } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -206,6 +219,7 @@ pub mod response { NurseStatus::RepositoryLocallyRestored(repos) => { repositories_locally_restored.append(&mut repos.clone()) } + NurseStatus::MovingGlobalRepostoryTo(_) => {} } } if !repositories_locally_removed.is_empty() { @@ -231,6 +245,12 @@ pub mod response { NurseStatus::RepositoryLocallyRemoved(val) => { write!(f, "Repositories removed locally: {}", val.join(" ")) } + NurseStatus::MovingGlobalRepostoryTo(net) => { + write!( + f, + "Global repository directory moved to subdirectory for network `{net}`" + ) + } } } } diff --git a/coffee_lib/src/utils.rs b/coffee_lib/src/utils.rs index 5c5c69ed..f951aae8 100644 --- a/coffee_lib/src/utils.rs +++ b/coffee_lib/src/utils.rs @@ -1,8 +1,7 @@ use super::macros::error; use std::path::Path; -use tokio::fs::create_dir; -use tokio::fs::rename; +use tokio::fs; use crate::errors::CoffeeError; @@ -23,16 +22,24 @@ pub fn get_plugin_info_from_path(path: &Path) -> Result<(String, String), Coffee pub async fn check_dir_or_make_if_missing(path: String) -> Result<(), CoffeeError> { if !Path::exists(Path::new(&path.to_owned())) { - create_dir(path.clone()).await?; + fs::create_dir(path.clone()).await?; log::debug!("created dir {path}"); } Ok(()) } -pub async fn move_dir_if_exist(origin: &str, destination: &str) -> Result<(), CoffeeError> { +pub async fn copy_dir_if_exist(origin: &str, destination: &str) -> Result<(), CoffeeError> { if Path::exists(Path::new(&origin)) { - rename(origin, destination).await?; - log::debug!("move dir from {origin} to {destination}"); + fs::copy(origin, destination).await?; + log::debug!("copying dir from {origin} to {destination}"); + } + Ok(()) +} + +pub async fn rm_dir_if_exist(origin: &str) -> Result<(), CoffeeError> { + if Path::exists(Path::new(&origin)) { + fs::remove_dir_all(origin).await?; + log::debug!("rm dir from {origin}"); } Ok(()) } diff --git a/git-bugreport-2024-02-07-1353.txt b/git-bugreport-2024-02-07-1353.txt deleted file mode 100644 index f278341c..00000000 --- a/git-bugreport-2024-02-07-1353.txt +++ /dev/null @@ -1,32 +0,0 @@ -Thank you for filling out a Git bug report! -Please answer the following questions to help us understand your issue. - -What did you do before the bug happened? (Steps to reproduce your issue) - -What did you expect to happen? (Expected behavior) - -What happened instead? (Actual behavior) - -What's different between what you expected and what actually happened? - -Anything else you want to add: - -Please review the rest of the bug report below. -You can delete any lines you don't wish to share. - - -[System Info] -git version: -git version 2.43.0 -cpu: x86_64 -no commit associated with this build -sizeof-long: 8 -sizeof-size_t: 8 -shell-path: /bin/sh -uname: Linux 6.6.15-2-lts #1 SMP PREEMPT_DYNAMIC Fri, 02 Feb 2024 17:04:24 +0000 x86_64 -compiler info: gnuc: 13.2 -libc info: glibc: 2.39 -$SHELL (typically, interactive shell): /usr/bin/zsh - - -[Enabled Hooks]