Some checks failed
Audit / audit-js (push) Failing after 0s
bench / bench (map[os:ubuntu-latest runner:xvfb-run --auto-servernum target:x86_64-unknown-linux-gnu], nightly) (push) Failing after 0s
covector version or publish / run-integration-tests (ubuntu-latest) (push) Failing after 0s
Audit / audit-rust (push) Failing after 0s
test `@tauri-apps/cli` / test (ubuntu-latest) (push) Failing after 0s
test `tauri-cli` / test (map[os:ubuntu-latest target:x86_64-unknown-linux-gnu]) (push) Failing after 0s
test core / test (map[args:--all-features key:all], map[cargo:cargo command:test os:ubuntu-latest target:x86_64-unknown-linux-gnu toolchain:1.90]) (push) Failing after 0s
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:test os:ubuntu-latest target:x86_64-unknown-linux-gnu toolchain:1.90]) (push) Failing after 0s
test core / test (map[args:--no-default-features key:no-default], map[cargo:cross command:build os:ubuntu-latest target:aarch64-linux-android toolchain:1.90]) (push) Failing after 0s
deploy schema worker / deploy (push) Failing after 0s
lint rust / clippy (map[cargo:cargo include: os:ubuntu-latest target:x86_64-unknown-linux-gnu]) (push) Failing after 0s
lint rust / clippy (map[cargo:cross include:--package api os:ubuntu-latest target:aarch64-linux-android]) (push) Failing after 0s
supply chain health status / check rust dependencies with cargo vet (push) Failing after 0s
test `@tauri-apps/api` e2e (mobile) / android (push) Failing after 0s
test `@tauri-apps/api` e2e / test (map[name:Linux os:ubuntu-latest]) (push) Failing after 0s
test core / test (map[args:--all-features key:all], map[cargo:cross command:build os:ubuntu-latest target:aarch64-linux-android toolchain:1.90]) (push) Failing after 0s
Udeps / changes (push) Failing after 0s
Udeps / setup (push) Has been skipped
Udeps / udeps (push) Has been skipped
bench / bench (map[os:macos-latest runner: target:aarch64-apple-darwin], nightly) (push) Has been cancelled
bench / bench (map[os:windows-latest runner: target:x86_64-pc-windows-msvc], nightly) (push) Has been cancelled
covector version or publish / run-integration-tests (macos-latest) (push) Has been cancelled
covector version or publish / run-integration-tests (windows-latest) (push) Has been cancelled
covector version or publish / version-or-publish (push) Has been cancelled
test `@tauri-apps/cli` / test (macos-latest) (push) Has been cancelled
test `tauri-cli` / test (map[args:--no-default-features --features native-tls-vendored os:windows-latest restore-only:true target:aarch64-pc-windows-msvc]) (push) Has been cancelled
test `tauri-cli` / test (map[os:macos-latest target:x86_64-apple-darwin]) (push) Has been cancelled
test `tauri-cli` / test (map[os:windows-latest target:x86_64-pc-windows-msvc]) (push) Has been cancelled
test core / test (map[args:--all-features key:all], map[cargo:cargo command:build os:macos-latest target:aarch64-apple-ios toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--all-features key:all], map[cargo:cargo command:test os:macos-14 target:aarch64-apple-darwin toolchain:1.90]) (push) Has been cancelled
lint rust / clippy (map[cargo:cargo include: os:macos-latest target:aarch64-apple-darwin]) (push) Has been cancelled
lint rust / clippy (map[cargo:cargo include: os:windows-latest target:x86_64-pc-windows-msvc]) (push) Has been cancelled
lint rust / clippy (map[cargo:cargo include:--package api os:macos-latest target:aarch64-apple-ios]) (push) Has been cancelled
test `@tauri-apps/api` e2e (mobile) / ios (push) Has been cancelled
test `@tauri-apps/api` e2e / test (map[name:Windows os:windows-latest]) (push) Has been cancelled
test `@tauri-apps/api` e2e / test (map[name:macOS os:macos-latest]) (push) Has been cancelled
test `@tauri-apps/cli` / test (windows-latest) (push) Has been cancelled
test core / test (map[args:--all-features key:all], map[cargo:cargo command:test os:windows-latest target:x86_64-pc-windows-msvc toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:build os:macos-latest target:aarch64-apple-ios toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:test os:macos-14 target:aarch64-apple-darwin toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:test os:windows-latest target:x86_64-pc-windows-msvc toolchain:1.90]) (push) Has been cancelled
244 lines
7.7 KiB
Rust
244 lines
7.7 KiB
Rust
// Copyright 2016-2019 Cargo-Bundle developers <https://github.com/burtonageo/cargo-bundle>
|
|
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
use crate::{Settings, bundle::settings::Arch, error::ErrorExt};
|
|
|
|
use rpm::{self, Dependency, FileMode, FileOptions, signature::pgp};
|
|
use std::{
|
|
env,
|
|
fs::{self, File},
|
|
path::{Path, PathBuf},
|
|
};
|
|
use tauri_utils::config::RpmCompression;
|
|
|
|
use super::freedesktop;
|
|
|
|
/// Bundles the project.
|
|
/// Returns a vector of PathBuf that shows where the RPM was created.
|
|
pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
|
let product_name = settings.product_name();
|
|
let version = settings.version_string();
|
|
let release = match settings.rpm().release.as_str() {
|
|
"" => "1", // Considered the default. If left empty, you get file with "-.".
|
|
v => v,
|
|
};
|
|
let epoch = settings.rpm().epoch;
|
|
let arch = match settings.binary_arch() {
|
|
Arch::X86_64 => "x86_64",
|
|
Arch::X86 => "i386",
|
|
Arch::AArch64 => "aarch64",
|
|
Arch::Armhf => "armhfp",
|
|
Arch::Armel => "armel",
|
|
Arch::Riscv64 => "riscv64",
|
|
target => {
|
|
return Err(crate::Error::ArchError(format!(
|
|
"Unsupported architecture: {target:?}"
|
|
)));
|
|
}
|
|
};
|
|
|
|
let summary = settings.short_description().trim();
|
|
|
|
let package_base_name = format!("{product_name}-{version}-{release}.{arch}");
|
|
let package_name = format!("{package_base_name}.rpm");
|
|
|
|
let base_dir = settings.project_out_directory().join("bundle/rpm");
|
|
let package_dir = base_dir.join(&package_base_name);
|
|
if package_dir.exists() {
|
|
fs::remove_dir_all(&package_dir).fs_context(
|
|
"Failed to remove old package directory",
|
|
package_dir.clone(),
|
|
)?;
|
|
}
|
|
fs::create_dir_all(&package_dir)
|
|
.fs_context("Failed to create package directory", package_dir.clone())?;
|
|
let package_path = base_dir.join(&package_name);
|
|
|
|
log::info!(action = "Bundling"; "{} ({})", package_name, package_path.display());
|
|
|
|
let license = settings.license().unwrap_or_default();
|
|
let name = heck::AsKebabCase(settings.product_name()).to_string();
|
|
|
|
let compression = settings
|
|
.rpm()
|
|
.compression
|
|
.map(|c| match c {
|
|
RpmCompression::Gzip { level } => rpm::CompressionWithLevel::Gzip(level),
|
|
RpmCompression::Zstd { level } => rpm::CompressionWithLevel::Zstd(level),
|
|
RpmCompression::Xz { level } => rpm::CompressionWithLevel::Xz(level),
|
|
RpmCompression::Bzip2 { level } => rpm::CompressionWithLevel::Bzip2(level),
|
|
_ => rpm::CompressionWithLevel::None,
|
|
})
|
|
// This matches .deb compression. On a 240MB source binary the bundle will be 100KB larger than rpm's default while reducing build times by ~25%.
|
|
// TODO: Default to Zstd in v3 to match rpm-rs new default in 0.16
|
|
.unwrap_or(rpm::CompressionWithLevel::Gzip(6));
|
|
|
|
let mut builder = rpm::PackageBuilder::new(&name, version, &license, arch, summary)
|
|
.epoch(epoch)
|
|
.release(release)
|
|
.compression(compression);
|
|
|
|
if let Some(description) = settings.long_description() {
|
|
builder = builder.description(description);
|
|
}
|
|
|
|
if let Some(homepage) = settings.homepage_url() {
|
|
builder = builder.url(homepage);
|
|
}
|
|
|
|
// Add requirements
|
|
for dep in settings.rpm().depends.as_ref().cloned().unwrap_or_default() {
|
|
builder = builder.requires(Dependency::any(dep));
|
|
}
|
|
|
|
// Add provides
|
|
for dep in settings
|
|
.rpm()
|
|
.provides
|
|
.as_ref()
|
|
.cloned()
|
|
.unwrap_or_default()
|
|
{
|
|
builder = builder.provides(Dependency::any(dep));
|
|
}
|
|
|
|
// Add recommends
|
|
for dep in settings
|
|
.rpm()
|
|
.recommends
|
|
.as_ref()
|
|
.cloned()
|
|
.unwrap_or_default()
|
|
{
|
|
builder = builder.recommends(Dependency::any(dep));
|
|
}
|
|
|
|
// Add conflicts
|
|
for dep in settings
|
|
.rpm()
|
|
.conflicts
|
|
.as_ref()
|
|
.cloned()
|
|
.unwrap_or_default()
|
|
{
|
|
builder = builder.conflicts(Dependency::any(dep));
|
|
}
|
|
|
|
// Add obsoletes
|
|
for dep in settings
|
|
.rpm()
|
|
.obsoletes
|
|
.as_ref()
|
|
.cloned()
|
|
.unwrap_or_default()
|
|
{
|
|
builder = builder.obsoletes(Dependency::any(dep));
|
|
}
|
|
|
|
// Add binaries
|
|
for bin in settings.binaries() {
|
|
let src = settings.binary_path(bin);
|
|
let dest = Path::new("/usr/bin").join(bin.name());
|
|
builder = builder.with_file(src, FileOptions::new(dest.to_string_lossy()))?;
|
|
}
|
|
|
|
// Add external binaries
|
|
for src in settings.external_binaries() {
|
|
let src = src?;
|
|
let dest = Path::new("/usr/bin").join(
|
|
src
|
|
.file_name()
|
|
.expect("failed to extract external binary filename")
|
|
.to_string_lossy()
|
|
.replace(&format!("-{}", settings.target()), ""),
|
|
);
|
|
builder = builder.with_file(&src, FileOptions::new(dest.to_string_lossy()))?;
|
|
}
|
|
|
|
// Add scripts
|
|
if let Some(script_path) = &settings.rpm().pre_install_script {
|
|
let script = fs::read_to_string(script_path)?;
|
|
builder = builder.pre_install_script(script);
|
|
}
|
|
|
|
if let Some(script_path) = &settings.rpm().post_install_script {
|
|
let script = fs::read_to_string(script_path)?;
|
|
builder = builder.post_install_script(script);
|
|
}
|
|
|
|
if let Some(script_path) = &settings.rpm().pre_remove_script {
|
|
let script = fs::read_to_string(script_path)?;
|
|
builder = builder.pre_uninstall_script(script);
|
|
}
|
|
|
|
if let Some(script_path) = &settings.rpm().post_remove_script {
|
|
let script = fs::read_to_string(script_path)?;
|
|
builder = builder.post_uninstall_script(script);
|
|
}
|
|
|
|
// Add resources
|
|
if settings.resource_files().count() > 0 {
|
|
let resource_dir = Path::new("/usr/lib").join(settings.product_name());
|
|
// Create an empty file, needed to add a directory to the RPM package
|
|
// (cf https://github.com/rpm-rs/rpm/issues/177)
|
|
let empty_file_path = &package_dir.join("empty");
|
|
File::create(empty_file_path)?;
|
|
// Then add the resource directory `/usr/lib/<product_name>` to the package.
|
|
builder = builder.with_file(
|
|
empty_file_path,
|
|
FileOptions::new(resource_dir.to_string_lossy()).mode(FileMode::Dir { permissions: 0o755 }),
|
|
)?;
|
|
// Then add the resources files in that directory
|
|
for resource in settings.resource_files().iter() {
|
|
let resource = resource?;
|
|
let dest = resource_dir.join(resource.target());
|
|
builder = builder.with_file(resource.path(), FileOptions::new(dest.to_string_lossy()))?;
|
|
}
|
|
}
|
|
|
|
// Add Desktop entry file
|
|
let (desktop_src_path, desktop_dest_path) =
|
|
freedesktop::generate_desktop_file(settings, &settings.rpm().desktop_template, &package_dir)?;
|
|
builder = builder.with_file(
|
|
desktop_src_path,
|
|
FileOptions::new(desktop_dest_path.to_string_lossy()),
|
|
)?;
|
|
|
|
// Add icons
|
|
for (icon, src) in &freedesktop::list_icon_files(settings, &PathBuf::from("/"))? {
|
|
builder = builder.with_file(src, FileOptions::new(icon.path.to_string_lossy()))?;
|
|
}
|
|
|
|
// Add custom files
|
|
for (rpm_path, src_path) in settings.rpm().files.iter() {
|
|
if src_path.is_file() {
|
|
builder = builder.with_file(src_path, FileOptions::new(rpm_path.to_string_lossy()))?;
|
|
} else {
|
|
for entry in walkdir::WalkDir::new(src_path) {
|
|
let entry_path = entry?.into_path();
|
|
if entry_path.is_file() {
|
|
let dest_path = rpm_path.join(entry_path.strip_prefix(src_path).unwrap());
|
|
builder =
|
|
builder.with_file(&entry_path, FileOptions::new(dest_path.to_string_lossy()))?;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let pkg = if let Ok(raw_secret_key) = env::var("TAURI_SIGNING_RPM_KEY") {
|
|
let mut signer = pgp::Signer::load_from_asc(&raw_secret_key)?;
|
|
if let Ok(passphrase) = env::var("TAURI_SIGNING_RPM_KEY_PASSPHRASE") {
|
|
signer = signer.with_key_passphrase(passphrase);
|
|
}
|
|
builder.build_and_sign(signer)?
|
|
} else {
|
|
builder.build()?
|
|
};
|
|
|
|
let mut f = fs::File::create(&package_path)?;
|
|
pkg.write(&mut f)?;
|
|
Ok(vec![package_path])
|
|
}
|