From b79eeb91cfdc3a122e6693d503117f68ff1fb44e Mon Sep 17 00:00:00 2001 From: Mitchell Berendhuysen <45570310+MitchellBerend@users.noreply.github.com> Date: Thu, 15 Sep 2022 09:28:25 +0200 Subject: [PATCH] [#73] Adds build.rs to generate a default config template with tool version (#78) Resolves #73 This adds a build script that generates the `src/config/template.rs` file. It is done this way because there is no access to version information after compile time. It uses the `CARGO_PKG_VERSION` environment variable made available for cargo after running the command `cargo build`. ### Additional tasks tasks following #73 --- - [x] Automatically embedding version. As discussed in this issue. - [x] Prefill all the tools supported by tool-sync. This requires converting the big match to a BTreeMap. - [x] Add comments around tool tables. To make sure that the code inside the comments stays up-to-date and is parsed by tool-sync itself. General tasks --- - [ ] Documentation for changes provided/changed - [x] Tests added Co-authored-by: Dmitrii Kovanikov --- .github/workflows/ci.yml | 11 ++++++ src/config/template.rs | 30 +++++++++++---- src/config/toml.rs | 57 ++++++++++++++++++++++++++++ src/lib.rs | 2 +- src/sync.rs | 2 +- src/sync/db.rs | 78 ++++++++++++++++++++++++++------------- tests/default-config.toml | 39 ++++++++++++++++++++ 7 files changed, 183 insertions(+), 36 deletions(-) create mode 100644 tests/default-config.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36adbf2..6dadbf9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,6 +89,17 @@ jobs: # disabled because of: https://github.com/alexcrichton/tar-rs/issues/295 # if [[ ! -x $SYNC_DIR/tokei ]]; then echo "error on: tokei"; false; fi + - if: matrix.os != 'windows-latest' + name: "Characterization test: [unix] [default-config]" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + cargo run -- default-config > tools.toml + + diff tools.toml tests/default-config.toml + + if [[ $? == 1 ]]; then diff tools.toml tests/default-config.toml; false; fi + - if: matrix.os == 'windows-latest' name: "Integration test: [windows] [full-database]" env: diff --git a/src/config/template.rs b/src/config/template.rs index c966172..c9b23fe 100644 --- a/src/config/template.rs +++ b/src/config/template.rs @@ -1,6 +1,22 @@ /// This file only holds the template that is used to generate a default .tools.toml. +use std::fmt::Write; -pub const CONFIG_TEMPLATE: &str = r##"# # tool-sync default configuration file +use crate::sync::db::build_db; + +pub fn config_template() -> String { + let mut tools: String = String::new(); + for tool in build_db().keys().cloned().collect::>() { + if let Err(e) = writeln!(tools, "# [{}]", tool) { + crate::err::abort_suggest_issue(&format!("{}", e)); + }; + } + // adding another hash to fil a new line before the next block + tools.push('#'); + + format!( + r###"# This config file was generated for version {version} +# +# # tool-sync default configuration file # https://github.com/chshersh/tool-sync # This file was automatically generated by tool-sync ##################################################### @@ -11,11 +27,7 @@ pub const CONFIG_TEMPLATE: &str = r##"# # tool-sync default configuration file # tool-sync provides native support for some of the tools without the need to configure them # Uncomment the tools you want to have them # -# [bat] -# [difftastic] -# [fd] -# [ripgrep] -# +{tools} # To add configuration for other tools these are the config options: # [ripgrep] # owner = "BurntSushi" @@ -34,5 +46,7 @@ pub const CONFIG_TEMPLATE: &str = r##"# # tool-sync default configuration file # asset_name.macos = "apple-darwin" # # uncomment if you want to install on Windows as well -# asset_name.windows = "x86_64-pc-windows-msvc" -"##; +# asset_name.windows = "x86_64-pc-windows-msvc""###, + version = env!("CARGO_PKG_VERSION"), + ) +} diff --git a/src/config/toml.rs b/src/config/toml.rs index 41aa369..cbbd35f 100644 --- a/src/config/toml.rs +++ b/src/config/toml.rs @@ -103,6 +103,63 @@ fn str_by_key(table: &Map, key: &str) -> Option { mod tests { use super::*; + #[test] + fn test_toml_error_display_io() { + let toml_error = TomlError::IO(String::from("some file error!")); + + assert_eq!( + String::from("[IO Error] some file error!"), + toml_error.display() + ); + } + + #[test] + fn test_toml_error_display_parse() { + let broken_toml_str: String = "broken toml".into(); + match parse_string(&broken_toml_str) { + Err(error) => { + assert_eq!( + String::from( + "[Parsing Error] expected an equals, found an identifier at line 1 column 8" + ), + error.display() + ); + } + Ok(_) => unreachable!(), + }; + } + + #[test] + fn test_toml_error_display_decode() { + let toml_error = TomlError::Decode; + assert_eq!(String::from("[Decode Error]"), toml_error.display()); + } + + #[test] + fn test_parse_file_correct_output() { + let result = std::panic::catch_unwind(|| { + let test_config_path = PathBuf::from("tests/full-database.toml"); + parse_file(&test_config_path).expect("This should not fail") + }); + + if let Ok(config) = result { + assert_eq!(String::from("full-database"), config.store_directory); + }; + } + + #[test] + fn test_parse_file_error() { + let test_config_path = PathBuf::from("src/main.rs"); + match parse_file(&test_config_path) { + Ok(_) => { + assert!(false, "Unexpected succces") + } + Err(_) => { + assert!(true, "Exepected a parsing error") + } + }; + } + #[test] fn empty_file() { let toml = ""; diff --git a/src/lib.rs b/src/lib.rs index 1626c33..e0a1134 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,5 +53,5 @@ fn resolve_config_path(config_path: Option) -> PathBuf { } fn generate_config() { - println!("{}", template::CONFIG_TEMPLATE); + println!("{}", template::config_template()); } diff --git a/src/sync.rs b/src/sync.rs index 2b30de0..b3b5aa0 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,6 +1,6 @@ mod archive; mod configure; -mod db; +pub mod db; mod download; mod install; mod prefetch; diff --git a/src/sync/db.rs b/src/sync/db.rs index b805674..231202c 100644 --- a/src/sync/db.rs +++ b/src/sync/db.rs @@ -1,10 +1,20 @@ +use std::collections::BTreeMap; + use crate::model::asset_name::AssetName; use crate::model::tool::{ToolInfo, ToolInfoTag}; /// Get info about known tools from a hardcoded database pub fn lookup_tool(tool_name: &str) -> Option { - match tool_name { - "bat" => Some(ToolInfo { + let mut known_db = build_db(); + known_db.remove(tool_name) +} + +pub fn build_db() -> BTreeMap { + let mut tools: BTreeMap = BTreeMap::new(); + + tools.insert( + "bat".into(), + ToolInfo { owner: "sharkdp".to_string(), repo: "bat".to_string(), exe_name: "bat".to_string(), @@ -14,8 +24,11 @@ pub fn lookup_tool(tool_name: &str) -> Option { windows: Some("x86_64-pc-windows-msvc".to_string()), }, tag: ToolInfoTag::Latest, - }), - "difftastic" => Some(ToolInfo { + }, + ); + tools.insert( + "difftastic".into(), + ToolInfo { owner: "Wilfred".to_string(), repo: "difftastic".to_string(), exe_name: "difft".to_string(), @@ -25,8 +38,11 @@ pub fn lookup_tool(tool_name: &str) -> Option { windows: Some("x86_64-pc-windows-msvc".to_string()), }, tag: ToolInfoTag::Latest, - }), - "exa" => Some(ToolInfo { + }, + ); + tools.insert( + "exa".into(), + ToolInfo { owner: "ogham".to_string(), repo: "exa".to_string(), exe_name: "exa".to_string(), @@ -36,8 +52,11 @@ pub fn lookup_tool(tool_name: &str) -> Option { windows: None, }, tag: ToolInfoTag::Latest, - }), - "fd" => Some(ToolInfo { + }, + ); + tools.insert( + "fd".into(), + ToolInfo { owner: "sharkdp".to_string(), repo: "fd".to_string(), exe_name: "fd".to_string(), @@ -47,8 +66,11 @@ pub fn lookup_tool(tool_name: &str) -> Option { windows: Some("x86_64-pc-windows-msvc".to_string()), }, tag: ToolInfoTag::Latest, - }), - "ripgrep" => Some(ToolInfo { + }, + ); + tools.insert( + "ripgrep".into(), + ToolInfo { owner: "BurntSushi".to_string(), repo: "ripgrep".to_string(), exe_name: "rg".to_string(), @@ -58,8 +80,11 @@ pub fn lookup_tool(tool_name: &str) -> Option { windows: Some("x86_64-pc-windows-msvc".to_string()), }, tag: ToolInfoTag::Latest, - }), - "tool-sync" => Some(ToolInfo { + }, + ); + tools.insert( + "tool-sync".into(), + ToolInfo { owner: "chshersh".to_string(), repo: "tool-sync".to_string(), exe_name: "tool".to_string(), @@ -69,18 +94,19 @@ pub fn lookup_tool(tool_name: &str) -> Option { windows: Some("x86_64-pc-windows-msvc".to_string()), }, tag: ToolInfoTag::Latest, - }), - // "tokei" => Some(ToolInfo { - // owner: "XAMPPRocky".to_string(), - // repo: "tokei".to_string(), - // exe_name: "tokei".to_string(), - // asset_name: AssetName { - // linux: Some("x86_64-unknown-linux-musl".to_string()), - // macos: Some("apple-darwin".to_string()), - // windows: Some("x86_64-pc-windows-msvc".to_string()), - // } - // tag: ToolInfoTag::Latest, - // }), - _ => None, - } + }, + ); + // tools.insert("tokei", ToolInfo { + // owner: "XAMPPRocky".to_string(), + // repo: "tokei".to_string(), + // exe_name: "tokei".to_string(), + // asset_name: AssetName { + // linux: Some("x86_64-unknown-linux-musl".to_string()), + // macos: Some("apple-darwin".to_string()), + // windows: Some("x86_64-pc-windows-msvc".to_string()), + // } + // tag: ToolInfoTag::Latest, + // })); + // + tools } diff --git a/tests/default-config.toml b/tests/default-config.toml new file mode 100644 index 0000000..0b3fbe5 --- /dev/null +++ b/tests/default-config.toml @@ -0,0 +1,39 @@ +# This config file was generated for version 0.1.0 +# +# # tool-sync default configuration file +# https://github.com/chshersh/tool-sync +# This file was automatically generated by tool-sync +##################################################### +# +# +# store_directory = "$HOME/.local/bin" +# +# tool-sync provides native support for some of the tools without the need to configure them +# Uncomment the tools you want to have them +# +# [bat] +# [difftastic] +# [exa] +# [fd] +# [ripgrep] +# [tool-sync] +# +# To add configuration for other tools these are the config options: +# [ripgrep] +# owner = "BurntSushi" +# repo = "ripgrep" +# exe_name = "rg" +# +# # Uncomment to download a specific version or tag. +# # Without this tag latest will be used +# # tag = "13.0.0" +# +# +# Asset name to download on linux OSes +# asset_name.linux = "x86_64-unknown-linux-musl" +# +# uncomment if you want to install on macOS as well +# asset_name.macos = "apple-darwin" +# +# uncomment if you want to install on Windows as well +# asset_name.windows = "x86_64-pc-windows-msvc"