mirror of
https://github.com/yuzu-emu/liftinstall.git
synced 2024-11-25 20:45: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 sources::types::Version;
|
||||||
|
|
||||||
use tasks::install::InstallTask;
|
use tasks::install::InstallTask;
|
||||||
|
use tasks::uninstall::UninstallTask;
|
||||||
use tasks::DependencyTree;
|
use tasks::DependencyTree;
|
||||||
|
|
||||||
/// A message thrown during the installation of packages.
|
/// A message thrown during the installation of packages.
|
||||||
@ -75,7 +76,7 @@ impl InstallerFramework {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a request for something to be installed.
|
/// 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
|
/// 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
|
||||||
pub fn install(
|
pub fn install(
|
||||||
@ -109,6 +110,26 @@ impl InstallerFramework {
|
|||||||
}).map(|_x| ())
|
}).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.
|
/// Saves the applications database.
|
||||||
pub fn save_database(&self) -> Result<(), String> {
|
pub fn save_database(&self) -> Result<(), String> {
|
||||||
// We have to have a install path for us to be able to do anything
|
// 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)
|
.with_body(file)
|
||||||
}
|
}
|
||||||
// Streams the installation of a particular set of packages
|
// 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") => {
|
(&Post, "/api/start-install") => {
|
||||||
// We need to bit of pipelining to get this to work
|
// We need to bit of pipelining to get this to work
|
||||||
let framework = self.framework.clone();
|
let framework = self.framework.clone();
|
||||||
|
@ -16,6 +16,7 @@ pub mod install_pkg;
|
|||||||
pub mod resolver;
|
pub mod resolver;
|
||||||
pub mod save_database;
|
pub mod save_database;
|
||||||
pub mod save_executable;
|
pub mod save_executable;
|
||||||
|
pub mod uninstall;
|
||||||
pub mod uninstall_pkg;
|
pub mod uninstall_pkg;
|
||||||
|
|
||||||
/// An abstraction over the various paramaters that can be passed around.
|
/// 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::Task;
|
||||||
use tasks::TaskParamType;
|
use tasks::TaskParamType;
|
||||||
|
|
||||||
|
use installer::LocalInstallation;
|
||||||
|
|
||||||
|
use std::fs::remove_dir;
|
||||||
|
use std::fs::remove_file;
|
||||||
|
|
||||||
pub struct UninstallPackageTask {
|
pub struct UninstallPackageTask {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub optional: bool,
|
pub optional: bool,
|
||||||
@ -13,13 +18,69 @@ pub struct UninstallPackageTask {
|
|||||||
impl Task for UninstallPackageTask {
|
impl Task for UninstallPackageTask {
|
||||||
fn execute(
|
fn execute(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: Vec<TaskParamType>,
|
input: Vec<TaskParamType>,
|
||||||
_: &mut InstallerFramework,
|
context: &mut InstallerFramework,
|
||||||
messenger: &Fn(&str, f32),
|
messenger: &Fn(&str, f32),
|
||||||
) -> Result<TaskParamType, String> {
|
) -> 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);
|
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)
|
Ok(TaskParamType::None)
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@
|
|||||||
<p class="modal-card-title">Are you sure you want to uninstall {{ config.general.name }}?</p>
|
<p class="modal-card-title">Are you sure you want to uninstall {{ config.general.name }}?</p>
|
||||||
</header>
|
</header>
|
||||||
<footer class="modal-card-foot">
|
<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>
|
<button class="button" v-on:click="cancel_uninstall">No</button>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@ -216,6 +216,27 @@
|
|||||||
"cancel_uninstall": function() {
|
"cancel_uninstall": function() {
|
||||||
app.confirm_uninstall = false;
|
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() {
|
"exit": function() {
|
||||||
ajax("/api/exit", function() {});
|
ajax("/api/exit", function() {});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user