From f0941f8818acb3f1e0a4558d7f7dbd4facbe0e65 Mon Sep 17 00:00:00 2001 From: Hugo C <911307+hugocaillard@users.noreply.github.com> Date: Wed, 25 Oct 2023 19:58:42 +0200 Subject: [PATCH] refactor: improve global settings management (#1225) --- .../clarinet-cli/src/frontend/clarinetrc.rs | 53 ++++++++ components/clarinet-cli/src/frontend/cli.rs | 127 ++++++++---------- components/clarinet-cli/src/frontend/mod.rs | 2 + components/clarity-repl/src/repl/debug/cli.rs | 2 +- 4 files changed, 111 insertions(+), 73 deletions(-) create mode 100644 components/clarinet-cli/src/frontend/clarinetrc.rs diff --git a/components/clarinet-cli/src/frontend/clarinetrc.rs b/components/clarinet-cli/src/frontend/clarinetrc.rs new file mode 100644 index 000000000..03e499dde --- /dev/null +++ b/components/clarinet-cli/src/frontend/clarinetrc.rs @@ -0,0 +1,53 @@ +use std::fs::{self}; + +use std::env; + +#[derive(Serialize, Deserialize, Default)] +pub struct GlobalSettings { + pub enable_hints: Option, + pub enable_telemetry: Option, +} + +impl GlobalSettings { + pub fn get_settings_file_path() -> &'static str { + "~/.clarinet/clarinetrc.toml" + } + + pub fn from_global_file() -> Self { + let home_dir = dirs::home_dir(); + + if let Some(path) = home_dir.map(|home_dir| home_dir.join(".clarinet/clarinetrc.toml")) { + if path.exists() { + match fs::read_to_string(path) { + Ok(content) => match toml::from_str::(&content) { + Ok(res) => return res, + Err(_) => { + println!( + "{} {}", + format_warn!("unable to parse"), + Self::get_settings_file_path() + ); + } + }, + Err(_) => { + println!( + "{} {}", + format_warn!("unable to read file"), + Self::get_settings_file_path() + ); + } + } + } + }; + + // Keep backwards compatibility with ENV var + let enable_hints = match env::var("CLARINET_DISABLE_HINTS") { + Ok(v) => Some(v == "1"), + Err(_) => None, + }; + Self { + enable_hints, + ..Default::default() + } + } +} diff --git a/components/clarinet-cli/src/frontend/cli.rs b/components/clarinet-cli/src/frontend/cli.rs index 2345e5646..621cf6c11 100644 --- a/components/clarinet-cli/src/frontend/cli.rs +++ b/components/clarinet-cli/src/frontend/cli.rs @@ -11,6 +11,9 @@ use crate::generate::{ use crate::integrate; use crate::lsp::run_lsp; +use clap::builder::ValueParser; +use clap::{IntoApp, Parser, Subcommand}; +use clap_generate::{Generator, Shell}; use clarinet_deployments::diagnostic_digest::DiagnosticsDigest; use clarinet_deployments::onchain::{ apply_on_chain_deployment, get_initial_transactions_trackers, update_deployment_costs, @@ -41,12 +44,10 @@ use std::fs::{self, File}; use std::io::prelude::*; use std::path::PathBuf; use std::{env, process}; - -use clap::builder::ValueParser; -use clap::{IntoApp, Parser, Subcommand}; -use clap_generate::{Generator, Shell}; use toml; +use super::clarinetrc::GlobalSettings; + #[cfg(feature = "telemetry")] use super::telemetry::{telemetry_report_event, DeveloperUsageDigest, DeveloperUsageEvent}; /// Clarinet is a command line tool for Clarity smart contract development. @@ -486,7 +487,7 @@ struct Test { #[derive(Parser, PartialEq, Clone, Debug)] struct Run { /// Script to run - pub script: String, + pub script: Option, /// Path to Clarinet.toml #[clap(long = "manifest-path", short = 'm')] pub manifest_path: Option, @@ -550,11 +551,6 @@ struct Check { pub use_computed_deployment_plan: bool, } -#[derive(Serialize, Deserialize)] -struct GlobalSettings { - disable_hints: bool, - enable_telemetry: Option, -} #[derive(Parser, PartialEq, Clone, Debug)] struct Completions { /// Specify which shell to generation completions script for @@ -584,40 +580,7 @@ pub fn main() { } }; - let mut global_settings = String::new(); - let global_settings_default = GlobalSettings { - disable_hints: false, - enable_telemetry: None, - }; - // This is backwards compatible with ENV var setting as well as the new ~/.clarinet/Settings.toml - let hints_enabled = env::var("CLARINET_DISABLE_HINTS") != Ok("1".into()); - let home_dir = dirs::home_dir(); - let mpath: Option = home_dir.map(|home_dir| home_dir.join(".clarinet/Settings.toml")); - let settings_file = "~/.clarinet/Settings.toml"; - let global_settings: GlobalSettings = match mpath { - Some(path) => { - if path.exists() { - let mut file = File::open(&path).expect("Unable to open the file"); - let result = file.read_to_string(&mut global_settings); - match result { - Ok(_) => match toml::from_str(&global_settings) { - Ok(res) => res, - Err(_) => { - println!("{}{}", format_warn!("unable to parse "), settings_file); - global_settings_default - } - }, - Err(_) => { - println!("{}{}", format_warn!("unable to read file "), settings_file); - global_settings_default - } - } - } else { - global_settings_default - } - } - None => global_settings_default, - }; + let global_settings = GlobalSettings::from_global_file(); match opts.command { Command::New(project_opts) => { @@ -636,22 +599,29 @@ pub fn main() { if project_opts.disable_telemetry { false } else { - let enabled = match global_settings.enable_telemetry { - Some(true) => true, - _ => env::var("CLARINET_TELEMETRY") == Ok("1".into()), - }; - if enabled { - true - } else { - println!("{}", yellow!("Send usage data to Hiro.")); - println!("{}", yellow!("Help Hiro improve its products and services by automatically sending diagnostics and usage data.")); - println!("{}", yellow!("Only high level usage information, and no information identifying you or your project are collected.")); - // TODO(lgalabru): once we have a privacy policy available, add a link - // println!("{}", yellow!("Visit http://hiro.so/clarinet-privacy for details.")); - println!("{}", yellow!("Enable [Y/n]?")); - let mut buffer = String::new(); - std::io::stdin().read_line(&mut buffer).unwrap(); - !buffer.starts_with("n") + match global_settings.enable_telemetry { + Some(enable) => enable, + _ => { + println!("{}", yellow!("Send usage data to Hiro.")); + println!("{}", yellow!("Help Hiro improve its products and services by automatically sending diagnostics and usage data.")); + println!("{}", yellow!("Only high level usage information, and no information identifying you or your project are collected.")); + println!("{}", + yellow!("Enable or disable clarinet telemetry globally with this command:") + ); + println!( + "{}", + blue!(format!( + " $ mkdir -p ~/.clarinet; echo \"enable_telemetry = true\" >> {}", + GlobalSettings::get_settings_file_path() + )) + ); + // TODO(lgalabru): once we have a privacy policy available, add a link + // println!("{}", yellow!("Visit http://hiro.so/clarinet-privacy for details.")); + println!("{}", yellow!("Enable [Y/n]?")); + let mut buffer = String::new(); + std::io::stdin().read_line(&mut buffer).unwrap(); + !buffer.starts_with('n') + } } } } else { @@ -686,7 +656,7 @@ pub fn main() { if !execute_changes(changes) { std::process::exit(1); } - if hints_enabled { + if global_settings.enable_hints.unwrap_or(true) { display_post_check_hint(); } if telemetry_enabled { @@ -987,7 +957,7 @@ pub fn main() { if !execute_changes(changes) { std::process::exit(1); } - if hints_enabled { + if global_settings.enable_hints.unwrap_or(true) { display_post_check_hint(); } } @@ -1022,7 +992,7 @@ pub fn main() { if !execute_changes(changes) { std::process::exit(1); } - if hints_enabled { + if global_settings.enable_hints.unwrap_or(true) { display_post_check_hint(); } } @@ -1046,7 +1016,7 @@ pub fn main() { if !execute_changes(vec![Changes::EditTOML(change)]) { std::process::exit(1); } - if hints_enabled { + if global_settings.enable_hints.unwrap_or(true) { display_post_check_hint(); } } @@ -1122,7 +1092,7 @@ pub fn main() { } } - if hints_enabled { + if global_settings.enable_hints.unwrap_or(true) { display_post_console_hint(); } } @@ -1229,7 +1199,7 @@ pub fn main() { false => 1, }; - if hints_enabled { + if global_settings.enable_hints.unwrap_or(true) { display_post_check_hint(); } if manifest.project.telemetry { @@ -1329,7 +1299,7 @@ pub fn main() { println!("{}", format_err!(e)); process::exit(1); } - if hints_enabled { + if global_settings.enable_hints.unwrap_or(true) { display_deploy_hint(); } } @@ -1372,12 +1342,14 @@ pub fn main() { }, Command::Test(_) => { - println!("{} `clarinet test` has been deprecated. Please check this blog post to see learn more ", yellow!("warning:")); + println!("{} `clarinet test` has been deprecated. Please check this blog post to see learn more:", yellow!("warning:")); + println!("https://hiro.so/blog/announcing-the-clarinet-sdk-a-javascript-programming-model-for-easy-smart-contract-testing"); std::process::exit(1); } Command::Run(_) => { - println!("{} `clarinet run` has been deprecated. Please check this blog post to see learn more ", yellow!("warning:")); + println!("{} `clarinet run` has been deprecated. Please check this blog post to see learn more:", yellow!("warning:")); + println!("https://hiro.so/blog/announcing-the-clarinet-sdk-a-javascript-programming-model-for-easy-smart-contract-testing"); std::process::exit(1); } }; @@ -1802,7 +1774,17 @@ fn display_hint_header() { fn display_hint_footer() { println!( "{}", - yellow!("Disable these hints with the env var CLARINET_DISABLE_HINTS=1") + yellow!(format!( + "These hints can be disabled in the {} file.", + GlobalSettings::get_settings_file_path() + )) + ); + println!( + "{}", + blue!(format!( + " $ mkdir -p ~/.clarinet; echo \"enable_hints = false\" >> {}", + GlobalSettings::get_settings_file_path() + )) ); display_separator(); } @@ -1814,12 +1796,13 @@ fn display_post_check_hint() { "{}", yellow!("Once you are ready to write TypeScript unit tests for your contract, run the following command:\n") ); - println!("{}", blue!(" $ clarinet test")); + println!("{}", blue!(" $ npm install")); + println!("{}", blue!(" $ npm test")); println!( "{}", yellow!(" Run all run tests in the ./tests folder.\n") ); - println!("{}", yellow!("Find more information on testing with Clarinet here: https://docs.hiro.so/clarinet/how-to-guides/how-to-set-up-local-development-environment#testing-with-the-test-harness")); + println!("{}", yellow!("Find more information on testing with Clarinet here: https://docs.hiro.so/clarinet/feature-guides/test-contract-with-clarinet-sdk")); display_hint_footer(); } diff --git a/components/clarinet-cli/src/frontend/mod.rs b/components/clarinet-cli/src/frontend/mod.rs index ac917a0ef..29136d2af 100644 --- a/components/clarinet-cli/src/frontend/mod.rs +++ b/components/clarinet-cli/src/frontend/mod.rs @@ -1,3 +1,5 @@ +mod clarinetrc; + pub mod cli; pub mod dap; #[cfg(feature = "telemetry")] diff --git a/components/clarity-repl/src/repl/debug/cli.rs b/components/clarity-repl/src/repl/debug/cli.rs index c77cc4279..1d067858d 100644 --- a/components/clarity-repl/src/repl/debug/cli.rs +++ b/components/clarity-repl/src/repl/debug/cli.rs @@ -554,7 +554,7 @@ fn print_help_breakpoint() { r#"Set a breakpoint using 'b' or 'break' and one of these formats b .:: SP000000000000000000002Q6VF78.bns:604:9 - Break at line 604, column 9 of the bns contract deployed by + Break at line 604, column 9 of the bns contract deployed by SP000000000000000000002Q6VF78 b .: