diff --git a/Cargo.lock b/Cargo.lock index c82ab83..0b4154a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -297,8 +297,6 @@ dependencies = [ "mime_guess 1.8.6 (registry+https://github.com/rust-lang/crates.io-index)", "nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_macros 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -546,15 +544,6 @@ dependencies = [ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "phf_macros" -version = "0.7.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf_generator 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "phf_shared" version = "0.7.22" @@ -1126,7 +1115,6 @@ dependencies = [ "checksum phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "7d37a244c75a9748e049225155f56dbcb98fe71b192fd25fd23cb914b5ad62f2" "checksum phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4e4048fe7dd7a06b8127ecd6d3803149126e9b33c7558879846da3a63f734f2b" "checksum phf_generator 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "05a079dd052e7b674d21cb31cbb6c05efd56a2cd2827db7692e2f1a507ebd998" -"checksum phf_macros 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6cfe846605e58552e1324c566bfb5bd5ac032245c9ae05c859f042e81c03b5" "checksum phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "c2261d544c2bb6aa3b10022b0be371b9c7c64f762ef28c6f5d4f1ef6d97b5930" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd" diff --git a/Cargo.toml b/Cargo.toml index 45c5d95..0f88f8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,9 +17,6 @@ url = "*" reqwest = "0.8.6" number_prefix = "0.2.7" -phf = "0.7.22" -phf_macros = "0.7.22" - serde = "1.0.27" serde_derive = "1.0.27" serde_json = "1.0.9" diff --git a/README.md b/README.md index 8a6cbc1..669eb72 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,10 @@ Building Add your logo to `static/img/logo.png`, modify the configuration file, then run: ```bash -cargo build +cargo build --release ``` -LiftInstall should build on both ~~Stable and~~ Nightly Rust. +LiftInstall should build on both Stable and Nightly Rust. Contributing ------------ diff --git a/src/assets.rs b/src/assets.rs index 3aa6946..81b514b 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -3,33 +3,21 @@ extern crate mime_guess; use assets::mime_guess::{get_mime_type, octet_stream}; -use phf; - macro_rules! include_files_as_assets { - ( $field_name:ident, $( $file_name:expr ),* ) => { - static $field_name: phf::Map<&'static str, &'static [u8]> = phf_map!( + ( $target_match:expr, $( $file_name:expr ),* ) => { + match $target_match { $( - $file_name => include_bytes!(concat!("../static/", $file_name)), + $file_name => Some(include_bytes!(concat!("../static/", $file_name)).as_ref()), )* - ); + _ => None + } } } -include_files_as_assets!( - ASSETS, - "/index.html", - "/css/bulma.css", - "/css/main.css", - "/img/logo.png", - "/js/helpers.js", - "/js/vue.js", - "/js/vue.min.js" -); - /// Returns a static file based upon a given String as a Path. /// /// file_path: String path, beginning with a / -pub fn file_from_string(file_path: &str) -> Option<(String, Vec)> { +pub fn file_from_string(file_path: &str) -> Option<(String, &'static [u8])> { let guessed_mime = match file_path.rfind(".") { Some(ext_ptr) => { let ext = &file_path[ext_ptr + 1..]; @@ -41,5 +29,16 @@ pub fn file_from_string(file_path: &str) -> Option<(String, Vec)> { let string_mime = guessed_mime.to_string(); - Some((string_mime, (*ASSETS.get(file_path)?).to_owned())) + let contents = include_files_as_assets!( + file_path, + "/index.html", + "/css/bulma.css", + "/css/main.css", + "/img/logo.png", + "/js/helpers.js", + "/js/vue.js", + "/js/vue.min.js" + )?; + + Some((string_mime, contents)) //(*ASSETS.get(file_path)?).to_owned())) } diff --git a/src/main.rs b/src/main.rs index c95ae4b..7180baf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,13 @@ #![windows_subsystem = "windows"] -#![feature(plugin)] -#![plugin(phf_macros)] extern crate web_view; -extern crate hyper; extern crate futures; +extern crate hyper; extern crate number_prefix; extern crate reqwest; -extern crate phf; - extern crate serde; #[macro_use] extern crate serde_derive; @@ -29,6 +25,7 @@ mod http; mod installer; mod rest; mod sources; +mod tasks; use web_view::*; diff --git a/src/sources/github/mod.rs b/src/sources/github/mod.rs index ec6853f..7d5a005 100644 --- a/src/sources/github/mod.rs +++ b/src/sources/github/mod.rs @@ -24,7 +24,7 @@ impl GithubReleases { impl ReleaseSource for GithubReleases { fn get_current_releases(&self, config: &TomlValue) -> Result, String> { // Reparse our Config as strongly typed - let config : GithubConfig = match config.clone().try_into() { + let config: GithubConfig = match config.clone().try_into() { Ok(v) => v, Err(v) => return Err(format!("Failed to parse release config: {:?}", v)), }; @@ -33,7 +33,11 @@ impl ReleaseSource for GithubReleases { // Build the HTTP client up let client = reqwest::Client::new(); - let mut response = client.get(&format!("https://api.github.com/repos/{}/releases", config.repo)) + let mut response = client + .get(&format!( + "https://api.github.com/repos/{}/releases", + config.repo + )) .header(UserAgent::new("liftinstall (j-selby)")) .send() .map_err(|x| format!("Error while sending HTTP request: {:?}", x))?; @@ -42,16 +46,16 @@ impl ReleaseSource for GithubReleases { return Err(format!("Bad status code: {:?}", response.status())); } - let body = response.text() + let body = response + .text() .map_err(|x| format!("Failed to decode HTTP response body: {:?}", x))?; - let result: serde_json::Value = serde_json::from_str(&body) - .map_err(|x| format!("Failed to parse response: {:?}", x))?; + let result: serde_json::Value = + serde_json::from_str(&body).map_err(|x| format!("Failed to parse response: {:?}", x))?; - let result: &Vec = - result - .as_array() - .ok_or(format!("Response was not an array!"))?; + let result: &Vec = result + .as_array() + .ok_or(format!("Response was not an array!"))?; // Parse JSON from server for entry in result.into_iter() { diff --git a/src/tasks/mod.rs b/src/tasks/mod.rs new file mode 100644 index 0000000..4846140 --- /dev/null +++ b/src/tasks/mod.rs @@ -0,0 +1,106 @@ +use std::any::Any; + +use std::fmt; +use std::fmt::Display; + +/// Allows for any time to be used as an Input to a Task. +type AnyInput = Box; + +/// A Task is a small, async task conforming to a fixed set of inputs/outputs. +pub trait Task { + type Input; + type Output; + type Error; + + /// Executes this individual task, evaluating to the given Output result. + /// + /// Each dependency is given an indice in the inputted vector. + fn execute( + &mut self, + input: Vec, + messenger: &Fn(&str, f32), + ) -> Result; + + /// Returns a vector containing all dependencies that need to be executed + /// before this task can function. + fn dependencies( + &self, + ) -> Vec>>; + + /// Returns a short name used for formatting the dependency tree. + fn name(&self) -> String; +} + +/// The dependency tree allows for smart iteration on a Task struct. +pub struct DependencyTree { + task: Box>, + dependencies: Vec>, +} + +impl DependencyTree { + /// Renders the dependency tree into a user-presentable string. + fn render(&self) -> String { + let mut buf = self.task.name(); + + buf += "\n"; + + for i in 0..self.dependencies.len() { + let dependencies = self.dependencies[i].render(); + let dependencies = dependencies.trim(); + + if i + 1 == self.dependencies.len() { + buf += "└── "; + buf += &dependencies.replace("\n", "\n "); + } else { + buf += "├── "; + buf += &dependencies.replace("\n", "\n│ "); + buf += "\n"; + } + } + + buf + } + + /// Executes this pipeline. + pub fn execute(&mut self, messenger: &Fn(&str, f32)) -> Result { + let total_tasks = (self.dependencies.len() + 1) as f32; + + let mut inputs = Vec::::with_capacity(self.dependencies.len()); + + let mut count = 0; + + for i in &mut self.dependencies { + inputs.push(i.execute(&|msg: &str, progress: f32| { + messenger( + msg, + progress / total_tasks + (1.0 / total_tasks) * count as f32, + ) + })?); + count += 1; + } + + self.task.execute(inputs, &|msg: &str, progress: f32| { + messenger( + msg, + progress / total_tasks + (1.0 / total_tasks) * count as f32, + ) + }) + } + + /// Builds a new pipeline from the specified task, iterating on dependencies. + pub fn build(task: Box>) -> DependencyTree { + let dependencies = task + .dependencies() + .into_iter() + .map(|x| DependencyTree::build(x)) + .collect(); + + DependencyTree { task, dependencies } + } +} + +impl Display for DependencyTree { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "{}", self.render()) + } +}