mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-11-29 04:55:40 +03:00
feat(bundler&tauri) add wix resource bundling and utils to get the path to the platform resource dir (#352)
* feat(bundler) copy resources to the out dir * feat(utils) add resource_dir fn * feat(examples) spawn node with resource JS instead of pkg bin * feat(bundler) WIP on windows resource bundler * feat(utils) add windows, macos resource_dir logic * fix(bundler) resource folder iteration on wix * chore(bundler) add comments to generate_resource_data fn * chore(bundler) add comments to the get_wix_data fn * change minor items. * run `cargo fmt` * run `rust fmt` and `clippy` and add fmt.toml * remove unnessecary rustfmt.toml files. Co-authored-by: Tensor-Programming <abeltensor@tensor-programming.com>
This commit is contained in:
parent
92d87137cc
commit
b7a6bc0f42
@ -42,6 +42,7 @@ pub fn bundle_project(settings: Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
});
|
||||
}
|
||||
|
||||
settings.copy_resources(settings.project_out_directory())?;
|
||||
settings.copy_binaries(settings.project_out_directory())?;
|
||||
|
||||
Ok(paths)
|
||||
|
@ -210,13 +210,7 @@ fn generate_md5sums(control_dir: &Path, data_dir: &Path) -> crate::Result<()> {
|
||||
/// `data_dir`.
|
||||
fn transfer_resource_files(settings: &Settings, data_dir: &Path) -> crate::Result<()> {
|
||||
let resource_dir = data_dir.join("usr/lib").join(settings.binary_name());
|
||||
for src in settings.resource_files() {
|
||||
let src = src?;
|
||||
let dest = resource_dir.join(common::resource_relpath(&src));
|
||||
common::copy_file(&src, &dest)
|
||||
.chain_err(|| format!("Failed to copy resource file {:?}", src))?;
|
||||
}
|
||||
Ok(())
|
||||
settings.copy_resources(&resource_dir)
|
||||
}
|
||||
|
||||
/// Generate the icon files and store them under the `data_dir`.
|
||||
|
@ -6,10 +6,10 @@ use handlebars::Handlebars;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::{File, write};
|
||||
use std::fs::{write, File};
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::io::Write;
|
||||
|
||||
// Create handlebars template for shell scripts
|
||||
lazy_static! {
|
||||
@ -55,7 +55,9 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
let seticon = include_bytes!("templates/seticon");
|
||||
let seticon_out = &output_path.join("seticon");
|
||||
let mut seticon_buffer = File::create(seticon_out).or_else(|e| Err(e.to_string()))?;
|
||||
seticon_buffer.write_all(seticon).or_else(|e| Err(e.to_string()))?;
|
||||
seticon_buffer
|
||||
.write_all(seticon)
|
||||
.or_else(|e| Err(e.to_string()))?;
|
||||
|
||||
// chmod script for execution
|
||||
|
||||
|
@ -36,12 +36,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
fs::create_dir_all(&bundle_dir)
|
||||
.chain_err(|| format!("Failed to create bundle directory at {:?}", bundle_dir))?;
|
||||
|
||||
for src in settings.resource_files() {
|
||||
let src = src?;
|
||||
let dest = bundle_dir.join(common::resource_relpath(&src));
|
||||
common::copy_file(&src, &dest)
|
||||
.chain_err(|| format!("Failed to copy resource file {:?}", src))?;
|
||||
}
|
||||
settings.copy_resources(bundle_dir);
|
||||
|
||||
let icon_filenames =
|
||||
generate_icon_files(&bundle_dir, settings).chain_err(|| "Failed to create app icons")?;
|
||||
|
@ -61,12 +61,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
copy_frameworks_to_bundle(&bundle_directory, settings)
|
||||
.chain_err(|| "Failed to bundle frameworks")?;
|
||||
|
||||
for src in settings.resource_files() {
|
||||
let src = src?;
|
||||
let dest = resources_dir.join(common::resource_relpath(&src));
|
||||
common::copy_file(&src, &dest)
|
||||
.chain_err(|| format!("Failed to copy resource file {:?}", src))?;
|
||||
}
|
||||
settings.copy_resources(&resources_dir)?;
|
||||
|
||||
settings
|
||||
.copy_binaries(&bin_dir)
|
||||
|
@ -445,6 +445,17 @@ impl Settings {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// copy resources to a path
|
||||
pub fn copy_resources(&self, path: &Path) -> crate::Result<()> {
|
||||
for src in self.resource_files() {
|
||||
let src = src?;
|
||||
let dest = path.join(common::resource_relpath(&src));
|
||||
common::copy_file(&src, &dest)
|
||||
.map_err(|_| format!("Failed to copy resource file {:?}", src))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn version_string(&self) -> &str {
|
||||
self
|
||||
.bundle_settings
|
||||
|
@ -48,6 +48,7 @@
|
||||
<File Id="PathFile_{{ external_bin.id }}" Source="{{external_bin.path}}" />
|
||||
</Component>
|
||||
{{/each~}}
|
||||
{{{resources}}}
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Directory>
|
||||
@ -85,6 +86,10 @@
|
||||
Display="expand"
|
||||
Absent="disallow">
|
||||
|
||||
{{#each resource_file_ids as |resource_file_id| ~}}
|
||||
<ComponentRef Id="{{ resource_file_id }}"/>
|
||||
{{/each~}}
|
||||
|
||||
<Feature Id="ShortcutsFeature"
|
||||
Title="Shortcuts"
|
||||
Level="1">
|
||||
|
@ -53,6 +53,8 @@ lazy_static! {
|
||||
};
|
||||
}
|
||||
|
||||
type ResourceMap = BTreeMap<String, ResourceDirectory>;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ExternalBinary {
|
||||
guid: String,
|
||||
@ -60,6 +62,58 @@ struct ExternalBinary {
|
||||
path: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
struct ResourceFile {
|
||||
guid: String,
|
||||
id: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ResourceDirectory {
|
||||
name: String,
|
||||
files: Vec<ResourceFile>,
|
||||
directories: Vec<ResourceDirectory>,
|
||||
}
|
||||
|
||||
impl ResourceDirectory {
|
||||
fn add_file(&mut self, file: ResourceFile) {
|
||||
self.files.push(file);
|
||||
}
|
||||
|
||||
// generates the wix XML string to bundle this directory resources recursively
|
||||
fn get_wix_data(self) -> crate::Result<(String, Vec<String>)> {
|
||||
let mut files = String::from("");
|
||||
let mut file_ids = Vec::new();
|
||||
for file in self.files {
|
||||
file_ids.push(file.id.clone());
|
||||
files.push_str(
|
||||
format!(
|
||||
r#"<Component Id="{id}" Guid="{guid}" Win64="$(var.Win64)" KeyPath="yes"><File Id="PathFile_{id}" Source="{path}" /></Component>"#,
|
||||
id = file.id,
|
||||
guid = file.guid,
|
||||
path = file.path
|
||||
).as_str()
|
||||
);
|
||||
}
|
||||
let mut directories = String::from("");
|
||||
for directory in self.directories {
|
||||
let (wix_string, ids) = directory.get_wix_data()?;
|
||||
for id in ids {
|
||||
file_ids.push(id)
|
||||
}
|
||||
directories.push_str(wix_string.as_str());
|
||||
}
|
||||
let wix_string = format!(
|
||||
r#"<Directory Id="{name}" Name="{name}">{contents}</Directory>"#,
|
||||
name = self.name,
|
||||
contents = format!("{}{}", files, directories)
|
||||
);
|
||||
|
||||
Ok((wix_string, file_ids))
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_icons(settings: &Settings) -> crate::Result<PathBuf> {
|
||||
let base_dir = settings.binary_path();
|
||||
let base_dir = base_dir.parent().expect("Failed to get dir");
|
||||
@ -378,6 +432,20 @@ pub fn build_wix_app_installer(
|
||||
let external_binaries_json = to_json(&external_binaries);
|
||||
data.insert("external_binaries", external_binaries_json);
|
||||
|
||||
let resources = generate_resource_data(&settings)?;
|
||||
let mut resources_wix_string = String::from("");
|
||||
let mut files_ids = Vec::new();
|
||||
for (_, dir) in resources {
|
||||
let (wix_string, ids) = dir.get_wix_data()?;
|
||||
resources_wix_string.push_str(wix_string.as_str());
|
||||
for id in ids {
|
||||
files_ids.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
data.insert("resources", to_json(resources_wix_string));
|
||||
data.insert("resource_file_ids", to_json(files_ids));
|
||||
|
||||
let app_exe_source = settings.binary_path().display().to_string();
|
||||
|
||||
data.insert("app_exe_source", to_json(&app_exe_source));
|
||||
@ -448,3 +516,92 @@ fn generate_external_binary_data(settings: &Settings) -> crate::Result<Vec<Exter
|
||||
|
||||
Ok(external_binaries)
|
||||
}
|
||||
|
||||
// generates the data required for the resource bundling on wix
|
||||
fn generate_resource_data(settings: &Settings) -> crate::Result<ResourceMap> {
|
||||
let mut resources = ResourceMap::new();
|
||||
let regex = Regex::new(r"[^\w\d\.]")?;
|
||||
let cwd = std::env::current_dir()?;
|
||||
for src in settings.resource_files() {
|
||||
let src = src?;
|
||||
|
||||
let filename = src
|
||||
.file_name()
|
||||
.expect("failed to extract resource filename")
|
||||
.to_os_string()
|
||||
.into_string()
|
||||
.expect("failed to convert resource filename to string");
|
||||
|
||||
let resource_path = cwd
|
||||
.join(src.clone())
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.expect("failed to read resource path");
|
||||
|
||||
let resource_entry = ResourceFile {
|
||||
guid: generate_guid(filename.as_bytes()).to_string(),
|
||||
path: resource_path,
|
||||
id: regex.replace_all(&filename, "").to_string(),
|
||||
};
|
||||
|
||||
// split the resource path directories
|
||||
let mut directories = src
|
||||
.components()
|
||||
.filter(|component| {
|
||||
let comp = component.as_os_str();
|
||||
comp != "." && comp != ".."
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
directories.truncate(directories.len() - 1);
|
||||
// transform the directory structure to a chained vec structure
|
||||
for directory in directories {
|
||||
let directory_name = directory
|
||||
.as_os_str()
|
||||
.to_os_string()
|
||||
.into_string()
|
||||
.expect("failed to read resource folder name");
|
||||
|
||||
// if the directory is already on the map
|
||||
if resources.contains_key(&directory_name) {
|
||||
let directory_entry = &mut resources
|
||||
.get_mut(&directory_name)
|
||||
.expect("Unable to handle resources");
|
||||
if directory_entry.name == directory_name {
|
||||
// the directory entry is the root of the chain
|
||||
directory_entry.add_file(resource_entry.clone());
|
||||
} else {
|
||||
let index = directory_entry
|
||||
.directories
|
||||
.iter()
|
||||
.position(|f| f.name == directory_name);
|
||||
if index.is_some() {
|
||||
// the directory entry is already a part of the chain
|
||||
let dir = directory_entry
|
||||
.directories
|
||||
.get_mut(index.expect("Unable to get index"))
|
||||
.expect("Unable to get directory");
|
||||
dir.add_file(resource_entry.clone());
|
||||
} else {
|
||||
// push it to the chain
|
||||
directory_entry.directories.push(ResourceDirectory {
|
||||
name: directory_name.clone(),
|
||||
directories: vec![],
|
||||
files: vec![resource_entry.clone()],
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
resources.insert(
|
||||
directory_name.clone(),
|
||||
ResourceDirectory {
|
||||
name: directory_name.clone(),
|
||||
directories: vec![],
|
||||
files: vec![resource_entry.clone()],
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(resources)
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ icon = [
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
]
|
||||
external_bin = [ "bin/packaged-node" ]
|
||||
resources = [ "resources" ]
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0.44"
|
||||
|
Binary file not shown.
Binary file not shown.
@ -16,11 +16,12 @@ fn main() {
|
||||
.setup(|_webview| {
|
||||
let handle1 = _webview.handle();
|
||||
std::thread::spawn(move || {
|
||||
let stdout = tauri::api::command::spawn_relative_command(
|
||||
tauri::api::command::binary_command("packaged-node".to_string()).expect("failed to get binary command"),
|
||||
Vec::new(),
|
||||
std::process::Stdio::piped(),
|
||||
)
|
||||
let resource_dir = tauri::api::platform::resource_dir().expect("failed to get resource dir");
|
||||
let node_package_path = resource_dir.join("resources/packaged-node.js");
|
||||
let stdout = std::process::Command::new("node")
|
||||
.args(vec!(node_package_path))
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Failed to spawn packaged node")
|
||||
.stdout.expect("Failed to get packaged node stdout");
|
||||
let reader = std::io::BufReader::new(stdout);
|
||||
|
@ -21,10 +21,8 @@ either = "1.5.3"
|
||||
tar = "0.4"
|
||||
flate2 = "1"
|
||||
error-chain = "0.12"
|
||||
|
||||
tauri-utils = {version = "0.3.0", path = "../tauri-utils"}
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
quickcheck = "0.9.2"
|
||||
quickcheck_macros = "0.9.1"
|
||||
|
@ -1,13 +0,0 @@
|
||||
max_width = 100
|
||||
hard_tabs = false
|
||||
tab_spaces = 2
|
||||
newline_style = "Auto"
|
||||
use_small_heuristics = "Default"
|
||||
reorder_imports = true
|
||||
reorder_modules = true
|
||||
remove_nested_parens = true
|
||||
edition = "2018"
|
||||
merge_derives = true
|
||||
use_try_shorthand = false
|
||||
use_field_init_shorthand = false
|
||||
force_explicit_abi = true
|
@ -15,6 +15,8 @@ pub mod file;
|
||||
pub mod rpc;
|
||||
pub mod version;
|
||||
|
||||
pub use tauri_utils::*;
|
||||
|
||||
use error_chain::error_chain;
|
||||
|
||||
error_chain! {
|
||||
|
@ -4,5 +4,8 @@ pub mod process;
|
||||
use error_chain::error_chain;
|
||||
|
||||
error_chain! {
|
||||
errors{}
|
||||
foreign_links {
|
||||
Io(::std::io::Error);
|
||||
}
|
||||
errors {}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::path::{PathBuf, MAIN_SEPARATOR};
|
||||
|
||||
/// Try to determine the current target triple.
|
||||
///
|
||||
/// Returns a target triple (e.g. `x86_64-unknown-linux-gnu` or `i686-pc-windows-msvc`) or an
|
||||
@ -51,3 +53,35 @@ pub fn target_triple() -> Result<String, crate::Error> {
|
||||
|
||||
Ok(format!("{}-{}", arch, os))
|
||||
}
|
||||
|
||||
pub fn resource_dir() -> crate::Result<PathBuf> {
|
||||
let exe = std::env::current_exe()?;
|
||||
let exe_dir = exe.parent().expect("failed to get exe directory");
|
||||
let app_name = exe
|
||||
.file_name()
|
||||
.expect("failed to get exe filename")
|
||||
.to_string_lossy();
|
||||
let curr_dir = exe_dir.display().to_string();
|
||||
|
||||
if curr_dir.ends_with(format!("{S}target{S}debug", S = MAIN_SEPARATOR).as_str())
|
||||
|| curr_dir.ends_with(format!("{S}target{S}release", S = MAIN_SEPARATOR).as_str())
|
||||
|| cfg!(target_os = "windows")
|
||||
{
|
||||
// running from the out dir or windows
|
||||
return Ok(exe_dir.to_path_buf());
|
||||
}
|
||||
|
||||
if cfg!(target_os = "linux") {
|
||||
if curr_dir.ends_with("/data/usr/bin") {
|
||||
// running from the deb bundle dir
|
||||
Ok(exe_dir.join(format!("../lib/{}", app_name)))
|
||||
} else {
|
||||
// running bundle
|
||||
Ok(PathBuf::from(format!("/usr/lib/{}", app_name)))
|
||||
}
|
||||
} else if cfg!(target_os = "macos") {
|
||||
Ok(exe_dir.join("../Resources"))
|
||||
} else {
|
||||
Err(crate::Error::from("Unknown target_os"))
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
include!(concat!(env!("OUT_DIR"), "/data.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/data.rs"));
|
||||
|
Loading…
Reference in New Issue
Block a user