Skip to content

Commit

Permalink
Some cleanup, tray improvements, feature-gate self-replacing
Browse files Browse the repository at this point in the history
  • Loading branch information
nullstalgia committed Nov 13, 2024
1 parent 7937e9d commit c3f017d
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 76 deletions.
9 changes: 5 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ jobs:
- uses: taiki-e/upload-rust-binary-action@v1
with:
bin: redefaulter
# features: portable
features: self-replace
target: ${{ matrix.target }}
include: LICENSE,README.md,example-profiles
# tar: unix
zip: windows
archive: $bin-$tag-$target
token: ${{ secrets.GITHUB_TOKEN }}
checksum: sha512
- uses: actions/attest-build-provenance@v1
with:
subject-path: "**/*.tar.gz,**/*.zip"
# - uses: actions/attest-build-provenance@v1
# with:
# subject-path: "**/*.zip"
# subject-path: "**/*.tar.gz,**/*.zip"
7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
[package]
name = "redefaulter"
repository = "https://github.com/nullstalgia/redefaulter"
version = "0.1.0"
version = "0.0.9"
edition = "2021"

[features]
# default = ["self-replace"]
# When active, ignores user dotfiles/AppData, using the current directory instead
portable = []
# When active, allows the executable to download updates and replace itself
self-replace = ["dep:self-replace"]

[dependencies]
argh = "0.1.12"
Expand Down Expand Up @@ -42,7 +45,7 @@ muda = "0.15.2"
serde_plain = "1.0.2"
derivative = "2.2.0"
sha2 = "0.10.8"
self-replace = "1.5.0"
self-replace = { version = "1.5.0", optional = true }
tempfile = "3.14.0"
reqwest = { version = "0.12.9", features = ["blocking"] }
http = "1.1.0"
Expand Down
32 changes: 0 additions & 32 deletions shadowplay-api-rs/.justfile

This file was deleted.

33 changes: 17 additions & 16 deletions src/popups/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pub fn fatal_error_popup(error: RedefaulterError, lock_file: Option<LockFile>) -

std::process::exit(libc::EXIT_FAILURE);
}

#[cfg(feature = "self-replace")]
pub fn start_new_version_popup() {
win_msgbox::information::<Okay>("Update complete! Ready to launch new version!")
.title("Redefaulter update success!")
Expand Down Expand Up @@ -184,6 +184,22 @@ Playback and Recording Communication devices always be forced to follow the Defa
_ => None,
}),
];

if auto_launch_init {
let auto_launch_prompt: Mapper = |c| match c {
YesNoCancel::Yes => Some(FirstTimeChoice::AutoLaunch(true)),
YesNoCancel::No => Some(FirstTimeChoice::AutoLaunch(false)),
_ => None,
};
prompts.insert(
0,
(
"Auto Launch Redefaulter on Login?".to_string(),
auto_launch_prompt,
),
);
}

let prompts_count = prompts.len();
let text = format!(
r#"Thanks for using Redefaulter! Most controls reside in the System Tray icon.
Expand All @@ -204,21 +220,6 @@ Only {prompts_count} quick questions, and you can Cancel at any time."#,
YesNo::No => return,
}

if auto_launch_init {
let auto_launch_prompt: Mapper = |c| match c {
YesNoCancel::Yes => Some(FirstTimeChoice::AutoLaunch(true)),
YesNoCancel::No => Some(FirstTimeChoice::AutoLaunch(false)),
_ => None,
};
prompts.insert(
0,
(
"Auto Launch Redefaulter on Login?".to_string(),
auto_launch_prompt,
),
);
}

for (index, (prompt, mapper)) in prompts.into_iter().enumerate() {
let title = format!("Redefaulter setup {}/{prompts_count}", index + 1);
let response = win_msgbox::information::<YesNoCancel>(&prompt)
Expand Down
4 changes: 3 additions & 1 deletion src/settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ use tracing::*;
use crate::errors::{AppResult, RedefaulterError};
use crate::platform::PlatformSettings;

// TODO Proper defaults.
// TODO Cleaner defaults.
// What I have now works and is predictable,
// but there's a lot of gross repetition.

#[derive(Debug, Clone, Serialize, Deserialize, MenuToggle, MenuId, TrayChecks, Derivative)]
#[derivative(Default)]
Expand Down
26 changes: 20 additions & 6 deletions src/tray_menu/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ pub mod common_ids {
pub const IGNORE_ID: &str = "ignore";

pub const UPDATE_PREFIX: &str = "update";

#[cfg(feature = "self-replace")]
pub const UPDATE_DOWNLOAD: &str = "update-download";

pub const UPDATE_OPEN_REPO: &str = "update-repo";
pub const UPDATE_DISMISS: &str = "update-dismiss";
pub const UPDATE_SKIP_VERSION: &str = "update-skip";
Expand Down Expand Up @@ -78,11 +81,20 @@ impl App {
}
pub fn update_tray_menu(&self) -> AppResult<()> {
if let Some(handle) = self.tray_menu.as_ref() {
let new_tooltip = format!(
"{} - {} profiles active",
TOOLTIP_PREFIX,
self.profiles.active_len()
);
let post_text = match &self.update_state {
UpdateState::Idle => {
let active_len = self.profiles.active_len();
if active_len == 1 {
"1 profile active".to_string()
} else {
format!("{active_len} profiles active")
}
}
UpdateState::UpdateFound(version) => format!("Update found! (v{version})"),
#[cfg(feature = "self-replace")]
UpdateState::Downloading => "Downloading update...".to_string(),
};
let new_tooltip = format!("{TOOLTIP_PREFIX} - {post_text}");
handle.set_tooltip(Some(new_tooltip))?;
let new_menu = self.build_tray_contents()?;
handle.set_menu(Some(Box::new(new_menu)));
Expand All @@ -96,6 +108,7 @@ impl App {

match &self.update_state {
UpdateState::Idle => (),
#[cfg(feature = "self-replace")]
UpdateState::Downloading => {
let downloading = label_item("Downloading update...");
menu.append(&downloading)?;
Expand Down Expand Up @@ -318,6 +331,7 @@ impl App {
let url = format!("{}/releases", env!("CARGO_PKG_REPOSITORY"));
opener::open_browser(url)?;
}
#[cfg(feature = "self-replace")]
UPDATE_DOWNLOAD => {
self.update_state = UpdateState::Downloading;
self.update_tray_menu()?;
Expand Down Expand Up @@ -402,7 +416,7 @@ impl App {
let reload = MenuItem::with_id(RELOAD_ID, "&Reload Profiles", true, None);
let reveal = MenuItem::with_id(REVEAL_ID, "Reveal Profiles &Folder", true, None);
let settings_submenu = self.build_tray_settings_submenu()?;
let quit = MenuItem::with_id(QUIT_ID, "&Quit", true, None);
let quit = MenuItem::with_id(QUIT_ID, "&Quit Redefaulter", true, None);

menu.append_items(&[
&PredefinedMenuItem::separator(),
Expand Down
1 change: 1 addition & 0 deletions src/tray_menu/updates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub fn tray_update_submenu(version: &str) -> AppResult<Submenu> {
// };

let menu_items: Vec<MenuItem> = vec![
#[cfg(feature = "self-replace")]
MenuItem::with_id(UPDATE_DOWNLOAD, "Download and Install", true, None),
MenuItem::with_id(UPDATE_OPEN_REPO, "Open GitHub Repository", true, None),
MenuItem::with_id(UPDATE_SKIP_VERSION, "Skip this Version", true, None),
Expand Down
50 changes: 35 additions & 15 deletions src/updates/mod.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,59 @@
use std::env::consts::EXE_SUFFIX;
use std::env::current_exe;
use std::io::{BufReader, BufWriter, Read, Write};
use std::path::PathBuf;

use crate::app::{App, AppEventProxy, CustomEvent};
use crate::errors::{AppResult, RedefaulterError};
use crate::is_portable;
use crate::popups::start_new_version_popup;
use crate::errors::AppResult;

use fs_err as fs;
use http::HeaderMap;
use self_update::cargo_crate_version;
use self_update::get_target;
use self_update::update::ReleaseAsset;
use self_update::version::bump_is_greater;
use sha2::{Digest, Sha512};
use std::sync::mpsc::{self, Receiver};
use tracing::*;

#[cfg(feature = "self-replace")]
use {
crate::errors::RedefaulterError,
crate::{is_portable, popups::start_new_version_popup},
fs_err as fs,
http::HeaderMap,
sha2::{Digest, Sha512},
std::env::{consts::EXE_SUFFIX, current_exe},
std::io::{BufReader, BufWriter, Read, Write},
std::path::PathBuf,
};

#[derive(Debug)]
enum UpdateCommand {
CheckForUpdate,
#[cfg(feature = "self-replace")]
DownloadUpdate,
#[cfg(feature = "self-replace")]
LaunchUpdatedApp,
}
#[derive(Debug)]
pub enum UpdateState {
Idle,
UpdateFound(String),
#[cfg(feature = "self-replace")]
Downloading,
// ReadyToLaunch,
}
#[derive(Debug)]
pub enum UpdateReply {
UpToDate,
UpdateFound(String),
// Not used since each time we update the menu, it'd hide it
// DownloadProgress(f64),
#[cfg(feature = "self-replace")]
ReadyToLaunch,
#[cfg(feature = "self-replace")]
Error(RedefaulterError),
// CheckError(RedefaulterError),
// Not used since each time we update the menu, it'd hide it
// DownloadProgress(f64),
}
#[derive(Debug)]
struct UpdateBackend {
command_rx: Receiver<UpdateCommand>,
event_proxy: AppEventProxy,
archive_asset: Option<ReleaseAsset>,
checksum_asset: Option<ReleaseAsset>,
#[cfg(feature = "self-replace")]
current_exe: Option<PathBuf>,
}
impl UpdateBackend {
Expand All @@ -56,6 +63,7 @@ impl UpdateBackend {
event_proxy,
archive_asset: None,
checksum_asset: None,
#[cfg(feature = "self-replace")]
current_exe: None,
}
}
Expand All @@ -66,6 +74,7 @@ impl UpdateBackend {
error!("Failed checking for update! {e}");
}
}
#[cfg(feature = "self-replace")]
UpdateCommand::DownloadUpdate => match self.update_executable() {
Ok(()) => self
.event_proxy
Expand All @@ -77,6 +86,7 @@ impl UpdateBackend {
.send_event(CustomEvent::UpdateReply(UpdateReply::Error(e)))
.expect("Failed to send updater error"),
},
#[cfg(feature = "self-replace")]
UpdateCommand::LaunchUpdatedApp => match self.start_new_version() {
Ok(()) => {
unreachable!()
Expand All @@ -88,6 +98,7 @@ impl UpdateBackend {
},
}
}
#[cfg(feature = "self-replace")]
/// Streams the supplied URL's contents into the given File, checking the SHA512 hash of the archive with a supplied checksum by URL
fn download_and_verify<T: Write + Unpin>(
&self,
Expand Down Expand Up @@ -183,6 +194,7 @@ impl UpdateBackend {
Err(RedefaulterError::BadChecksum)
}
}
#[cfg(feature = "self-replace")]
/// This should never return, unless an error occurs.
fn start_new_version(&mut self) -> AppResult<()> {
let current_exe = self.current_exe.take().unwrap();
Expand All @@ -192,6 +204,7 @@ impl UpdateBackend {

unreachable!()
}
#[cfg(feature = "self-replace")]
fn update_executable(&mut self) -> AppResult<()> {
if !is_portable() {
return Err(RedefaulterError::NotPortable);
Expand Down Expand Up @@ -325,12 +338,14 @@ impl UpdateHandle {
.send(msg)
.expect("Unable to start query for version");
}
#[cfg(feature = "self-replace")]
pub fn download_update(&self) {
let msg = UpdateCommand::DownloadUpdate;
self.command_tx
.send(msg)
.expect("Unable to start query for version");
}
#[cfg(feature = "self-replace")]
pub fn start_new_version(&self) {
let msg = UpdateCommand::LaunchUpdatedApp;
self.command_tx
Expand All @@ -342,11 +357,13 @@ impl UpdateHandle {
// Yoinked from
// https://github.com/lichess-org/fishnet/blob/eac238abbd77b7fc8cacd2d1f7c408252746e2f5/src/main.rs#L399

#[cfg(feature = "self-replace")]
fn restart_process(current_exe: PathBuf) -> std::io::Error {
exec(std::process::Command::new(current_exe).args(std::env::args_os().skip(1)))
}

#[cfg(unix)]
#[cfg(feature = "self-replace")]
fn exec(command: &mut std::process::Command) -> std::io::Error {
use std::os::unix::process::CommandExt as _;
// Completely replace the current process image. If successful, execution
Expand All @@ -355,6 +372,7 @@ fn exec(command: &mut std::process::Command) -> std::io::Error {
}

#[cfg(windows)]
#[cfg(feature = "self-replace")]
fn exec(command: &mut std::process::Command) -> std::io::Error {
use std::os::windows::process::CommandExt as _;
// No equivalent for Unix exec() exists. So create a new independent
Expand All @@ -371,6 +389,7 @@ impl App {
pub fn handle_update_reply(&mut self, reply: UpdateReply) -> AppResult<()> {
use UpdateReply::*;
match reply {
#[cfg(feature = "self-replace")]
ReadyToLaunch => {
self.kill_tray_menu();
start_new_version_popup();
Expand All @@ -391,8 +410,9 @@ impl App {
}
}
}
#[cfg(feature = "self-replace")]
Error(e) => {
error!("Error during update! {e}");
error!("Error during self update! {e}");
_ = self.updates.take();
return Err(e);
}
Expand Down

0 comments on commit c3f017d

Please sign in to comment.