diff --git a/src/new/templates/test/chat/tests.toml b/src/new/templates/test/chat/tests.toml index c08a7ee4..4dbc9824 100644 --- a/src/new/templates/test/chat/tests.toml +++ b/src/new/templates/test/chat/tests.toml @@ -6,7 +6,7 @@ runtime_build_release = false [[tests]] setup_package_paths = [".."] test_packages = [ - { path = "{package_name}_test", grant_capabilities = ["{package_name}:{package_name}:template.os"] }, + { path = "{package_name}_test", grant_capabilities = ["{package_name}:{package_name}:{publisher}"] }, ] timeout_secs = 5 fakechain_router = 8545 diff --git a/src/new/templates/test/chat/{package_name}_test/{package_name}_test/src/lib.rs b/src/new/templates/test/chat/{package_name}_test/{package_name}_test/src/lib.rs index 531bba95..c0637710 100644 --- a/src/new/templates/test/chat/{package_name}_test/{package_name}_test/src/lib.rs +++ b/src/new/templates/test/chat/{package_name}_test/{package_name}_test/src/lib.rs @@ -1,7 +1,7 @@ use crate::kinode::process::{package_name}::{ChatMessage, Request as ChatRequest, Response as ChatResponse, SendRequest}; use crate::kinode::process::tester::{Request as TesterRequest, Response as TesterResponse, RunRequest, FailResponse}; -use kinode_process_lib::{await_message, call_init, print_to_terminal, println, Address, Message, ProcessId, Request, Response}; +use kinode_process_lib::{await_message, call_init, print_to_terminal, println, Address, ProcessId, Request, Response}; mod tester_lib; @@ -15,80 +15,79 @@ wit_bindgen::generate!({ fn handle_message (our: &Address) -> anyhow::Result<()> { let message = await_message().unwrap(); - match message { - Message::Response { .. } => { unimplemented!() }, - Message::Request { ref source, ref body, .. } => { - if our.node != source.node { - return Err(anyhow::anyhow!( - "rejecting foreign Message from {:?}", - source, - )); - } - match serde_json::from_slice(body)? { - TesterRequest::Run(RunRequest { input_node_names: node_names, .. }) => { - print_to_terminal(0, "{package_name}_test: a"); - assert!(node_names.len() >= 2); - if our.node != node_names[0] { - // we are not master node: return - Response::new() - .body(TesterResponse::Run(Ok(()))) - .send() - .unwrap(); - return Ok(()); - } + if !message.is_request() { + unimplemented!(); + } + let source = message.source(); + if our.node != source.node { + return Err(anyhow::anyhow!( + "rejecting foreign Message from {:?}", + source, + )); + } + let TesterRequest::Run(RunRequest { + input_node_names: node_names, + .. + }) = message.body().try_into()?; + print_to_terminal(0, "{package_name}_test: a"); + assert!(node_names.len() >= 2); + if our.node != node_names[0] { + // we are not master node: return + Response::new() + .body(TesterResponse::Run(Ok(()))) + .send() + .unwrap(); + return Ok(()); + } - // we are master node + // we are master node - let our_chat_address = Address { - node: our.node.clone(), - process: ProcessId::new(Some("{package_name}"), "{package_name}", "{publisher}"), - }; - let their_chat_address = Address { - node: node_names[1].clone(), - process: ProcessId::new(Some("{package_name}"), "{package_name}", "{publisher}"), - }; + let our_chat_address = Address { + node: our.node.clone(), + process: ProcessId::new(Some("{package_name}"), "{package_name}", "{publisher}"), + }; + let their_chat_address = Address { + node: node_names[1].clone(), + process: ProcessId::new(Some("{package_name}"), "{package_name}", "{publisher}"), + }; - // Send - print_to_terminal(0, "{package_name}_test: b"); - let message: String = "hello".into(); - let _ = Request::new() - .target(our_chat_address.clone()) - .body(ChatRequest::Send(SendRequest { - target: node_names[1].clone(), - message: message.clone(), - })) - .send_and_await_response(15)?.unwrap(); + // Send + print_to_terminal(0, "{package_name}_test: b"); + let message: String = "hello".into(); + let _ = Request::new() + .target(our_chat_address.clone()) + .body(ChatRequest::Send(SendRequest { + target: node_names[1].clone(), + message: message.clone(), + })) + .send_and_await_response(15)?.unwrap(); - // Get history from receiver & test - print_to_terminal(0, "{package_name}_test: c"); - let response = Request::new() - .target(their_chat_address.clone()) - .body(ChatRequest::History(our.node.clone())) - .send_and_await_response(15)?.unwrap(); - if response.is_request() { panic!("") }; - let ChatResponse::History(messages) = response.body().try_into()? else { - fail!("{package_name}_test"); - }; - let expected_messages = vec![ChatMessage { - author: our.node.clone(), - content: message, - }]; + // Get history from receiver & test + print_to_terminal(0, "{package_name}_test: c"); + let response = Request::new() + .target(their_chat_address.clone()) + .body(ChatRequest::History(our.node.clone())) + .send_and_await_response(15)?.unwrap(); + if response.is_request() { fail!("{package_name}_test"); }; + let ChatResponse::History(messages) = response.body().try_into()? else { + fail!("{package_name}_test"); + }; + let expected_messages = vec![ChatMessage { + author: our.node.clone(), + content: message, + }]; - if messages != expected_messages { - println!("{messages:?} != {expected_messages:?}"); - fail!("{package_name}_test"); - } + if messages != expected_messages { + println!("{messages:?} != {expected_messages:?}"); + fail!("{package_name}_test"); + } - Response::new() - .body(TesterResponse::Run(Ok(()))) - .send() - .unwrap(); - }, - } + Response::new() + .body(TesterResponse::Run(Ok(()))) + .send() + .unwrap(); - Ok(()) - }, - } + Ok(()) } call_init!(init); diff --git a/src/new/templates/test/echo/tests.toml b/src/new/templates/test/echo/tests.toml new file mode 100644 index 00000000..e1172f01 --- /dev/null +++ b/src/new/templates/test/echo/tests.toml @@ -0,0 +1,18 @@ +runtime = { FetchVersion = "latest" } +# runtime = { RepoPath = "~/git/kinode" } +runtime_build_release = false + + +[[tests]] +setup_package_paths = [".."] +test_packages = [ + { path = "{package_name}_test", grant_capabilities = ["{package_name}:{package_name}:{publisher}"] }, +] +timeout_secs = 5 +fakechain_router = 8545 + +[[tests.nodes]] +port = 8080 +home = "home/first" +fake_node_name = "first.dev" +runtime_verbosity = 0 diff --git a/src/new/templates/test/echo/{package_name}_test/Cargo.toml_ b/src/new/templates/test/echo/{package_name}_test/Cargo.toml_ new file mode 100644 index 00000000..6c797c34 --- /dev/null +++ b/src/new/templates/test/echo/{package_name}_test/Cargo.toml_ @@ -0,0 +1,10 @@ +[workspace] +resolver = "2" +members = [ + "{package_name}_test", +] + +[profile.release] +panic = "abort" +opt-level = "s" +lto = true diff --git a/src/new/templates/test/echo/{package_name}_test/api/tester:sys-v0.wit b/src/new/templates/test/echo/{package_name}_test/api/tester:sys-v0.wit new file mode 100644 index 00000000..7fe0574b --- /dev/null +++ b/src/new/templates/test/echo/{package_name}_test/api/tester:sys-v0.wit @@ -0,0 +1,27 @@ +interface tester { + variant request { + run(run-request), + } + + variant response { + run(result<_, fail-response>) + } + + record run-request { + input-node-names: list, + test-names: list, + test-timeout: u64, + } + + record fail-response { + test: string, + file: string, + line: u32, + column: u32, + } +} + +world tester-sys-v0 { + import tester; + include process-v0; +} diff --git a/src/new/templates/test/echo/{package_name}_test/metadata.json b/src/new/templates/test/echo/{package_name}_test/metadata.json new file mode 100644 index 00000000..cea44761 --- /dev/null +++ b/src/new/templates/test/echo/{package_name}_test/metadata.json @@ -0,0 +1,17 @@ +{ + "name": "{package_name} Test", + "description": "A test for {package_name}.", + "image": "", + "properties": { + "package_name": "{package_name}_test", + "current_version": "0.1.0", + "publisher": "{publisher}", + "mirrors": [], + "code_hashes": { + "0.1.0": "" + }, + "wit_version": 0 + }, + "external_url": "", + "animation_url": "" +} diff --git a/src/new/templates/test/echo/{package_name}_test/pkg/manifest.json b/src/new/templates/test/echo/{package_name}_test/pkg/manifest.json new file mode 100644 index 00000000..61ef3388 --- /dev/null +++ b/src/new/templates/test/echo/{package_name}_test/pkg/manifest.json @@ -0,0 +1,13 @@ +[ + { + "process_name": "{package_name}_test", + "process_wasm_path": "/{package_name}_test.wasm", + "on_exit": "Restart", + "request_networking": false, + "request_capabilities": [], + "grant_capabilities": [ + "{package_name}:{package_name}:{publisher}" + ], + "public": true + } +] diff --git a/src/new/templates/test/echo/{package_name}_test/{package_name}_test/Cargo.toml_ b/src/new/templates/test/echo/{package_name}_test/{package_name}_test/Cargo.toml_ new file mode 100644 index 00000000..402919e0 --- /dev/null +++ b/src/new/templates/test/echo/{package_name}_test/{package_name}_test/Cargo.toml_ @@ -0,0 +1,21 @@ +[package] +name = "{package_name}_test" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0" +bincode = "1.3" +kinode_process_lib = { git = "https://github.com/kinode-dao/process_lib", rev = "b492f3b" } +process_macros = { git = "https://github.com/kinode-dao/process_macros", rev = "626e501" } +rmp-serde = "1.1" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +thiserror = "1.0" +wit-bindgen = "0.24.0" + +[lib] +crate-type = ["cdylib"] + +[package.metadata.component] +package = "kinode:process" diff --git a/src/new/templates/test/echo/{package_name}_test/{package_name}_test/src/lib.rs b/src/new/templates/test/echo/{package_name}_test/{package_name}_test/src/lib.rs new file mode 100644 index 00000000..7ef21508 --- /dev/null +++ b/src/new/templates/test/echo/{package_name}_test/{package_name}_test/src/lib.rs @@ -0,0 +1,75 @@ +use crate::kinode::process::tester::{Request as TesterRequest, Response as TesterResponse, RunRequest, FailResponse}; + +use kinode_process_lib::{await_message, call_init, print_to_terminal, println, Address, ProcessId, Request, Response}; + +mod tester_lib; + +wit_bindgen::generate!({ + path: "target/wit", + world: "tester-sys-v0", + generate_unused_types: true, + additional_derives: [PartialEq, serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], +}); + +fn handle_message (our: &Address) -> anyhow::Result<()> { + let message = await_message().unwrap(); + + if !message.is_request() { + unimplemented!(); + } + let source = message.source(); + if our.node != source.node { + return Err(anyhow::anyhow!( + "rejecting foreign Message from {:?}", + source, + )); + } + let TesterRequest::Run(RunRequest { + input_node_names: node_names, + .. + }) = message.body().try_into()?; + print_to_terminal(0, "{package_name}_test: a"); + assert!(node_names.len() == 1); + + let our_echo_address = Address { + node: our.node.clone(), + process: ProcessId::new(Some("{package_name}"), "{package_name}", "{publisher}"), + }; + + // Send + print_to_terminal(0, "{package_name}_test: b"); + let message: String = "hello".into(); + let response = Request::new() + .target(our_echo_address) + .body(serde_json::to_vec("test")?) + .send_and_await_response(15)?.unwrap(); + if response.is_request() { fail!("{package_name}_test"); }; + if serde_json::json!("Ack") != serde_json::from_slice::( + response.body() + ) { + fail!("{package_name}_test"); + }; + + Response::new() + .body(TesterResponse::Run(Ok(()))) + .send() + .unwrap(); + + Ok(()) +} + +call_init!(init); +fn init(our: Address) { + print_to_terminal(0, "begin"); + + loop { + match handle_message(&our) { + Ok(()) => {}, + Err(e) => { + print_to_terminal(0, format!("{package_name}_test: error: {e:?}").as_str()); + + fail!("{package_name}_test"); + }, + }; + } +} diff --git a/src/new/templates/test/echo/{package_name}_test/{package_name}_test/src/tester_lib.rs b/src/new/templates/test/echo/{package_name}_test/{package_name}_test/src/tester_lib.rs new file mode 100644 index 00000000..9b367d36 --- /dev/null +++ b/src/new/templates/test/echo/{package_name}_test/{package_name}_test/src/tester_lib.rs @@ -0,0 +1,31 @@ +use crate::kinode::process::tester::{ + Response as TesterResponse, FailResponse, +}; + +#[macro_export] +macro_rules! fail { + ($test:expr) => { + Response::new() + .body(TesterResponse::Run(Err(FailResponse { + test: $test.into(), + file: file!().into(), + line: line!(), + column: column!(), + }))) + .send() + .unwrap(); + panic!("") + }; + ($test:expr, $file:expr, $line:expr, $column:expr) => { + Response::new() + .body(TesterResponse::Run(Err(FailResponse { + test: $test.into(), + file: $file.into(), + line: $line, + column: $column, + }))) + .send() + .unwrap(); + panic!("") + }; +} diff --git a/src/new/templates/test/fibonacci/tests.toml b/src/new/templates/test/fibonacci/tests.toml new file mode 100644 index 00000000..e1172f01 --- /dev/null +++ b/src/new/templates/test/fibonacci/tests.toml @@ -0,0 +1,18 @@ +runtime = { FetchVersion = "latest" } +# runtime = { RepoPath = "~/git/kinode" } +runtime_build_release = false + + +[[tests]] +setup_package_paths = [".."] +test_packages = [ + { path = "{package_name}_test", grant_capabilities = ["{package_name}:{package_name}:{publisher}"] }, +] +timeout_secs = 5 +fakechain_router = 8545 + +[[tests.nodes]] +port = 8080 +home = "home/first" +fake_node_name = "first.dev" +runtime_verbosity = 0 diff --git a/src/new/templates/test/fibonacci/{package_name}_test/Cargo.toml_ b/src/new/templates/test/fibonacci/{package_name}_test/Cargo.toml_ new file mode 100644 index 00000000..6c797c34 --- /dev/null +++ b/src/new/templates/test/fibonacci/{package_name}_test/Cargo.toml_ @@ -0,0 +1,10 @@ +[workspace] +resolver = "2" +members = [ + "{package_name}_test", +] + +[profile.release] +panic = "abort" +opt-level = "s" +lto = true diff --git a/src/new/templates/test/fibonacci/{package_name}_test/api/tester:sys-v0.wit b/src/new/templates/test/fibonacci/{package_name}_test/api/tester:sys-v0.wit new file mode 100644 index 00000000..7fe0574b --- /dev/null +++ b/src/new/templates/test/fibonacci/{package_name}_test/api/tester:sys-v0.wit @@ -0,0 +1,27 @@ +interface tester { + variant request { + run(run-request), + } + + variant response { + run(result<_, fail-response>) + } + + record run-request { + input-node-names: list, + test-names: list, + test-timeout: u64, + } + + record fail-response { + test: string, + file: string, + line: u32, + column: u32, + } +} + +world tester-sys-v0 { + import tester; + include process-v0; +} diff --git a/src/new/templates/test/fibonacci/{package_name}_test/api/{package_name}:{publisher}-v0.wit b/src/new/templates/test/fibonacci/{package_name}_test/api/{package_name}:{publisher}-v0.wit new file mode 100644 index 00000000..73615f3f --- /dev/null +++ b/src/new/templates/test/fibonacci/{package_name}_test/api/{package_name}:{publisher}-v0.wit @@ -0,0 +1,16 @@ +interface {package_name_kebab} { + variant request { + number(u32), + numbers(tuple), + } + + variant response { + number(u64), + numbers(tuple), + } +} + +world {package_name_kebab}-{publisher_dotted_kebab}-v0 { + import {package_name_kebab}; + include process-v0; +} diff --git a/src/new/templates/test/fibonacci/{package_name}_test/api/{package_name}_test:{publisher}-v0.wit b/src/new/templates/test/fibonacci/{package_name}_test/api/{package_name}_test:{publisher}-v0.wit new file mode 100644 index 00000000..79c71980 --- /dev/null +++ b/src/new/templates/test/fibonacci/{package_name}_test/api/{package_name}_test:{publisher}-v0.wit @@ -0,0 +1,5 @@ +world {package_name_kebab}-test-{publisher_dotted_kebab}-v0 { + import {package_name_kebab}; + import tester; + include process-v0; +} diff --git a/src/new/templates/test/fibonacci/{package_name}_test/metadata.json b/src/new/templates/test/fibonacci/{package_name}_test/metadata.json new file mode 100644 index 00000000..cea44761 --- /dev/null +++ b/src/new/templates/test/fibonacci/{package_name}_test/metadata.json @@ -0,0 +1,17 @@ +{ + "name": "{package_name} Test", + "description": "A test for {package_name}.", + "image": "", + "properties": { + "package_name": "{package_name}_test", + "current_version": "0.1.0", + "publisher": "{publisher}", + "mirrors": [], + "code_hashes": { + "0.1.0": "" + }, + "wit_version": 0 + }, + "external_url": "", + "animation_url": "" +} diff --git a/src/new/templates/test/fibonacci/{package_name}_test/pkg/manifest.json b/src/new/templates/test/fibonacci/{package_name}_test/pkg/manifest.json new file mode 100644 index 00000000..61ef3388 --- /dev/null +++ b/src/new/templates/test/fibonacci/{package_name}_test/pkg/manifest.json @@ -0,0 +1,13 @@ +[ + { + "process_name": "{package_name}_test", + "process_wasm_path": "/{package_name}_test.wasm", + "on_exit": "Restart", + "request_networking": false, + "request_capabilities": [], + "grant_capabilities": [ + "{package_name}:{package_name}:{publisher}" + ], + "public": true + } +] diff --git a/src/new/templates/test/fibonacci/{package_name}_test/{package_name}_test/Cargo.toml_ b/src/new/templates/test/fibonacci/{package_name}_test/{package_name}_test/Cargo.toml_ new file mode 100644 index 00000000..402919e0 --- /dev/null +++ b/src/new/templates/test/fibonacci/{package_name}_test/{package_name}_test/Cargo.toml_ @@ -0,0 +1,21 @@ +[package] +name = "{package_name}_test" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0" +bincode = "1.3" +kinode_process_lib = { git = "https://github.com/kinode-dao/process_lib", rev = "b492f3b" } +process_macros = { git = "https://github.com/kinode-dao/process_macros", rev = "626e501" } +rmp-serde = "1.1" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +thiserror = "1.0" +wit-bindgen = "0.24.0" + +[lib] +crate-type = ["cdylib"] + +[package.metadata.component] +package = "kinode:process" diff --git a/src/new/templates/test/fibonacci/{package_name}_test/{package_name}_test/src/lib.rs b/src/new/templates/test/fibonacci/{package_name}_test/{package_name}_test/src/lib.rs new file mode 100644 index 00000000..7e33be91 --- /dev/null +++ b/src/new/templates/test/fibonacci/{package_name}_test/{package_name}_test/src/lib.rs @@ -0,0 +1,104 @@ +use crate::kinode::process::{package_name}::{Request as FibRequest, Response as FibResponse}; +use crate::kinode::process::tester::{Request as TesterRequest, Response as TesterResponse, RunRequest, FailResponse}; + +use kinode_process_lib::{await_message, call_init, print_to_terminal, Address, ProcessId, Request, Response}; + +mod tester_lib; + +wit_bindgen::generate!({ + path: "target/wit", + world: "{package_name_kebab}-test-{publisher_dotted_kebab}-v0", + generate_unused_types: true, + additional_derives: [PartialEq, serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], +}); + +fn test_number(n: u32, address: &Address) -> anyhow::Result { + let response = Request::new() + .target(address) + .body(FibRequest::Number(n)) + .send_and_await_response(15)?.unwrap(); + if response.is_request() { fail!("{package_name}_test"); }; + let FibResponse::Number(fib_number) = response.body().try_into()? else { + fail!("{package_name}_test"); + }; + Ok(fib_number) +} + +fn test_numbers(n: u32, n_trials: u32, address: &Address) -> anyhow::Result { + let response = Request::new() + .target(address) + .body(FibRequest::Numbers((n, n_trials))) + .send_and_await_response(15)?.unwrap(); + if response.is_request() { fail!("{package_name}_test"); }; + let FibResponse::Numbers((fib_number, _)) = response.body().try_into()? else { + fail!("{package_name}_test"); + }; + Ok(fib_number) +} + +fn handle_message (our: &Address) -> anyhow::Result<()> { + let message = await_message().unwrap(); + + if !message.is_request() { + unimplemented!(); + } + let source = message.source(); + if our.node != source.node { + return Err(anyhow::anyhow!( + "rejecting foreign Message from {:?}", + source, + )); + } + let TesterRequest::Run(RunRequest { + input_node_names: node_names, + .. + }) = message.body().try_into()?; + print_to_terminal(0, "{package_name}_test: a"); + assert!(node_names.len() == 1); + + let our_fib_address = Address { + node: our.node.clone(), + process: ProcessId::new(Some("{package_name}"), "{package_name}", "{publisher}"), + }; + + let numbers = vec![0, 1, 2, 5, 10, 20, 30, 47]; + let expecteds = vec![0, 1, 1, 5, 55, 6_765, 832_040, 2_971_215_073]; + for (number, expected) in numbers.iter().zip(expecteds.iter()) { + let result = test_number(number.clone(), &our_fib_address)?; + if &result != expected { + fail!("{package_name}_test"); + } + } + + let numbers = vec![0, 1, 2, 5, 10, 20, 30, 47]; + let expecteds = vec![0, 1, 1, 5, 55, 6_765, 832_040, 2_971_215_073]; + for (number, expected) in numbers.iter().zip(expecteds.iter()) { + let result = test_numbers(number.clone(), 5, &our_fib_address)?; + if &result != expected { + fail!("{package_name}_test"); + } + } + + Response::new() + .body(TesterResponse::Run(Ok(()))) + .send() + .unwrap(); + + Ok(()) +} + +call_init!(init); +fn init(our: Address) { + print_to_terminal(0, "begin"); + + loop { + match handle_message(&our) { + Ok(()) => {}, + Err(e) => { + print_to_terminal(0, format!("{package_name}_test: error: {e:?}").as_str()); + + fail!("{package_name}_test"); + }, + }; + } +} diff --git a/src/new/templates/test/fibonacci/{package_name}_test/{package_name}_test/src/tester_lib.rs b/src/new/templates/test/fibonacci/{package_name}_test/{package_name}_test/src/tester_lib.rs new file mode 100644 index 00000000..9b367d36 --- /dev/null +++ b/src/new/templates/test/fibonacci/{package_name}_test/{package_name}_test/src/tester_lib.rs @@ -0,0 +1,31 @@ +use crate::kinode::process::tester::{ + Response as TesterResponse, FailResponse, +}; + +#[macro_export] +macro_rules! fail { + ($test:expr) => { + Response::new() + .body(TesterResponse::Run(Err(FailResponse { + test: $test.into(), + file: file!().into(), + line: line!(), + column: column!(), + }))) + .send() + .unwrap(); + panic!("") + }; + ($test:expr, $file:expr, $line:expr, $column:expr) => { + Response::new() + .body(TesterResponse::Run(Err(FailResponse { + test: $test.into(), + file: $file.into(), + line: $line, + column: $column, + }))) + .send() + .unwrap(); + panic!("") + }; +} diff --git a/src/run_tests/mod.rs b/src/run_tests/mod.rs index 5da012d0..ebe435f6 100644 --- a/src/run_tests/mod.rs +++ b/src/run_tests/mod.rs @@ -457,8 +457,26 @@ async fn handle_test( pub async fn execute(config_path: &str) -> Result<()> { let detached = true; // TODO: to arg? - let config_content = fs::read_to_string(config_path)?; - let config = toml::from_str::(&config_content)?.expand_home_paths(); + let config_path = PathBuf::from(config_path); + if !config_path.exists() { + return Err(eyre!("given config path {config_path:?} does not exist")); + } + let config_path = if config_path.is_file() { + config_path + } else { + let config_path = config_path.join("test").join("tests.toml"); + if !config_path.exists() { + return Err(eyre!("given config path {config_path:?} does not exist")); + } + if config_path.is_file() { + config_path + } else { + return Err(eyre!("given config path {config_path:?} is not a file")); + } + }; + + let content = fs::read_to_string(&config_path)?; + let config = toml::from_str::(&content)?.expand_home_paths(); debug!("{:?}", config);