This repository has been archived by the owner on Jul 5, 2024. It is now read-only.
forked from Squirrel/Squirrel.Windows
-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
810 additions
and
805 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"rust-analyzer.cargo.features": ["windows"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
use crate::shared::{ | ||
self, | ||
bundle::{self, BundleInfo, Manifest}, | ||
}; | ||
use anyhow::{bail, Result}; | ||
use glob::glob; | ||
use std::path::PathBuf; | ||
|
||
pub fn apply<'a>(restart: bool, wait_for_parent: bool, package: Option<&PathBuf>, exe_name: Option<&String>, exe_args: Option<Vec<&str>>) -> Result<()> { | ||
if wait_for_parent { | ||
let _ = shared::wait_for_parent_to_exit(60_000); // 1 minute | ||
} | ||
|
||
if let Err(e) = apply_package(package) { | ||
error!("Error applying package: {}", e); | ||
if !restart { | ||
return Err(e); | ||
} | ||
} | ||
|
||
if restart { | ||
super::start(false, exe_name, exe_args, None)?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn apply_package<'a>(package: Option<&PathBuf>) -> Result<()> { | ||
let mut package_manifest: Option<Manifest> = None; | ||
let mut package_bundle: Option<BundleInfo<'a>> = None; | ||
|
||
let (root_path, app) = shared::detect_current_manifest()?; | ||
|
||
if let Some(pkg) = package { | ||
info!("Loading package from argument '{}'.", pkg.to_string_lossy()); | ||
let bun = bundle::load_bundle_from_file(&pkg)?; | ||
package_manifest = Some(bun.read_manifest()?); | ||
package_bundle = Some(bun); | ||
} else { | ||
info!("No package specified, searching for latest."); | ||
let packages_dir = app.get_packages_path(&root_path); | ||
if let Ok(paths) = glob(format!("{}/*.nupkg", packages_dir).as_str()) { | ||
for path in paths { | ||
if let Ok(path) = path { | ||
trace!("Checking package: '{}'", path.to_string_lossy()); | ||
if let Ok(bun) = bundle::load_bundle_from_file(&path) { | ||
if let Ok(mani) = bun.read_manifest() { | ||
if package_manifest.is_none() || mani.version > package_manifest.clone().unwrap().version { | ||
info!("Found {}: '{}'", mani.version, path.to_string_lossy()); | ||
package_manifest = Some(mani); | ||
package_bundle = Some(bun); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
if package_manifest.is_none() || package_bundle.is_none() { | ||
bail!("Unable to find/load suitable package."); | ||
} | ||
|
||
let package_manifest = package_manifest.unwrap(); | ||
|
||
let found_version = package_manifest.clone().version; | ||
if found_version <= app.version { | ||
bail!("Latest package found is {}, which is not newer than current version {}.", found_version, app.version); | ||
} | ||
|
||
info!("Applying package to current: {}", found_version); | ||
|
||
#[cfg(target_os = "windows")] | ||
crate::windows::run_hook(&app, &root_path, "--squirrel-obsoleted", 15); | ||
|
||
let current_dir = app.get_current_path(&root_path); | ||
shared::replace_dir_with_rollback(current_dir.clone(), || { | ||
if let Some(bundle) = package_bundle.take() { | ||
bundle.extract_lib_contents_to_path(¤t_dir, |_| {}) | ||
} else { | ||
bail!("No bundle could be loaded."); | ||
} | ||
})?; | ||
|
||
#[cfg(target_os = "windows")] | ||
crate::windows::run_hook(&package_manifest, &root_path, "--squirrel-updated", 15); | ||
|
||
info!("Package applied successfully."); | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
mod apply; | ||
pub use apply::*; | ||
|
||
mod start; | ||
pub use start::*; | ||
|
||
#[cfg(target_os = "windows")] | ||
mod uninstall; | ||
#[cfg(target_os = "windows")] | ||
pub use uninstall::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use crate::shared; | ||
use anyhow::{bail, Result}; | ||
use std::path::Path; | ||
|
||
#[cfg(target_os = "windows")] | ||
pub fn start(wait_for_parent: bool, exe_name: Option<&String>, exe_args: Option<Vec<&str>>, legacy_args: Option<&String>) -> Result<()> { | ||
if legacy_args.is_some() { | ||
info!(" Legacy Args: {:?}", legacy_args); | ||
warn!("Legacy args format is deprecated and will be removed in a future release. Please update your application to use the new format."); | ||
} | ||
|
||
if legacy_args.is_some() && exe_args.is_some() { | ||
bail!("Cannot use both legacy args and new args format."); | ||
} | ||
|
||
if wait_for_parent { | ||
shared::wait_for_parent_to_exit(60_000)?; // 1 minute | ||
} | ||
|
||
let (root_path, app) = shared::detect_current_manifest()?; | ||
|
||
let current = app.get_current_path(&root_path); | ||
let exe_to_execute = if let Some(exe) = exe_name { | ||
Path::new(¤t).join(exe) | ||
} else { | ||
let exe = app.get_main_exe_path(&root_path); | ||
Path::new(&exe).to_path_buf() | ||
}; | ||
|
||
if !exe_to_execute.exists() { | ||
bail!("Unable to find executable to start: '{}'", exe_to_execute.to_string_lossy()); | ||
} | ||
|
||
crate::windows::assert_can_run_binary_authenticode(&exe_to_execute)?; | ||
|
||
info!("About to launch: '{}' in dir '{}'", exe_to_execute.to_string_lossy(), current); | ||
|
||
if let Some(args) = exe_args { | ||
crate::shared::run_process(exe_to_execute, args, current)?; | ||
} else if let Some(args) = legacy_args { | ||
crate::windows::run_process_raw_args(exe_to_execute, args, current)?; | ||
} else { | ||
crate::shared::run_process(exe_to_execute, vec![], current)?; | ||
}; | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
use crate::shared::{self, bundle::Manifest}; | ||
use crate::windows; | ||
use anyhow::Result; | ||
use std::fs::File; | ||
use std::path::PathBuf; | ||
|
||
pub fn uninstall(log_file: &PathBuf) -> Result<()> { | ||
info!("Command: Uninstall"); | ||
let (root_path, app) = shared::detect_current_manifest()?; | ||
|
||
fn _uninstall_impl(app: &Manifest, root_path: &PathBuf) -> bool { | ||
// the real app could be running at the moment | ||
let _ = shared::force_stop_package(&root_path); | ||
|
||
let mut finished_with_errors = false; | ||
|
||
// run uninstall hook | ||
windows::run_hook(&app, root_path, "--squirrel-uninstall", 60); | ||
|
||
if let Err(e) = windows::remove_all_shortcuts_for_root_dir(&root_path) { | ||
error!("Unable to remove shortcuts ({}).", e); | ||
// finished_with_errors = true; | ||
} | ||
|
||
info!("Removing directory '{}'", root_path.to_string_lossy()); | ||
if let Err(e) = shared::retry_io(|| remove_dir_all::remove_dir_containing_current_executable()) { | ||
error!("Unable to remove directory, some files may be in use ({}).", e); | ||
finished_with_errors = true; | ||
} | ||
|
||
if let Err(e) = app.remove_uninstall_entry() { | ||
error!("Unable to remove uninstall registry entry ({}).", e); | ||
// finished_with_errors = true; | ||
} | ||
|
||
!finished_with_errors | ||
} | ||
|
||
// if it returns true, it was a success. | ||
// if it returns false, it was completed with errors which the user should be notified of. | ||
let result = _uninstall_impl(&app, &root_path); | ||
|
||
if result { | ||
info!("Finished successfully."); | ||
shared::dialogs::show_info("The application was successfully uninstalled.", format!("{} Uninstall", app.title)); | ||
} else { | ||
error!("Finished with errors."); | ||
shared::dialogs::show_uninstall_complete_with_errors_dialog(&app, &log_file); | ||
} | ||
|
||
let dead_path = root_path.join(".dead"); | ||
let _ = File::create(dead_path); | ||
if let Err(e) = windows::register_intent_to_delete_self(5, &root_path) { | ||
warn!("Unable to schedule self delete ({}).", e); | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
use std::path::PathBuf; | ||
use anyhow::Result; | ||
use simplelog::*; | ||
|
||
pub fn trace_logger() { | ||
TermLogger::init(LevelFilter::Trace, Config::default(), TerminalMode::Mixed, ColorChoice::Never).unwrap(); | ||
} | ||
|
||
pub fn setup_logging(file: Option<&PathBuf>, console: bool, verbose: bool, nocolor: bool) -> Result<()> { | ||
let mut loggers: Vec<Box<dyn SharedLogger>> = Vec::new(); | ||
let color_choice = if nocolor { ColorChoice::Never } else { ColorChoice::Auto }; | ||
if console { | ||
let console_level = if verbose { LevelFilter::Debug } else { LevelFilter::Info }; | ||
loggers.push(TermLogger::new(console_level, Config::default(), TerminalMode::Mixed, color_choice)); | ||
} | ||
|
||
if let Some(f) = file { | ||
let file_level = if verbose { LevelFilter::Trace } else { LevelFilter::Info }; | ||
let writer = file_rotate::FileRotate::new( | ||
f.clone(), | ||
file_rotate::suffix::AppendCount::new(1), // keep 1 old log file | ||
file_rotate::ContentLimit::Bytes(1 * 1024 * 1024), // 1MB max log file size | ||
file_rotate::compression::Compression::None, | ||
); | ||
loggers.push(WriteLogger::new(file_level, Config::default(), writer)); | ||
} | ||
|
||
CombinedLogger::init(loggers)?; | ||
Ok(()) | ||
} |
Oops, something went wrong.