From 34e7698d76d59aa773157146e280a47714e4ec6a Mon Sep 17 00:00:00 2001 From: James Date: Tue, 30 Jan 2018 17:19:54 +1100 Subject: [PATCH] Check installation path, add error messages to frontend --- src/installer.rs | 29 ++++++++++++++++++++++++++++- src/rest.rs | 11 ++++++++++- static/index.html | 26 ++++++++++++++++++++++++-- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/installer.rs b/src/installer.rs index f00fb98..0ee153a 100644 --- a/src/installer.rs +++ b/src/installer.rs @@ -4,6 +4,9 @@ use regex::Regex; +use std::fs::create_dir_all; +use std::fs::read_dir; + use std::env::home_dir; use std::env::var; use std::env::consts::OS; @@ -62,10 +65,34 @@ impl InstallerFramework { pub fn install( &self, items: Vec, + path: &str, messages: &Sender, ) -> Result<(), String> { // TODO: Error handling - println!("Framework: Installing {:?}", items); + println!("Framework: Installing {:?} to {}", items, path); + + // Create our install directory + let path = PathBuf::from(path); + if !path.exists() { + match create_dir_all(&path) { + Ok(_) => {}, + Err(v) => return Err(format!("Failed to create install directory: {:?}", v)), + } + } + + if !path.is_dir() { + return Err(format!("Install destination is not a directory.")); + } + + // Make sure it is empty + let paths = match read_dir(path) { + Ok(v) => v, + Err(v) => return Err(format!("Failed to read install destination: {:?}", v)), + }; + + if paths.count() != 0 { + return Err(format!("Install destination is not empty.")); + } // Resolve items in config let mut to_install = Vec::new(); diff --git a/src/rest.rs b/src/rest.rs index cd83bd6..38ce625 100644 --- a/src/rest.rs +++ b/src/rest.rs @@ -158,20 +158,29 @@ impl Service for WebService { .collect::>(); let mut to_install = Vec::new(); + let mut path : Option = None; // Transform results into just an array of stuff to install for (key, value) in results.iter() { + if key == "path" { + path = Some(value.to_owned()); + continue; + } + if value == "true" { to_install.push(key.to_owned()); } } + // The frontend always provides this + let path = path.unwrap(); + let (sender, receiver) = channel(); let (tx, rx) = hyper::Body::pair(); // Startup a thread to do this operation for us thread::spawn(move || { - match cloned_element.install(to_install, &sender) { + match cloned_element.install(to_install, &path, &sender) { Err(v) => sender.send(InstallMessage::Error(v)).unwrap(), _ => {} } diff --git a/static/index.html b/static/index.html index c05cd78..00b725d 100644 --- a/static/index.html +++ b/static/index.html @@ -33,7 +33,15 @@ -
+
+

An error occurred:

+ +
{{ error }}
+ + + Back +
+

Select your preferred settings:

@@ -108,7 +116,9 @@ is_installing : false, is_finished : false, progress : 0, - progress_message : "" + progress_message : "", + has_error : false, + error : "" }, methods: { "select_file": function() { @@ -134,17 +144,29 @@ } console.log(results); + results["path"] = this.install_location; + stream_ajax("/api/start-install", function(line) { console.log(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, results); }, + "back_to_packages": function() { + app.select_packages = true; + app.has_error = false; + }, "exit": function() { ajax("/api/exit", function() {}); }