diff --git a/Cargo.toml b/Cargo.toml index 6c6e246..c929043 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ tokio = { version = "1.41", features = ["full"] } #tracing-subscriber = "0.3" [dev-dependencies] -#assert2 = "0.3" +assert2 = "0.3" mutants = "0.0" #pretty_assertions = "1.4" -#test-log = { version = "0.2", features = ["trace"] } +test-log = { version = "0.2", features = ["trace"] } diff --git a/src/default-config.toml b/src/default-config.toml new file mode 100644 index 0000000..3b73a8f --- /dev/null +++ b/src/default-config.toml @@ -0,0 +1,11 @@ +[trello] +api_key = "" +api_secret = "" +user = "" +board_name = "" + +[nextcloud] +username = "" +password = "" +hostname = "" +board_id = 1 diff --git a/src/init.rs b/src/init.rs new file mode 100644 index 0000000..418cb0e --- /dev/null +++ b/src/init.rs @@ -0,0 +1,25 @@ +// +use std::collections::HashMap; + +use color_eyre::eyre::{eyre, Result}; + +use crate::{f, p, s, template, Ctx, NAME}; + +pub(crate) fn run(ctx: &Ctx) -> Result<()> { + let path = ctx.fs.base().join(f!("{NAME}.toml")); + let file = ctx.fs.file(&path); + + if file.exists()? { + Err(eyre!("File already exists - not overwriting: {file}")) + } else { + file.write(include_str!("default-config.toml"))?; + p!( + "{}", + template::expand( + include_str!("post-init-instructions.txt"), + HashMap::from([("NAME", NAME), ("file", s!(file).as_str())]) + ) + ); + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 6ed90a4..b06130f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,12 @@ use std::path::PathBuf; use clap::Parser; use kxio::{fs::FileSystem, net::Net}; +mod init; mod macros; +mod template; + +#[cfg(test)] +mod tests; pub const NAME: &str = "trello-to-deck"; @@ -36,14 +41,15 @@ impl Default for Ctx { } #[cfg_attr(test, mutants::skip)] -pub async fn run(_ctx: Ctx) -> color_eyre::Result<()> { +pub async fn run(ctx: Ctx) -> color_eyre::Result<()> { color_eyre::install()?; let commands = Commands::parse(); match commands.command { - Command::Init => todo!("init"), + Command::Init => init::run(&ctx)?, Command::Check => todo!("check"), Command::Import => todo!("import"), }; - // Ok(()) + + Ok(()) } diff --git a/src/post-init-instructions.txt b/src/post-init-instructions.txt new file mode 100644 index 0000000..41c3676 --- /dev/null +++ b/src/post-init-instructions.txt @@ -0,0 +1,10 @@ +The default configuration has been written to {file}. + +Next: + +- Edit the file to; + - add credentials for Trello and NextCloud + - add details of the Trello Board and Lists that should be imported + - add details of the NextCloud Deck to import to +- Verify the file: {NAME} check +- When happy: {NAME} import diff --git a/src/template.rs b/src/template.rs new file mode 100644 index 0000000..48ecc1a --- /dev/null +++ b/src/template.rs @@ -0,0 +1,10 @@ +// +use std::collections::HashMap; + +pub(crate) fn expand(template: &str, params: HashMap<&str, &str>) -> String { + let mut result = template.to_string(); + for (key, value) in params { + result = result.replace(&format!("{{{key}}}"), value); + } + result +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs new file mode 100644 index 0000000..f1a8183 --- /dev/null +++ b/src/tests/mod.rs @@ -0,0 +1,90 @@ +// + +// type TestResult = Result<(), Box>; + +use assert2::let_assert; + +mod init { + + use test_log::test; + + use crate::{f, init::run, NAME}; + + use super::given; + use super::*; + + #[test] + fn when_file_does_not_exist_should_create() { + //given + let fs = given::a_filesystem(); + let ctx = given::a_context(fs.as_real(), given::a_network().into()); + + //when + let_assert!(Ok(_) = run(&ctx)); + + //then + let path = ctx.fs.base().join(f!("{NAME}.toml")); + let file = ctx.fs.file(&path); + let contents = file.reader().expect("read file").to_string(); + assert_eq!(contents, include_str!("../default-config.toml")); + } + + #[test] + fn when_file_exists_should_err() { + //given + let fs = given::a_filesystem(); + let path = fs.base().join(f!("{NAME}.toml")); + let file = fs.file(&path); + file.write("").expect("create file"); + + let ctx = given::a_context(fs.as_real(), given::a_network().into()); + //when + let_assert!(Err(err) = run(&ctx)); + + //then + assert!(err + .to_string() + .contains("File already exists - not overwriting")); + } +} + +mod template { + + use std::collections::HashMap; + + use crate::template; + + #[test] + fn expand_should_substitute_values() { + //given + let template = "pre{param1}mid{param2}post"; + let params = HashMap::from([("param1", "-v1-"), ("param2", "-v2-")]); + + //when + let result = template::expand(template, params); + + //then + assert_eq!(result, "pre-v1-mid-v2-post"); + } +} + +mod given { + use kxio::{ + fs::{FileSystem, TempFileSystem}, + net::{MockNet, Net}, + }; + + use crate::Ctx; + + pub fn a_context(fs: FileSystem, net: Net) -> Ctx { + Ctx { fs, net } + } + + pub fn a_filesystem() -> TempFileSystem { + kxio::fs::temp().expect("temp fs") + } + + pub fn a_network() -> MockNet { + kxio::net::mock() + } +}