Skip to content

Commit

Permalink
core: fixing the nurse run command
Browse files Browse the repository at this point in the history
Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
  • Loading branch information
vincenzopalazzo committed Apr 9, 2024
1 parent b1d3a6a commit 2a1fa61
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 67 deletions.
51 changes: 50 additions & 1 deletion coffee_cmd/src/coffee_term/command_show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use term::Element;

use coffee_lib::error;
use coffee_lib::errors::CoffeeError;
use coffee_lib::types::response::{CoffeeList, CoffeeNurse, CoffeeRemote, CoffeeTip, NurseStatus};
use coffee_lib::types::response::{
ChainOfResponsibilityStatus, CoffeeList, CoffeeNurse, CoffeeRemote, CoffeeTip, Defect,
NurseStatus,
};

pub fn show_list(coffee_list: Result<CoffeeList, CoffeeError>) -> Result<(), CoffeeError> {
let remotes = coffee_list?;
Expand Down Expand Up @@ -86,6 +89,52 @@ pub fn show_remote_list(remote_list: Result<CoffeeRemote, CoffeeError>) -> Resul
Ok(())
}

pub fn show_nurse_verify(nurse_verify: &ChainOfResponsibilityStatus) -> Result<(), CoffeeError> {
if nurse_verify.defects.is_empty() {
term::success!("Coffee configuration is not corrupt! No need to run coffee nurse");
} else {
let mut table = radicle_term::Table::new(TableOptions::bordered());
table.push([
term::format::dim(String::from("●")),
term::format::bold(String::from("Defects")),
term::format::bold(String::from("Affected repositories")),
]);
table.divider();

for defect in nurse_verify.defects.iter() {
match defect {
Defect::RepositoryLocallyAbsent(repos) => {
let defect = "Repository missing locally";
for repo in repos {
table.push([
term::format::positive("●").into(),
term::format::bold(defect.to_owned()),
term::format::highlight(repo.clone()),
]);
}
}
Defect::CoffeeGlobalrepoCleanup(networks) => {
let defect = format!(
"Global repository migration completed for the networks: {}",
networks
.iter()
.map(|(network, _)| format!("{network} "))
.collect::<String>()
.trim_end()
);
table.push([
term::format::positive("●").into(),
term::format::bold(defect.to_owned()),
term::format::highlight("_".to_owned()),
]);
}
}
}
table.print();
}
Ok(())
}

pub fn show_nurse_result(
nurse_result: Result<CoffeeNurse, CoffeeError>,
) -> Result<(), CoffeeError> {
Expand Down
4 changes: 2 additions & 2 deletions coffee_cmd/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,9 @@ async fn run(args: CoffeeArgs, mut coffee: CoffeeManager) -> Result<(), CoffeeEr
CoffeeCommand::Nurse { verify } => {
if verify {
let result = coffee.nurse_verify().await?;
term::info!("{}", result);
coffee_term::show_nurse_verify(&result)?;
if !result.is_sane() {
term::info!("Coffee local directory is damaged, please run `coffee nurse` to try to fix it");
term::warning(term::style("Coffee local directory is damaged, please run `coffee nurse` to try to fix it").bold());
}
} else {
let nurse_result = coffee.nurse().await;
Expand Down
21 changes: 11 additions & 10 deletions coffee_core/src/coffee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +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::utils::{check_dir_or_make_if_missing, 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;
Expand Down Expand Up @@ -80,8 +80,8 @@ pub struct CoffeeManager {
}

impl CoffeeManager {
pub async fn new(conf: &dyn CoffeeArgs) -> Result<Self, CoffeeError> {
let conf = CoffeeConf::new(conf).await?;
pub async fn new(conf_args: &dyn CoffeeArgs) -> Result<Self, CoffeeError> {
let conf = CoffeeConf::new(conf_args).await?;
let mut coffee = CoffeeManager {
config: conf.clone(),
coffee_cln_config: CLNConf::new(conf.config_path, true),
Expand All @@ -98,6 +98,7 @@ impl CoffeeManager {
/// when coffee is configured, run an inventory to collect all the necessary information
/// about the coffee ecosystem.
async fn inventory(&mut self) -> Result<(), CoffeeError> {
let skip_verify = self.config.skip_verify;
let _ = self
.storage
.load::<CoffeeStorageInfo>(&self.config.network)
Expand All @@ -123,7 +124,7 @@ impl CoffeeManager {
if let Err(err) = self.coffee_cln_config.parse() {
log::error!("{}", err.cause);
}
if !self.config.skip_verify {
if !skip_verify {
// Check for the chain of responsibility
let status = self.recovery_strategies.scan(self).await?;
log::debug!("Chain of responsibility status: {:?}", status);
Expand Down Expand Up @@ -427,15 +428,10 @@ impl PluginManager for CoffeeManager {
}

async fn add_remote(&mut self, name: &str, url: &str) -> Result<(), CoffeeError> {
// FIXME: we should allow some error here like
// for the add remote command the no found error for the `repository`
// directory is fine.

if self.repos.contains_key(name) {
return Err(error!("repository with name: {name} already exists"));
}
let local_path = format!("{}/{}", self.config.root_path, self.config.network);
let url = URL::new(&local_path, url, name);
let url = URL::new(&self.config.path(), url, name);
log::debug!("remote adding: {} {}", name, &url.url_string);
let mut repo = Github::new(name, &url);
repo.init().await?;
Expand Down Expand Up @@ -551,6 +547,8 @@ impl PluginManager for CoffeeManager {
Defect::CoffeeGlobalrepoCleanup(networks) => {
let global_repo = format!("{}/repositories", self.config.root_path);
for (network, path) in networks {
log::info!("{network} - {path}");
check_dir_or_make_if_missing(path.to_owned()).await?;
if !Path::exists(Path::new(&path)) {
copy_dir_if_exist(&global_repo, path).await?;
}
Expand All @@ -565,6 +563,8 @@ impl PluginManager for CoffeeManager {
status: nurse_actions,
};
nurse.organize();
// Refesh the status
self.flush().await?;
Ok(nurse)
}

Expand All @@ -587,6 +587,7 @@ impl PluginManager for CoffeeManager {
.get_mut(repo_name)
.ok_or_else(|| error!("repository with name: {repo_name} not found"))?;

repo.change_root_path(&self.config.path());
match repo.recover().await {
Ok(_) => {
log::info!("repository {} recovered", repo_name.clone());
Expand Down
35 changes: 17 additions & 18 deletions coffee_core/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,40 @@
//! Coffee configuration utils.
use log::info;
use serde::{Deserialize, Serialize};
use std::env;

use crate::CoffeeOperation;
use coffee_lib::utils::{check_dir_or_make_if_missing, copy_dir_if_exist};
use serde::{Deserialize, Serialize};

use coffee_lib::utils::check_dir_or_make_if_missing;
use coffee_lib::{errors::CoffeeError, plugin::Plugin};

use crate::CoffeeArgs;
use crate::CoffeeOperation;

/// Custom coffee configuration, given by a command line list of arguments
/// or a coffee configuration file.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CoffeeConf {
/// Network configuration related
/// to core lightning network
pub network: String,
/// root path plugin manager
pub root_path: String,
/// path of core lightning configuration file
/// managed by coffee
pub config_path: String,
/// path of the core lightning configuration file
/// not managed by core lightning
/// (this file included the file managed by coffee)
///
/// This file included the file managed by coffee
pub cln_config_path: Option<String>,
/// root cln directory path
pub cln_root: Option<String>,
/// root path plugin manager
pub root_path: String,
/// all plugins that are installed
/// with the plugin manager.
pub plugins: Vec<Plugin>,
/// A flag that indicates if the
/// user wants to skip the verification
/// of nurse.
#[serde(skip)]
pub skip_verify: bool,
}

Expand All @@ -47,7 +50,7 @@ impl CoffeeConf {
def_path = def_path.strip_suffix('/').unwrap_or(&def_path).to_string();
def_path += "/.coffee";
check_dir_or_make_if_missing(def_path.to_string()).await?;
info!("creating coffee home at {def_path}");
log::info!("creating coffee home at {def_path}");

let mut coffee = CoffeeConf {
network: "bitcoin".to_owned(),
Expand All @@ -62,14 +65,8 @@ impl CoffeeConf {
// check the command line arguments and bind them
// inside the coffee conf
coffee.bind_cmd_line_params(conf)?;

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);
// 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
// something stored already to the disk.
Expand Down Expand Up @@ -105,10 +102,12 @@ impl CoffeeConf {
}
}
}

// FIXME: be able to put the directory also in another place!
// for now it is fixed in the Home/.coffee but another good place
// will be, the .lightning dir
Ok(())
}

/// Return the root path of the coffee manager instance
/// this include also the network path.
pub fn path(&self) -> String {
format!("{}/{}", self.root_path, self.network)
}
}
2 changes: 1 addition & 1 deletion coffee_core/src/nurse/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ impl RecoveryChainOfResponsibility {
pub async fn new() -> Result<Self, CoffeeError> {
Ok(Self {
handlers: vec![
Arc::new(GitRepositoryLocallyAbsentStrategy),
Arc::new(CoffeeRepositoryDirCleanUp),
Arc::new(GitRepositoryLocallyAbsentStrategy),
],
})
}
Expand Down
5 changes: 5 additions & 0 deletions coffee_core/src/nurse/strategy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ impl Handler for CoffeeRepositoryDirCleanUp {
// Check whether there exists a network-specific repositories folder for each network.
let mut directory_moving = vec![];
for network in networks {
let network_dir = format!("{}/{network}", coffee.config.root_path);
if !Path::exists(Path::new(&network_dir)) {
log::debug!("network dir `{network_dir}` not found");
continue;
}
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));
Expand Down
4 changes: 4 additions & 0 deletions coffee_github/src/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ impl Repository for Github {
}
}

fn change_root_path(&mut self, path: &str) {
self.url.set_coffee_path(path);
}

async fn upgrade(
&mut self,
plugins: &Vec<Plugin>,
Expand Down
5 changes: 5 additions & 0 deletions coffee_lib/src/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ pub trait Repository: Any {
/// recover the repository from the commit id.
async fn recover(&mut self) -> Result<(), CoffeeError>;

/// While migrating there is a possibility that we should
/// move an old repository into a new path. So this
/// is semplyfing this process.
fn change_root_path(&mut self, path: &str);

/// return the name of the repository.
fn name(&self) -> String;

Expand Down
35 changes: 3 additions & 32 deletions coffee_lib/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,37 +166,6 @@ pub mod response {
}
}

impl fmt::Display for ChainOfResponsibilityStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.defects.is_empty() {
write!(f, "Coffee is sane")
} else {
writeln!(f, "Coffee has the following defects:")?;
for (i, defect) in self.defects.iter().enumerate() {
match defect {
Defect::RepositoryLocallyAbsent(repos) => {
write!(f, "{}. Repository missing locally: ", i + 1)?;
for repo in repos {
write!(f, " {}", repo)?;
}
}
Defect::CoffeeGlobalrepoCleanup(networks) => {
writeln!(
f,
"Global repository migration completed for the networks: {}",
networks
.iter()
.map(|(network, _)| network.to_owned())
.collect::<String>()
)?;
}
}
}
Ok(())
}
}
}

/// This struct is used to represent the status of nurse,
/// either sane or not.
/// If not sane, return the action that nurse has taken.
Expand Down Expand Up @@ -231,7 +200,9 @@ pub mod response {
NurseStatus::RepositoryLocallyRestored(repos) => {
repositories_locally_restored.append(&mut repos.clone())
}
NurseStatus::MovingGlobalRepostoryTo(_) => {}
NurseStatus::MovingGlobalRepostoryTo(status) => {
new_status.push(NurseStatus::MovingGlobalRepostoryTo(status.to_owned()));
}
}
}
if !repositories_locally_removed.is_empty() {
Expand Down
4 changes: 4 additions & 0 deletions coffee_lib/src/url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ impl URL {
repo_name: get_repo_name_from_url(url),
}
}

pub fn set_coffee_path(&mut self, path: &str) {
self.path_string = format!("{path}/{}", self.repo_name);
}
}

impl fmt::Display for URL {
Expand Down
Loading

0 comments on commit 2a1fa61

Please sign in to comment.