mirror of
https://github.com/yuzu-emu/liftinstall
synced 2024-11-23 14:43:35 +00:00
commit
137d2ec539
11 changed files with 924 additions and 643 deletions
1389
Cargo.lock
generated
1389
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
36
Cargo.toml
36
Cargo.toml
|
@ -8,41 +8,41 @@ description = "An adaptable installer for your application."
|
|||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
web-view = {git = "https://github.com/Boscop/web-view.git", rev = "555f422d09cbb94e82a728d47e9e07ca91963f6e"}
|
||||
web-view = "0.4.0"
|
||||
|
||||
hyper = "0.11.27"
|
||||
futures = "*"
|
||||
mime_guess = "1.8.3"
|
||||
url = "*"
|
||||
futures = "0.1.25"
|
||||
mime_guess = "1.8.6"
|
||||
url = "1.7.2"
|
||||
|
||||
reqwest = "0.9.0"
|
||||
number_prefix = "0.2.7"
|
||||
reqwest = "0.9.12"
|
||||
number_prefix = "0.3.0"
|
||||
|
||||
serde = "1.0.27"
|
||||
serde_derive = "1.0.27"
|
||||
serde_json = "1.0.9"
|
||||
serde = "1.0.89"
|
||||
serde_derive = "1.0.89"
|
||||
serde_json = "1.0.39"
|
||||
|
||||
toml = "0.4"
|
||||
toml = "0.5.0"
|
||||
|
||||
semver = {version = "0.9.0", features = ["serde"]}
|
||||
regex = "0.2"
|
||||
regex = "1.1.2"
|
||||
|
||||
dirs = "1.0"
|
||||
zip = "0.4.2"
|
||||
xz-decom = {git = "https://github.com/j-selby/xz-decom.git", rev = "9ebf3d00d9ff909c39eec1d2cf7e6e068ce214e5"}
|
||||
zip = "0.5.1"
|
||||
xz2 = "0.1.6"
|
||||
tar = "0.4"
|
||||
|
||||
log = "0.4"
|
||||
fern = "0.5"
|
||||
chrono = "0.4.5"
|
||||
chrono = "0.4.6"
|
||||
|
||||
clap = "2.32.0"
|
||||
|
||||
[build-dependencies]
|
||||
walkdir = "2"
|
||||
serde = "1.0.27"
|
||||
serde_derive = "1.0.27"
|
||||
toml = "0.4"
|
||||
walkdir = "2.2.7"
|
||||
serde = "1.0.89"
|
||||
serde_derive = "1.0.89"
|
||||
toml = "0.5.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
# NFD is needed on Windows, as web-view doesn't work correctly here
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::io::Read;
|
|||
use std::iter::Iterator;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use xz_decom;
|
||||
use xz2::read::XzDecoder;
|
||||
|
||||
pub trait Archive<'a> {
|
||||
/// func: iterator value, max size, file name, file contents
|
||||
|
@ -92,8 +92,10 @@ pub fn read_archive<'a>(name: &str, data: &'a [u8]) -> Result<Box<Archive<'a> +
|
|||
Ok(Box::new(ZipArchive { archive }))
|
||||
} else if name.ends_with(".tar.xz") {
|
||||
// Decompress a .tar.xz file
|
||||
let decompressed_data = xz_decom::decompress(data)
|
||||
.map_err(|x| format!("Failed to build decompressor: {:?}", x))?;
|
||||
let mut decompresser = XzDecoder::new(data);
|
||||
let mut decompressed_data = Vec::new();
|
||||
decompresser.read_to_end(&mut decompressed_data)
|
||||
.map_err(|x| format!("Failed to decompress data: {:?}", x))?;
|
||||
|
||||
let decompressed_contents: Box<Read> = Box::new(Cursor::new(decompressed_data));
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ use std::fs::remove_file;
|
|||
|
||||
use http;
|
||||
|
||||
use number_prefix::{decimal_prefix, Prefixed, Standalone};
|
||||
use number_prefix::{NumberPrefix, Prefixed, Standalone};
|
||||
|
||||
/// A message thrown during the installation of packages.
|
||||
#[derive(Serialize)]
|
||||
|
@ -264,11 +264,11 @@ impl InstallerFramework {
|
|||
};
|
||||
|
||||
// Pretty print data volumes
|
||||
let pretty_current = match decimal_prefix(downloaded as f64) {
|
||||
let pretty_current = match NumberPrefix::decimal(downloaded as f64) {
|
||||
Standalone(bytes) => format!("{} bytes", bytes),
|
||||
Prefixed(prefix, n) => format!("{:.0} {}B", n, prefix),
|
||||
};
|
||||
let pretty_total = match decimal_prefix(size as f64) {
|
||||
let pretty_total = match NumberPrefix::decimal(size as f64) {
|
||||
Standalone(bytes) => format!("{} bytes", bytes),
|
||||
Prefixed(prefix, n) => format!("{:.0} {}B", n, prefix),
|
||||
};
|
||||
|
@ -328,7 +328,8 @@ impl InstallerFramework {
|
|||
x.to_str()
|
||||
.log_expect("Unable to convert argument to String")
|
||||
.to_string()
|
||||
}).collect();
|
||||
})
|
||||
.collect();
|
||||
|
||||
{
|
||||
let new_app_file = match File::create(&args_file) {
|
||||
|
|
|
@ -17,7 +17,8 @@ pub fn setup_logger(file_name: String) -> Result<(), fern::InitError> {
|
|||
record.level(),
|
||||
message
|
||||
))
|
||||
}).level(log::LevelFilter::Info)
|
||||
})
|
||||
.level(log::LevelFilter::Info)
|
||||
.chain(io::stdout())
|
||||
.chain(fern::log_file(file_name)?)
|
||||
.apply()?;
|
||||
|
|
46
src/main.rs
46
src/main.rs
|
@ -30,7 +30,7 @@ extern crate semver;
|
|||
|
||||
extern crate dirs;
|
||||
extern crate tar;
|
||||
extern crate xz_decom;
|
||||
extern crate xz2;
|
||||
extern crate zip;
|
||||
|
||||
extern crate fern;
|
||||
|
@ -40,7 +40,7 @@ extern crate log;
|
|||
extern crate chrono;
|
||||
|
||||
extern crate clap;
|
||||
|
||||
#[cfg(windows)]
|
||||
extern crate winapi;
|
||||
|
||||
mod archives;
|
||||
|
@ -112,7 +112,8 @@ fn main() {
|
|||
.value_name("TARGET")
|
||||
.help("Launches the specified executable after checking for updates")
|
||||
.takes_value(true),
|
||||
).arg(
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("swap")
|
||||
.long("swap")
|
||||
.value_name("TARGET")
|
||||
|
@ -280,14 +281,15 @@ fn main() {
|
|||
let resizable = false;
|
||||
let debug = true;
|
||||
|
||||
run(
|
||||
&format!("{} Installer", app_name),
|
||||
Content::Url(http_address),
|
||||
Some(size),
|
||||
resizable,
|
||||
debug,
|
||||
|_| {},
|
||||
|wv, msg, _| {
|
||||
web_view::builder()
|
||||
.title(&format!("{} Installer", app_name))
|
||||
.content(Content::Url(http_address))
|
||||
.size(size.0, size.1)
|
||||
.resizable(resizable)
|
||||
.debug(debug)
|
||||
.user_data(())
|
||||
.invoke_handler(|wv, msg| {
|
||||
let mut cb_result = Ok(());
|
||||
let command: CallbackType =
|
||||
serde_json::from_str(msg).log_expect(&format!("Unable to parse string: {:?}", msg));
|
||||
|
||||
|
@ -299,20 +301,21 @@ fn main() {
|
|||
let result = match nfd::open_pick_folder(None)
|
||||
.log_expect("Unable to open folder dialog")
|
||||
{
|
||||
Response::Okay(v) => v,
|
||||
_ => return,
|
||||
Response::Okay(v) => Ok(v),
|
||||
_ => Err(()),
|
||||
};
|
||||
|
||||
#[cfg(not(windows))]
|
||||
let result =
|
||||
wv.dialog(Dialog::ChooseDirectory, "Select a install directory...", "");
|
||||
let result = wv
|
||||
.dialog()
|
||||
.choose_directory("Select a install directory...", "");
|
||||
|
||||
if !result.is_empty() {
|
||||
let result = serde_json::to_string(&result)
|
||||
if result.is_ok() {
|
||||
let result = serde_json::to_string(&result.ok())
|
||||
.log_expect("Unable to serialize response");
|
||||
let command = format!("{}({});", callback_name, result);
|
||||
debug!("Injecting response: {}", command);
|
||||
wv.eval(&command);
|
||||
cb_result = wv.eval(&command);
|
||||
}
|
||||
}
|
||||
CallbackType::Log { msg, kind } => {
|
||||
|
@ -326,7 +329,8 @@ fn main() {
|
|||
log!(target: "liftinstall::frontend-js", kind, "{}", msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
(),
|
||||
);
|
||||
cb_result
|
||||
})
|
||||
.run()
|
||||
.expect("Unable to launch Web UI!");
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
/// Basic definition of some running process.
|
||||
#[derive(Debug)]
|
||||
pub struct Process {
|
||||
pub pid : usize,
|
||||
pub name : String
|
||||
pub pid: usize,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
|
@ -23,14 +23,13 @@ mod natives {
|
|||
use std::process::Command;
|
||||
|
||||
use winapi::shared::minwindef::{DWORD, FALSE, MAX_PATH};
|
||||
use winapi::um::processthreadsapi::OpenProcess;
|
||||
use winapi::um::psapi::{
|
||||
EnumProcessModulesEx, GetModuleFileNameExW, K32EnumProcesses, LIST_MODULES_ALL,
|
||||
};
|
||||
use winapi::um::winnt::{
|
||||
HANDLE, PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE, PROCESS_VM_READ,
|
||||
};
|
||||
use winapi::um::processthreadsapi::{OpenProcess};
|
||||
use winapi::um::psapi::{
|
||||
K32EnumProcesses,
|
||||
EnumProcessModulesEx, GetModuleFileNameExW, LIST_MODULES_ALL,
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
pub fn saveShortcut(
|
||||
|
@ -149,9 +148,7 @@ mod natives {
|
|||
|
||||
let size = ::std::mem::size_of::<DWORD>() * process_ids.len();
|
||||
unsafe {
|
||||
if K32EnumProcesses(process_ids.as_mut_ptr(),
|
||||
size as DWORD,
|
||||
&mut cb_needed) == 0 {
|
||||
if K32EnumProcesses(process_ids.as_mut_ptr(), size as DWORD, &mut cb_needed) == 0 {
|
||||
return vec![];
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +157,7 @@ mod natives {
|
|||
|
||||
let mut processes = Vec::new();
|
||||
|
||||
for i in 0 .. nb_processes {
|
||||
for i in 0..nb_processes {
|
||||
let pid = process_ids[i as usize];
|
||||
|
||||
unsafe {
|
||||
|
@ -169,20 +166,25 @@ mod natives {
|
|||
let mut process_name = [0u16; MAX_PATH + 1];
|
||||
let mut cb_needed = 0;
|
||||
|
||||
if EnumProcessModulesEx(process_handler,
|
||||
&mut h_mod,
|
||||
::std::mem::size_of::<DWORD>() as DWORD,
|
||||
&mut cb_needed,
|
||||
LIST_MODULES_ALL) != 0 {
|
||||
GetModuleFileNameExW(process_handler,
|
||||
h_mod,
|
||||
process_name.as_mut_ptr(),
|
||||
MAX_PATH as DWORD + 1);
|
||||
if EnumProcessModulesEx(
|
||||
process_handler,
|
||||
&mut h_mod,
|
||||
::std::mem::size_of::<DWORD>() as DWORD,
|
||||
&mut cb_needed,
|
||||
LIST_MODULES_ALL,
|
||||
) != 0
|
||||
{
|
||||
GetModuleFileNameExW(
|
||||
process_handler,
|
||||
h_mod,
|
||||
process_name.as_mut_ptr(),
|
||||
MAX_PATH as DWORD + 1,
|
||||
);
|
||||
|
||||
let mut pos = 0;
|
||||
for x in process_name.iter() {
|
||||
if *x == 0 {
|
||||
break
|
||||
break;
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
|
@ -210,11 +212,11 @@ mod natives {
|
|||
use logging::LoggingErrors;
|
||||
|
||||
pub fn create_shortcut(
|
||||
name: &str,
|
||||
description: &str,
|
||||
target: &str,
|
||||
args: &str,
|
||||
working_dir: &str,
|
||||
_name: &str,
|
||||
_description: &str,
|
||||
_target: &str,
|
||||
_args: &str,
|
||||
_working_dir: &str,
|
||||
) -> Result<String, String> {
|
||||
// TODO: no-op
|
||||
warn!("create_shortcut is stubbed!");
|
||||
|
|
|
@ -62,7 +62,8 @@ impl WebServer {
|
|||
Ok(WebService {
|
||||
framework: framework.clone(),
|
||||
})
|
||||
}).log_expect("Failed to bind to port");
|
||||
})
|
||||
.log_expect("Failed to bind to port");
|
||||
|
||||
server.run().log_expect("Failed to run HTTP server");
|
||||
});
|
||||
|
|
|
@ -41,7 +41,8 @@ impl ReleaseSource for GithubReleases {
|
|||
.get(&format!(
|
||||
"https://api.github.com/repos/{}/releases",
|
||||
config.repo
|
||||
)).header(USER_AGENT, "liftinstall (j-selby)")
|
||||
))
|
||||
.header(USER_AGENT, "liftinstall (j-selby)")
|
||||
.send()
|
||||
.map_err(|x| format!("Error while sending HTTP request: {:?}", x))?;
|
||||
|
||||
|
@ -87,14 +88,16 @@ impl ReleaseSource for GithubReleases {
|
|||
let string = match asset["name"].as_str() {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
return Err("JSON payload missing information about release name".to_string())
|
||||
return Err(
|
||||
"JSON payload missing information about release name".to_string()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let url = match asset["browser_download_url"].as_str() {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
return Err("JSON payload missing information about release URL".to_string())
|
||||
return Err("JSON payload missing information about release URL".to_string());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ use tasks::resolver::ResolvePackageTask;
|
|||
|
||||
use http::stream_file;
|
||||
|
||||
use number_prefix::{decimal_prefix, Prefixed, Standalone};
|
||||
use number_prefix::{NumberPrefix, Prefixed, Standalone};
|
||||
|
||||
use logging::LoggingErrors;
|
||||
|
||||
|
@ -68,11 +68,11 @@ impl Task for DownloadPackageTask {
|
|||
};
|
||||
|
||||
// Pretty print data volumes
|
||||
let pretty_current = match decimal_prefix(downloaded as f64) {
|
||||
let pretty_current = match NumberPrefix::decimal(downloaded as f64) {
|
||||
Standalone(bytes) => format!("{} bytes", bytes),
|
||||
Prefixed(prefix, n) => format!("{:.0} {}B", n, prefix),
|
||||
};
|
||||
let pretty_total = match decimal_prefix(size as f64) {
|
||||
let pretty_total = match NumberPrefix::decimal(size as f64) {
|
||||
Standalone(bytes) => format!("{} bytes", bytes),
|
||||
Prefixed(prefix, n) => format!("{:.0} {}B", n, prefix),
|
||||
};
|
||||
|
|
|
@ -7,8 +7,8 @@ use tasks::TaskDependency;
|
|||
use tasks::TaskMessage;
|
||||
use tasks::TaskParamType;
|
||||
|
||||
use native::Process;
|
||||
use native::get_process_names;
|
||||
use native::Process;
|
||||
|
||||
use std::process;
|
||||
|
||||
|
@ -23,7 +23,7 @@ impl Task for EnsureOnlyInstanceTask {
|
|||
) -> Result<TaskParamType, String> {
|
||||
assert_eq!(input.len(), 0);
|
||||
|
||||
let current_pid = process::id() as usize;
|
||||
let current_pid = process::id() as usize;
|
||||
for Process { pid, name } in get_process_names() {
|
||||
if pid == current_pid {
|
||||
continue;
|
||||
|
|
Loading…
Reference in a new issue