/
githubmirror
/
tauri
Обзор
Документация
Войти
/
githubmirror
/
tauri
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy.rs
264 строки
9 KB
Fabian-Lars
fix(bundler): stop bundling xdg-open and xdg-utils (#15804)
03 авг 2026, 10:09
Не верифицирован
03 авг 2026, 10:09
eaf9669
Код
Авторство
О чём код?
// 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 super::{super::debian, write_and_make_executable}; use crate::{ bundle::settings::Arch, error::Context, utils::{fs_utils, http_utils::download, CommandExt}, Settings, }; use std::{ fs, path::{Path, PathBuf}, process::Command, }; /// Bundles the project. /// Returns a vector of PathBuf that shows where the AppImage was created. pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> { // generate the deb binary name let appimage_arch: &str = match settings.binary_arch() { Arch::X86_64 => "amd64", Arch::X86 => "i386", Arch::AArch64 => "aarch64", Arch::Armhf => "armhf", target => { return Err(crate::Error::ArchError(format!( "Unsupported architecture: {target:?}" ))); } }; let tools_arch = if settings.binary_arch() == Arch::Armhf { "armhf" } else { settings.target().split('-').next().unwrap() }; let output_path = settings.project_out_directory().join("bundle/appimage"); if output_path.exists() { fs::remove_dir_all(&output_path)?; } let tools_path = settings .local_tools_directory() .map(|d| d.join(".tauri")) .unwrap_or_else(|| { dirs::cache_dir().map_or_else(|| output_path.to_path_buf(), |p| p.join("tauri")) }); fs::create_dir_all(&tools_path)?; let linuxdeploy_path = prepare_tools( &tools_path, tools_arch, settings.log_level() != log::Level::Error, )?; let package_dir = settings.project_out_directory().join("bundle/appimage_deb"); let main_binary = settings.main_binary()?; let product_name = settings.product_name(); let mut settings = settings.clone(); if main_binary.name().contains(' ') { let main_binary_path = settings.binary_path(main_binary); let project_out_directory = settings.project_out_directory(); let main_binary_name_kebab = heck::AsKebabCase(main_binary.name()).to_string(); let new_path = project_out_directory.join(&main_binary_name_kebab); fs::copy(main_binary_path, new_path)?; let main_binary = settings.main_binary_mut()?; main_binary.set_name(main_binary_name_kebab); } // generate deb_folder structure let (data_dir, icons) = debian::generate_data(&settings, &package_dir) .with_context(|| "Failed to build data folders and files")?; fs_utils::copy_custom_files(&settings.appimage().files, &data_dir) .with_context(|| "Failed to copy custom files")?; fs::create_dir_all(&output_path)?; let app_dir_path = output_path.join(format!("{}.AppDir", settings.product_name())); let appimage_filename = format!( "{}_{}_{}.AppImage", settings.product_name(), settings.version_string(), appimage_arch ); let appimage_path = output_path.join(&appimage_filename); fs_utils::create_dir(&app_dir_path, true)?; fs::create_dir_all(&tools_path)?; let larger_icon = icons .iter() .filter(|i| i.width == i.height) .max_by_key(|i| i.width) .expect("couldn't find a square icon to use as AppImage icon"); let larger_icon_path = larger_icon .path .strip_prefix(package_dir.join("data")) .unwrap() .to_string_lossy() .to_string(); log::info!(action = "Bundling"; "{} ({})", appimage_filename, appimage_path.display()); let app_dir_usr = app_dir_path.join("usr/"); let app_dir_usr_bin = app_dir_usr.join("bin/"); let app_dir_usr_lib = app_dir_usr.join("lib/"); fs_utils::copy_dir(&data_dir.join("usr/"), &app_dir_usr)?; // Using create_dir_all for a single dir so we don't get errors if the path already exists fs::create_dir_all(&app_dir_usr_bin)?; fs::create_dir_all(app_dir_usr_lib)?; let search_dirs = [ match settings.binary_arch() { Arch::X86_64 => "/usr/lib/x86_64-linux-gnu/", Arch::X86 => "/usr/lib/i386-linux-gnu/", Arch::AArch64 => "/usr/lib/aarch64-linux-gnu/", Arch::Armhf => "/usr/lib/arm-linux-gnueabihf/", _ => unreachable!(), }, "/usr/lib64", "/usr/lib", "/usr/libexec", ]; for file in [ "WebKitNetworkProcess", "WebKitWebProcess", "injected-bundle/libwebkit2gtkinjectedbundle.so", ] { for source in search_dirs.map(PathBuf::from) { // TODO: Check if it's the same dir name on all systems let source = source.join("webkit2gtk-4.1").join(file); if source.exists() { fs_utils::copy_file( &source, &app_dir_path.join(source.strip_prefix("/").unwrap()), )?; } } } fs::copy( tools_path.join(format!("AppRun-{tools_arch}")), app_dir_path.join("AppRun"), )?; fs::copy( app_dir_path.join(larger_icon_path), app_dir_path.join(format!("{product_name}.png")), )?; std::os::unix::fs::symlink(format!("{product_name}.png"), app_dir_path.join(".DirIcon"))?; std::os::unix::fs::symlink( format!("usr/share/applications/{product_name}.desktop"), app_dir_path.join(format!("{product_name}.desktop")), )?; let log_level = match settings.log_level() { log::Level::Error => "3", log::Level::Warn => "2", log::Level::Info => "1", _ => "0", }; let mut cmd = Command::new(linuxdeploy_path); cmd.env("OUTPUT", &appimage_path); cmd.env("ARCH", tools_arch); // Looks like the cli arg isn't enough for the updated AppImage output-plugin. cmd.env("APPIMAGE_EXTRACT_AND_RUN", "1"); cmd.args([ "--appimage-extract-and-run", "--verbosity", log_level, "--appdir", &app_dir_path.display().to_string(), "--plugin", "gtk", ]); if settings.appimage().bundle_media_framework { cmd.args(["--plugin", "gstreamer"]); } cmd.args(["--output", "appimage"]); // Linuxdeploy logs everything into stderr so we have to ignore the output ourselves here if settings.log_level() == log::Level::Error { log::debug!(action = "Running"; "Command `linuxdeploy {}`", cmd.get_args().map(|arg| arg.to_string_lossy()).fold(String::new(), |acc, arg| format!("{acc} {arg}"))); if !cmd.output()?.status.success() { return Err(crate::Error::GenericError( "failed to run linuxdeploy".to_string(), )); } } else { cmd.output_ok()?; } fs::remove_dir_all(&package_dir)?; Ok(vec![appimage_path]) } // returns the linuxdeploy path to keep linuxdeploy_arch contained fn prepare_tools(tools_path: &Path, arch: &str, verbose: bool) -> crate::Result<PathBuf> { let apprun = tools_path.join(format!("AppRun-{arch}")); if !apprun.exists() { let data = download(&format!( "https://github.com/tauri-apps/binary-releases/releases/download/apprun-old/AppRun-{arch}" ))?; write_and_make_executable(&apprun, data)?; } let linuxdeploy_arch = if arch == "i686" { "i386" } else { arch }; let linuxdeploy = tools_path.join(format!("linuxdeploy-{linuxdeploy_arch}.AppImage")); if !linuxdeploy.exists() { let data = download(&format!("https://github.com/tauri-apps/binary-releases/releases/download/linuxdeploy/linuxdeploy-{linuxdeploy_arch}.AppImage"))?; write_and_make_executable(&linuxdeploy, data)?; } let gtk = tools_path.join("linuxdeploy-plugin-gtk.sh"); if !gtk.exists() { let data = download("https://raw.githubusercontent.com/tauri-apps/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh")?; write_and_make_executable(>k, data)?; } let gstreamer = tools_path.join("linuxdeploy-plugin-gstreamer.sh"); if !gstreamer.exists() { let data = download("https://raw.githubusercontent.com/tauri-apps/linuxdeploy-plugin-gstreamer/master/linuxdeploy-plugin-gstreamer.sh")?; write_and_make_executable(&gstreamer, data)?; } let appimage = tools_path.join("linuxdeploy-plugin-appimage.AppImage"); if !appimage.exists() { // This is optional, linuxdeploy will fall back to its built-in version if the download failed. let data = download(&format!("https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-{arch}.AppImage")); match data { Ok(data) => write_and_make_executable(&appimage, data)?, Err(err) => { log::error!("Download of AppImage plugin failed. Using older built-in version instead."); if verbose { log::debug!("{err:?}"); } } } } // This should prevent linuxdeploy to be detected by appimage integration tools let _ = Command::new("dd") .args([ "if=/dev/zero", "bs=1", "count=3", "seek=8", "conv=notrunc", &format!("of={}", linuxdeploy.display()), ]) .output(); Ok(linuxdeploy) }