diff --git a/server/Cargo.toml b/server/Cargo.toml index e061ded1c..cdb125071 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parseable" -version = "0.0.1" +version = "0.0.3" authors = [ "NitishTiwari ", "AdheipSingh ", @@ -18,6 +18,7 @@ async-trait = "0.1" aws-sdk-s3 = "0.17" bytes = "1" chrono = "0.4.19" +chrono-humanize = "0.2.2" crossterm = "0.23.2" datafusion = "11.0" object_store = { version = "0.4", features=["aws"] } @@ -34,6 +35,7 @@ os_info = "3.0.7" hostname = "0.3" rand = "0.8.4" rust-flatten-json = "0.2.0" +semver = "1.0.14" serde = "^1.0.8" serde_derive = "^1.0.8" serde_json = "^1.0.8" @@ -47,7 +49,7 @@ clokwerk = "0.4.0-rc1" actix-web-static-files = "4.0" static-files = "0.2.1" walkdir = "2" -ureq = "2.5.0" +ureq = { version = "2.5.0", features = ["json"] } [build-dependencies] static-files = "0.2.1" diff --git a/server/src/banner.rs b/server/src/banner.rs index 2df5d4e28..e99cf1a55 100644 --- a/server/src/banner.rs +++ b/server/src/banner.rs @@ -43,3 +43,60 @@ pub fn warning_line() { "Warning:".to_string().red().bold(), ); } + +pub mod version { + use chrono::Duration; + use chrono_humanize::{Accuracy, Tense}; + use crossterm::style::Stylize; + use semver::Version; + + use crate::utils::github; + + pub fn print() { + // print current version + let current_version = current_version(); + // not eprintln because if it is old release then time passed with be displayed beside it + eprint!( + " + {} {} ", + "Current Version:".to_string().blue().bold(), + current_version + ); + + // check for latest release, if it cannot be fetched then print error as warn and return + let latest_release = match github::get_latest() { + Ok(latest_release) => latest_release, + Err(e) => { + log::warn!("{}", e); + return; + } + }; + + if latest_release.version > current_version { + let time_since_latest_release = chrono::Utc::now() - latest_release.date; + let time_since_latest_release = humanize_time(time_since_latest_release); + + let fmt_latest_version = format!( + "( v{} released {} ago )", + latest_release.version, time_since_latest_release + ); + + eprint!("{}", fmt_latest_version.yellow().bold()); + eprintln!( + " + Download latest version from https://github.com/parseablehq/parseable/releases/latest" + ); + } else { + eprintln!(); + } + } + + fn current_version() -> Version { + let current_version = env!("CARGO_PKG_VERSION"); + semver::Version::parse(current_version).expect("CARGO_PKG_VERSION is always valid semver") + } + + fn humanize_time(time_passed: Duration) -> String { + chrono_humanize::HumanTime::from(time_passed).to_text_en(Accuracy::Rough, Tense::Present) + } +} diff --git a/server/src/option.rs b/server/src/option.rs index b1adc65fc..4478cc124 100644 --- a/server/src/option.rs +++ b/server/src/option.rs @@ -61,6 +61,7 @@ impl Config { pub fn print(&self) { let scheme = CONFIG.parseable.get_scheme(); self.status_info(&scheme); + banner::version::print(); self.warning(); self.storage_info(); banner::system_info(); diff --git a/server/src/utils.rs b/server/src/utils.rs index dcdd3d92d..021eba995 100644 --- a/server/src/utils.rs +++ b/server/src/utils.rs @@ -129,6 +129,39 @@ pub fn hostname_unchecked() -> String { hostname::get().unwrap().into_string().unwrap() } +pub mod github { + use anyhow::anyhow; + use chrono::{DateTime, Utc}; + + pub struct LatestRelease { + pub version: semver::Version, + pub date: DateTime, + } + + pub fn get_latest() -> Result { + let json: serde_json::Value = + ureq::get("https://api.github.com/repos/parseablehq/parseable/releases/latest") + .call()? + .into_json()?; + + let version = json["tag_name"] + .as_str() + .and_then(|ver| ver.strip_prefix('v')) + .and_then(|ver| semver::Version::parse(ver).ok()) + .ok_or_else(|| anyhow!("Bad parse when parsing verison"))?; + + let date = json["published_at"] + .as_str() + .ok_or_else(|| anyhow!("Bad parse when parsing published date"))?; + + let date = chrono::DateTime::parse_from_rfc3339(date) + .expect("date-time from github is in rfc3339 format") + .into(); + + Ok(LatestRelease { version, date }) + } +} + /// Convert minutes to a slot range /// e.g. given minute = 15 and OBJECT_STORE_DATA_GRANULARITY = 10 returns "10-19" pub fn minute_to_slot(minute: u32, data_granularity: u32) -> Option {