Add launcher functionality

This commit is contained in:
James 2018-08-04 23:35:56 +10:00
parent c0387c9a0a
commit 58530ef352
8 changed files with 205 additions and 11 deletions

83
Cargo.lock generated
View file

@ -11,6 +11,24 @@ dependencies = [
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "base64"
version = "0.9.0"
@ -87,6 +105,20 @@ dependencies = [
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clap"
version = "2.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "core-foundation"
version = "0.2.3"
@ -320,6 +352,7 @@ name = "liftinstall"
version = "0.1.0"
dependencies = [
"chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"fern 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
@ -637,6 +670,14 @@ name = "redox_syscall"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.2.5"
@ -805,6 +846,11 @@ name = "smallvec"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "0.11.11"
@ -836,6 +882,24 @@ dependencies = [
"rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.3.5"
@ -958,6 +1022,11 @@ name = "unicode-normalization"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.0.4"
@ -1005,6 +1074,11 @@ name = "vcpkg"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
version = "0.1.3"
@ -1106,6 +1180,8 @@ dependencies = [
[metadata]
"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45"
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "229d032f1a99302697f10b27167ae6d03d49d032e6a8e2550e8d3fc13356d2b4"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
@ -1117,6 +1193,7 @@ dependencies = [
"checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e48d85528df61dc964aa43c5f6ca681a19cfa74939b2348d204bd08a981f2fb0"
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67"
"checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d"
"checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7"
@ -1180,6 +1257,7 @@ dependencies = [
"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1"
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa"
"checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e"
"checksum relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f301bafeb60867c85170031bdb2fcf24c8041f33aee09e7b116a58d4e9f781c5"
@ -1200,10 +1278,13 @@ dependencies = [
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
"checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d"
"checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5"
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098"
"checksum tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "52b4e32d8edbf29501aabb3570f027c6ceb00ccef6538f4bddba0200503e74e8"
@ -1217,6 +1298,7 @@ dependencies = [
"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2"
@ -1224,6 +1306,7 @@ dependencies = [
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363"
"checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a05d9d966753fa4b5c8db73fcab5eed4549cfe0e1e4e66911e5564a0085c35d1"

View file

@ -38,6 +38,8 @@ log = "0.4"
fern = "0.5"
chrono = "0.4.5"
clap = "2.32.0"
[target.'cfg(windows)'.dependencies]
# NFD is needed on Windows, as web-view doesn't work correctly here
nfd = "0.0.4"

View file

@ -13,6 +13,7 @@ pub fn stream_file<F>(url: &str, mut callback: F) -> Result<(), String>
where
F: FnMut(Vec<u8>, u64) -> (),
{
// TODO: Decrease check time
let mut client = match reqwest::get(url) {
Ok(v) => v,
Err(v) => return Err(format!("Failed to GET resource: {:?}", v)),

View file

@ -40,6 +40,8 @@ pub struct InstallerFramework {
pub database: Vec<LocalInstallation>,
pub install_path: Option<PathBuf>,
pub preexisting_install: bool,
pub is_launcher: bool,
pub launcher_path: Option<String>,
}
/// Contains basic properties on the status of the session. Subset of InstallationFramework.
@ -48,6 +50,8 @@ pub struct InstallationStatus {
pub database: Vec<LocalInstallation>,
pub install_path: Option<String>,
pub preexisting_install: bool,
pub is_launcher: bool,
pub launcher_path: Option<String>,
}
/// Tracks the state of a local installation
@ -184,6 +188,8 @@ impl InstallerFramework {
None => None,
},
preexisting_install: self.preexisting_install,
is_launcher: self.is_launcher,
launcher_path: self.launcher_path.clone(),
}
}
@ -194,6 +200,8 @@ impl InstallerFramework {
database: Vec::new(),
install_path: None,
preexisting_install: false,
is_launcher: false,
launcher_path: None,
}
}
@ -217,6 +225,8 @@ impl InstallerFramework {
database,
install_path: Some(path),
preexisting_install: true,
is_launcher: false,
launcher_path: None,
})
}
}

View file

@ -37,6 +37,8 @@ extern crate log;
extern crate chrono;
extern crate clap;
mod assets;
mod config;
mod http;
@ -65,12 +67,17 @@ use std::sync::RwLock;
use logging::LoggingErrors;
use clap::App;
use clap::Arg;
use log::Level;
// TODO: Fetch this over a HTTP request?
static RAW_CONFIG: &'static str = include_str!("../config.toml");
#[derive(Deserialize, Debug)]
enum CallbackType {
SelectInstallDir { callback_name: String },
Log { msg: String, kind: String },
}
fn main() {
@ -80,6 +87,17 @@ fn main() {
let app_name = config.general.name.clone();
let matches = App::new(format!("{} installer", app_name))
.version(env!("CARGO_PKG_VERSION"))
.about(format!("An interactive installer for {}", app_name).as_ref())
.arg(
Arg::with_name("launcher")
.long("launcher")
.value_name("TARGET")
.help("Launches the specified executable after checking for updates")
.takes_value(true),
).get_matches();
info!("{} installer", app_name);
let current_exe = std::env::current_exe().log_expect("Current executable could not be found");
@ -87,7 +105,7 @@ fn main() {
.parent()
.log_expect("Parent directory of executable could not be found");
let metadata_file = current_path.join("metadata.json");
let framework = if metadata_file.exists() {
let mut framework = if metadata_file.exists() {
info!("Using pre-existing metadata file: {:?}", metadata_file);
InstallerFramework::new_with_db(config, current_path).log_expect("Unable to parse metadata")
} else {
@ -95,6 +113,14 @@ fn main() {
InstallerFramework::new(config)
};
let is_launcher = if let Some(string) = matches.value_of("launcher") {
framework.is_launcher = true;
framework.launcher_path = Some(string.to_string());
true
} else {
false
};
// Firstly, allocate us an epidermal port
let target_port = {
let listener = TcpListener::bind("127.0.0.1:0")
@ -134,7 +160,8 @@ fn main() {
let http_address = format!("http://localhost:{}", http_address.port());
// Init the web view
let size = (1024, 500);
let size = if is_launcher { (600, 300) } else { (1024, 500) };
let resizable = false;
let debug = true;
@ -173,6 +200,16 @@ fn main() {
wv.eval(&command);
}
}
CallbackType::Log { msg, kind } => {
let kind = match kind.as_ref() {
"info" | "log" => Level::Info,
"warn" => Level::Warn,
"error" => Level::Error,
_ => Level::Error,
};
log!(target: "liftinstall::frontend-js", kind, "{}", msg);
}
}
},
(),

View file

@ -30,6 +30,7 @@ use installer::InstallMessage;
use installer::InstallerFramework;
use logging::LoggingErrors;
use std::process::Command;
#[derive(Serialize)]
struct FileSelection {
@ -135,6 +136,17 @@ impl Service for WebService {
}
// Immediately exits the application
(&Get, "/api/exit") => {
let framework = self
.framework
.read()
.log_expect("InstallerFramework has been dirtied");
if let Some(ref v) = framework.launcher_path {
Command::new(v)
.spawn()
.log_expect("Unable to start child process");
}
exit(0);
}
// Gets properties such as if the application is in maintenance mode

View file

@ -19,7 +19,7 @@
<section class="section">
<div class="container">
<div class="columns">
<div class="column is-one-third">
<div class="column is-one-third" v-if="!is_launcher">
<h1 class="title">
Welcome to the {{ config.general.name }} installer!
</h1>
@ -97,7 +97,8 @@
</div>
<div class="column" v-else-if="is_installing">
<h4 class="subtitle">Installing...</h4>
<h4 class="subtitle" v-if="is_launcher">Checking for updates...</h4>
<h4 class="subtitle" v-else>Installing...</h4>
<div v-html="config.general.installing_message"></div>
<br />
@ -136,10 +137,37 @@
</div>
<script src="/api/config"></script>
<script src="/api/packages"></script>
<script src="/js/helpers.js"></script>
<script src="/js/vue.min.js"></script>
<script>
// Overwrite loggers with the logging backend
window.onerror = function(msg, url, line) {
window.external.invoke(JSON.stringify({
Log: {
kind: "error",
msg: msg + " @ " + url + ":" + line
}
}));
};
// Borrowed from http://tobyho.com/2012/07/27/taking-over-console-log/
function intercept(method){
console[method] = function(){
var message = Array.prototype.slice.apply(arguments).join(' ');
window.external.invoke(JSON.stringify({
Log: {
kind: method,
msg: message
}
}));
}
}
var methods = ['log', 'warn', 'error'];
for (var i = 0; i < methods.length; i++) {
intercept(methods[i]);
}
document.getElementById("window-title").innerText = config.name + " Installer";
function selectFileCallback(name) {
@ -150,16 +178,24 @@
el: '#app',
data: {
config : config,
packages : packages,
install_location : "",
// If the initial modify menu should be shown
modify_install : false,
// If the package selection screen should be shown
select_packages : true,
// If an installation operation is happening
is_installing : false,
// If an installation has completed successfully
is_finished : false,
// If the application should act as an launcher, rather than as an installer
is_launcher : false,
launcher_path : undefined,
// If a confirmation prompt should be shown
confirm_uninstall : false,
progress : 0,
progress_message : "",
has_error : false,
// If the option to pick an install location should be provided
show_install_location : true,
error : "",
metadata : {
@ -205,10 +241,19 @@
app.is_installing = false;
app.has_error = true;
app.error = line.Error;
// Exit anyway - don't want to disturb the user
if (app.is_launcher) {
app.exit();
}
}
}, function(e) {
app.is_installing = false;
if (app.is_launcher) {
app.exit();
} else {
app.is_finished = true;
}
}, undefined, results);
},
"back_to_packages": function() {
@ -269,16 +314,22 @@
app.config.packages[x].installed = false;
}
for (var i = 0; i < packages.length; i++) {
for (var i = 0; i < app.metadata.database.length; i++) {
// Find this config package
for (var x = 0; x < app.config.packages.length; x++) {
if (app.config.packages[x].name === packages[i].name) {
if (app.config.packages[x].name === app.metadata.database[i].name) {
app.config.packages[x].default = true;
app.config.packages[x].installed = true;
}
}
}
if (e.is_launcher) {
document.getElementById("window-title").innerText = config.name + " Updater";
app.is_launcher = true;
app.install();
}
} else {
for (var x = 0; x < app.config.packages.length; x++) {
app.config.packages[x].installed = false;

View file

@ -90,8 +90,6 @@ function stream_ajax(path, callback, successCallback, failCallback, data) {
continue;
}
console.log("Incoming line: " + line);
var contents = JSON.parse(line);
callback(contents);
}