Skip to content

Commit 87b29fe

Browse files
core: fixing the nurse run command
Signed-off-by: Vincenzo Palazzo <[email protected]>
1 parent a5fc3da commit 87b29fe

File tree

10 files changed

+124
-61
lines changed

10 files changed

+124
-61
lines changed

coffee_cmd/src/coffee_term/command_show.rs

+47-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ use term::Element;
77

88
use coffee_lib::error;
99
use coffee_lib::errors::CoffeeError;
10-
use coffee_lib::types::response::{CoffeeList, CoffeeNurse, CoffeeRemote, CoffeeTip, NurseStatus};
10+
use coffee_lib::types::response::{
11+
ChainOfResponsibilityStatus, CoffeeList, CoffeeNurse, CoffeeRemote, CoffeeTip, Defect,
12+
NurseStatus,
13+
};
1114

1215
pub fn show_list(coffee_list: Result<CoffeeList, CoffeeError>) -> Result<(), CoffeeError> {
1316
let remotes = coffee_list?;
@@ -86,6 +89,49 @@ pub fn show_remote_list(remote_list: Result<CoffeeRemote, CoffeeError>) -> Resul
8689
Ok(())
8790
}
8891

92+
pub fn show_nurse_verify(nurse_verify: &ChainOfResponsibilityStatus) -> Result<(), CoffeeError> {
93+
if nurse_verify.defects.is_empty() {
94+
term::success!("Coffee configuration is not corrupt! No need to run coffee nurse");
95+
} else {
96+
let mut table = radicle_term::Table::new(TableOptions::bordered());
97+
table.push([
98+
term::format::dim(String::from("●")),
99+
term::format::bold(String::from("Defects")),
100+
term::format::bold(String::from("Affected repositories")),
101+
]);
102+
table.divider();
103+
104+
for defect in nurse_verify.defects.iter() {
105+
match defect {
106+
Defect::RepositoryLocallyAbsent(repos) => {
107+
let defect = "Repository missing locally";
108+
for repo in repos {
109+
table.push([
110+
term::format::positive("●").into(),
111+
term::format::bold(defect.to_owned()),
112+
term::format::highlight(repo.clone()),
113+
]);
114+
}
115+
}
116+
Defect::CoffeeGlobalRepoCleanup(networks) => {
117+
let defect = "Network specific repository missing";
118+
let networks = networks
119+
.iter()
120+
.map(|(network, _)| network.clone())
121+
.collect::<Vec<String>>();
122+
table.push([
123+
term::format::positive("●").into(),
124+
term::format::bold(defect.to_owned()),
125+
term::format::highlight(networks.join(", ")),
126+
]);
127+
}
128+
}
129+
}
130+
table.print();
131+
}
132+
Ok(())
133+
}
134+
89135
pub fn show_nurse_result(
90136
nurse_result: Result<CoffeeNurse, CoffeeError>,
91137
) -> Result<(), CoffeeError> {

coffee_cmd/src/main.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,9 @@ async fn run(args: CoffeeArgs, mut coffee: CoffeeManager) -> Result<(), CoffeeEr
154154
CoffeeCommand::Nurse { verify } => {
155155
if verify {
156156
let result = coffee.nurse_verify().await?;
157-
term::info!("{}", result);
157+
coffee_term::show_nurse_verify(&result)?;
158158
if !result.is_sane() {
159-
term::info!("Coffee local directory is damaged, please run `coffee nurse` to try to fix it");
159+
term::warning(term::style("Coffee local directory is damaged, please run `coffee nurse` to try to fix it").bold());
160160
}
161161
} else {
162162
let nurse_result = coffee.nurse().await;

coffee_core/src/coffee.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ pub struct CoffeeManager {
7979
}
8080

8181
impl CoffeeManager {
82-
pub async fn new(conf: &dyn CoffeeArgs) -> Result<Self, CoffeeError> {
83-
let conf = CoffeeConf::new(conf).await?;
82+
pub async fn new(conf_args: &dyn CoffeeArgs) -> Result<Self, CoffeeError> {
83+
let conf = CoffeeConf::new(conf_args).await?;
8484
let mut coffee = CoffeeManager {
8585
config: conf.clone(),
8686
coffee_cln_config: CLNConf::new(conf.config_path, true),
@@ -97,6 +97,7 @@ impl CoffeeManager {
9797
/// when coffee is configured, run an inventory to collect all the necessary information
9898
/// about the coffee ecosystem.
9999
async fn inventory(&mut self) -> Result<(), CoffeeError> {
100+
let skip_verify = self.config.skip_verify;
100101
let _ = self
101102
.storage
102103
.load::<CoffeeStorageInfo>(&self.config.network)
@@ -122,7 +123,7 @@ impl CoffeeManager {
122123
if let Err(err) = self.coffee_cln_config.parse() {
123124
log::error!("{}", err.cause);
124125
}
125-
if !self.config.skip_verify {
126+
if !skip_verify {
126127
// Check for the chain of responsibility
127128
let status = self.recovery_strategies.scan(self).await?;
128129
log::debug!("Chain of responsibility status: {:?}", status);
@@ -429,8 +430,7 @@ impl PluginManager for CoffeeManager {
429430
if !force && self.repos.contains_key(name) {
430431
return Err(error!("repository with name: {name} already exists"));
431432
}
432-
let local_path = format!("{}/{}", self.config.root_path, self.config.network);
433-
let url = URL::new(&local_path, url, name);
433+
let url = URL::new(&self.config.path(), url, name);
434434
log::debug!("remote adding: {} {}", name, &url.url_string);
435435
let mut repo = Github::new(name, &url);
436436
repo.init().await?;
@@ -567,6 +567,8 @@ impl PluginManager for CoffeeManager {
567567
status: nurse_actions,
568568
};
569569
nurse.organize();
570+
// Refesh the status
571+
self.flush().await?;
570572
Ok(nurse)
571573
}
572574

@@ -589,6 +591,7 @@ impl PluginManager for CoffeeManager {
589591
.get_mut(repo_name)
590592
.ok_or_else(|| error!("repository with name: {repo_name} not found"))?;
591593

594+
repo.change_root_path(&self.config.path());
592595
match repo.recover().await {
593596
Ok(_) => {
594597
log::info!("repository {} recovered", repo_name.clone());

coffee_core/src/config.rs

+17-18
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,40 @@
11
//! Coffee configuration utils.
2-
use log::info;
3-
use serde::{Deserialize, Serialize};
42
use std::env;
53

6-
use crate::CoffeeOperation;
7-
use coffee_lib::utils::{check_dir_or_make_if_missing, copy_dir_if_exist};
4+
use serde::{Deserialize, Serialize};
5+
6+
use coffee_lib::utils::check_dir_or_make_if_missing;
87
use coffee_lib::{errors::CoffeeError, plugin::Plugin};
98

109
use crate::CoffeeArgs;
10+
use crate::CoffeeOperation;
11+
1112
/// Custom coffee configuration, given by a command line list of arguments
1213
/// or a coffee configuration file.
1314
#[derive(Clone, Debug, Serialize, Deserialize)]
1415
pub struct CoffeeConf {
1516
/// Network configuration related
1617
/// to core lightning network
1718
pub network: String,
19+
/// root path plugin manager
20+
pub root_path: String,
1821
/// path of core lightning configuration file
1922
/// managed by coffee
2023
pub config_path: String,
2124
/// path of the core lightning configuration file
2225
/// not managed by core lightning
23-
/// (this file included the file managed by coffee)
26+
///
27+
/// This file included the file managed by coffee
2428
pub cln_config_path: Option<String>,
2529
/// root cln directory path
2630
pub cln_root: Option<String>,
27-
/// root path plugin manager
28-
pub root_path: String,
2931
/// all plugins that are installed
3032
/// with the plugin manager.
3133
pub plugins: Vec<Plugin>,
3234
/// A flag that indicates if the
3335
/// user wants to skip the verification
3436
/// of nurse.
37+
#[serde(skip)]
3538
pub skip_verify: bool,
3639
}
3740

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

5255
let mut coffee = CoffeeConf {
5356
network: "bitcoin".to_owned(),
@@ -62,14 +65,8 @@ impl CoffeeConf {
6265
// check the command line arguments and bind them
6366
// inside the coffee conf
6467
coffee.bind_cmd_line_params(conf)?;
65-
6668
check_dir_or_make_if_missing(format!("{def_path}/{}", coffee.network)).await?;
6769
check_dir_or_make_if_missing(format!("{def_path}/{}/plugins", coffee.network)).await?;
68-
let repo_dir = format!("{def_path}/{}/repositories", coffee.network);
69-
// older version of coffee has a repository inside the directory
70-
copy_dir_if_exist(&format!("{def_path}/repositories"), &repo_dir).await?;
71-
// FIXME: nurse should clean up the `{def_path}/repositories`.
72-
check_dir_or_make_if_missing(repo_dir).await?;
7370
// after we know all the information regarding
7471
// the configuration we try to see if there is
7572
// something stored already to the disk.
@@ -105,10 +102,12 @@ impl CoffeeConf {
105102
}
106103
}
107104
}
108-
109-
// FIXME: be able to put the directory also in another place!
110-
// for now it is fixed in the Home/.coffee but another good place
111-
// will be, the .lightning dir
112105
Ok(())
113106
}
107+
108+
/// Return the root path of the coffee manager instance
109+
/// this include also the network path.
110+
pub fn path(&self) -> String {
111+
format!("{}/{}", self.root_path, self.network)
112+
}
114113
}

coffee_github/src/repository.rs

+4
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,10 @@ impl Repository for Github {
233233
}
234234
}
235235

236+
fn change_root_path(&mut self, path: &str) {
237+
self.url.set_coffee_path(path);
238+
}
239+
236240
async fn upgrade(
237241
&mut self,
238242
plugins: &Vec<Plugin>,

coffee_lib/src/repository.rs

+5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ pub trait Repository: Any {
3434
/// recover the repository from the commit id.
3535
async fn recover(&mut self) -> Result<(), CoffeeError>;
3636

37+
/// While migrating there is a possibility that we should
38+
/// move an old repository into a new path. So this
39+
/// is semplyfing this process.
40+
fn change_root_path(&mut self, path: &str);
41+
3742
/// return the name of the repository.
3843
fn name(&self) -> String;
3944

coffee_lib/src/types/mod.rs

+3-32
Original file line numberDiff line numberDiff line change
@@ -166,37 +166,6 @@ pub mod response {
166166
}
167167
}
168168

169-
impl fmt::Display for ChainOfResponsibilityStatus {
170-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171-
if self.defects.is_empty() {
172-
write!(f, "Coffee is sane")
173-
} else {
174-
writeln!(f, "Coffee has the following defects:")?;
175-
for (i, defect) in self.defects.iter().enumerate() {
176-
match defect {
177-
Defect::RepositoryLocallyAbsent(repos) => {
178-
write!(f, "{}. Repository missing locally: ", i + 1)?;
179-
for repo in repos {
180-
write!(f, " {}", repo)?;
181-
}
182-
}
183-
Defect::CoffeeGlobalRepoCleanup(networks) => {
184-
writeln!(
185-
f,
186-
"Global repository migration completed for the networks: {}",
187-
networks
188-
.iter()
189-
.map(|(network, _)| network.to_owned())
190-
.collect::<String>()
191-
)?;
192-
}
193-
}
194-
}
195-
Ok(())
196-
}
197-
}
198-
}
199-
200169
/// This struct is used to represent the status of nurse,
201170
/// either sane or not.
202171
/// If not sane, return the action that nurse has taken.
@@ -231,7 +200,9 @@ pub mod response {
231200
NurseStatus::RepositoryLocallyRestored(repos) => {
232201
repositories_locally_restored.append(&mut repos.clone())
233202
}
234-
NurseStatus::MovingGlobalRepostoryTo(_) => {}
203+
NurseStatus::MovingGlobalRepostoryTo(status) => {
204+
new_status.push(NurseStatus::MovingGlobalRepostoryTo(status.to_owned()));
205+
}
235206
}
236207
}
237208
if !repositories_locally_removed.is_empty() {

coffee_lib/src/url.rs

+4
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ impl URL {
5757
repo_name: get_repo_name_from_url(url),
5858
}
5959
}
60+
61+
pub fn set_coffee_path(&mut self, path: &str) {
62+
self.path_string = format!("{path}/{}", self.repo_name);
63+
}
6064
}
6165

6266
impl fmt::Display for URL {

coffee_lib/src/utils.rs

+33-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::macros::error;
2-
use std::path::Path;
2+
use std::path::{Path, PathBuf};
33

44
use tokio::fs;
55

@@ -21,6 +21,7 @@ pub fn get_plugin_info_from_path(path: &Path) -> Result<(String, String), Coffee
2121
}
2222

2323
pub async fn check_dir_or_make_if_missing(path: String) -> Result<(), CoffeeError> {
24+
log::trace!("check_dir_or_make_if_missing: `{path}`");
2425
if !Path::exists(Path::new(&path.to_owned())) {
2526
fs::create_dir(path.clone()).await?;
2627
log::debug!("created dir {path}");
@@ -29,13 +30,43 @@ pub async fn check_dir_or_make_if_missing(path: String) -> Result<(), CoffeeErro
2930
}
3031

3132
pub async fn copy_dir_if_exist(origin: &str, destination: &str) -> Result<(), CoffeeError> {
33+
log::trace!("copy_dir_if_exist: from: `{origin}` to `{destination}`");
3234
if Path::exists(Path::new(&origin)) {
33-
fs::copy(origin, destination).await?;
35+
copy_dir_recursive(origin.to_owned(), destination.to_owned()).await?;
3436
log::debug!("copying dir from {origin} to {destination}");
3537
}
3638
Ok(())
3739
}
3840

41+
async fn copy_dir_recursive(source: String, destination: String) -> Result<(), CoffeeError> {
42+
async fn inner_copy_dir_recursive(
43+
source: PathBuf,
44+
destination: PathBuf,
45+
) -> Result<(), CoffeeError> {
46+
check_dir_or_make_if_missing(destination.to_string_lossy().to_string()).await?;
47+
48+
let mut entries = fs::read_dir(source).await?;
49+
while let Some(entry) = entries.next_entry().await? {
50+
let file_type = entry.file_type().await?;
51+
let dest_path = destination.join(entry.file_name());
52+
log::debug!("copy entry {:?} in {:?}", entry, dest_path);
53+
if file_type.is_dir() {
54+
// Here we use Box::pin to allow recursion
55+
let fut = inner_copy_dir_recursive(entry.path(), dest_path);
56+
Box::pin(fut).await?;
57+
} else if file_type.is_file() {
58+
fs::copy(entry.path(), &dest_path).await?;
59+
}
60+
}
61+
62+
Ok(())
63+
}
64+
let source = Path::new(&source);
65+
let destination = Path::new(&destination);
66+
log::info!("{:?} - {:?}", source, destination);
67+
inner_copy_dir_recursive(source.to_path_buf(), destination.to_path_buf()).await
68+
}
69+
3970
pub async fn rm_dir_if_exist(origin: &str) -> Result<(), CoffeeError> {
4071
if Path::exists(Path::new(&origin)) {
4172
fs::remove_dir_all(origin).await?;

rust-toolchain

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.75
1+
1.77

0 commit comments

Comments
 (0)