Skip to content

Commit 644fe7c

Browse files
committed
Enhance backend executable handling in build process
- Added logic to copy the backend executable to the Tauri resources directory and ensure it has execute permissions. - Improved the resolution of backend executable paths in the Rust code to prioritize platform-specific executables and filter out placeholders. - Enhanced logging for backend executable resolution to provide better visibility during application startup. These changes improve the reliability of the backend executable handling in both development and production environments.
1 parent d81a383 commit 644fe7c

File tree

3 files changed

+223
-30
lines changed

3 files changed

+223
-30
lines changed

build.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,16 @@ if [ "$BUILD_BACKEND" = true ]; then
215215
print_warning "Dist directory does not exist"
216216
fi
217217
fi
218+
219+
# Copy backend executable to Tauri resources directory and ensure it's executable
220+
if [ -f "$EXE_PATH" ]; then
221+
RESOURCES_DIR="$FRONTEND_DIR/src-tauri/resources"
222+
mkdir -p "$RESOURCES_DIR"
223+
print_info "Copying backend executable to Tauri resources..."
224+
cp "$EXE_PATH" "$RESOURCES_DIR/"
225+
chmod +x "$RESOURCES_DIR/$(basename "$EXE_PATH")"
226+
print_success "Backend executable copied to resources with execute permissions"
227+
fi
218228
else
219229
print_error "PyInstaller build failed. The app will fall back to using Python if available"
220230
print_info "Check the output above for error details"

frontend/src-tauri/resources/backend-server

100644100755
70.6 MB
Binary file not shown.

frontend/src-tauri/src/lib.rs

Lines changed: 213 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -423,35 +423,118 @@ fn start_backend_server(
423423
let exe_path = std::env::current_exe().ok();
424424
let exe_dir = exe_path.as_ref().and_then(|p| p.parent());
425425

426-
let mut possible_exe_paths: Vec<PathBuf> = vec![
427-
backend_path.join("dist").join("backend-server.exe"),
428-
backend_path.join("dist").join("backend-server"),
429-
];
426+
// Build list of possible executable paths, prioritizing platform-specific executables
427+
let mut possible_exe_paths: Vec<PathBuf> = vec![];
428+
429+
// Platform-specific executable names (check platform-specific first)
430+
#[cfg(windows)]
431+
{
432+
possible_exe_paths.push(backend_path.join("dist").join("backend-server.exe"));
433+
possible_exe_paths.push(backend_path.join("dist").join("backend-server"));
434+
}
435+
436+
#[cfg(not(windows))]
437+
{
438+
possible_exe_paths.push(backend_path.join("dist").join("backend-server"));
439+
possible_exe_paths.push(backend_path.join("dist").join("backend-server.exe"));
440+
}
430441

431442
// Try Tauri resource resolution (for bundled resources)
432443
if let Ok(resource_dir) = app.path().resource_dir() {
433-
possible_exe_paths.push(resource_dir.join("backend-server.exe"));
434-
possible_exe_paths.push(resource_dir.join("backend-server"));
444+
#[cfg(windows)]
445+
{
446+
possible_exe_paths.push(resource_dir.join("backend-server.exe"));
447+
possible_exe_paths.push(resource_dir.join("backend-server"));
448+
}
449+
#[cfg(not(windows))]
450+
{
451+
possible_exe_paths.push(resource_dir.join("backend-server"));
452+
possible_exe_paths.push(resource_dir.join("backend-server.exe"));
453+
}
435454
}
436455

437456
// Add paths relative to executable (fallback)
438457
if let Some(exe_dir) = exe_dir {
439-
possible_exe_paths.push(exe_dir.join("backend-server.exe"));
440-
possible_exe_paths.push(exe_dir.join("backend-server"));
441-
possible_exe_paths.push(exe_dir.join("resources").join("backend-server.exe"));
442-
possible_exe_paths.push(exe_dir.join("resources").join("backend-server"));
458+
#[cfg(windows)]
459+
{
460+
possible_exe_paths.push(exe_dir.join("backend-server.exe"));
461+
possible_exe_paths.push(exe_dir.join("backend-server"));
462+
possible_exe_paths.push(exe_dir.join("resources").join("backend-server.exe"));
463+
possible_exe_paths.push(exe_dir.join("resources").join("backend-server"));
464+
}
465+
#[cfg(not(windows))]
466+
{
467+
possible_exe_paths.push(exe_dir.join("backend-server"));
468+
possible_exe_paths.push(exe_dir.join("backend-server.exe"));
469+
possible_exe_paths.push(exe_dir.join("resources").join("backend-server"));
470+
possible_exe_paths.push(exe_dir.join("resources").join("backend-server.exe"));
471+
}
472+
443473
// Also check parent directories (for nested bundle structures)
444474
if let Some(parent) = exe_dir.parent() {
445-
possible_exe_paths.push(parent.join("backend-server.exe"));
446-
possible_exe_paths.push(parent.join("backend-server"));
475+
#[cfg(windows)]
476+
{
477+
possible_exe_paths.push(parent.join("backend-server.exe"));
478+
possible_exe_paths.push(parent.join("backend-server"));
479+
}
480+
#[cfg(not(windows))]
481+
{
482+
possible_exe_paths.push(parent.join("backend-server"));
483+
possible_exe_paths.push(parent.join("backend-server.exe"));
484+
}
447485
}
448486
}
449487

450-
let backend_exe = possible_exe_paths.iter().find(|p| p.exists()).cloned();
488+
// Find the first existing executable, filtering out placeholders (very small files)
489+
let backend_exe = possible_exe_paths.iter().find(|p| {
490+
if !p.exists() {
491+
return false;
492+
}
493+
494+
// On non-Windows, skip .exe files (they're Windows executables)
495+
#[cfg(not(windows))]
496+
{
497+
if p.file_name().and_then(|n| n.to_str()).map(|s| s.ends_with(".exe")).unwrap_or(false) {
498+
return false;
499+
}
500+
}
501+
502+
// Filter out placeholder files (very small files < 1KB are likely placeholders)
503+
if let Ok(metadata) = std::fs::metadata(p) {
504+
let size = metadata.len();
505+
if size < 1024 {
506+
warn!("Skipping potential placeholder file: {:?} (size: {} bytes)", p, size);
507+
return false;
508+
}
509+
}
510+
511+
true
512+
}).cloned();
451513

452514
if let Some(exe_path) = backend_exe {
453515
info!("Found bundled backend executable: {:?}", exe_path);
454516

517+
// On Unix systems, ensure the executable has execute permissions
518+
#[cfg(not(windows))]
519+
{
520+
use std::os::unix::fs::PermissionsExt;
521+
if let Ok(metadata) = std::fs::metadata(&exe_path) {
522+
let mut perms = metadata.permissions();
523+
let mode = perms.mode();
524+
// Check if execute bit is set for owner, group, or others
525+
if mode & 0o111 == 0 {
526+
warn!("Backend executable does not have execute permissions, attempting to fix...");
527+
perms.set_mode(mode | 0o111); // Add execute permissions for all
528+
if let Err(e) = std::fs::set_permissions(&exe_path, perms) {
529+
error!("Failed to set execute permissions on backend executable: {}", e);
530+
return Err(format!("Backend executable at {:?} does not have execute permissions and could not be fixed: {}", exe_path, e).into());
531+
} else {
532+
info!("Successfully set execute permissions on backend executable");
533+
}
534+
}
535+
}
536+
}
537+
455538
// Run migrations in background
456539
let exe_path_clone = exe_path.clone();
457540
let db_path_clone = db_path.clone();
@@ -848,6 +931,41 @@ pub fn run() {
848931

849932
let mut possible_exe_paths: Vec<PathBuf> = vec![];
850933

934+
// First, check backend/dist directory (development build location)
935+
// Try to find the project root by going up from executable directory
936+
let mut check_backend_dist = |base_dir: &std::path::Path| {
937+
// Try various relative paths to find backend/dist
938+
let candidates = vec![
939+
base_dir.join("backend").join("dist"),
940+
base_dir.join("..").join("backend").join("dist"),
941+
base_dir.join("../..").join("backend").join("dist"),
942+
base_dir.join("../../..").join("backend").join("dist"),
943+
base_dir.join("../../../..").join("backend").join("dist"),
944+
];
945+
946+
for backend_dist in candidates {
947+
let backend_dist = backend_dist.canonicalize().unwrap_or(backend_dist);
948+
#[cfg(windows)]
949+
{
950+
possible_exe_paths.push(backend_dist.join("backend-server.exe"));
951+
possible_exe_paths.push(backend_dist.join("backend-server"));
952+
}
953+
#[cfg(not(windows))]
954+
{
955+
possible_exe_paths.push(backend_dist.join("backend-server"));
956+
possible_exe_paths.push(backend_dist.join("backend-server.exe"));
957+
}
958+
}
959+
};
960+
961+
// Check from executable directory
962+
check_backend_dist(exe_dir);
963+
964+
// Also check from current working directory (for development)
965+
if let Ok(current_dir) = std::env::current_dir() {
966+
check_backend_dist(&current_dir);
967+
}
968+
851969
// Try Tauri resource resolution (for bundled resources)
852970
match app_handle.path().resource_dir() {
853971
Ok(resource_dir) => {
@@ -863,8 +981,17 @@ pub fn run() {
863981
} else {
864982
warn!("Resource directory does not exist: {:?}", resource_dir);
865983
}
866-
possible_exe_paths.push(resource_dir.join("backend-server.exe"));
867-
possible_exe_paths.push(resource_dir.join("backend-server"));
984+
// Prioritize platform-specific executables
985+
#[cfg(windows)]
986+
{
987+
possible_exe_paths.push(resource_dir.join("backend-server.exe"));
988+
possible_exe_paths.push(resource_dir.join("backend-server"));
989+
}
990+
#[cfg(not(windows))]
991+
{
992+
possible_exe_paths.push(resource_dir.join("backend-server"));
993+
possible_exe_paths.push(resource_dir.join("backend-server.exe"));
994+
}
868995
}
869996
Err(e) => {
870997
warn!("Could not resolve resource directory: {}", e);
@@ -874,13 +1001,24 @@ pub fn run() {
8741001
// Also try resolving the resource directly using Tauri's resolve method
8751002
// This might work better in some bundle configurations
8761003
// Note: In Tauri v2, resolve might work differently, so we try both approaches
877-
if let Ok(resource_path) = app_handle.path().resolve("backend-server", tauri::path::BaseDirectory::Resource) {
878-
info!("Resolved resource path (backend-server): {:?}", resource_path);
879-
possible_exe_paths.push(resource_path);
1004+
// Prioritize platform-specific executables
1005+
#[cfg(not(windows))]
1006+
{
1007+
if let Ok(resource_path) = app_handle.path().resolve("backend-server", tauri::path::BaseDirectory::Resource) {
1008+
info!("Resolved resource path (backend-server): {:?}", resource_path);
1009+
possible_exe_paths.push(resource_path);
1010+
}
8801011
}
881-
if let Ok(resource_path) = app_handle.path().resolve("backend-server.exe", tauri::path::BaseDirectory::Resource) {
882-
info!("Resolved resource path (backend-server.exe): {:?}", resource_path);
883-
possible_exe_paths.push(resource_path);
1012+
#[cfg(windows)]
1013+
{
1014+
if let Ok(resource_path) = app_handle.path().resolve("backend-server.exe", tauri::path::BaseDirectory::Resource) {
1015+
info!("Resolved resource path (backend-server.exe): {:?}", resource_path);
1016+
possible_exe_paths.push(resource_path);
1017+
}
1018+
if let Ok(resource_path) = app_handle.path().resolve("backend-server", tauri::path::BaseDirectory::Resource) {
1019+
info!("Resolved resource path (backend-server): {:?}", resource_path);
1020+
possible_exe_paths.push(resource_path);
1021+
}
8841022
}
8851023

8861024
// For Linux AppImages, resources might be in a different location
@@ -911,10 +1049,21 @@ pub fn run() {
9111049

9121050
// Add paths relative to executable (fallback)
9131051
// For standalone binaries, resources might be next to the executable
914-
possible_exe_paths.push(exe_dir.join("backend-server.exe"));
915-
possible_exe_paths.push(exe_dir.join("backend-server"));
916-
possible_exe_paths.push(exe_dir.join("resources").join("backend-server.exe"));
917-
possible_exe_paths.push(exe_dir.join("resources").join("backend-server"));
1052+
// Prioritize platform-specific executables
1053+
#[cfg(windows)]
1054+
{
1055+
possible_exe_paths.push(exe_dir.join("backend-server.exe"));
1056+
possible_exe_paths.push(exe_dir.join("backend-server"));
1057+
possible_exe_paths.push(exe_dir.join("resources").join("backend-server.exe"));
1058+
possible_exe_paths.push(exe_dir.join("resources").join("backend-server"));
1059+
}
1060+
#[cfg(not(windows))]
1061+
{
1062+
possible_exe_paths.push(exe_dir.join("backend-server"));
1063+
possible_exe_paths.push(exe_dir.join("backend-server.exe"));
1064+
possible_exe_paths.push(exe_dir.join("resources").join("backend-server"));
1065+
possible_exe_paths.push(exe_dir.join("resources").join("backend-server.exe"));
1066+
}
9181067

9191068
// For Linux, also check lib and share directories relative to executable
9201069
// This is common for Linux applications and standalone binaries
@@ -928,10 +1077,20 @@ pub fn run() {
9281077

9291078
// Also check parent directories (for nested bundle structures)
9301079
if let Some(parent) = exe_dir.parent() {
931-
possible_exe_paths.push(parent.join("backend-server.exe"));
932-
possible_exe_paths.push(parent.join("backend-server"));
933-
possible_exe_paths.push(parent.join("resources").join("backend-server.exe"));
934-
possible_exe_paths.push(parent.join("resources").join("backend-server"));
1080+
#[cfg(windows)]
1081+
{
1082+
possible_exe_paths.push(parent.join("backend-server.exe"));
1083+
possible_exe_paths.push(parent.join("backend-server"));
1084+
possible_exe_paths.push(parent.join("resources").join("backend-server.exe"));
1085+
possible_exe_paths.push(parent.join("resources").join("backend-server"));
1086+
}
1087+
#[cfg(not(windows))]
1088+
{
1089+
possible_exe_paths.push(parent.join("backend-server"));
1090+
possible_exe_paths.push(parent.join("backend-server.exe"));
1091+
possible_exe_paths.push(parent.join("resources").join("backend-server"));
1092+
possible_exe_paths.push(parent.join("resources").join("backend-server.exe"));
1093+
}
9351094

9361095
#[cfg(target_os = "linux")]
9371096
{
@@ -947,7 +1106,31 @@ pub fn run() {
9471106
info!(" {:?} - {}", path, if exists { "EXISTS" } else { "not found" });
9481107
}
9491108

950-
let bundled_exe = possible_exe_paths.iter().find(|p| p.exists()).cloned();
1109+
// Find the first existing executable, filtering out placeholders and platform-incompatible files
1110+
let bundled_exe = possible_exe_paths.iter().find(|p| {
1111+
if !p.exists() {
1112+
return false;
1113+
}
1114+
1115+
// On non-Windows, skip .exe files (they're Windows executables)
1116+
#[cfg(not(windows))]
1117+
{
1118+
if p.file_name().and_then(|n| n.to_str()).map(|s| s.ends_with(".exe")).unwrap_or(false) {
1119+
return false;
1120+
}
1121+
}
1122+
1123+
// Filter out placeholder files (very small files < 1KB are likely placeholders)
1124+
if let Ok(metadata) = std::fs::metadata(p) {
1125+
let size = metadata.len();
1126+
if size < 1024 {
1127+
warn!("Skipping potential placeholder file: {:?} (size: {} bytes)", p, size);
1128+
return false;
1129+
}
1130+
}
1131+
1132+
true
1133+
}).cloned();
9511134

9521135
// If bundled executable found, use it directly
9531136
if let Some(exe_path) = bundled_exe {

0 commit comments

Comments
 (0)