mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
Auto update (w/ cli)
This commit is contained in:
233
src/system/auto_update.rs
Normal file
233
src/system/auto_update.rs
Normal file
@@ -0,0 +1,233 @@
|
||||
//! ## Auto update
|
||||
//!
|
||||
//! Automatic update module. This module is used to upgrade the current version of termscp to the latest available on Github
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* termscp - Copyright (c) 2021 Christian Visintin
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
use crate::utils::parser::parse_semver;
|
||||
|
||||
pub use self_update::errors::Error as UpdateError;
|
||||
use self_update::{
|
||||
backends::github::Update as GithubUpdater, cargo_crate_version, update::Release as UpdRelease,
|
||||
Status,
|
||||
};
|
||||
|
||||
/// ### UpdateStatus
|
||||
///
|
||||
/// The status of the update in case of success
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum UpdateStatus {
|
||||
/// Termscp is already up to date
|
||||
AlreadyUptodate,
|
||||
/// The update has been correctly installed
|
||||
UpdateInstalled(String),
|
||||
}
|
||||
|
||||
/// ## Release
|
||||
///
|
||||
/// Info related to a github release
|
||||
#[derive(Debug)]
|
||||
pub struct Release {
|
||||
pub version: String,
|
||||
pub body: String,
|
||||
}
|
||||
|
||||
/// ## Update
|
||||
///
|
||||
/// The update structure defines the options used to install the update.
|
||||
/// Once you're fine with the options, just call the `upgrade()` method to upgrade termscp.
|
||||
#[derive(Debug)]
|
||||
pub struct Update {
|
||||
ask_confirm: bool,
|
||||
progress: bool,
|
||||
}
|
||||
|
||||
impl Update {
|
||||
/// ### show_progress
|
||||
///
|
||||
/// Set whether to show or not the progress bar
|
||||
pub fn show_progress(mut self, opt: bool) -> Self {
|
||||
self.progress = opt;
|
||||
self
|
||||
}
|
||||
|
||||
/// ### ask_confirm
|
||||
///
|
||||
/// Set whether to ask for confirm when updating
|
||||
pub fn ask_confirm(mut self, opt: bool) -> Self {
|
||||
self.ask_confirm = opt;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn upgrade(self) -> Result<UpdateStatus, UpdateError> {
|
||||
info!("Updating termscp...");
|
||||
GithubUpdater::configure()
|
||||
// Set default options
|
||||
.repo_owner("veeso")
|
||||
.repo_name("termscp")
|
||||
.bin_name("termscp")
|
||||
.current_version(cargo_crate_version!())
|
||||
.no_confirm(!self.ask_confirm)
|
||||
.show_download_progress(self.progress)
|
||||
.show_output(self.progress)
|
||||
.build()?
|
||||
.update()
|
||||
.map(UpdateStatus::from)
|
||||
}
|
||||
|
||||
/// ### is_new_version_available
|
||||
///
|
||||
/// Returns whether a new version of termscp is available
|
||||
/// In case of success returns Ok(Option<Release>), where the Option is Some(new_version);
|
||||
/// otherwise if no version is available, return None
|
||||
/// In case of error returns Error with the error description
|
||||
pub fn is_new_version_available() -> Result<Option<Release>, UpdateError> {
|
||||
info!("Checking whether a new version is available...");
|
||||
GithubUpdater::configure()
|
||||
// Set default options
|
||||
.repo_owner("veeso")
|
||||
.repo_name("termscp")
|
||||
.bin_name("termscp")
|
||||
.current_version(cargo_crate_version!())
|
||||
.no_confirm(true)
|
||||
.show_download_progress(false)
|
||||
.show_output(false)
|
||||
.build()?
|
||||
.get_latest_release()
|
||||
.map(Release::from)
|
||||
.map(Self::check_version)
|
||||
}
|
||||
|
||||
/// ### check_version
|
||||
///
|
||||
/// In case received version is newer than current one, version as Some is returned; otherwise None
|
||||
fn check_version(r: Release) -> Option<Release> {
|
||||
match parse_semver(r.version.as_str()) {
|
||||
Some(new_version) => {
|
||||
// Check if version is different
|
||||
debug!(
|
||||
"New version: {}; current version: {}",
|
||||
new_version,
|
||||
cargo_crate_version!()
|
||||
);
|
||||
if new_version.as_str() > "cargo_crate_version!()" {
|
||||
Some(r) // New version is available
|
||||
} else {
|
||||
None // No new version
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Update {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
progress: false,
|
||||
ask_confirm: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Status> for UpdateStatus {
|
||||
fn from(s: Status) -> Self {
|
||||
match s {
|
||||
Status::UpToDate(_) => Self::AlreadyUptodate,
|
||||
Status::Updated(v) => Self::UpdateInstalled(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UpdRelease> for Release {
|
||||
fn from(r: UpdRelease) -> Self {
|
||||
Self {
|
||||
version: r.version,
|
||||
body: r.body.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use super::*;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn auto_update_default() {
|
||||
let upd: Update = Update::default();
|
||||
assert_eq!(upd.ask_confirm, false);
|
||||
assert_eq!(upd.progress, false);
|
||||
let upd = upd.ask_confirm(true).show_progress(true);
|
||||
assert_eq!(upd.ask_confirm, true);
|
||||
assert_eq!(upd.progress, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_update() {
|
||||
// Wno version
|
||||
assert_eq!(
|
||||
Update::default()
|
||||
.show_progress(true)
|
||||
.upgrade()
|
||||
.ok()
|
||||
.unwrap(),
|
||||
UpdateStatus::AlreadyUptodate,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_for_updates() {
|
||||
println!("{:?}", Update::is_new_version_available());
|
||||
assert!(Update::is_new_version_available().is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_status() {
|
||||
assert_eq!(
|
||||
UpdateStatus::from(Status::Updated(String::from("0.6.0"))),
|
||||
UpdateStatus::UpdateInstalled(String::from("0.6.0"))
|
||||
);
|
||||
assert_eq!(
|
||||
UpdateStatus::from(Status::UpToDate(String::from("0.6.0"))),
|
||||
UpdateStatus::AlreadyUptodate
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn release() {
|
||||
let release: UpdRelease = UpdRelease {
|
||||
name: String::from("termscp 0.7.0"),
|
||||
version: String::from("0.7.0"),
|
||||
date: String::from("2021-09-12T00:00:00Z"),
|
||||
body: Some(String::from("fixed everything")),
|
||||
assets: vec![],
|
||||
};
|
||||
let release: Release = Release::from(release);
|
||||
assert_eq!(release.body.as_str(), "fixed everything");
|
||||
assert_eq!(release.version.as_str(), "0.7.0");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user