Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 586d32c

Browse files
authored
feat: notify new version
1 parent b8bbd52 commit 586d32c

9 files changed

Lines changed: 270 additions & 89 deletions

File tree

Cargo.lock

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

synth/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,8 @@ mongodb = {version = "2.0.0-beta.3", features = ["sync", "bson-chrono-0_4"] , de
6868

6969
sqlx = { version = "0.5.7", features = [ "postgres", "mysql", "runtime-async-std-native-tls", "decimal", "chrono" ] }
7070

71-
beau_collector = "0.2.1"
71+
beau_collector = "0.2.1"
72+
73+
reqwest = { version = "0.11", features = ["json", "blocking"] }
74+
75+
semver = "1.0.4"

synth/src/cli/config.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use anyhow::Result;
2+
use std::sync::{Mutex};
3+
use lazy_static::lazy_static;
4+
use std::collections::HashSet;
5+
use std::path::PathBuf;
6+
use serde::{Serialize, Deserialize};
7+
8+
lazy_static! {
9+
static ref CONFIG: Mutex<Config> = Mutex::new(Config::new());
10+
}
11+
12+
13+
macro_rules! config {
14+
{
15+
$($val_name:ident: $ty:ty => $getter:ident, $setter:ident)*
16+
} => {
17+
/// Note: Fields should only be added to the config.
18+
/// Also let's assume only a single instance of synth is running
19+
#[derive(Serialize, Deserialize, Default)]
20+
struct Config {
21+
$(
22+
#[serde(skip_serializing_if = "Option::is_none")]
23+
$val_name: Option<$ty>,
24+
)*
25+
}
26+
27+
$(
28+
#[allow(dead_code)]
29+
pub fn $setter($val_name: $ty) {
30+
let mut config = CONFIG.lock().unwrap();
31+
config.$val_name = Some($val_name);
32+
config.save();
33+
}
34+
#[allow(dead_code)]
35+
pub fn $getter() -> Option<$ty> {
36+
CONFIG.lock().unwrap().$val_name.clone()
37+
}
38+
)*
39+
40+
}
41+
}
42+
43+
config! {
44+
uuid: String => get_uuid, set_uuid
45+
telemetry_enabled: bool => get_telemetry_enabled, set_telemetry_enabled
46+
seen_versions: HashSet<String> => get_seen_versions, set_seen_versions
47+
}
48+
49+
impl Config {
50+
fn new() -> Self {
51+
Self::from_file().unwrap_or_else(|_| Config::default())
52+
}
53+
54+
fn from_file() -> Result<Self> {
55+
let file_contents = std::fs::read_to_string(Self::file_path()?)?;
56+
let config = serde_json::from_str(&file_contents)?;
57+
Ok(config)
58+
}
59+
60+
fn file_path() -> Result<PathBuf> {
61+
Ok(Self::synth_config_dir()?.join("config.json"))
62+
}
63+
64+
fn synth_config_dir() -> Result<PathBuf> {
65+
let synth_config_dir = dirs::config_dir()
66+
.ok_or_else(|| {
67+
anyhow!("Could not find a configuration directory. Your operating system may not be supported.")
68+
})?;
69+
Ok(synth_config_dir.join("synth"))
70+
}
71+
72+
fn save(&self) {
73+
// There are way too many unwraps here.
74+
// Create config dir if it doesn't exist
75+
let config_dir = Self::synth_config_dir().unwrap();
76+
if !config_dir.exists() {
77+
std::fs::create_dir_all(&config_dir).unwrap();
78+
}
79+
// Save the config
80+
let mut config_file_path = std::fs::OpenOptions::new()
81+
.write(true)
82+
.create(true)
83+
.open(Self::file_path().unwrap())
84+
.unwrap();
85+
serde_json::to_writer_pretty(&mut config_file_path, &self).unwrap();
86+
}
87+
}

synth/src/cli/mod.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,23 @@ use anyhow::{Context, Result};
1717

1818
use std::path::PathBuf;
1919
use structopt::StructOpt;
20+
use structopt::clap::AppSettings;
2021

2122
use rand::RngCore;
2223

2324
use synth_core::{Name, graph::json};
25+
use crate::version::print_version_message;
26+
use std::process::exit;
2427

2528
#[cfg(feature = "telemetry")]
2629
pub mod telemetry;
30+
pub(crate) mod config;
2731

2832
pub struct Cli {
2933
store: Store
3034
}
3135

3236
impl Cli {
33-
/// this is going to get confusing with `init` command
3437
pub fn new() -> Result<Self> {
3538
env_logger::init();
3639

@@ -83,6 +86,11 @@ impl Cli {
8386
} => self.import(namespace.clone(), collection.clone(), from.clone()),
8487
#[cfg(feature = "telemetry")]
8588
Args::Telemetry(cmd) => self.telemetry(cmd),
89+
Args::Version => {
90+
print_version_message();
91+
// Exiting so we don't get the message twice
92+
exit(0);
93+
}
8694
}
8795
}
8896

@@ -95,9 +103,7 @@ impl Cli {
95103
if telemetry::is_enabled() {
96104
println!("Telemetry is enabled. To disable it run `synth telemetry disable`.");
97105
} else {
98-
println!(
99-
"Telemetry is disabled. To enable it run `synth telemetry enable`."
100-
);
106+
println!("Telemetry is disabled. To enable it run `synth telemetry enable`.");
101107
}
102108
Ok(())
103109
}
@@ -163,8 +169,13 @@ impl Cli {
163169
}
164170
}
165171

172+
166173
#[derive(StructOpt)]
167-
#[structopt(name = "synth", about = "synthetic data engine on the command line")]
174+
#[structopt(
175+
name = "synth",
176+
about = "synthetic data engine on the command line",
177+
no_version,
178+
global_settings = &[AppSettings::DisableVersion])]
168179
pub enum Args {
169180
#[structopt(about = "(DEPRECATED). For backward compatibility and is a no-op.")]
170181
Init {
@@ -218,6 +229,8 @@ pub enum Args {
218229
#[cfg(feature = "telemetry")]
219230
#[structopt(about = "Toggle anonymous usage data collection")]
220231
Telemetry(TelemetryCommand),
232+
#[structopt(about = "Version information")]
233+
Version
221234
}
222235

223236
#[cfg(feature = "telemetry")]

synth/src/cli/telemetry.rs

Lines changed: 21 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,37 @@
1-
use anyhow::{Context, Result};
2-
use serde::{Deserialize, Serialize};
3-
1+
use anyhow::Result;
42
use std::collections::HashMap;
5-
use std::path::PathBuf;
63
use std::future::Future;
74
use std::error::Error;
5+
use uuid::Uuid;
86

9-
use crate::utils::{version, META_OS};
7+
use crate::utils::META_OS;
8+
use crate::version::version;
9+
use crate::cli::config;
1010

1111
use super::{Args, TelemetryCommand};
1212

1313
const API_KEY: &str = "L-AQtrFVtZGL_PjK2FbFLBR3oXNtfv8OrCD8ObyeBQo";
1414
const EVENT_NAME: &str = "synth-command";
1515

1616
pub(crate) fn enable() -> Result<()> {
17-
TelemetryConfig::enable_telemetry()
17+
// Initialise the `uuid` if it hasn't been initialised yet.
18+
let _ = get_or_initialise_uuid();
19+
Ok(config::set_telemetry_enabled(true))
1820
}
1921

2022
pub(crate) fn disable() -> Result<()> {
21-
TelemetryConfig::disable_telemetry()
23+
Ok(config::set_telemetry_enabled(false))
2224
}
2325

2426
pub(crate) fn is_enabled() -> bool {
25-
TelemetryConfig::is_enabled()
27+
config::get_telemetry_enabled().unwrap_or(false)
28+
}
29+
30+
fn get_or_initialise_uuid() -> String {
31+
if config::get_uuid().is_none() {
32+
config::set_uuid(Uuid::new_v4().to_hyphenated().to_string());
33+
}
34+
config::get_uuid().expect("is ok here as was set earlier")
2635
}
2736

2837
pub async fn with_telemetry<F, Fut, T, E>(args: Args, func: F) -> Result<T, E>
@@ -39,7 +48,8 @@ where
3948
Args::Import { .. } => "import",
4049
Args::Telemetry(TelemetryCommand::Enable) => "telemetry::enable",
4150
Args::Telemetry(TelemetryCommand::Disable) => "telemetry::disable",
42-
Args::Telemetry(TelemetryCommand::Status) => "telemetry::status"
51+
Args::Telemetry(TelemetryCommand::Status) => "telemetry::status",
52+
Args::Version => "version"
4353
};
4454

4555
func(args)
@@ -48,71 +58,6 @@ where
4858
.or_else(|err| client.failed(command_name, err))
4959
}
5060

51-
#[derive(Serialize, Deserialize)]
52-
struct TelemetryConfig {
53-
uuid: String,
54-
}
55-
56-
impl TelemetryConfig {
57-
pub fn initialise() -> Self {
58-
Self::from_file().unwrap_or_else(|_| Self::new())
59-
}
60-
61-
fn new() -> Self {
62-
Self {
63-
uuid: uuid::Uuid::new_v4().to_hyphenated().to_string(),
64-
}
65-
}
66-
67-
fn from_file() -> Result<Self> {
68-
let file_contents = std::fs::read_to_string(Self::file_path()?)?;
69-
let tc = serde_json::from_str(&file_contents)?;
70-
Ok(tc)
71-
}
72-
73-
fn synth_config_dir() -> Result<PathBuf> {
74-
let synth_config_dir = dirs::config_dir().ok_or_else(|| {
75-
anyhow!(
76-
"Could not find a configuration directory. Your operating system may not be supported."
77-
)
78-
})?;
79-
Ok(synth_config_dir.join("synth"))
80-
}
81-
82-
fn file_path() -> Result<PathBuf> {
83-
Ok(Self::synth_config_dir()?.join("config.json"))
84-
}
85-
86-
fn enable_telemetry() -> Result<()> {
87-
let config_dir = Self::synth_config_dir()?;
88-
if !config_dir.exists() {
89-
std::fs::create_dir_all(&config_dir)
90-
.with_context(|| anyhow!("Could not create the directory: {}", config_dir.display()))?;
91-
}
92-
if !Self::is_enabled() {
93-
let mut config_file_path = std::fs::OpenOptions::new()
94-
.write(true)
95-
.create(true)
96-
.open(Self::file_path()?)
97-
.map_err(|e| anyhow!("There was an issue enabling telemetry: {}", e))?;
98-
serde_json::to_writer_pretty(&mut config_file_path, &TelemetryConfig::new())?;
99-
}
100-
Ok(())
101-
}
102-
103-
fn disable_telemetry() -> Result<()> {
104-
if Self::is_enabled() {
105-
std::fs::remove_file(Self::file_path()?)
106-
.map_err(|e| anyhow!("There was an issue disabling telemetry: {}", e))?;
107-
}
108-
Ok(())
109-
}
110-
111-
fn is_enabled() -> bool {
112-
Self::file_path().map(|path| path.exists()).unwrap_or(false)
113-
}
114-
}
115-
11661
enum CommandResult {
11762
Success,
11863
Failed,
@@ -142,10 +87,10 @@ impl TelemetryClient {
14287

14388
Self {
14489
ph_client: posthog_rs::client(API_KEY),
145-
uuid: TelemetryConfig::initialise().uuid,
90+
uuid: get_or_initialise_uuid(),
14691
synth_version,
14792
os,
148-
enabled: TelemetryConfig::is_enabled(),
93+
enabled: is_enabled(),
14994
}
15095
}
15196

synth/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![feature(format_args_capture, async_closure, map_first_last, box_patterns)]
1+
#![feature(format_args_capture, async_closure, map_first_last, box_patterns, concat_idents)]
22
#![feature(error_iter)]
33
#![allow(type_alias_bounds)]
44

@@ -16,3 +16,4 @@ pub mod cli;
1616
pub mod datasource;
1717
pub mod sampler;
1818
pub mod utils;
19+
pub mod version;

synth/src/main.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,31 @@
11
use anyhow::Result;
22
use structopt::StructOpt;
3+
use synth::cli::Args;
4+
use synth::cli::Cli;
5+
use std::thread;
6+
use std::thread::JoinHandle;
7+
38

49
#[async_std::main]
510
async fn main() -> Result<()> {
6-
let args = synth::cli::Args::from_args();
7-
let cli = synth::cli::Cli::new()?;
11+
let args = Args::from_args();
12+
let cli = Cli::new()?;
13+
14+
let notify_handle = thread::spawn(|| synth::version::notify_new_version_message().unwrap());
815

916
#[cfg(feature = "telemetry")]
1017
synth::cli::telemetry::with_telemetry(args, |args| cli.run(args)).await?;
1118

1219
#[cfg(not(feature = "telemetry"))]
1320
cli.run(args).await?;
1421

22+
print_notify(notify_handle);
23+
1524
Ok(())
1625
}
26+
27+
fn print_notify(handle: JoinHandle<Option<String>>) {
28+
if let Some(notify_message) = handle.join().unwrap_or_default() {
29+
eprintln!("{}", notify_message);
30+
}
31+
}

0 commit comments

Comments
 (0)