added installation commands for MVP

This commit is contained in:
tensor-programming 2019-08-06 01:47:43 -04:00
parent 2664bfb22b
commit b0e70e74ae
8 changed files with 280 additions and 36 deletions

View File

@ -214,6 +214,7 @@ dependencies = [
"serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"slog-term 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tar 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)",
"target_build_utils 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1364,6 +1365,27 @@ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.6.5"
@ -1784,6 +1806,18 @@ name = "slog"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "slog-term"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "smallvec"
version = "0.6.10"
@ -1886,6 +1920,16 @@ dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "term"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.11.0"
@ -2138,6 +2182,7 @@ name = "uuid"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
"sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -2517,6 +2562,8 @@ dependencies = [
"checksum publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5afecba86dcf1e4fd610246f89899d1924fe12e1e89f555eb7c7f710f3c5ad1d"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
@ -2564,6 +2611,7 @@ dependencies = [
"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cc9c640a4adbfbcc11ffb95efe5aa7af7309e002adab54b185507dbf2377b99"
"checksum slog-term 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cb9b3fd9a3c2c86580fce3558a98ed7c69039da0288b08a3f15b371635254e08"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
@ -2577,6 +2625,7 @@ dependencies = [
"checksum target_build_utils 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "013d134ae4a25ee744ad6129db589018558f620ddfa44043887cdd45fa08e75c"
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
"checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"

View File

@ -28,9 +28,10 @@ tar = "0.4"
target_build_utils = "0.3"
term = "0.4"
toml = "0.4"
uuid = { version = "0.5", features = ["v5"] }
uuid = { version = "0.5", features = ["v5", "v4"] }
walkdir = "2"
slog-term = "2.4.1"
sha2 = "0.8"
lazy_static = "1.3"
handlebars = "1.1"

View File

@ -0,0 +1,3 @@
use semver::Version;
use Platform;
use WIX;

View File

@ -1,10 +1,14 @@
use super::common;
use super::settings::Settings;
use super::wix;
use crate::ResultExt;
use cab;
use msi;
use slog::Drain;
use slog_term;
use std;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::env;
use std::ffi::OsStr;
use std::fs;
use std::io::{self, Write};
@ -90,39 +94,45 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
let cabinets = divide_resources_into_cabinets(resources);
generate_resource_cabinets(&mut package, &cabinets)
.chain_err(|| "Failed to generate resource cabinets")?;
let decorator = slog_term::TermDecorator::new().build();
let drain = slog_term::CompactFormat::new(decorator).build();
let drain = std::sync::Mutex::new(drain).fuse();
let logger = slog::Logger::root(drain, o!());
wix::get_and_extract_wix(&logger, &env::home_dir().unwrap());
// Set up installer database tables:
create_directory_table(&mut package, &directories)
.chain_err(|| "Failed to generate Directory table")?;
create_feature_table(&mut package, settings).chain_err(|| "Failed to generate Feature table")?;
create_component_table(&mut package, guid, &directories)
.chain_err(|| "Failed to generate Component table")?;
create_feature_components_table(&mut package, &directories)
.chain_err(|| "Failed to generate FeatureComponents table")?;
create_media_table(&mut package, &cabinets).chain_err(|| "Failed to generate Media table")?;
create_file_table(&mut package, &cabinets).chain_err(|| "Failed to generate File table")?;
// TODO: Create other needed tables.
// create_directory_table(&mut package, &directories)
// .chain_err(|| "Failed to generate Directory table")?;
// create_feature_table(&mut package, settings).chain_err(|| "Failed to generate Feature table")?;
// create_component_table(&mut package, guid, &directories)
// .chain_err(|| "Failed to generate Component table")?;
// create_feature_components_table(&mut package, &directories)
// .chain_err(|| "Failed to generate FeatureComponents table")?;
// create_media_table(&mut package, &cabinets).chain_err(|| "Failed to generate Media table")?;
// create_file_table(&mut package, &cabinets).chain_err(|| "Failed to generate File table")?;
// // TODO: Create other needed tables.
// Create app icon:
package.create_table(
"Icon",
vec![
msi::Column::build("Name").primary_key().id_string(72),
msi::Column::build("Data").binary(),
],
)?;
let icon_name = format!("{}.ico", settings.binary_name());
{
let stream_name = format!("Icon.{}", icon_name);
let mut stream = package.write_stream(&stream_name)?;
create_app_icon(&mut stream, settings)?;
}
package.insert_rows(msi::Insert::into("Icon").row(vec![
msi::Value::Str(icon_name.clone()),
msi::Value::from("Name"),
]))?;
// // Create app icon:
// package.create_table(
// "Icon",
// vec![
// msi::Column::build("Name").primary_key().id_string(72),
// msi::Column::build("Data").binary(),
// ],
// )?;
// let icon_name = format!("{}.ico", settings.binary_name());
// {
// let stream_name = format!("Icon.{}", icon_name);
// let mut stream = package.write_stream(&stream_name)?;
// create_app_icon(&mut stream, settings)?;
// }
// package.insert_rows(msi::Insert::into("Icon").row(vec![
// msi::Value::Str(icon_name.clone()),
// msi::Value::from("Name"),
// ]))?;
package.flush()?;
// package.flush()?;
Ok(vec![msi_path])
}

View File

@ -252,7 +252,7 @@ impl Settings {
- Stop at the first one found.
- If one is found before reaching "/" then this folder belongs to that parent workspace
*/
fn get_workspace_dir(current_dir: &PathBuf) -> PathBuf {
pub fn get_workspace_dir(current_dir: &PathBuf) -> PathBuf {
let mut dir = current_dir.clone();
while dir.pop() {
let set = CargoSettings::load(&dir);

View File

@ -9,5 +9,71 @@
<?endif?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product
Id="*"
Name="{{{product_name}}}"
UpgradeCode="{{{upgrade_code}}}"
Language="1033"
Codepage="1252"
Manufacturer="{{{manufacturer}}}"
Version="{{{version}}}">
<Package Id="*"
Keywords="Installer"
InstallerVersion="450"
Languages="1033"
Compressed="yes"
InstallScope="perMachine"
SummaryCodepage="1252"/>
<MajorUpgrade
Schedule="afterInstallInitialize"
DowngradeErrorMessage="A newer version of [ProductName] is already installed. Setup will now exit."/>
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes"/>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="$(var.PlatformProgramFilesFolder)" Name="PFiles">
<Directory Id="APPLICATIONFOLDER" Name="{{{product_name}}}">
<Component Id="Path" Guid="{{{path_component_guid}}}" Win64="$(var.Win64)" KeyPath="yes">
<Environment
Id="PATH"
Name="PATH"
Value="[Bin]"
Permanent="no"
Part="last"
Action="set"
System="yes"/>
</Component>
</Directory>
</Directory>
</Directory>
<Feature
Id="MainProgram"
Title="Application"
Description="Installs the executable."
Level="1"
ConfigurableDirectory="APPLICATIONFOLDER"
AllowAdvertise="no"
Display="expand"
Absent="disallow">
<ComponentGroupRef Id="AppFiles"/>
<Feature
Id="Environment"
Title="PATH Environment Variable"
Description="Add the install location of the [ProductName] executable to the PATH system environment variable. This allows the [ProductName] executable to be called from any location."
Level="1"
Absent="allow">
<ComponentRef Id="Path"/>
</Feature>
</Feature>
<SetProperty Id="ARPINSTALLLOCATION" Value="[APPLICATIONFOLDER]" After="CostFinalize"/>
<UI>
<UIRef Id="WixUI_FeatureTree"/>
</UI>
</Product>
</Wix>

View File

@ -1,18 +1,20 @@
use super::settings::Settings;
use handlebars::Handlebars;
use lazy_static::lazy_static;
use sha2::Digest;
use slog::info;
use slog::Logger;
use std::collections::BTreeMap;
use std::fs::{create_dir_all, File};
use std::fs::{create_dir_all, remove_dir_all, write, File};
use std::io::{BufRead, BufReader, Cursor, Read, Write};
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use uuid::Uuid;
use zip::ZipArchive;
const WIX_URL: &str =
pub const WIX_URL: &str =
"https://github.com/wixtoolset/wix3/releases/download/wix3111rtm/wix311-binaries.zip";
const WIX_SHA256: &str = "37f0a533b0978a454efb5dc3bd3598becf9660aaf4287e55bf68ca6b527d051d";
pub const WIX_SHA256: &str = "37f0a533b0978a454efb5dc3bd3598becf9660aaf4287e55bf68ca6b527d051d";
const VC_REDIST_X86_URL: &str =
"https://download.visualstudio.microsoft.com/download/pr/c8edbb87-c7ec-4500-a461-71e8912d25e9/99ba493d660597490cbb8b3211d2cae4/vc_redist.x86.exe";
@ -63,6 +65,20 @@ fn download_and_verify(logger: &Logger, url: &str, hash: &str) -> Result<Vec<u8>
}
}
fn app_installer_dir(settings: &Settings) -> PathBuf {
let arch = match settings.binary_arch() {
"i686-pc-windows-msvc" => "x86",
"x86_64-pc-windows-msvc" => "amd64",
target => panic!("unsupported target: {}", target),
};
settings.project_out_directory().to_path_buf().join(format!(
"{}.{}.msi",
settings.bundle_name(),
arch
))
}
fn extract_zip(data: &Vec<u8>, path: &Path) -> Result<(), String> {
let cursor = Cursor::new(data);
@ -89,7 +105,7 @@ fn extract_zip(data: &Vec<u8>, path: &Path) -> Result<(), String> {
Ok(())
}
fn get_and_extract_wix(logger: &Logger, path: &Path) -> Result<(), String> {
pub fn get_and_extract_wix(logger: &Logger, path: &Path) -> Result<(), String> {
info!(logger, "downloading WIX Toolkit...");
let data = download_and_verify(logger, WIX_URL, WIX_SHA256)?;
@ -151,6 +167,7 @@ fn run_heat_exe(
}
fn run_candle(
settings: &Settings,
logger: &Logger,
wix_toolset_path: &Path,
build_path: &Path,
@ -159,9 +176,14 @@ fn run_candle(
let arch = "x64";
let args = vec![
"-ext".to_string(),
"WixBalExtension".to_string(),
"-ext".to_string(),
"WixUtilExtension".to_string(),
"-arch".to_string(),
arch.to_string(),
wxs_file_name.to_string(),
format!("-dSourceDir={}", settings.binary_path().display()),
];
let candle_exe = wix_toolset_path.join("candle.exe");
@ -229,3 +251,93 @@ fn run_light(
Err("error running light.exe".to_string())
}
}
pub fn build_wix_app_installer(
logger: &Logger,
settings: &Settings,
wix_toolset_path: &Path,
current_dir: PathBuf,
) -> Result<(), String> {
let arch = match settings.binary_arch() {
"i686-pc-windows-msvc" => "x86",
"x86_64-pc-windows-msvc" => "amd64",
target => return Err(format!("unsupported target: {}", target)),
};
let output_path = settings.project_out_directory().join("wix").join(arch);
let mut data = BTreeMap::new();
data.insert("product_name", settings.bundle_name());
data.insert("version", settings.version_string());
let upgrade_code = if arch == "x86" {
Uuid::new_v5(
&uuid::NAMESPACE_DNS,
format!("{}.app.x64", &settings.bundle_name()).as_str(),
)
.to_string()
} else if arch == "x64" {
Uuid::new_v5(
&uuid::NAMESPACE_DNS,
format!("{}.app.x64", &settings.bundle_name()).as_str(),
)
.to_string()
} else {
panic!("unsupported target: {}");
};
data.insert("upgrade_code", &upgrade_code);
let path_guid = Uuid::new_v4().to_string();
data.insert("path_component_guid", &path_guid);
let app_exe_name = settings
.binary_path()
.file_name()
.unwrap()
.to_string_lossy()
.to_string();
data.insert("app_exe_name", &app_exe_name);
let app_exe_source = settings.binary_path().display().to_string();
data.insert("app_exe_source", &app_exe_source);
let temp = HANDLEBARS
.render("main.wxs", &data)
.or_else(|e| Err(e.to_string()))?;
if output_path.exists() {
remove_dir_all(&output_path).or_else(|e| Err(e.to_string()))?;
}
create_dir_all(&output_path).or_else(|e| Err(e.to_string()))?;
let main_wxs_path = output_path.join("main.wxs");
write(&main_wxs_path, temp).or_else(|e| Err(e.to_string()))?;
run_heat_exe(
logger,
&wix_toolset_path,
&output_path,
&Settings::get_workspace_dir(&current_dir),
arch,
)?;
let input_basenames = vec!["main", "appdir"];
for basename in &input_basenames {
let wxs = format!("{}.wxs", basename);
run_candle(settings, logger, &wix_toolset_path, &output_path, &wxs)?;
}
let wixobjs = vec!["main.wixobj", "appdir.wixobj"];
run_light(
logger,
&wix_toolset_path,
&output_path,
&wixobjs,
&app_installer_dir(settings),
)?;
Ok(())
}

View File

@ -10,6 +10,9 @@ extern crate serde_derive;
#[cfg(test)]
extern crate tempfile;
#[macro_use]
extern crate slog;
mod bundle;
use crate::bundle::{bundle_project, BuildArtifact, PackageType, Settings};