Skip to content
Open
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
13 changes: 12 additions & 1 deletion bench/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ pub fn get_target() -> &'static str {
#[cfg(target_os = "linux")]
return "x86_64-unknown-linux-gnu";

#[cfg(all(target_os = "freebsd", target_arch = "x86_64"))]
return "x86_64-unknown-freebsd";

#[cfg(all(target_os = "freebsd", target_arch = "aarch64"))]
return "aarch64-unknown-freebsd";

#[cfg(target_os = "windows")]
unimplemented!("Windows target not implemented yet");
}
Expand All @@ -84,7 +90,12 @@ pub fn bench_root_path() -> PathBuf {

/// Get the home directory of the current user.
pub fn home_path() -> PathBuf {
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "linux"))]
#[cfg(any(
target_os = "macos",
target_os = "ios",
target_os = "linux",
target_os = "freebsd"
))]
{
PathBuf::from(std::env::var("HOME").unwrap_or_default())
}
Expand Down
27 changes: 23 additions & 4 deletions crates/tauri-bundler/src/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// SPDX-License-Identifier: MIT

mod category;
#[cfg(target_os = "freebsd")]
mod freebsd;
mod kmp;
#[cfg(target_os = "linux")]
mod linux;
Expand Down Expand Up @@ -33,6 +35,16 @@ fn patch_binary(binary: &PathBuf, package_type: &PackageType) -> crate::Result<(
))
}
};
#[cfg(target_os = "freebsd")]
let bundle_type = match package_type {
crate::PackageType::Pkg => b"__TAURI_BUNDLE_TYPE_VAR_PKG",
_ => {
return Err(crate::Error::InvalidPackageType(
package_type.short_name().to_owned(),
"FreeBSD".to_owned(),
))
}
};
#[cfg(target_os = "windows")]
let bundle_type = match package_type {
crate::PackageType::Nsis => b"__TAURI_BUNDLE_TYPE_VAR_NSS",
Expand Down Expand Up @@ -81,8 +93,9 @@ pub use self::{
category::AppCategory,
settings::{
AppImageSettings, BundleBinary, BundleSettings, CustomSignCommandSettings, DebianSettings,
DmgSettings, Entitlements, IosSettings, MacOsSettings, PackageSettings, PackageType, PlistKind,
Position, RpmSettings, Settings, SettingsBuilder, Size, UpdaterSettings,
DmgSettings, Entitlements, IosSettings, MacOsSettings, PackageSettings, PackageType,
PkgSettings, PlistKind, Position, RpmSettings, Settings, SettingsBuilder, Size,
UpdaterSettings,
},
};
pub use settings::{NsisSettings, WindowsSettings, WixLanguage, WixLanguageConfig, WixSettings};
Expand Down Expand Up @@ -184,6 +197,8 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<Bundle>> {
PackageType::Rpm => linux::rpm::bundle_project(settings)?,
#[cfg(target_os = "linux")]
PackageType::AppImage => linux::appimage::bundle_project(settings)?,
#[cfg(target_os = "freebsd")]
PackageType::Pkg => freebsd::pkg::bundle_project(settings)?,
_ => {
log::warn!("ignoring {}", package_type.short_name());
continue;
Expand Down Expand Up @@ -229,11 +244,15 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<Bundle>> {
// Self contained updater, no need to zip
matches!(
package_type,
PackageType::AppImage | PackageType::Nsis | PackageType::WindowsMsi | PackageType::Deb
PackageType::AppImage
| PackageType::Nsis
| PackageType::WindowsMsi
| PackageType::Deb
| PackageType::Pkg
)
})
{
log::warn!("The bundler was configured to create updater artifacts but no updater-enabled targets were built. Please enable one of these targets: app, appimage, msi, nsis");
log::warn!("The bundler was configured to create updater artifacts but no updater-enabled targets were built. Please enable one of these targets: app, appimage, deb, msi, nsis, pkg");
}
if updater.v1_compatible {
log::warn!("Legacy v1 compatible updater is deprecated and will be removed in v3, change bundle > createUpdaterArtifacts to true when your users are updated to the version with v2 updater plugin");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[Desktop Entry]
Categories={{categories}}
{{#if comment}}
Comment={{comment}}
{{/if}}
Exec={{exec}}
StartupWMClass={{exec}}
Icon={{icon}}
Name={{name}}
Terminal=false
Type=Application
{{#if mime_type}}
MimeType={{mime_type}}
{{/if}}
170 changes: 170 additions & 0 deletions crates/tauri-bundler/src/bundle/freebsd/freedesktop/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

//! Freedesktop helpers used by FreeBSD desktop packages.
//!
//! FreeBSD desktop environments commonly consume the same freedesktop.org
//! desktop entry and icon hierarchy specifications used on Linux. FreeBSD pkg
//! installs these files under the package prefix, usually `/usr/local`.

use std::{
collections::BTreeMap,
ffi::OsStr,
fs::{read_to_string, File},
io::BufReader,
path::{Path, PathBuf},
};

use handlebars::Handlebars;
use image::{codecs::png::PngDecoder, ImageDecoder};
use serde::Serialize;

use crate::{
error::Context,
utils::{self, fs_utils},
Settings,
};

#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct Icon {
pub width: u32,
pub height: u32,
pub is_high_density: bool,
pub path: PathBuf,
}

pub fn list_icon_files(
settings: &Settings,
prefix_dir: &Path,
) -> crate::Result<BTreeMap<Icon, PathBuf>> {
let base_dir = prefix_dir.join("share/icons/hicolor");
let main_binary_name = settings.main_binary_name()?;
let get_dest_path = |width: u32, height: u32, is_high_density: bool| {
base_dir.join(format!(
"{}x{}{}/apps/{}.png",
width,
height,
if is_high_density { "@2" } else { "" },
main_binary_name
))
};

let mut icons = BTreeMap::new();
for icon_path in settings.icon_files() {
let icon_path = icon_path?;
if icon_path.extension() != Some(OsStr::new("png")) {
continue;
}
let icon = {
let decoder = PngDecoder::new(BufReader::new(File::open(&icon_path)?))?;
let width = decoder.dimensions().0;
let height = decoder.dimensions().1;
let is_high_density = utils::is_retina(&icon_path);
let dest_path = get_dest_path(width, height, is_high_density);
Icon {
width,
height,
is_high_density,
path: dest_path,
}
};
icons.entry(icon).or_insert(icon_path);
}

Ok(icons)
}

pub fn copy_icon_files(settings: &Settings, prefix_dir: &Path) -> crate::Result<Vec<Icon>> {
let icons = list_icon_files(settings, prefix_dir)?;
for (icon, src) in &icons {
fs_utils::copy_file(src, &icon.path)?;
}

Ok(icons.into_keys().collect())
}

pub fn generate_desktop_file(
settings: &Settings,
custom_template_path: &Option<PathBuf>,
prefix_dir: &Path,
) -> crate::Result<(PathBuf, PathBuf)> {
let bin_name = settings.main_binary_name()?;
let product_name = settings.product_name();
let desktop_file_name = format!("{product_name}.desktop");
let path = PathBuf::from("share/applications").join(desktop_file_name);
let dest_path = PathBuf::from("/usr/local").join(&path);
let file_path = prefix_dir.join(&path);
let file = &mut fs_utils::create_file(&file_path)?;

let mut handlebars = Handlebars::new();
handlebars.register_escape_fn(handlebars::no_escape);
if let Some(template) = custom_template_path {
handlebars
.register_template_string("main.desktop", read_to_string(template)?)
.map_err(Into::into)
.context("Failed to setup custom handlebar template")?;
} else {
handlebars
.register_template_string("main.desktop", include_str!("./main.desktop"))
.map_err(Into::into)
.context("Failed to setup default handlebar template")?;
}

#[derive(Serialize)]
struct DesktopTemplateParams<'a> {
categories: &'a str,
comment: Option<&'a str>,
exec: &'a str,
icon: &'a str,
name: &'a str,
mime_type: Option<String>,
long_description: String,
}

let mut mime_type = Vec::new();
if let Some(associations) = settings.file_associations() {
mime_type.extend(
associations
.iter()
.filter_map(|association| association.mime_type.clone()),
);
}
if let Some(protocols) = settings.deep_link_protocols() {
mime_type.extend(
protocols
.iter()
.flat_map(|protocol| &protocol.schemes)
.map(|scheme| format!("x-scheme-handler/{scheme}")),
);
}
let mime_type = (!mime_type.is_empty()).then_some(mime_type.join(";"));
let bin_name_exec = if bin_name.contains(' ') {
format!("\"{}\"", bin_name.replace('"', "\\\""))
} else {
bin_name.to_string()
};

handlebars.render_to_write(
"main.desktop",
&DesktopTemplateParams {
categories: settings
.app_category()
.map(|app_category| app_category.freedesktop_categories())
.unwrap_or(""),
comment: if !settings.short_description().is_empty() {
Some(settings.short_description())
} else {
None
},
exec: &bin_name_exec,
icon: bin_name,
name: settings.product_name(),
mime_type,
long_description: settings.long_description().unwrap_or_default().to_string(),
},
file,
)?;

Ok((file_path, dest_path))
}
6 changes: 6 additions & 0 deletions crates/tauri-bundler/src/bundle/freebsd/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

pub mod freedesktop;
pub mod pkg;
Loading