Auto update (w/ cli)

This commit is contained in:
veeso
2021-09-10 22:22:15 +02:00
parent 8bb05406c8
commit 06a67de14f
21 changed files with 1093 additions and 215 deletions

View File

@@ -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)),
}
}
}

View File

@@ -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) => {

View File

@@ -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

View File

@@ -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