Skip to content

Commit b22b599

Browse files
Improve MSI install dir, debug info, and Apache config test
Added detailed troubleshooting documentation for MSI installer issues. Enhanced installation path detection and debug output in Rust backend, including config and permission checks. Implemented a new `test_apache_config` command for validating Apache configuration, and exposed it in the DebugPanel UI. Updated WiX installer fragment to enforce installation to C:\dsb\ using early custom actions.
1 parent 0a83e93 commit b22b599

File tree

4 files changed

+224
-15
lines changed

4 files changed

+224
-15
lines changed

MSI_TROUBLESHOOTING.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# MSI Installer Issues - Diagnosis & Fixes
2+
3+
## Issues Identified
4+
5+
### 1. Installation Directory Problem
6+
- **Problem**: MSI installs to `C:\Program Files\DevStackBox\` instead of `C:\dsb\`
7+
- **Cause**: Tauri's default WiX template overrides custom directory settings
8+
- **Fix Applied**: Enhanced WiX fragment with custom actions that run early in installation sequence
9+
10+
### 2. File Display Issue During Installation
11+
- **Problem**: Installer shows "[1] size: [1]" instead of actual filenames
12+
- **Cause**: Likely due to glob patterns in resources causing WiX file enumeration issues
13+
- **Investigation**: Need to check if file count/names are properly enumerated
14+
15+
### 3. Apache Startup Failure in Installed Version
16+
- **Problem**: Apache won't start when installed via MSI
17+
- **Potential Causes**:
18+
- Path detection issues in installed environment
19+
- Permission problems in Program Files
20+
- Missing configuration files
21+
- Incorrect working directory
22+
23+
## Fixes Implemented
24+
25+
### Enhanced Path Detection
26+
```rust
27+
fn get_installation_path() -> PathBuf {
28+
// 1. Check executable location first
29+
// 2. Validate server components exist
30+
// 3. Fallback to common paths
31+
// 4. Better Program Files handling
32+
}
33+
```
34+
35+
### Improved WiX Configuration
36+
```xml
37+
<!-- Custom actions with proper sequence timing -->
38+
<CustomAction Id="OverrideInstallDir" Property="APPLICATIONFOLDER" Value="C:\dsb\" Execute="immediate" />
39+
<InstallExecuteSequence>
40+
<Custom Action="OverrideInstallDir" After="LaunchConditions">NOT Installed</Custom>
41+
</InstallExecuteSequence>
42+
```
43+
44+
### Debug Commands Added
45+
- `debug_installation()`: Shows detailed path detection and component status
46+
- `test_apache_config()`: Tests Apache configuration without starting service
47+
- Enhanced error reporting with full paths and permission checks
48+
49+
### Terminal Flashing Fix
50+
- All commands use `CREATE_NO_WINDOW` flag
51+
- Hidden window creation for service startup
52+
- No more command prompt flashing
53+
54+
## Testing Approach
55+
56+
1. **Install MSI and Check**:
57+
- Installation directory: Should be `C:\dsb\`
58+
- Component files: All server files should be present
59+
- Permissions: Read/execute access to binaries
60+
61+
2. **Debug Commands**:
62+
- Run `debug_installation` to see path detection results
63+
- Run `test_apache_config` to check Apache configuration
64+
- Verify server component existence and accessibility
65+
66+
3. **Service Startup**:
67+
- Check if Apache config test passes
68+
- Verify working directory is correct
69+
- Test manual Apache startup from command line
70+
71+
## Expected Results After Fixes
72+
73+
**MSI Installation**: Should install to `C:\dsb\` instead of Program Files
74+
**File Display**: Should show proper filenames during installation
75+
**Apache Startup**: Should start successfully from installed location
76+
**Debug Info**: Should provide detailed troubleshooting information
77+
**No Terminal Flashing**: Services start silently in background
78+
79+
## If Issues Persist
80+
81+
If MSI still installs to Program Files:
82+
1. Check WiX log files for custom action execution
83+
2. Verify property values during installation
84+
3. Consider using MSI command line: `msiexec /i installer.msi APPLICATIONFOLDER="C:\dsb\"`
85+
86+
If Apache still won't start:
87+
1. Use `debug_installation` to check detected paths
88+
2. Use `test_apache_config` to verify configuration
89+
3. Check file permissions in installation directory
90+
4. Verify config files were created properly

src-tauri/src/lib.rs

Lines changed: 94 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,21 @@ fn get_installation_path() -> PathBuf {
4141
// First, try to get the path from the installed location
4242
if let Ok(exe_path) = env::current_exe() {
4343
if let Some(parent) = exe_path.parent() {
44-
// Check if we're in the installed directory (C:\dsb\)
45-
if parent.to_string_lossy().contains("dsb") || parent.to_string_lossy().contains("DevStackBox") {
44+
// Check if we're in any installation directory
45+
let parent_str = parent.to_string_lossy();
46+
47+
// Check for C:\dsb\ installation
48+
if parent_str.contains("dsb") {
49+
return parent.to_path_buf();
50+
}
51+
52+
// Check for Program Files installation
53+
if parent_str.contains("DevStackBox") {
54+
return parent.to_path_buf();
55+
}
56+
57+
// Check if this directory actually has our server components
58+
if parent.join("apache").join("bin").join("httpd.exe").exists() {
4659
return parent.to_path_buf();
4760
}
4861
}
@@ -63,7 +76,7 @@ fn get_installation_path() -> PathBuf {
6376
}
6477
}
6578

66-
// Final fallback - try common installation paths
79+
// Try common installation paths in order of preference
6780
let possible_paths = [
6881
PathBuf::from("C:\\dsb"),
6982
PathBuf::from("C:\\Program Files\\DevStackBox"),
@@ -171,16 +184,40 @@ async fn debug_installation() -> Result<HashMap<String, String>, String> {
171184
let install_path = get_installation_path();
172185
debug_info.insert("detected_install_path".to_string(), install_path.display().to_string());
173186

174-
// Check if server components exist
175-
let apache_exists = install_path.join("apache").join("bin").join("httpd.exe").exists();
176-
let mysql_exists = install_path.join("mysql").join("bin").join("mysqld.exe").exists();
177-
let php_exists = install_path.join("php").join("8.2").join("php.exe").exists();
178-
let phpmyadmin_exists = install_path.join("phpmyadmin").join("index.php").exists();
187+
// Check if server components exist with detailed paths
188+
let apache_bin = install_path.join("apache").join("bin").join("httpd.exe");
189+
let mysql_bin = install_path.join("mysql").join("bin").join("mysqld.exe");
190+
let php_bin = install_path.join("php").join("8.2").join("php.exe");
191+
let phpmyadmin_index = install_path.join("phpmyadmin").join("index.php");
192+
193+
debug_info.insert("apache_bin_path".to_string(), apache_bin.display().to_string());
194+
debug_info.insert("apache_exists".to_string(), apache_bin.exists().to_string());
195+
196+
debug_info.insert("mysql_bin_path".to_string(), mysql_bin.display().to_string());
197+
debug_info.insert("mysql_exists".to_string(), mysql_bin.exists().to_string());
198+
199+
debug_info.insert("php_bin_path".to_string(), php_bin.display().to_string());
200+
debug_info.insert("php_exists".to_string(), php_bin.exists().to_string());
179201

180-
debug_info.insert("apache_exists".to_string(), apache_exists.to_string());
181-
debug_info.insert("mysql_exists".to_string(), mysql_exists.to_string());
182-
debug_info.insert("php_exists".to_string(), php_exists.to_string());
183-
debug_info.insert("phpmyadmin_exists".to_string(), phpmyadmin_exists.to_string());
202+
debug_info.insert("phpmyadmin_path".to_string(), phpmyadmin_index.display().to_string());
203+
debug_info.insert("phpmyadmin_exists".to_string(), phpmyadmin_index.exists().to_string());
204+
205+
// Check config files
206+
let apache_config = install_path.join("config").join("httpd.conf");
207+
let mysql_config = install_path.join("config").join("my.cnf");
208+
209+
debug_info.insert("apache_config_path".to_string(), apache_config.display().to_string());
210+
debug_info.insert("apache_config_exists".to_string(), apache_config.exists().to_string());
211+
212+
debug_info.insert("mysql_config_path".to_string(), mysql_config.display().to_string());
213+
debug_info.insert("mysql_config_exists".to_string(), mysql_config.exists().to_string());
214+
215+
// Check permissions by trying to access directories
216+
let apache_dir_readable = install_path.join("apache").exists();
217+
let mysql_dir_readable = install_path.join("mysql").exists();
218+
219+
debug_info.insert("apache_dir_readable".to_string(), apache_dir_readable.to_string());
220+
debug_info.insert("mysql_dir_readable".to_string(), mysql_dir_readable.to_string());
184221

185222
// Check common installation paths
186223
let common_paths = [
@@ -194,11 +231,16 @@ async fn debug_installation() -> Result<HashMap<String, String>, String> {
194231
let exists = path_buf.exists();
195232
let apache_in_path = path_buf.join("apache").join("bin").join("httpd.exe").exists();
196233
debug_info.insert(
197-
format!("path_{}_exists", path.replace("\\", "_").replace(":", "")),
198-
format!("dir: {}, apache: {}", exists, apache_in_path)
234+
format!("path_{}_status", path.replace("\\", "_").replace(":", "")),
235+
format!("dir_exists: {}, apache_exists: {}", exists, apache_in_path)
199236
);
200237
}
201238

239+
// Check current working directory
240+
if let Ok(cwd) = env::current_dir() {
241+
debug_info.insert("current_working_dir".to_string(), cwd.display().to_string());
242+
}
243+
202244
Ok(debug_info)
203245
}
204246

@@ -221,6 +263,43 @@ async fn stop_all_services() -> Result<String, String> {
221263
Ok(results.join("; "))
222264
}
223265

266+
#[tauri::command]
267+
async fn test_apache_config() -> Result<String, String> {
268+
let base_path = get_installation_path();
269+
let apache_path = base_path.join("apache").join("bin").join("httpd.exe");
270+
let config_path = base_path.join("config").join("httpd.conf");
271+
272+
if !apache_path.exists() {
273+
return Err(format!("Apache binary not found at: {}", apache_path.display()));
274+
}
275+
276+
if !config_path.exists() {
277+
return Err(format!("Apache config not found at: {}", config_path.display()));
278+
}
279+
280+
// Test Apache configuration
281+
let mut test_cmd = create_hidden_command(&apache_path.to_string_lossy());
282+
test_cmd.arg("-f")
283+
.arg(&config_path)
284+
.arg("-t")
285+
.stdout(std::process::Stdio::piped())
286+
.stderr(std::process::Stdio::piped());
287+
288+
match test_cmd.output() {
289+
Ok(output) => {
290+
let stdout = String::from_utf8_lossy(&output.stdout);
291+
let stderr = String::from_utf8_lossy(&output.stderr);
292+
293+
if output.status.success() {
294+
Ok(format!("Apache config test PASSED\nOutput: {}\nPath used: {}", stdout, apache_path.display()))
295+
} else {
296+
Err(format!("Apache config test FAILED\nError: {}\nOutput: {}\nPath used: {}", stderr, stdout, apache_path.display()))
297+
}
298+
}
299+
Err(e) => Err(format!("Failed to run Apache config test: {}\nPath: {}", e, apache_path.display())),
300+
}
301+
}
302+
224303
#[tauri::command]
225304
async fn get_mysql_status() -> Result<ServiceInfo, String> {
226305
let running = {
@@ -1117,6 +1196,7 @@ pub fn run() {
11171196
debug_paths,
11181197
debug_installation,
11191198
stop_all_services,
1199+
test_apache_config,
11201200
get_mysql_status,
11211201
get_php_status,
11221202
get_apache_status,
Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,30 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
33
<Fragment>
4-
<!-- Set installation directory to C:\dsb -->
4+
<!-- Properties to override installation directory -->
55
<Property Id="APPLICATIONFOLDER" Value="C:\dsb\" />
6+
<Property Id="ARPINSTALLLOCATION" Value="C:\dsb\" />
7+
8+
<!-- Custom action to set the folder before directory resolution -->
9+
<CustomAction Id="OverrideInstallDir"
10+
Property="APPLICATIONFOLDER"
11+
Value="C:\dsb\"
12+
Execute="immediate" />
13+
14+
<CustomAction Id="SetARPLocation"
15+
Property="ARPINSTALLLOCATION"
16+
Value="[APPLICATIONFOLDER]"
17+
Execute="immediate" />
18+
19+
<!-- Execute the custom actions early in the sequence -->
20+
<InstallExecuteSequence>
21+
<Custom Action="OverrideInstallDir" After="LaunchConditions">NOT Installed</Custom>
22+
<Custom Action="SetARPLocation" After="OverrideInstallDir">NOT Installed</Custom>
23+
</InstallExecuteSequence>
24+
25+
<InstallUISequence>
26+
<Custom Action="OverrideInstallDir" After="LaunchConditions">NOT Installed</Custom>
27+
<Custom Action="SetARPLocation" After="OverrideInstallDir">NOT Installed</Custom>
28+
</InstallUISequence>
629
</Fragment>
730
</Wix>

src/components/DebugPanel.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ export function DebugPanel() {
3030
}
3131
};
3232

33+
const testApacheConfig = async () => {
34+
try {
35+
const result = await invoke<string>('test_apache_config');
36+
alert('Apache Config Test Result: ' + result);
37+
} catch (error) {
38+
alert('Apache Config Test Failed: ' + error);
39+
}
40+
};
41+
3342
return (
3443
<div className="p-4 bg-gray-100 rounded-lg">
3544
<h3 className="text-lg font-bold mb-4">Debug Installation</h3>
@@ -49,6 +58,13 @@ export function DebugPanel() {
4958
>
5059
Stop All Services
5160
</button>
61+
62+
<button
63+
onClick={testApacheConfig}
64+
className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600"
65+
>
66+
Test Apache Config
67+
</button>
5268
</div>
5369

5470
{Object.keys(debugInfo).length > 0 && (

0 commit comments

Comments
 (0)