fix(bundler): inline linuxdeploy plugin scripts - #2
Conversation
📝 WalkthroughWalkthroughThe 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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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(>k, 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. |
There was a problem hiding this comment.
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.
| 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.
| 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" |
There was a problem hiding this comment.
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.
| 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(>k, data)?; | ||
| } |
There was a problem hiding this comment.
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(>k, 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.
| 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(>k, 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(>k, 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(>k, 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.
| // 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> { |
There was a problem hiding this comment.
🧩 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 5Repository: 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 errorRepository: 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 -80Repository: 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 3Repository: 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 5Repository: 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.
| 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)?; |
There was a problem hiding this comment.
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.
| 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.
Benchmark PR from agentic-review-benchmarks#2
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.