meta: add repair functionality

This commit is contained in:
liushuyu 2020-05-27 21:36:49 -06:00
parent c7628c1474
commit 45c562d723
9 changed files with 112 additions and 10 deletions

View File

@ -23,11 +23,12 @@ pub fn handle(service: &WebService, req: Request) -> Future {
Box::new(req.body().concat2().map(move |b| { Box::new(req.body().concat2().map(move |b| {
let results = form_urlencoded::parse(b.as_ref()) let results = form_urlencoded::parse(b.as_ref())
.into_owned() .into_owned()
.collect::<HashMap<String, String>>(); .collect::<HashMap<String, String>>();
let mut to_install = Vec::new(); let mut to_install = Vec::new();
let mut path: Option<String> = None; let mut path: Option<String> = None;
let mut force_install = false;
// Transform results into just an array of stuff to install // Transform results into just an array of stuff to install
for (key, value) in &results { for (key, value) in &results {
@ -36,6 +37,11 @@ pub fn handle(service: &WebService, req: Request) -> Future {
continue; continue;
} }
if key == "mode" && value == "force" {
force_install = true;
continue;
}
if value == "true" { if value == "true" {
to_install.push(key.to_owned()); to_install.push(key.to_owned());
} }
@ -55,7 +61,7 @@ pub fn handle(service: &WebService, req: Request) -> Future {
framework.set_install_dir(&path); framework.set_install_dir(&path);
} }
if let Err(v) = framework.install(to_install, &sender, new_install) { if let Err(v) = framework.install(to_install, &sender, new_install, force_install) {
error!("Install error occurred: {:?}", v); error!("Install error occurred: {:?}", v);
if let Err(v) = sender.send(InstallMessage::Error(v)) { if let Err(v) = sender.send(InstallMessage::Error(v)) {
error!("Failed to send install error: {:?}", v); error!("Failed to send install error: {:?}", v);

View File

@ -153,11 +153,13 @@ impl InstallerFramework {
/// items: Array of named packages to be installed/kept /// items: Array of named packages to be installed/kept
/// messages: Channel used to send progress messages /// messages: Channel used to send progress messages
/// fresh_install: If the install directory must be empty /// fresh_install: If the install directory must be empty
/// force_install: If the install directory should be erased first
pub fn install( pub fn install(
&mut self, &mut self,
items: Vec<String>, items: Vec<String>,
messages: &Sender<InstallMessage>, messages: &Sender<InstallMessage>,
fresh_install: bool, fresh_install: bool,
force_install: bool,
) -> Result<(), String> { ) -> Result<(), String> {
info!( info!(
"Framework: Installing {:?} to {:?}", "Framework: Installing {:?} to {:?}",
@ -186,6 +188,7 @@ impl InstallerFramework {
items, items,
uninstall_items, uninstall_items,
fresh_install, fresh_install,
force_install
}); });
let mut tree = DependencyTree::build(task); let mut tree = DependencyTree::build(task);

View File

@ -6,6 +6,7 @@ use crate::tasks::ensure_only_instance::EnsureOnlyInstanceTask;
use crate::tasks::install_dir::VerifyInstallDirTask; use crate::tasks::install_dir::VerifyInstallDirTask;
use crate::tasks::install_global_shortcut::InstallGlobalShortcutsTask; use crate::tasks::install_global_shortcut::InstallGlobalShortcutsTask;
use crate::tasks::install_pkg::InstallPackageTask; use crate::tasks::install_pkg::InstallPackageTask;
use crate::tasks::remove_target_dir::RemoveTargetDirTask;
use crate::tasks::save_executable::SaveExecutableTask; use crate::tasks::save_executable::SaveExecutableTask;
use crate::tasks::uninstall_pkg::UninstallPackageTask; use crate::tasks::uninstall_pkg::UninstallPackageTask;
@ -19,6 +20,8 @@ pub struct InstallTask {
pub items: Vec<String>, pub items: Vec<String>,
pub uninstall_items: Vec<String>, pub uninstall_items: Vec<String>,
pub fresh_install: bool, pub fresh_install: bool,
// force_install: remove the target directory before installing
pub force_install: bool,
} }
impl Task for InstallTask { impl Task for InstallTask {
@ -40,6 +43,13 @@ impl Task for InstallTask {
Box::new(EnsureOnlyInstanceTask {}), Box::new(EnsureOnlyInstanceTask {}),
)); ));
if self.force_install {
elements.push(TaskDependency::build(
TaskOrdering::Pre,
Box::new(RemoveTargetDirTask {}),
));
}
elements.push(TaskDependency::build( elements.push(TaskDependency::build(
TaskOrdering::Pre, TaskOrdering::Pre,
Box::new(VerifyInstallDirTask { Box::new(VerifyInstallDirTask {

View File

@ -23,6 +23,7 @@ pub mod uninstall;
pub mod uninstall_global_shortcut; pub mod uninstall_global_shortcut;
pub mod uninstall_pkg; pub mod uninstall_pkg;
pub mod uninstall_shortcuts; pub mod uninstall_shortcuts;
pub mod remove_target_dir;
/// An abstraction over the various parameters that can be passed around. /// An abstraction over the various parameters that can be passed around.
pub enum TaskParamType { pub enum TaskParamType {

View File

@ -0,0 +1,58 @@
//! remove the whole target directory from the existence
use crate::installer::InstallerFramework;
use crate::tasks::Task;
use crate::tasks::TaskDependency;
use crate::tasks::TaskMessage;
use crate::tasks::TaskParamType;
pub struct RemoveTargetDirTask {}
impl Task for RemoveTargetDirTask {
fn execute(
&mut self,
_: Vec<TaskParamType>,
context: &mut InstallerFramework,
messenger: &dyn Fn(&TaskMessage),
) -> Result<TaskParamType, String> {
messenger(&TaskMessage::DisplayMessage(
"Removing previous install...",
0.1,
));
// erase the database as well
context.database.packages = Vec::new();
if let Some(path) = context.install_path.as_ref() {
let entries = std::fs::read_dir(path)
.map_err(|e| format!("Error reading {}: {}", path.to_string_lossy(), e))?;
// remove everything except the maintenancetool
for entry in entries {
let path = entry
.map_err(|e| format!("Error reading file: {}", e))?
.path();
if let Some(filename) = path.file_name() {
if filename.to_string_lossy().starts_with("maintenancetool") {
continue;
}
}
if path.is_dir() {
std::fs::remove_dir_all(&path)
.map_err(|e| format!("Error removing {}: {}", path.to_string_lossy(), e))?;
} else {
std::fs::remove_file(&path)
.map_err(|e| format!("Error removing {}: {}", path.to_string_lossy(), e))?;
}
}
}
Ok(TaskParamType::None)
}
fn dependencies(&self) -> Vec<TaskDependency> {
vec![]
}
fn name(&self) -> String {
"RemoveTargetDirTask".to_string()
}
}

View File

@ -13,10 +13,12 @@
}, },
"select_packages":{ "select_packages":{
"title":"Select which packages you want to install:", "title":"Select which packages you want to install:",
"title_repair":"Select which packages you want to repair:",
"installed":"(installed)", "installed":"(installed)",
"advanced":"Advanced...", "advanced":"Advanced...",
"install":"Install", "install":"Install",
"modify":"Modify", "modify":"Modify",
"repair": "Repair",
"location":"Install Location", "location":"Install Location",
"location_placeholder":"Enter a install path here", "location_placeholder":"Enter a install path here",
"select":"Select" "select":"Select"
@ -44,6 +46,7 @@
"title":"Choose an option:", "title":"Choose an option:",
"update":"Update", "update":"Update",
"modify":"Modify", "modify":"Modify",
"repair": "Repair",
"uninstall":"Uninstall", "uninstall":"Uninstall",
"prompt":"Are you sure you want to uninstall {name}?" "prompt":"Are you sure you want to uninstall {name}?"
}, },

View File

@ -24,6 +24,7 @@ export default {
is_uninstall: false, is_uninstall: false,
is_updater_update: false, is_updater_update: false,
is_update: false, is_update: false,
is_repair: false,
failed_with_error: false, failed_with_error: false,
packages_installed: 0 packages_installed: 0
} }
@ -32,6 +33,7 @@ export default {
this.is_uninstall = this.$route.params.kind === 'uninstall' this.is_uninstall = this.$route.params.kind === 'uninstall'
this.is_updater_update = this.$route.params.kind === 'updater' this.is_updater_update = this.$route.params.kind === 'updater'
this.is_update = this.$route.params.kind === 'update' this.is_update = this.$route.params.kind === 'update'
this.is_repair = this.$route.params.kind === 'repair'
console.log('Installer kind: ' + this.$route.params.kind) console.log('Installer kind: ' + this.$route.params.kind)
this.install() this.install()
}, },
@ -51,6 +53,10 @@ export default {
results.path = app.install_location results.path = app.install_location
if (this.is_repair) {
results['mode'] = 'force'
}
var targetUrl = '/api/start-install' var targetUrl = '/api/start-install'
if (this.is_uninstall) { if (this.is_uninstall) {
targetUrl = '/api/uninstall' targetUrl = '/api/uninstall'

View File

@ -14,6 +14,12 @@
<br /> <br />
<br /> <br />
<a class="button is-dark is-medium" v-on:click="repair_packages">
{{ $t('modify.repair') }}
</a>
<br />
<br />
<b-button class="is-dark is-medium" v-on:click="prepare_uninstall"> <b-button class="is-dark is-medium" v-on:click="prepare_uninstall">
{{ $t('modify.uninstall') }} {{ $t('modify.uninstall') }}
</b-button> </b-button>
@ -48,6 +54,9 @@ export default {
modify_packages: function () { modify_packages: function () {
this.$router.push('/packages') this.$router.push('/packages')
}, },
repair_packages: function () {
this.$router.push({ name: 'packages', params: { repair: true } })
},
prepare_uninstall: function () { prepare_uninstall: function () {
this.show_uninstall = true this.show_uninstall = true
}, },
@ -56,7 +65,8 @@ export default {
}, },
uninstall: function () { uninstall: function () {
this.$router.push('/install/uninstall') this.$router.push('/install/uninstall')
} },
view_files: function () {}
} }
} }
</script> </script>

View File

@ -1,6 +1,7 @@
<template> <template>
<div class="column has-padding"> <div class="column has-padding">
<h4 class="subtitle">{{ $t('select_packages.title') }}</h4> <h4 class="subtitle" v-if="!repair">{{ $t('select_packages.title') }}</h4>
<h4 class="subtitle" v-if="repair">{{ $t('select_packages.title_repair') }}</h4>
<!-- Build options --> <!-- Build options -->
<div class="tile is-ancestor"> <div class="tile is-ancestor">
@ -45,8 +46,8 @@
v-on:click="install">{{ $t('select_packages.install') }}</b-button> v-on:click="install">{{ $t('select_packages.install') }}</b-button>
</p> </p>
<p class="control"> <p class="control">
<b-button class="is-dark is-medium" v-if="$root.$data.metadata.preexisting_install" <a class="button is-dark is-medium" v-if="$root.$data.metadata.preexisting_install"
v-on:click="install">{{ $t('select_packages.modify') }}</b-button> v-on:click="install">{{ repair ? $t('select_packages.repair') : $t('select_packages.modify') }}</a>
</p> </p>
</div> </div>
</div> </div>
@ -65,9 +66,13 @@ export default {
name: 'SelectPackages', name: 'SelectPackages',
data: function () { data: function () {
return { return {
advanced: false advanced: false,
repair: false
} }
}, },
mounted: function () {
this.repair = this.$route.params.repair
},
methods: { methods: {
select_file: function () { select_file: function () {
window.external.invoke(JSON.stringify({ window.external.invoke(JSON.stringify({
@ -77,7 +82,7 @@ export default {
})) }))
}, },
install: function () { install: function () {
this.$router.push('/install/regular') this.$router.push(this.repair ? '/install/repair' : '/install/regular')
}, },
go_back: function () { go_back: function () {
this.$router.go(-1) this.$router.go(-1)