Skip to content

fix(bundler): inline linuxdeploy plugin scripts - #2

Open
tomerqodo wants to merge 2 commits into
coderabbit_full_base_fixbundler_inline_linuxdeploy_plugin_scripts_pr2from
coderabbit_full_head_fixbundler_inline_linuxdeploy_plugin_scripts_pr2
Open

fix(bundler): inline linuxdeploy plugin scripts#2
tomerqodo wants to merge 2 commits into
coderabbit_full_base_fixbundler_inline_linuxdeploy_plugin_scripts_pr2from
coderabbit_full_head_fixbundler_inline_linuxdeploy_plugin_scripts_pr2

Conversation

@tomerqodo

@tomerqodo tomerqodo commented Jan 30, 2026

Copy link
Copy Markdown

Benchmark PR from agentic-review-benchmarks#2

Summary by CodeRabbit

  • Bug Fixes
    • Fixed intermittent failures when creating Linux AppImage bundles by inlining GStreamer and GTK linuxdeploy plugins instead of downloading them at runtime.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 30, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The pull request embeds linuxdeploy plugin scripts (GTK and GStreamer) directly into the tauri-bundler source code instead of downloading them at runtime from remote URLs. This change resolves 429 rate-limit errors previously encountered when fetching from GitHub raw content endpoints. The bundler module is updated to include these scripts and adjust related file-writing logic.

Changes

Cohort / File(s) Summary
Changelog & Plugin Scripts
.changes/bundler-inline-linuxdeploy-plugins.md, crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy-plugin-gstreamer.sh, crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy-plugin-gtk.sh
Adds changelog entry and two new Bash plugin scripts for bundling GStreamer and GTK libraries into AppImages. Scripts include dependency validation, plugin discovery, AppRun hook generation, and library patching logic.
Module Implementation
crates/tauri-bundler/src/bundle/linux/appimage/mod.rs
Refactors file-writing logic to embed plugin scripts via include_bytes! instead of downloading at runtime. Updates write_and_make_executable signature to accept &[u8] instead of Vec<u8> and returns new FileWriteError type. Adjusts AppImage/LinuxDeploy architecture handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 No more waiting for downloads from on high,
Our plugins bundled in code—now passing by!
GStreamer and GTK no longer astray,
Rate limits defeated, hooray, hooray! 🚀✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: inlining linuxdeploy plugin scripts into the bundler code instead of downloading them at runtime.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch coderabbit_full_head_fixbundler_inline_linuxdeploy_plugin_scripts_pr2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In @.changes/bundler-inline-linuxdeploy-plugins.md:
- Line 5: The sentence in the changelog entry duplicates "which" ("Inline
linuxdeploy plugins which were previously downloaded from
`https://raw.githubusercontent.com` which lately blocks many users with a 429
error."); edit the line to remove the redundant "which" and tighten the
wording—for example, rephrase to "Inline linuxdeploy plugins previously
downloaded from `https://raw.githubusercontent.com`, which recently blocked many
users with 429 errors" or a similar concise variant; update the single line in
.changes/bundler-inline-linuxdeploy-plugins.md accordingly.

In
`@crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy-plugin-gstreamer.sh`:
- Around line 141-160: The 0.10 branch incorrectly exports 1.0 paths; update the
environment exports in the GSTREAMER_VERSION == "0.10" block so
GST_PLUGIN_SYSTEM_PATH_0_10, GST_PLUGIN_SCANNER_0_10 and GST_PTP_HELPER_0_10
point to the GStreamer 0.10 install locations (e.g. use
${APPDIR}/usr/lib/gstreamer-0.10 for GST_PLUGIN_SYSTEM_PATH_0_10 and the
corresponding 0.10 scanner/helper binary paths for GST_PLUGIN_SCANNER_0_10 and
GST_PTP_HELPER_0_10) instead of the current gstreamer-1.0 paths.

In `@crates/tauri-bundler/src/bundle/linux/appimage/mod.rs`:
- Around line 309-313: The function write_and_make_executable currently calls
fs::set_permissions before writing, which fails if the file doesn't exist;
modify write_and_make_executable to first write the data to the given path
(using fs::write and mapping errors to FileWriteError::Write) and only after a
successful write call fs::set_permissions (mapping errors to
FileWriteError::Permissions) so permissions are applied to an existing file;
keep the same signature and error mappings and reference the
write_and_make_executable function to locate where to change the call order.
- Around line 242-246: The GTK plugin is only written when the target file
already exists, which prevents fresh caches from receiving it; change the guard
around the gtk write so it writes the embedded bytes when the file is missing
(mirror the gstreamer behavior) by updating the condition around the gtk
variable so the include_bytes!("./linuxdeploy-plugin-gtk.sh") and
write_and_make_executable(&gtk, data)?; call run when gtk does not exist (or
remove the existence check entirely), referencing the gtk variable,
include_bytes!, and write_and_make_executable to locate the code to modify.
- Around line 284-309: The code uses the `?` operator in
`write_and_make_executable` which returns `FileWriteError`, but there is no
`From<FileWriteError> for crate::Error`, causing a compilation failure; fix by
either adding `impl From<FileWriteError> for Error` in your error enum (in
`error.rs`) mapping the `Write` and `Permissions` cases to appropriate `Error`
variants, or replace each `?` at the call sites with explicit `.map_err(|e| /*
convert e to crate::Error */)` calls so `FileWriteError` is converted to
`crate::Error` explicitly; reference `FileWriteError`,
`write_and_make_executable`, and `Error` when making the change.

tauri-bundler: "patch:enhance"
---

Inline linuxdeploy plugins which were previously downloaded from `https://raw.githubusercontent.com` which lately blocks many users with a 429 error.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Tighten wording to avoid the duplicated “which”.

Minor clarity/grammar cleanup in the changelog entry.

✏️ Suggested wording
-Inline linuxdeploy plugins which were previously downloaded from `https://raw.githubusercontent.com` which lately blocks many users with a 429 error.
+Inline linuxdeploy plugins previously downloaded from `https://raw.githubusercontent.com`, which has recently blocked many users with 429 errors.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Inline linuxdeploy plugins which were previously downloaded from `https://raw.githubusercontent.com` which lately blocks many users with a 429 error.
Inline linuxdeploy plugins previously downloaded from `https://raw.githubusercontent.com`, which has recently blocked many users with 429 errors.
🤖 Prompt for AI Agents
In @.changes/bundler-inline-linuxdeploy-plugins.md at line 5, The sentence in
the changelog entry duplicates "which" ("Inline linuxdeploy plugins which were
previously downloaded from `https://raw.githubusercontent.com` which lately
blocks many users with a 429 error."); edit the line to remove the redundant
"which" and tighten the wording—for example, rephrase to "Inline linuxdeploy
plugins previously downloaded from `https://raw.githubusercontent.com`, which
recently blocked many users with 429 errors" or a similar concise variant;
update the single line in .changes/bundler-inline-linuxdeploy-plugins.md
accordingly.

Comment on lines +141 to +160
if [ "$GSTREAMER_VERSION" == "1.0" ]; then
cat > "$APPDIR"/apprun-hooks/linuxdeploy-plugin-gstreamer.sh <<\EOF
#! /bin/bash

export GST_REGISTRY_REUSE_PLUGIN_SCANNER="no"
export GST_PLUGIN_SYSTEM_PATH_1_0="${APPDIR}/usr/lib/gstreamer-1.0"
export GST_PLUGIN_PATH_1_0="${APPDIR}/usr/lib/gstreamer-1.0"

export GST_PLUGIN_SCANNER_1_0="${APPDIR}/usr/lib/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner"
export GST_PTP_HELPER_1_0="${APPDIR}/usr/lib/gstreamer1.0/gstreamer-1.0/gst-ptp-helper"
EOF
elif [ "$GSTREAMER_VERSION" == "0.10" ]; then
cat > "$APPDIR"/apprun-hooks/linuxdeploy-plugin-gstreamer.sh <<\EOF
#! /bin/bash

export GST_REGISTRY_REUSE_PLUGIN_SCANNER="no"
export GST_PLUGIN_SYSTEM_PATH_0_10="${APPDIR}/usr/lib/gstreamer-1.0"

export GST_PLUGIN_SCANNER_0_10="${APPDIR}/usr/lib/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner"
export GST_PTP_HELPER_0_10="${APPDIR}/usr/lib/gstreamer1.0/gstreamer-1.0/gst-ptp-helper"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

GStreamer 0.10 hook paths still reference 1.0 directories.

The 0.10 branch exports 1.0 paths, which won’t match the helpers/plugins copied for 0.10.

🐛 Suggested fix
-export GST_PLUGIN_SYSTEM_PATH_0_10="${APPDIR}/usr/lib/gstreamer-1.0"
+export GST_PLUGIN_SYSTEM_PATH_0_10="${APPDIR}/usr/lib/gstreamer-0.10"

-export GST_PLUGIN_SCANNER_0_10="${APPDIR}/usr/lib/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner"
-export GST_PTP_HELPER_0_10="${APPDIR}/usr/lib/gstreamer1.0/gstreamer-1.0/gst-ptp-helper"
+export GST_PLUGIN_SCANNER_0_10="${APPDIR}/usr/lib/gstreamer0.10/gstreamer-0.10/gst-plugin-scanner"
+export GST_PTP_HELPER_0_10="${APPDIR}/usr/lib/gstreamer0.10/gstreamer-0.10/gst-ptp-helper"
🤖 Prompt for AI Agents
In
`@crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy-plugin-gstreamer.sh`
around lines 141 - 160, The 0.10 branch incorrectly exports 1.0 paths; update
the environment exports in the GSTREAMER_VERSION == "0.10" block so
GST_PLUGIN_SYSTEM_PATH_0_10, GST_PLUGIN_SCANNER_0_10 and GST_PTP_HELPER_0_10
point to the GStreamer 0.10 install locations (e.g. use
${APPDIR}/usr/lib/gstreamer-0.10 for GST_PLUGIN_SYSTEM_PATH_0_10 and the
corresponding 0.10 scanner/helper binary paths for GST_PLUGIN_SCANNER_0_10 and
GST_PTP_HELPER_0_10) instead of the current gstreamer-1.0 paths.

Comment on lines 242 to 246
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")?;
if gtk.exists() {
let data = include_bytes!("./linuxdeploy-plugin-gtk.sh");
write_and_make_executable(&gtk, data)?;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix GTK plugin write guard (currently skips creation on fresh runs).

The file is only written when it already exists, so new caches won’t get the plugin. This should mirror the gstreamer branch.

🐛 Suggested fix
-  if gtk.exists() {
+  if !gtk.exists() {
     let data = include_bytes!("./linuxdeploy-plugin-gtk.sh");
     write_and_make_executable(&gtk, data)?;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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")?;
if gtk.exists() {
let data = include_bytes!("./linuxdeploy-plugin-gtk.sh");
write_and_make_executable(&gtk, data)?;
}
let gtk = tools_path.join("linuxdeploy-plugin-gtk.sh");
if !gtk.exists() {
let data = include_bytes!("./linuxdeploy-plugin-gtk.sh");
write_and_make_executable(&gtk, data)?;
}
🤖 Prompt for AI Agents
In `@crates/tauri-bundler/src/bundle/linux/appimage/mod.rs` around lines 242 -
246, The GTK plugin is only written when the target file already exists, which
prevents fresh caches from receiving it; change the guard around the gtk write
so it writes the embedded bytes when the file is missing (mirror the gstreamer
behavior) by updating the condition around the gtk variable so the
include_bytes!("./linuxdeploy-plugin-gtk.sh") and
write_and_make_executable(&gtk, data)?; call run when gtk does not exist (or
remove the existence check entirely), referencing the gtk variable,
include_bytes!, and write_and_make_executable to locate the code to modify.

Comment on lines +284 to +309
// Custom error type for file operations
#[derive(Debug)]
enum FileWriteError {
Write(std::io::Error),
Permissions(std::io::Error),
}

impl std::fmt::Display for FileWriteError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
FileWriteError::Write(e) => write!(f, "Failed to write file: {}", e),
FileWriteError::Permissions(e) => write!(f, "Failed to set permissions: {}", e),
}
}
}

impl std::error::Error for FileWriteError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
FileWriteError::Write(e) => Some(e),
FileWriteError::Permissions(e) => Some(e),
}
}
}

fn write_and_make_executable(path: &Path, data: &[u8]) -> Result<(), FileWriteError> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify FileWriteError conversion or mapping.
cd crates/tauri-bundler/src/bundle/linux/appimage && \
rg -n "FileWriteError" -C 3 && \
echo "---" && \
rg -n "impl From.*FileWriteError" && \
echo "---" && \
rg -n "write_and_make_executable" -C 5

Repository: agentic-review-benchmarks/tauri-combined-coderabbit

Length of output: 1453


🏁 Script executed:

#!/bin/bash
# Find all calls to write_and_make_executable and check prepare_tools
cd crates/tauri-bundler/src/bundle/linux/appimage && \
rg -n "write_and_make_executable" && \
echo "---" && \
rg -n "fn prepare_tools" -A 30 && \
echo "---" && \
rg -n "impl From" | grep -i error

Repository: agentic-review-benchmarks/tauri-combined-coderabbit

Length of output: 2218


🏁 Script executed:

#!/bin/bash
# Check for From implementations more broadly and crate::Error definition
cd crates/tauri-bundler/src && \
rg -n "impl From.*FileWriteError" -C 2 && \
echo "---" && \
rg -n "type Result" && \
echo "---" && \
rg -n "pub enum Error" -A 20 | head -50 && \
echo "---" && \
# Check if there's a From impl for generic errors
rg -n "impl.*From.*dyn.*Error" && \
echo "---" && \
# Check the full structure around prepare_tools
rg -n "fn prepare_tools" -A 50 | head -80

Repository: agentic-review-benchmarks/tauri-combined-coderabbit

Length of output: 77


🏁 Script executed:

#!/bin/bash
cd crates/tauri-bundler/src && \
# Find lib.rs and check for Result/Error definitions
cat lib.rs | grep -n "type Result\|pub enum Error\|pub struct Error" && \
echo "---" && \
# Check if there's an error module
ls -la | grep -i error && \
echo "---" && \
# Find error module
fd -t f "error" . --max-depth 2 && \
echo "---" && \
# Check for generic From impl
rg "impl From" lib.rs -A 3

Repository: agentic-review-benchmarks/tauri-combined-coderabbit

Length of output: 77


🏁 Script executed:

#!/bin/bash
cd crates/tauri-bundler/src && \
echo "=== Files in src ===" && \
ls -la && \
echo "=== Checking lib.rs exists ===" && \
wc -l lib.rs && \
echo "=== Search for Error and Result ===" && \
head -100 lib.rs | grep -n "Result\|Error" && \
echo "=== Search in entire crate ===" && \
rg "type Result" . --max-count 5

Repository: agentic-review-benchmarks/tauri-combined-coderabbit

Length of output: 724


🏁 Script executed:

#!/bin/bash
cd crates/tauri-bundler/src && \
echo "=== error.rs ===" && \
cat -n error.rs && \
echo "=== Check for FileWriteError From impl ===" && \
rg "FileWriteError" .

Repository: agentic-review-benchmarks/tauri-combined-coderabbit

Length of output: 11644


Add From<FileWriteError> implementation or use explicit error mapping.

The ? operator on write_and_make_executable (lines 232, 239, 245, 251, 259) requires a From<FileWriteError> implementation to convert into crate::Error. Since no such impl exists in the Error enum, the code will fail to compile. Either add a From<FileWriteError> for Error variant to the Error enum in error.rs, or replace all ? usages with explicit .map_err() calls.

🤖 Prompt for AI Agents
In `@crates/tauri-bundler/src/bundle/linux/appimage/mod.rs` around lines 284 -
309, The code uses the `?` operator in `write_and_make_executable` which returns
`FileWriteError`, but there is no `From<FileWriteError> for crate::Error`,
causing a compilation failure; fix by either adding `impl From<FileWriteError>
for Error` in your error enum (in `error.rs`) mapping the `Write` and
`Permissions` cases to appropriate `Error` variants, or replace each `?` at the
call sites with explicit `.map_err(|e| /* convert e to crate::Error */)` calls
so `FileWriteError` is converted to `crate::Error` explicitly; reference
`FileWriteError`, `write_and_make_executable`, and `Error` when making the
change.

Comment on lines +309 to +313
fn write_and_make_executable(path: &Path, data: &[u8]) -> Result<(), FileWriteError> {
use std::os::unix::fs::PermissionsExt;

fs::write(path, data)?;
fs::set_permissions(path, fs::Permissions::from_mode(0o770))?;
fs::set_permissions(path, fs::Permissions::from_mode(0o770)).map_err(FileWriteError::Permissions)?;
fs::write(path, data).map_err(FileWriteError::Write)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Write the file before setting permissions to avoid first-run failures.

set_permissions on a non-existent path fails, and this function is called when files don’t exist yet.

🐛 Suggested fix
-  fs::set_permissions(path, fs::Permissions::from_mode(0o770)).map_err(FileWriteError::Permissions)?;
-  fs::write(path, data).map_err(FileWriteError::Write)?;
+  fs::write(path, data).map_err(FileWriteError::Write)?;
+  fs::set_permissions(path, fs::Permissions::from_mode(0o770)).map_err(FileWriteError::Permissions)?;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn write_and_make_executable(path: &Path, data: &[u8]) -> Result<(), FileWriteError> {
use std::os::unix::fs::PermissionsExt;
fs::write(path, data)?;
fs::set_permissions(path, fs::Permissions::from_mode(0o770))?;
fs::set_permissions(path, fs::Permissions::from_mode(0o770)).map_err(FileWriteError::Permissions)?;
fs::write(path, data).map_err(FileWriteError::Write)?;
fn write_and_make_executable(path: &Path, data: &[u8]) -> Result<(), FileWriteError> {
use std::os::unix::fs::PermissionsExt;
fs::write(path, data).map_err(FileWriteError::Write)?;
fs::set_permissions(path, fs::Permissions::from_mode(0o770)).map_err(FileWriteError::Permissions)?;
🤖 Prompt for AI Agents
In `@crates/tauri-bundler/src/bundle/linux/appimage/mod.rs` around lines 309 -
313, The function write_and_make_executable currently calls fs::set_permissions
before writing, which fails if the file doesn't exist; modify
write_and_make_executable to first write the data to the given path (using
fs::write and mapping errors to FileWriteError::Write) and only after a
successful write call fs::set_permissions (mapping errors to
FileWriteError::Permissions) so permissions are applied to an existing file;
keep the same signature and error mappings and reference the
write_and_make_executable function to locate where to change the call order.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants