Add a global shortcut for the maintenance tool

This commit is contained in:
James 2018-08-08 19:58:30 +10:00
parent 82b3681a74
commit 19bec5d80c
10 changed files with 177 additions and 19 deletions

View file

@ -27,6 +27,7 @@ use logging::LoggingErrors;
use dirs::home_dir;
use std::fs::remove_file;
use tasks::uninstall_global_shortcut::UninstallGlobalShortcutsTask;
/// A message thrown during the installation of packages.
#[derive(Serialize)]
@ -36,12 +37,29 @@ pub enum InstallMessage {
EOF,
}
/// Metadata about the current installation itself.
#[derive(Serialize, Deserialize, Clone)]
pub struct InstallationDatabase {
pub packages: Vec<LocalInstallation>,
pub shortcuts: Vec<String>,
}
impl InstallationDatabase {
/// Creates a new, empty installation database.
pub fn new() -> InstallationDatabase {
InstallationDatabase {
packages: Vec::new(),
shortcuts: Vec::new(),
}
}
}
/// The installer framework contains metadata about packages, what is installable, what isn't,
/// etc.
pub struct InstallerFramework {
pub base_attributes: BaseAttributes,
pub config: Option<Config>,
pub database: Vec<LocalInstallation>,
pub database: InstallationDatabase,
pub install_path: Option<PathBuf>,
pub preexisting_install: bool,
pub is_launcher: bool,
@ -51,7 +69,7 @@ pub struct InstallerFramework {
/// Contains basic properties on the status of the session. Subset of InstallationFramework.
#[derive(Serialize)]
pub struct InstallationStatus {
pub database: Vec<LocalInstallation>,
pub database: InstallationDatabase,
pub install_path: Option<String>,
pub preexisting_install: bool,
pub is_launcher: bool,
@ -110,7 +128,7 @@ impl InstallerFramework {
// Calculate packages to *uninstall*
let mut uninstall_items = Vec::new();
if !fresh_install {
for package in &self.database {
for package in &self.database.packages {
if !items.contains(&package.name) {
uninstall_items.push(package.name.clone());
}
@ -141,7 +159,12 @@ impl InstallerFramework {
/// Sends a request for everything to be uninstalled.
pub fn uninstall(&mut self, messages: &Sender<InstallMessage>) -> Result<(), String> {
let items: Vec<String> = self.database.iter().map(|x| x.name.clone()).collect();
let items: Vec<String> = self
.database
.packages
.iter()
.map(|x| x.name.clone())
.collect();
let task = Box::new(UninstallTask { items });
@ -155,6 +178,17 @@ impl InstallerFramework {
}
}).map(|_x| ())?;
// Uninstall shortcuts
let task = Box::new(UninstallGlobalShortcutsTask {});
let mut tree = DependencyTree::build(task);
tree.execute(self, &|msg: &str, progress: f64| {
if let Err(v) = messages.send(InstallMessage::Status(msg.to_string(), progress as _)) {
error!("Failed to submit queue message: {:?}", v);
}
}).map(|_x| ())?;
// Delete the metadata file
let path = self
.install_path
@ -216,7 +250,7 @@ impl InstallerFramework {
InstallerFramework {
base_attributes: attrs,
config: None,
database: Vec::new(),
database: InstallationDatabase::new(),
install_path: None,
preexisting_install: false,
is_launcher: false,
@ -234,7 +268,7 @@ impl InstallerFramework {
Err(v) => return Err(format!("Unable to open file handle: {:?}", v)),
};
let database: Vec<LocalInstallation> = match serde_json::from_reader(metadata_file) {
let database: InstallationDatabase = match serde_json::from_reader(metadata_file) {
Ok(v) => v,
Err(v) => return Err(format!("Unable to read metadata file: {:?}", v)),
};

View file

@ -35,7 +35,7 @@ impl Task for DownloadPackageTask {
};
// Check to see if this is the newest file available already
for element in &context.database {
for element in &context.database.packages {
if element.name == self.name {
if element.version == version {
info!("{:?} is already up to date.", self.name);

View file

@ -7,6 +7,7 @@ use tasks::install_pkg::InstallPackageTask;
use tasks::save_executable::SaveExecutableTask;
use tasks::uninstall_pkg::UninstallPackageTask;
use tasks::install_global_shortcut::InstallGlobalShortcutsTask;
use tasks::Task;
use tasks::TaskDependency;
use tasks::TaskOrdering;
@ -61,6 +62,11 @@ impl Task for InstallTask {
TaskOrdering::Pre,
Box::new(SaveExecutableTask {}),
));
elements.push(TaskDependency::build(
TaskOrdering::Pre,
Box::new(InstallGlobalShortcutsTask {}),
));
}
elements

View file

@ -0,0 +1,72 @@
//! Generates the global shortcut for this application.
use installer::InstallerFramework;
use tasks::Task;
use tasks::TaskDependency;
use tasks::TaskParamType;
use logging::LoggingErrors;
use native::create_shortcut;
use tasks::save_database::SaveDatabaseTask;
use tasks::TaskOrdering;
pub struct InstallGlobalShortcutsTask {}
impl Task for InstallGlobalShortcutsTask {
fn execute(
&mut self,
_: Vec<TaskParamType>,
context: &mut InstallerFramework,
messenger: &Fn(&str, f64),
) -> Result<TaskParamType, String> {
messenger(&format!("Generating global shortcut..."), 0.0);
let path = context
.install_path
.as_ref()
.log_expect("No install path specified");
let starting_dir = path
.to_str()
.log_expect("Unable to build shortcut metadata (startingdir)");
// Generate installer path
let platform_extension = if cfg!(windows) {
"maintenancetool.exe"
} else {
"maintenancetool"
};
let tool_path = path.join(platform_extension);
let tool_path = tool_path
.to_str()
.log_expect("Unable to build shortcut metadata (tool)");
context.database.shortcuts.push(create_shortcut(
&format!("{} maintenance tool", context.base_attributes.name),
&format!(
"Launch the {} maintenance tool to update, modify and uninstall the application.",
context.base_attributes.name
),
tool_path,
// TODO: Send by list
"",
&starting_dir,
)?);
Ok(TaskParamType::None)
}
fn dependencies(&self) -> Vec<TaskDependency> {
vec![TaskDependency::build(
TaskOrdering::Post,
Box::new(SaveDatabaseTask {}),
)]
}
fn name(&self) -> String {
"InstallGlobalShortcutsTask".to_string()
}
}

View file

@ -163,7 +163,7 @@ impl Task for InstallPackageTask {
})?;
// Save metadata about this package
context.database.push(LocalInstallation {
context.database.packages.push(LocalInstallation {
name: package.name.to_owned(),
version,
shortcuts,

View file

@ -12,12 +12,14 @@ use sources::types::Version;
pub mod download_pkg;
pub mod install;
pub mod install_dir;
pub mod install_global_shortcut;
pub mod install_pkg;
pub mod install_shortcuts;
pub mod resolver;
pub mod save_database;
pub mod save_executable;
pub mod uninstall;
pub mod uninstall_global_shortcut;
pub mod uninstall_pkg;
pub mod uninstall_shortcuts;

View file

@ -0,0 +1,44 @@
//! Uninstalls a specific package.
use installer::InstallerFramework;
use tasks::Task;
use tasks::TaskDependency;
use tasks::TaskParamType;
use std::fs::remove_file;
use tasks::save_database::SaveDatabaseTask;
use tasks::TaskOrdering;
pub struct UninstallGlobalShortcutsTask {}
impl Task for UninstallGlobalShortcutsTask {
fn execute(
&mut self,
input: Vec<TaskParamType>,
context: &mut InstallerFramework,
messenger: &Fn(&str, f64),
) -> Result<TaskParamType, String> {
assert_eq!(input.len(), 0);
messenger(&format!("Uninstalling global shortcut..."), 0.0);
while let Some(file) = context.database.shortcuts.pop() {
info!("Deleting shortcut {:?}", file);
remove_file(file).map_err(|x| format!("Unable to delete global shortcut: {:?}", x))?;
}
Ok(TaskParamType::None)
}
fn dependencies(&self) -> Vec<TaskDependency> {
vec![TaskDependency::build(
TaskOrdering::Post,
Box::new(SaveDatabaseTask {}),
)]
}
fn name(&self) -> String {
"UninstallGlobalShortcutsTask".to_string()
}
}

View file

@ -36,9 +36,9 @@ impl Task for UninstallPackageTask {
.log_expect("No install path specified");
let mut metadata: Option<LocalInstallation> = None;
for i in 0..context.database.len() {
if self.name == context.database[i].name {
metadata = Some(context.database.remove(i));
for i in 0..context.database.packages.len() {
if self.name == context.database.packages[i].name {
metadata = Some(context.database.packages.remove(i));
break;
}
}

View file

@ -33,9 +33,9 @@ impl Task for UninstallShortcutsTask {
.log_expect("No install path specified");
let mut metadata: Option<LocalInstallation> = None;
for i in 0..context.database.len() {
if self.name == context.database[i].name {
metadata = Some(context.database[i].clone());
for i in 0..context.database.packages.len() {
if self.name == context.database.packages[i].name {
metadata = Some(context.database.packages[i].clone());
break;
}
}
@ -66,10 +66,10 @@ impl Task for UninstallShortcutsTask {
for (i, file) in package.shortcuts.iter().enumerate() {
let name = file.clone();
let file = path.join(file);
info!("Deleting {:?}", file);
info!("Deleting shortcut {:?}", file);
messenger(
&format!("Deleting {} ({} of {})", name, i + 1, max),
&format!("Deleting shortcut {} ({} of {})", name, i + 1, max),
(i as f64) / (max as f64),
);
@ -80,7 +80,7 @@ impl Task for UninstallShortcutsTask {
};
if let Err(v) = result {
error!("Failed to delete file: {:?}", v);
error!("Failed to delete shortcut: {:?}", v);
}
}

View file

@ -53,10 +53,10 @@ const DownloadConfig = {
app.config.packages[x].installed = false;
}
for (var i = 0; i < app.metadata.database.length; i++) {
for (var i = 0; i < app.metadata.database.packages.length; i++) {
// Find this config package
for (var x = 0; x < app.config.packages.length; x++) {
if (app.config.packages[x].name === app.metadata.database[i].name) {
if (app.config.packages[x].name === app.metadata.database.packages[i].name) {
app.config.packages[x].default = true;
app.config.packages[x].installed = true;
}