Skip to content

Improve windows module installer support #111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions install/uvm-install-editor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ impl UvmCommand {
}

pub fn exec(&self, options: &Options) -> io::Result<()> {
#[cfg(windows)]
install::install_editor(options.installer(), Some(options.destination()), None)?;
#[cfg(unix)]
install::install_editor(options.installer(), Some(options.destination()))?;

self.stderr
.write_line(&format!("{}", style("success").green().bold()))
}
Expand Down
4 changes: 4 additions & 0 deletions install/uvm-install-module/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ impl UvmCommand {
}

pub fn exec(&self, options: &Options) -> io::Result<()> {
#[cfg(windows)]
install::install_module(options.installer(), Some(options.destination()), None)?;
#[cfg(unix)]
install::install_module(options.installer(), Some(options.destination()))?;

self.stderr
.write_line(&format!("{}", style("success").green().bold()))
}
Expand Down
9 changes: 7 additions & 2 deletions install/uvm-install/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,13 @@ impl UvmCommand {
_ => install::install_module,
};

install_f(&installer, destination.as_ref())
.map(|result| {
{
#[cfg(windows)]
let r = install_f(&installer, destination.as_ref(),None);
#[cfg(unix)]
let r = install_f(&installer, destination.as_ref());
r
}.map(|result| {
debug!("installation finished {}.", &install_object.variant);
pb.finish_with_message(&format!("{}", style("done").green().bold()));
if install_object.variant == InstallVariant::Editor {
Expand Down
1 change: 1 addition & 0 deletions uvm_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ dmg = "0.1.1"
cluFlock = "1.2.5"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winver","memoryapi"] }
widestring = "0.4.0"
libc = "0.2.43"
tempfile = "3"

Expand Down
150 changes: 119 additions & 31 deletions uvm_core/src/sys/win/installer.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,46 @@
use crate::sys::shared::installer::*;
use std::io;
use std::io::Write as IoWrite;
use std::path::Path;
use std::process::{Command, Stdio};
use tempfile::Builder;

pub fn install_editor<P, D>(installer: P, destination: Option<D>) -> io::Result<()>
pub fn install_editor<P, D>(
installer: P,
destination: Option<D>,
cmd: Option<&str>,
) -> io::Result<()>
where
P: AsRef<Path>,
D: AsRef<Path>,
{
let installer = installer.as_ref();
let destination = destination.ok_or(io::Error::new(
io::ErrorKind::InvalidInput,
"Missing destination path",
))?;
let destination = match destination {
Some(ref d) => Some(d.as_ref()),
_ => None,
};

let destination = destination.as_ref();
debug!("install editor {}", installer.display(),);
if let Some(destination) = destination {
debug!("to {}", destination.display());
}

debug!(
"install editor to destination: {} with installer: {}",
&destination.display(),
&installer.display()
);
install_from_exe(installer, destination)
install_from_exe(installer, destination, cmd)
}

pub fn install_module<P, D>(installer: P, destination: Option<D>) -> io::Result<()>
pub fn install_module<P, D>(
installer: P,
destination: Option<D>,
cmd: Option<&str>,
) -> io::Result<()>
where
P: AsRef<Path>,
D: AsRef<Path>,
{
_install_module(installer, destination)
_install_module(installer, destination, cmd)
}

fn _install_module<P, D>(installer: P, destination: Option<D>) -> io::Result<()>
fn _install_module<P, D>(installer: P, destination: Option<D>, cmd: Option<&str>) -> io::Result<()>
where
P: AsRef<Path>,
D: AsRef<Path>,
Expand All @@ -50,34 +57,60 @@ where
}

match installer.extension() {
Some(ext) if ext == "exe" => {
Some(ext) if ext == "exe" => install_from_exe(installer, destination, cmd),
Some(ext) if ext == "zip" => {
let destination = destination.ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"Missing destination path for exe intaller",
"Missing destination path for zip intaller",
)
})?;

install_from_exe(installer, destination)
install_module_from_zip(installer, destination).map_err(|err| {
cleanup_directory_failable(destination);
err
})
}
Some(ext) if ext == "msi" => {
let cmd = cmd.ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"Missing cmd parameter path for msi intaller",
)
})?;

install_from_msi(installer, cmd)
}
Some(ext) if ext == "po" => {
let destination = destination.ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"Missing destination path for po module",
)
})?;
install_po_file(installer, destination)
}

_ => Err(io::Error::new(
io::ErrorKind::Other,
format!(
"Wrong installer. Expect .exe {}",
"Wrong installer. Expect .exe, .msi, .zip or .po {}",
&installer.display()
),
)),
}
}

fn install_from_exe<P, D>(installer: P, destination: D) -> io::Result<()>
fn install_from_exe<P, D>(installer: P, destination: Option<D>, cmd: Option<&str>) -> io::Result<()>
where
P: AsRef<Path>,
D: AsRef<Path>,
{
let installer = installer.as_ref();
let destination = destination.as_ref();
let destination = match destination {
Some(ref d) => Some(d.as_ref()),
_ => None,
};

debug!("install unity from installer exe");
let mut install_helper = Builder::new().suffix(".cmd").rand_bytes(20).tempfile()?;
Expand All @@ -86,26 +119,49 @@ where
"create install helper script {}",
install_helper.path().display()
);

{
let script = install_helper.as_file_mut();
let parameter_option = match cmd {
Some(parameters) => parameters,
_ => "/S",
};

let destination_option = match destination {
Some(destination) => format!("/D={}", destination.display()),
_ => "".to_string(),
};

let install_command = format!(
r#"CALL "{}" /S /D={}"#,
installer.display(),
destination.display()
r#"CALL "{installer}" {parameters} {destination}"#,
installer = installer.display(),
parameters = parameter_option,
destination = destination_option
);

trace!("install helper script content:");
writeln!(script, "ECHO OFF")?;
trace!("{}", &install_command);
writeln!(script, "{}", install_command)?;
}

info!(
"install {} to {}",
installer.display(),
destination.display()
);
info!("install {}", installer.display());
if let Some(destination) = destination {
info!("to {}", destination.display());
}

let installer_script = install_helper.into_temp_path();
let install_process = Command::new(&installer_script)
install_from_temp_command(&installer_script)?;
installer_script.close()?;
Ok(())
}

fn install_from_temp_command<P>(command: P) -> io::Result<()>
where
P: AsRef<Path>,
{
let command = command.as_ref();
let install_process = Command::new(command)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
Expand All @@ -114,7 +170,6 @@ where
err
})?;
let output = install_process.wait_with_output()?;
installer_script.close()?;
if !output.status.success() {
return Err(io::Error::new(
io::ErrorKind::Other,
Expand All @@ -127,3 +182,36 @@ where
}
Ok(())
}

fn install_from_msi<P>(installer: P, cmd: &str) -> io::Result<()>
where
P: AsRef<Path>,
{
let installer = installer.as_ref();

debug!("install unity module from installer msi");
let mut install_helper = Builder::new().suffix(".cmd").rand_bytes(20).tempfile()?;

info!(
"create install helper script {}",
install_helper.path().display()
);

{
let script = install_helper.as_file_mut();

let install_command = cmd.replace("/i", &format!(r#"/i "{}""#, installer.display()));

trace!("install helper script content:");
writeln!(script, "ECHO OFF")?;
trace!("{}", &install_command);
writeln!(script, "{}", install_command)?;
}

info!("install {}", installer.display());

let installer_script = install_helper.into_temp_path();
install_from_temp_command(&installer_script)?;
installer_script.close()?;
Ok(())
}