mirror of
https://github.com/yuzu-emu/liftinstall.git
synced 2024-11-25 20:25:38 +01:00
Implement uninstall pipeline
This commit is contained in:
parent
66ce12c0aa
commit
cb29b4acdf
@ -19,6 +19,7 @@ use config::Config;
|
||||
use sources::types::Version;
|
||||
|
||||
use tasks::install::InstallTask;
|
||||
use tasks::uninstall::UninstallTask;
|
||||
use tasks::DependencyTree;
|
||||
|
||||
/// A message thrown during the installation of packages.
|
||||
@ -75,7 +76,7 @@ impl InstallerFramework {
|
||||
}
|
||||
|
||||
/// Sends a request for something to be installed.
|
||||
/// items: Array of named packages to be installed
|
||||
/// 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
|
||||
pub fn install(
|
||||
@ -109,6 +110,26 @@ impl InstallerFramework {
|
||||
}).map(|_x| ())
|
||||
}
|
||||
|
||||
/// Sends a request for everything to be uninstalled.
|
||||
pub fn uninstall(&mut self, messages: &Sender<InstallMessage>) -> Result<(), String> {
|
||||
// TODO: Cleanup maintenance tool
|
||||
|
||||
let items: Vec<String> = self.database.iter().map(|x| x.name.clone()).collect();
|
||||
|
||||
let task = Box::new(UninstallTask { items });
|
||||
|
||||
let mut tree = DependencyTree::build(task);
|
||||
|
||||
println!("Dependency tree:\n{}", tree);
|
||||
|
||||
tree.execute(self, &|msg: &str, progress: f32| match messages
|
||||
.send(InstallMessage::Status(msg.to_string(), progress as _))
|
||||
{
|
||||
Err(v) => eprintln!("Failed to submit queue message: {:?}", v),
|
||||
_ => {}
|
||||
}).map(|_x| ())
|
||||
}
|
||||
|
||||
/// Saves the applications database.
|
||||
pub fn save_database(&self) -> Result<(), String> {
|
||||
// We have to have a install path for us to be able to do anything
|
||||
|
43
src/rest.rs
43
src/rest.rs
@ -143,6 +143,49 @@ impl Service for WebService {
|
||||
.with_body(file)
|
||||
}
|
||||
// Streams the installation of a particular set of packages
|
||||
(&Post, "/api/uninstall") => {
|
||||
// We need to bit of pipelining to get this to work
|
||||
let framework = self.framework.clone();
|
||||
|
||||
return Box::new(req.body().concat2().map(move |_b| {
|
||||
let (sender, receiver) = channel();
|
||||
let (tx, rx) = hyper::Body::pair();
|
||||
|
||||
// Startup a thread to do this operation for us
|
||||
thread::spawn(move || {
|
||||
let mut framework = framework.write().unwrap();
|
||||
|
||||
match framework.uninstall(&sender) {
|
||||
Err(v) => sender.send(InstallMessage::Error(v)).unwrap(),
|
||||
_ => {}
|
||||
}
|
||||
sender.send(InstallMessage::EOF).unwrap();
|
||||
});
|
||||
|
||||
// Spawn a thread for transforming messages to chunk messages
|
||||
thread::spawn(move || {
|
||||
let mut tx = tx;
|
||||
loop {
|
||||
let response = receiver.recv().unwrap();
|
||||
|
||||
match &response {
|
||||
&InstallMessage::EOF => break,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let mut response = serde_json::to_string(&response).unwrap();
|
||||
response.push('\n');
|
||||
tx = tx.send(Ok(response.into_bytes().into())).wait().unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
Response::<hyper::Body>::new()
|
||||
//.with_header(ContentLength(file.len() as u64))
|
||||
.with_header(ContentType::plaintext())
|
||||
.with_body(rx)
|
||||
}));
|
||||
}
|
||||
// Streams the installation of a particular set of packages
|
||||
(&Post, "/api/start-install") => {
|
||||
// We need to bit of pipelining to get this to work
|
||||
let framework = self.framework.clone();
|
||||
|
@ -16,6 +16,7 @@ pub mod install_pkg;
|
||||
pub mod resolver;
|
||||
pub mod save_database;
|
||||
pub mod save_executable;
|
||||
pub mod uninstall;
|
||||
pub mod uninstall_pkg;
|
||||
|
||||
/// An abstraction over the various paramaters that can be passed around.
|
||||
|
44
src/tasks/uninstall.rs
Normal file
44
src/tasks/uninstall.rs
Normal file
@ -0,0 +1,44 @@
|
||||
//! Uninstalls a set of packages.
|
||||
|
||||
use installer::InstallerFramework;
|
||||
|
||||
use tasks::Task;
|
||||
use tasks::TaskParamType;
|
||||
|
||||
use tasks::save_database::SaveDatabaseTask;
|
||||
use tasks::uninstall_pkg::UninstallPackageTask;
|
||||
|
||||
pub struct UninstallTask {
|
||||
pub items: Vec<String>,
|
||||
}
|
||||
|
||||
impl Task for UninstallTask {
|
||||
fn execute(
|
||||
&mut self,
|
||||
_: Vec<TaskParamType>,
|
||||
_: &mut InstallerFramework,
|
||||
messenger: &Fn(&str, f32),
|
||||
) -> Result<TaskParamType, String> {
|
||||
messenger("Wrapping up...", 0.0);
|
||||
Ok(TaskParamType::None)
|
||||
}
|
||||
|
||||
fn dependencies(&self) -> Vec<Box<Task>> {
|
||||
let mut elements = Vec::<Box<Task>>::new();
|
||||
|
||||
for item in &self.items {
|
||||
elements.push(Box::new(UninstallPackageTask {
|
||||
name: item.clone(),
|
||||
optional: false,
|
||||
}));
|
||||
}
|
||||
|
||||
elements.push(Box::new(SaveDatabaseTask {}));
|
||||
|
||||
elements
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
format!("UninstallTask")
|
||||
}
|
||||
}
|
@ -5,6 +5,11 @@ use installer::InstallerFramework;
|
||||
use tasks::Task;
|
||||
use tasks::TaskParamType;
|
||||
|
||||
use installer::LocalInstallation;
|
||||
|
||||
use std::fs::remove_dir;
|
||||
use std::fs::remove_file;
|
||||
|
||||
pub struct UninstallPackageTask {
|
||||
pub name: String,
|
||||
pub optional: bool,
|
||||
@ -13,13 +18,69 @@ pub struct UninstallPackageTask {
|
||||
impl Task for UninstallPackageTask {
|
||||
fn execute(
|
||||
&mut self,
|
||||
_: Vec<TaskParamType>,
|
||||
_: &mut InstallerFramework,
|
||||
input: Vec<TaskParamType>,
|
||||
context: &mut InstallerFramework,
|
||||
messenger: &Fn(&str, f32),
|
||||
) -> Result<TaskParamType, String> {
|
||||
assert_eq!(input.len(), 0);
|
||||
|
||||
let path = context
|
||||
.install_path
|
||||
.as_ref()
|
||||
.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));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let mut package = match metadata {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
if self.optional {
|
||||
return Ok(TaskParamType::None);
|
||||
}
|
||||
|
||||
return Err(format!(
|
||||
"Package {:?} could not be found for uninstall.",
|
||||
self.name
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
messenger(&format!("Uninstalling package {:?}...", self.name), 0.0);
|
||||
|
||||
// TODO: Find files to uninstall, wipe them out, then clean up DB
|
||||
// Reverse, as to delete directories last
|
||||
package.files.reverse();
|
||||
|
||||
let max = package.files.len();
|
||||
let mut i = 0;
|
||||
for file in package.files {
|
||||
let name = file.clone();
|
||||
let file = path.join(file);
|
||||
println!("Deleting {:?}", file);
|
||||
|
||||
messenger(
|
||||
&format!("Deleting {} ({} of {})", name, i + 1, max),
|
||||
(i as f32) / (max as f32),
|
||||
);
|
||||
|
||||
let result = if file.is_dir() {
|
||||
remove_dir(file)
|
||||
} else {
|
||||
remove_file(file)
|
||||
};
|
||||
|
||||
match result {
|
||||
Err(v) => eprintln!("Failed to delete file: {:?}", v),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
Ok(TaskParamType::None)
|
||||
}
|
||||
|
@ -127,7 +127,7 @@
|
||||
<p class="modal-card-title">Are you sure you want to uninstall {{ config.general.name }}?</p>
|
||||
</header>
|
||||
<footer class="modal-card-foot">
|
||||
<button class="button is-danger">Yes</button>
|
||||
<button class="button is-danger" v-on:click="uninstall">Yes</button>
|
||||
<button class="button" v-on:click="cancel_uninstall">No</button>
|
||||
</footer>
|
||||
</div>
|
||||
@ -216,6 +216,27 @@
|
||||
"cancel_uninstall": function() {
|
||||
app.confirm_uninstall = false;
|
||||
},
|
||||
"uninstall": function() {
|
||||
app.confirm_uninstall = false;
|
||||
this.select_packages = false;
|
||||
this.is_installing = true;
|
||||
|
||||
stream_ajax("/api/uninstall", function(line) {
|
||||
if (line.hasOwnProperty("Status")) {
|
||||
app.progress_message = line.Status[0];
|
||||
app.progress = line.Status[1] * 100;
|
||||
}
|
||||
|
||||
if (line.hasOwnProperty("Error")) {
|
||||
app.is_installing = false;
|
||||
app.has_error = true;
|
||||
app.error = line.Error;
|
||||
}
|
||||
}, function(e) {
|
||||
app.is_installing = false;
|
||||
app.is_finished = true;
|
||||
}, undefined, {});
|
||||
},
|
||||
"exit": function() {
|
||||
ajax("/api/exit", function() {});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user