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:
@@ -53,13 +53,13 @@ extern crate path_slash;
|
||||
extern crate rand;
|
||||
extern crate regex;
|
||||
extern crate s3;
|
||||
extern crate self_update;
|
||||
extern crate ssh2;
|
||||
extern crate suppaftp;
|
||||
extern crate tempfile;
|
||||
extern crate textwrap;
|
||||
extern crate tui_realm_stdlib;
|
||||
extern crate tuirealm;
|
||||
extern crate ureq;
|
||||
#[cfg(target_family = "unix")]
|
||||
extern crate users;
|
||||
extern crate whoami;
|
||||
|
||||
20
src/main.rs
20
src/main.rs
@@ -62,6 +62,7 @@ use system::logging;
|
||||
enum Task {
|
||||
Activity(NextActivity),
|
||||
ImportTheme(PathBuf),
|
||||
InstallUpdate,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
@@ -84,6 +85,12 @@ struct Args {
|
||||
quiet: bool,
|
||||
#[argh(option, short = 't', description = "import specified theme")]
|
||||
theme: Option<String>,
|
||||
#[argh(
|
||||
switch,
|
||||
short = 'u',
|
||||
description = "update termscp to the latest version"
|
||||
)]
|
||||
update: bool,
|
||||
#[argh(
|
||||
option,
|
||||
short = 'T',
|
||||
@@ -177,6 +184,9 @@ fn parse_args(args: Args) -> Result<RunOpts, String> {
|
||||
if let Some(theme) = args.theme {
|
||||
run_opts.task = Task::ImportTheme(PathBuf::from(theme));
|
||||
}
|
||||
if args.update {
|
||||
run_opts.task = Task::InstallUpdate;
|
||||
}
|
||||
// @! Ordinary mode
|
||||
// Remote argument
|
||||
if let Some(remote) = args.positional.get(0) {
|
||||
@@ -256,6 +266,16 @@ fn run(mut run_opts: RunOpts) -> i32 {
|
||||
1
|
||||
}
|
||||
},
|
||||
Task::InstallUpdate => match support::install_update() {
|
||||
Ok(msg) => {
|
||||
println!("{}", msg);
|
||||
0
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("Could not install update: {}", err);
|
||||
1
|
||||
}
|
||||
},
|
||||
Task::Activity(activity) => {
|
||||
// Get working directory
|
||||
let wrkdir: PathBuf = match env::current_dir() {
|
||||
|
||||
@@ -26,7 +26,11 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
// mod
|
||||
use crate::system::{environment, theme_provider::ThemeProvider};
|
||||
use crate::system::{
|
||||
auto_update::{Update, UpdateStatus},
|
||||
environment,
|
||||
theme_provider::ThemeProvider,
|
||||
};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
@@ -51,6 +55,23 @@ pub fn import_theme(p: &Path) -> Result<(), String> {
|
||||
.map_err(|e| format!("Could not import theme: {}", e))
|
||||
}
|
||||
|
||||
/// ### install_update
|
||||
///
|
||||
/// Install latest version of termscp if an update is available
|
||||
pub fn install_update() -> Result<String, String> {
|
||||
match Update::default()
|
||||
.show_progress(true)
|
||||
.ask_confirm(true)
|
||||
.upgrade()
|
||||
{
|
||||
Ok(UpdateStatus::AlreadyUptodate) => Ok("termscp is already up to date".to_string()),
|
||||
Ok(UpdateStatus::UpdateInstalled(v)) => {
|
||||
Ok(format!("termscp has been updated to version {}", v))
|
||||
}
|
||||
Err(err) => Err(err.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_config_dir
|
||||
///
|
||||
/// Get configuration directory
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
// modules
|
||||
pub mod auto_update;
|
||||
pub mod bookmarks_client;
|
||||
pub mod config_client;
|
||||
pub mod environment;
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
*/
|
||||
use super::{AuthActivity, FileTransferParams, FileTransferProtocol};
|
||||
use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams};
|
||||
use crate::system::auto_update::{Update, UpdateStatus};
|
||||
|
||||
use tuirealm::tui::style::Color;
|
||||
|
||||
impl AuthActivity {
|
||||
/// ### protocol_opt_to_enum
|
||||
@@ -151,4 +154,31 @@ impl AuthActivity {
|
||||
entry_directory: None,
|
||||
})
|
||||
}
|
||||
|
||||
// -- update install
|
||||
|
||||
/// ### install_update
|
||||
///
|
||||
/// Install latest termscp version via GUI
|
||||
pub(super) fn install_update(&mut self) {
|
||||
// Umount release notes
|
||||
self.umount_release_notes();
|
||||
// Mount wait box
|
||||
self.mount_wait("Installing update. Please wait…");
|
||||
// Install update
|
||||
let result = Update::default().show_progress(false).upgrade();
|
||||
// Umount wait
|
||||
self.umount_wait();
|
||||
// Show outcome
|
||||
match result {
|
||||
Ok(UpdateStatus::AlreadyUptodate) => {
|
||||
self.mount_info("termscp is already up to date!", Color::Cyan)
|
||||
}
|
||||
Ok(UpdateStatus::UpdateInstalled(ver)) => self.mount_info(
|
||||
format!("termscp has been updated to version {}!", ver),
|
||||
Color::Green,
|
||||
),
|
||||
Err(err) => self.mount_error(format!("Could not install update: {}", err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ mod view;
|
||||
use super::{Activity, Context, ExitReason};
|
||||
use crate::config::themes::Theme;
|
||||
use crate::filetransfer::{FileTransferParams, FileTransferProtocol};
|
||||
use crate::system::auto_update::{Release, Update as TermscpUpdate};
|
||||
use crate::system::bookmarks_client::BookmarksClient;
|
||||
use crate::utils::git;
|
||||
|
||||
// Includes
|
||||
use crossterm::event::Event;
|
||||
@@ -51,6 +51,8 @@ const COMPONENT_TEXT_NEW_VERSION_NOTES: &str = "TEXTAREA_NEW_VERSION";
|
||||
const COMPONENT_TEXT_FOOTER: &str = "TEXT_FOOTER";
|
||||
const COMPONENT_TEXT_HELP: &str = "TEXT_HELP";
|
||||
const COMPONENT_TEXT_ERROR: &str = "TEXT_ERROR";
|
||||
const COMPONENT_TEXT_INFO: &str = "TEXT_INFO";
|
||||
const COMPONENT_TEXT_WAIT: &str = "TEXT_WAIT";
|
||||
const COMPONENT_TEXT_SIZE_ERR: &str = "TEXT_SIZE_ERR";
|
||||
const COMPONENT_INPUT_ADDR: &str = "INPUT_ADDRESS";
|
||||
const COMPONENT_INPUT_PORT: &str = "INPUT_PORT";
|
||||
@@ -65,6 +67,7 @@ const COMPONENT_RADIO_QUIT: &str = "RADIO_QUIT";
|
||||
const COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK: &str = "RADIO_DELETE_BOOKMARK";
|
||||
const COMPONENT_RADIO_BOOKMARK_DEL_RECENT: &str = "RADIO_DELETE_RECENT";
|
||||
const COMPONENT_RADIO_BOOKMARK_SAVE_PWD: &str = "RADIO_SAVE_PASSWORD";
|
||||
const COMPONENT_RADIO_INSTALL_UPDATE: &str = "RADIO_INSTALL_UPDATE";
|
||||
const COMPONENT_BOOKMARKS_LIST: &str = "BOOKMARKS_LIST";
|
||||
const COMPONENT_RECENTS_LIST: &str = "RECENTS_LIST";
|
||||
|
||||
@@ -119,12 +122,12 @@ impl AuthActivity {
|
||||
if ctx.config().get_check_for_updates() {
|
||||
debug!("Check for updates is enabled");
|
||||
// Send request
|
||||
match git::check_for_updates(env!("CARGO_PKG_VERSION")) {
|
||||
Ok(Some(git::GithubTag { tag_name, body })) => {
|
||||
match TermscpUpdate::is_new_version_available() {
|
||||
Ok(Some(Release { version, body })) => {
|
||||
// If some, store version and release notes
|
||||
info!("Latest version is: {}", tag_name);
|
||||
info!("Latest version is: {}", version);
|
||||
ctx.store_mut()
|
||||
.set_string(STORE_KEY_LATEST_VERSION, tag_name);
|
||||
.set_string(STORE_KEY_LATEST_VERSION, version);
|
||||
ctx.store_mut().set_string(STORE_KEY_RELEASE_NOTES, body);
|
||||
}
|
||||
Ok(None) => {
|
||||
|
||||
@@ -32,8 +32,9 @@ use super::{
|
||||
COMPONENT_INPUT_S3_BUCKET, COMPONENT_INPUT_S3_PROFILE, COMPONENT_INPUT_S3_REGION,
|
||||
COMPONENT_INPUT_USERNAME, COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK,
|
||||
COMPONENT_RADIO_BOOKMARK_DEL_RECENT, COMPONENT_RADIO_BOOKMARK_SAVE_PWD,
|
||||
COMPONENT_RADIO_PROTOCOL, COMPONENT_RADIO_QUIT, COMPONENT_RECENTS_LIST, COMPONENT_TEXT_ERROR,
|
||||
COMPONENT_TEXT_HELP, COMPONENT_TEXT_NEW_VERSION_NOTES, COMPONENT_TEXT_SIZE_ERR,
|
||||
COMPONENT_RADIO_INSTALL_UPDATE, COMPONENT_RADIO_PROTOCOL, COMPONENT_RADIO_QUIT,
|
||||
COMPONENT_RECENTS_LIST, COMPONENT_TEXT_ERROR, COMPONENT_TEXT_HELP, COMPONENT_TEXT_INFO,
|
||||
COMPONENT_TEXT_NEW_VERSION_NOTES, COMPONENT_TEXT_SIZE_ERR, COMPONENT_TEXT_WAIT,
|
||||
};
|
||||
use crate::ui::keymap::*;
|
||||
use tui_realm_stdlib::InputPropsBuilder;
|
||||
@@ -252,15 +253,44 @@ impl Update for AuthActivity {
|
||||
self.umount_error();
|
||||
None
|
||||
}
|
||||
(COMPONENT_TEXT_ERROR, _) => None,
|
||||
(COMPONENT_TEXT_NEW_VERSION_NOTES, key)
|
||||
if key == &MSG_KEY_ESC || key == &MSG_KEY_ENTER =>
|
||||
{
|
||||
// -- Text info
|
||||
(COMPONENT_TEXT_INFO, key) if key == &MSG_KEY_ESC || key == &MSG_KEY_ENTER => {
|
||||
// Umount text info
|
||||
self.umount_info();
|
||||
None
|
||||
}
|
||||
(COMPONENT_TEXT_ERROR, _) | (COMPONENT_TEXT_INFO, _) => None,
|
||||
// -- Text wait
|
||||
(COMPONENT_TEXT_WAIT, _) => None,
|
||||
// -- Release notes
|
||||
(COMPONENT_TEXT_NEW_VERSION_NOTES, key) if key == &MSG_KEY_ESC => {
|
||||
// Umount release notes
|
||||
self.umount_release_notes();
|
||||
None
|
||||
}
|
||||
(COMPONENT_TEXT_NEW_VERSION_NOTES, key) if key == &MSG_KEY_TAB => {
|
||||
// Focus to radio update
|
||||
self.view.active(COMPONENT_RADIO_INSTALL_UPDATE);
|
||||
None
|
||||
}
|
||||
(COMPONENT_TEXT_NEW_VERSION_NOTES, _) => None,
|
||||
// -- Install update radio
|
||||
(COMPONENT_RADIO_INSTALL_UPDATE, Msg::OnSubmit(Payload::One(Value::Usize(0)))) => {
|
||||
// Install update
|
||||
self.install_update();
|
||||
None
|
||||
}
|
||||
(COMPONENT_RADIO_INSTALL_UPDATE, Msg::OnSubmit(Payload::One(Value::Usize(1)))) => {
|
||||
// Umount
|
||||
self.umount_release_notes();
|
||||
None
|
||||
}
|
||||
(COMPONENT_RADIO_INSTALL_UPDATE, key) if key == &MSG_KEY_TAB => {
|
||||
// Focus to changelog
|
||||
self.view.active(COMPONENT_TEXT_NEW_VERSION_NOTES);
|
||||
None
|
||||
}
|
||||
(COMPONENT_RADIO_INSTALL_UPDATE, _) => None,
|
||||
// Help
|
||||
(_, key) if key == &MSG_KEY_CTRL_H => {
|
||||
// Show help
|
||||
|
||||
@@ -209,7 +209,7 @@ impl AuthActivity {
|
||||
.with_spans(vec![
|
||||
TextSpan::from("termscp "),
|
||||
TextSpan::new(version.as_str()).underlined().bold(),
|
||||
TextSpan::from(" is NOW available! Get it from <https://veeso.github.io/termscp/>; view release notes with <CTRL+R>"),
|
||||
TextSpan::from(" is NOW available! Install update and view release notes with <CTRL+R>"),
|
||||
])
|
||||
.build(),
|
||||
)),
|
||||
@@ -360,6 +360,22 @@ impl AuthActivity {
|
||||
self.view.render(super::COMPONENT_TEXT_ERROR, f, popup);
|
||||
}
|
||||
}
|
||||
if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_INFO) {
|
||||
if props.visible {
|
||||
let popup = draw_area_in(f.size(), 50, 10);
|
||||
f.render_widget(Clear, popup);
|
||||
// make popup
|
||||
self.view.render(super::COMPONENT_TEXT_INFO, f, popup);
|
||||
}
|
||||
}
|
||||
if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_WAIT) {
|
||||
if props.visible {
|
||||
let popup = draw_area_in(f.size(), 50, 10);
|
||||
f.render_widget(Clear, popup);
|
||||
// make popup
|
||||
self.view.render(super::COMPONENT_TEXT_WAIT, f, popup);
|
||||
}
|
||||
}
|
||||
if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_SIZE_ERR) {
|
||||
if props.visible {
|
||||
let popup = draw_area_in(f.size(), 80, 20);
|
||||
@@ -403,10 +419,22 @@ impl AuthActivity {
|
||||
if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_NEW_VERSION_NOTES) {
|
||||
if props.visible {
|
||||
// make popup
|
||||
let popup = draw_area_in(f.size(), 90, 90);
|
||||
let popup = draw_area_in(f.size(), 90, 85);
|
||||
f.render_widget(Clear, popup);
|
||||
let popup_chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Percentage(90), // Notes
|
||||
Constraint::Length(3), // Install radio
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.split(popup);
|
||||
self.view
|
||||
.render(super::COMPONENT_TEXT_NEW_VERSION_NOTES, f, popup);
|
||||
.render(super::COMPONENT_TEXT_NEW_VERSION_NOTES, f, popup_chunks[0]);
|
||||
self.view
|
||||
.render(super::COMPONENT_RADIO_INSTALL_UPDATE, f, popup_chunks[1]);
|
||||
}
|
||||
}
|
||||
if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_HELP) {
|
||||
@@ -515,7 +543,7 @@ impl AuthActivity {
|
||||
/// ### mount_error
|
||||
///
|
||||
/// Mount error box
|
||||
pub(super) fn mount_error(&mut self, text: &str) {
|
||||
pub(super) fn mount_error<S: AsRef<str>>(&mut self, text: S) {
|
||||
// Mount
|
||||
let err_color = self.theme().misc_error_dialog;
|
||||
self.view.mount(
|
||||
@@ -526,7 +554,7 @@ impl AuthActivity {
|
||||
.with_borders(Borders::ALL, BorderType::Thick, err_color)
|
||||
.bold()
|
||||
.with_text_alignment(Alignment::Center)
|
||||
.with_texts(vec![TextSpan::from(text)])
|
||||
.with_texts(vec![TextSpan::from(text.as_ref().to_string())])
|
||||
.build(),
|
||||
)),
|
||||
);
|
||||
@@ -541,6 +569,61 @@ impl AuthActivity {
|
||||
self.view.umount(super::COMPONENT_TEXT_ERROR);
|
||||
}
|
||||
|
||||
/// ### mount_info
|
||||
///
|
||||
/// Mount info box
|
||||
pub(super) fn mount_info<S: AsRef<str>>(&mut self, text: S, color: Color) {
|
||||
// Mount
|
||||
self.view.mount(
|
||||
super::COMPONENT_TEXT_INFO,
|
||||
Box::new(Paragraph::new(
|
||||
ParagraphPropsBuilder::default()
|
||||
.with_borders(Borders::ALL, BorderType::Thick, color)
|
||||
.bold()
|
||||
.with_text_alignment(Alignment::Center)
|
||||
.with_texts(vec![TextSpan::from(text.as_ref().to_string())])
|
||||
.with_foreground(color)
|
||||
.build(),
|
||||
)),
|
||||
);
|
||||
// Give focus to error
|
||||
self.view.active(super::COMPONENT_TEXT_INFO);
|
||||
}
|
||||
|
||||
/// ### umount_info
|
||||
///
|
||||
/// Umount info message
|
||||
pub(super) fn umount_info(&mut self) {
|
||||
self.view.umount(super::COMPONENT_TEXT_INFO);
|
||||
}
|
||||
|
||||
/// ### mount_error
|
||||
///
|
||||
/// Mount wait box
|
||||
pub(super) fn mount_wait(&mut self, text: &str) {
|
||||
// Mount
|
||||
self.view.mount(
|
||||
super::COMPONENT_TEXT_WAIT,
|
||||
Box::new(Paragraph::new(
|
||||
ParagraphPropsBuilder::default()
|
||||
.with_borders(Borders::ALL, BorderType::Thick, Color::Reset)
|
||||
.bold()
|
||||
.with_text_alignment(Alignment::Center)
|
||||
.with_texts(vec![TextSpan::from(text)])
|
||||
.build(),
|
||||
)),
|
||||
);
|
||||
// Give focus to error
|
||||
self.view.active(super::COMPONENT_TEXT_WAIT);
|
||||
}
|
||||
|
||||
/// ### umount_wait
|
||||
///
|
||||
/// Umount wait message
|
||||
pub(super) fn umount_wait(&mut self) {
|
||||
self.view.umount(super::COMPONENT_TEXT_WAIT);
|
||||
}
|
||||
|
||||
/// ### mount_size_err
|
||||
///
|
||||
/// Mount size error
|
||||
@@ -785,7 +868,22 @@ impl AuthActivity {
|
||||
.build(),
|
||||
)),
|
||||
);
|
||||
self.view.active(super::COMPONENT_TEXT_NEW_VERSION_NOTES);
|
||||
// Mount install popup
|
||||
self.view.mount(
|
||||
super::COMPONENT_RADIO_INSTALL_UPDATE,
|
||||
Box::new(Radio::new(
|
||||
RadioPropsBuilder::default()
|
||||
.with_color(Color::LightYellow)
|
||||
.with_inverted_color(Color::Black)
|
||||
.with_borders(Borders::ALL, BorderType::Rounded, Color::LightYellow)
|
||||
.with_title("Install new version?", Alignment::Left)
|
||||
.with_options(&["Yes", "No"])
|
||||
.with_value(0)
|
||||
.rewind(true)
|
||||
.build(),
|
||||
)),
|
||||
);
|
||||
self.view.active(super::COMPONENT_RADIO_INSTALL_UPDATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -795,6 +893,7 @@ impl AuthActivity {
|
||||
/// Umount release notes text area
|
||||
pub(super) fn umount_release_notes(&mut self) {
|
||||
self.view.umount(super::COMPONENT_TEXT_NEW_VERSION_NOTES);
|
||||
self.view.umount(super::COMPONENT_RADIO_INSTALL_UPDATE);
|
||||
}
|
||||
|
||||
/// ### get_protocol
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
//! ## git
|
||||
//!
|
||||
//! `git` is the module which provides utilities to interact through the GIT API and to perform some stuff at git level
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
// Locals
|
||||
use super::parser::parse_semver;
|
||||
// Others
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
/// ## GithubTag
|
||||
///
|
||||
/// Info related to a github tag
|
||||
pub struct GithubTag {
|
||||
pub tag_name: String,
|
||||
pub body: String,
|
||||
}
|
||||
|
||||
/// ### check_for_updates
|
||||
///
|
||||
/// Check if there is a new version available for termscp.
|
||||
/// This is performed through the Github API
|
||||
/// In case of success returns Ok(Option<GithubTag>), 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 check_for_updates(current_version: &str) -> Result<Option<GithubTag>, String> {
|
||||
// Send request
|
||||
let github_tag: Result<GithubTag, String> =
|
||||
match ureq::get("https://api.github.com/repos/veeso/termscp/releases/latest").call() {
|
||||
Ok(response) => response.into_json::<GithubTag>().map_err(|x| x.to_string()),
|
||||
Err(err) => Err(err.to_string()),
|
||||
};
|
||||
// Check version
|
||||
match github_tag {
|
||||
Err(err) => Err(err),
|
||||
Ok(tag) => {
|
||||
// Parse version
|
||||
match parse_semver(tag.tag_name.as_str()) {
|
||||
Some(new_version) => {
|
||||
// Check if version is different
|
||||
if new_version.as_str() > current_version {
|
||||
Ok(Some(tag)) // New version is available
|
||||
} else {
|
||||
Ok(None) // No new version
|
||||
}
|
||||
}
|
||||
None => Err(String::from("Got bad response from Github")),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg(not(all(
|
||||
any(
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "netbsd"
|
||||
),
|
||||
feature = "github-actions"
|
||||
)))]
|
||||
fn test_utils_git_check_for_updates() {
|
||||
assert!(check_for_updates("100.0.0").ok().unwrap().is_none());
|
||||
assert!(check_for_updates("0.0.1").ok().unwrap().is_some());
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@
|
||||
pub mod crypto;
|
||||
pub mod file;
|
||||
pub mod fmt;
|
||||
pub mod git;
|
||||
pub mod parser;
|
||||
pub mod path;
|
||||
pub mod random;
|
||||
|
||||
Reference in New Issue
Block a user