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| {
let results = form_urlencoded::parse(b.as_ref())
.into_owned()
.collect::<HashMap<String, String>>();
.into_owned()
.collect::<HashMap<String, String>>();
let mut to_install = Vec::new();
let mut path: Option<String> = None;
let mut force_install = false;
// Transform results into just an array of stuff to install
for (key, value) in &results {
@ -36,6 +37,11 @@ pub fn handle(service: &WebService, req: Request) -> Future {
continue;
}
if key == "mode" && value == "force" {
force_install = true;
continue;
}
if value == "true" {
to_install.push(key.to_owned());
}
@ -55,7 +61,7 @@ pub fn handle(service: &WebService, req: Request) -> Future {
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);
if let Err(v) = sender.send(InstallMessage::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
/// messages: Channel used to send progress messages
/// fresh_install: If the install directory must be empty
/// force_install: If the install directory should be erased first
pub fn install(
&mut self,
items: Vec<String>,
messages: &Sender<InstallMessage>,
fresh_install: bool,
force_install: bool,
) -> Result<(), String> {
info!(
"Framework: Installing {:?} to {:?}",
@ -186,6 +188,7 @@ impl InstallerFramework {
items,
uninstall_items,
fresh_install,
force_install
});
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_global_shortcut::InstallGlobalShortcutsTask;
use crate::tasks::install_pkg::InstallPackageTask;
use crate::tasks::remove_target_dir::RemoveTargetDirTask;
use crate::tasks::save_executable::SaveExecutableTask;
use crate::tasks::uninstall_pkg::UninstallPackageTask;
@ -19,6 +20,8 @@ pub struct InstallTask {
pub items: Vec<String>,
pub uninstall_items: Vec<String>,
pub fresh_install: bool,
// force_install: remove the target directory before installing
pub force_install: bool,
}
impl Task for InstallTask {
@ -40,6 +43,13 @@ impl Task for InstallTask {
Box::new(EnsureOnlyInstanceTask {}),
));
if self.force_install {
elements.push(TaskDependency::build(
TaskOrdering::Pre,
Box::new(RemoveTargetDirTask {}),
));
}
elements.push(TaskDependency::build(
TaskOrdering::Pre,
Box::new(VerifyInstallDirTask {

View File

@ -23,6 +23,7 @@ pub mod uninstall;
pub mod uninstall_global_shortcut;
pub mod uninstall_pkg;
pub mod uninstall_shortcuts;
pub mod remove_target_dir;
/// An abstraction over the various parameters that can be passed around.
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":{
"title":"Select which packages you want to install:",
"title_repair":"Select which packages you want to repair:",
"installed":"(installed)",
"advanced":"Advanced...",
"install":"Install",
"modify":"Modify",
"repair": "Repair",
"location":"Install Location",
"location_placeholder":"Enter a install path here",
"select":"Select"
@ -44,6 +46,7 @@
"title":"Choose an option:",
"update":"Update",
"modify":"Modify",
"repair": "Repair",
"uninstall":"Uninstall",
"prompt":"Are you sure you want to uninstall {name}?"
},

View File

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

View File

@ -14,6 +14,12 @@
<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">
{{ $t('modify.uninstall') }}
</b-button>
@ -48,6 +54,9 @@ export default {
modify_packages: function () {
this.$router.push('/packages')
},
repair_packages: function () {
this.$router.push({ name: 'packages', params: { repair: true } })
},
prepare_uninstall: function () {
this.show_uninstall = true
},
@ -56,7 +65,8 @@ export default {
},
uninstall: function () {
this.$router.push('/install/uninstall')
}
},
view_files: function () {}
}
}
</script>

View File

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