From 4e2eaf9059032a45099c71e88a15dab124c4a864 Mon Sep 17 00:00:00 2001 From: stan44 Date: Sat, 28 Feb 2026 14:46:59 -0600 Subject: [PATCH] maybe fixed running on other OS's --- Journal.App/src-tauri/src/lib.rs | 61 ++++++++++++++--------- Journal.DevTool/Runner/ProcessRunner.cs | 26 ++++++++-- Journal.Sidecar/App.cs | 3 ++ devtool.json | 52 ++++++++++++++++---- scripts/run-webgateway.ps1 | 51 ++++++++++++++------ scripts/sync-output.ps1 | 64 +++++++++++++++++++++++++ 6 files changed, 205 insertions(+), 52 deletions(-) create mode 100644 scripts/sync-output.ps1 diff --git a/Journal.App/src-tauri/src/lib.rs b/Journal.App/src-tauri/src/lib.rs index 49dfa3a..cb96fe6 100644 --- a/Journal.App/src-tauri/src/lib.rs +++ b/Journal.App/src-tauri/src/lib.rs @@ -222,37 +222,47 @@ fn effective_root(root_override: &Option) -> Result { } fn resolve_sidecar_path(root: &Path) -> Result { - let root_exe_path = root.join("Journal.Sidecar.exe"); - if root_exe_path.exists() { - return Ok(root_exe_path); + #[cfg(windows)] + let exe_name = "Journal.Sidecar.exe"; + #[cfg(not(windows))] + let exe_name = "Journal.Sidecar"; + + // 1. If root is explicitly pointing to the executable file itself: + if root.is_file() && root.file_name().and_then(|n| n.to_str()) == Some(exe_name) { + return Ok(root.to_path_buf()); } - let root_publish_exe_path = root.join("publish").join("Journal.Sidecar.exe"); - if root_publish_exe_path.exists() { - return Ok(root_publish_exe_path); + // 2. Direct paths relative to the folder: + let direct_paths = [ + root.join(exe_name), + root.join("output").join(exe_name), + root.join("publish").join(exe_name), + root.join("Journal.Sidecar/bin/Debug/net10.0").join(exe_name), + root.join("Journal.Sidecar/bin/Release/net10.0/win-x64/publish").join(exe_name), + ]; + + for path in direct_paths { + if path.exists() { + return Ok(path); + } } - let debug_path = root.join("Journal.Sidecar/bin/Debug/net10.0/Journal.Sidecar.exe"); - if debug_path.exists() { - return Ok(debug_path); - } - - let release_path = - root.join("Journal.Sidecar/bin/Release/net10.0/win-x64/publish/Journal.Sidecar.exe"); - if release_path.exists() { - return Ok(release_path); - } - - let sidecar_root = root.join("Journal.Sidecar"); - if let Some(path) = find_sidecar_executable(&sidecar_root) { + // 3. Fallback: recursively search the known sidecar folder + let sidecar_src_root = root.join("Journal.Sidecar"); + if let Some(path) = find_sidecar_executable(&sidecar_src_root, exe_name) { return Ok(path); } - Err("Journal.Sidecar.exe not found. Build Journal.Sidecar first.".to_string()) + // 4. Fallback: recursively search the provided root itself + if let Some(path) = find_sidecar_executable(root, exe_name) { + return Ok(path); + } + + Err(format!("{exe_name} not found in {}. Build Journal.Sidecar first.", root.display())) } -fn find_sidecar_executable(search_root: &Path) -> Option { - if !search_root.exists() { +fn find_sidecar_executable(search_root: &Path, exe_name: &str) -> Option { + if !search_root.is_dir() { return None; } @@ -268,6 +278,11 @@ fn find_sidecar_executable(search_root: &Path) -> Option { }; let path = entry.path(); if path.is_dir() { + if let Some(name) = path.file_name().and_then(|n| n.to_str()) { + if name == "node_modules" || name == ".git" || name == ".vs" { + continue; + } + } stack.push(path); continue; } @@ -275,7 +290,7 @@ fn find_sidecar_executable(search_root: &Path) -> Option { let is_sidecar_exe = path .file_name() .and_then(|name| name.to_str()) - .map(|name| name.eq_ignore_ascii_case("Journal.Sidecar.exe")) + .map(|name| name.eq_ignore_ascii_case(exe_name)) .unwrap_or(false); if is_sidecar_exe { return Some(path); diff --git a/Journal.DevTool/Runner/ProcessRunner.cs b/Journal.DevTool/Runner/ProcessRunner.cs index 33516cc..ced1d32 100644 --- a/Journal.DevTool/Runner/ProcessRunner.cs +++ b/Journal.DevTool/Runner/ProcessRunner.cs @@ -36,13 +36,29 @@ public static class ProcessRunner var sw = Stopwatch.StartNew(); using var process = new Process { StartInfo = psi }; - process.Start(); - var stdoutTask = DrainAsync(process.StandardOutput, line => onOutput(line, false), cancellationToken); - var stderrTask = DrainAsync(process.StandardError, line => onOutput(line, true), cancellationToken); + void OnCancel(object? sender, ConsoleCancelEventArgs e) + { + e.Cancel = true; // Prevent SDT from exiting immediately + try { process.Kill(entireProcessTree: true); } catch { } + } - await Task.WhenAll(stdoutTask, stderrTask).ConfigureAwait(false); - await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false); + Console.CancelKeyPress += OnCancel; + + try + { + process.Start(); + + var stdoutTask = DrainAsync(process.StandardOutput, line => onOutput(line, false), cancellationToken); + var stderrTask = DrainAsync(process.StandardError, line => onOutput(line, true), cancellationToken); + + await Task.WhenAll(stdoutTask, stderrTask).ConfigureAwait(false); + await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false); + } + finally + { + Console.CancelKeyPress -= OnCancel; + } sw.Stop(); return new RunResult(process.ExitCode, sw.Elapsed); diff --git a/Journal.Sidecar/App.cs b/Journal.Sidecar/App.cs index e3246b5..311abc4 100644 --- a/Journal.Sidecar/App.cs +++ b/Journal.Sidecar/App.cs @@ -2,6 +2,9 @@ using Microsoft.Extensions.DependencyInjection; using Journal.Core; using Journal.Core.Services.Sidecar; +Console.OutputEncoding = System.Text.Encoding.UTF8; +Console.InputEncoding = System.Text.Encoding.UTF8; + var services = new ServiceCollection(); services.AddFragmentServices(); services.AddSingleton(); diff --git a/devtool.json b/devtool.json index ff9e98b..57504e0 100644 --- a/devtool.json +++ b/devtool.json @@ -74,6 +74,22 @@ "workingDir": ".", "dependsOn": [] }, + { + "id": "sync-output", + "label": "Sync Build Assets to Output", + "description": "Sweep repo for newest builds (Web/Sidecar/Gateway/Tauri) and copy them to the output dir", + "group": "Build", + "command": "pwsh", + "args": [ + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "scripts/sync-output.ps1" + ], + "workingDir": ".", + "dependsOn": [] + }, { "id": "webgateway", "label": "Publish WebGateway", @@ -168,9 +184,9 @@ ] }, { - "id": "run-gateway", - "label": "Run WebGateway", - "description": "Start HTTP gateway dev server at http://localhost:5180", + "id": "run-gateway-dev", + "label": "Run WebGateway Server (Dev)", + "description": "Start HTTP gateway via 'dotnet run' at http://localhost:5180", "group": "Dev", "command": "pwsh", "args": [ @@ -178,7 +194,27 @@ "-ExecutionPolicy", "Bypass", "-File", - "scripts/run-webgateway.ps1" + "scripts/run-webgateway.ps1", + "-Mode", + "Dev" + ], + "workingDir": ".", + "dependsOn": [] + }, + { + "id": "run-gateway-prod", + "label": "Run WebGateway Server (Output)", + "description": "Start compiled gateway from output/webgateway at http://localhost:5180", + "group": "Dev", + "command": "pwsh", + "args": [ + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "scripts/run-webgateway.ps1", + "-Mode", + "Output" ], "workingDir": ".", "dependsOn": [] @@ -244,8 +280,7 @@ ], "workingDir": ".", "dependsOn": [] - } - , + }, { "id": "npm-clean", "label": "Clean Node Modules", @@ -261,8 +296,7 @@ ], "workingDir": ".", "dependsOn": [] - } - , + }, { "id": "stage-output", "label": "Stage Output Bundle", @@ -332,4 +366,4 @@ "options": [] } ] -} +} \ No newline at end of file diff --git a/scripts/run-webgateway.ps1 b/scripts/run-webgateway.ps1 index eb2c6d6..c76b3a7 100644 --- a/scripts/run-webgateway.ps1 +++ b/scripts/run-webgateway.ps1 @@ -2,7 +2,9 @@ param( [ValidateSet("Release", "Debug")] [string]$Configuration = "Release", [string]$Urls = "http://0.0.0.0:5180", - [string]$ProjectRoot + [string]$ProjectRoot, + [ValidateSet("Dev", "Output")] + [string]$Mode = "Dev" ) $commonScript = Join-Path $PSScriptRoot "script-common.ps1" @@ -29,20 +31,39 @@ Clear-JournalProxyEnv Initialize-JournalDotnetEnv -RepoRoot $repoRoot $env:JOURNAL_PROJECT_ROOT = $effectiveProjectRoot -Write-Host "Running Journal.WebGateway ($Configuration)..." -ForegroundColor Cyan -Write-Host "Project: $gatewayProject" -ForegroundColor DarkGray -Write-Host "URLs: $Urls" -ForegroundColor DarkGray -Write-Host "JOURNAL_PROJECT_ROOT: $effectiveProjectRoot" -ForegroundColor DarkGray +if ($Mode -eq "Output") { + $exeName = if ([System.Environment]::OSVersion.Platform -eq "Win32NT") { "Journal.WebGateway.exe" } else { "Journal.WebGateway" } + $exePath = Join-Path $repoRoot "output\webgateway\$exeName" + + if (-not (Test-Path $exePath)) { + Write-Host "Output executable not found at $exePath" -ForegroundColor Red + Write-Host "Please build WebGateway first (e.g. scripts\publish-webgateway.ps1)" -ForegroundColor Yellow + exit 1 + } -$runArgs = @( - "run", - "--project", $gatewayProject, - "-c", $Configuration, - "--no-launch-profile", - "--urls", $Urls, - "-p:RestoreIgnoreFailedSources=true", - "-p:NuGetAudit=false" -) + Write-Host "Running Journal.WebGateway (Published Output)..." -ForegroundColor Cyan + Write-Host "Executable: $exePath" -ForegroundColor DarkGray + Write-Host "URLs: $Urls" -ForegroundColor DarkGray + Write-Host "JOURNAL_PROJECT_ROOT: $effectiveProjectRoot" -ForegroundColor DarkGray -& dotnet @runArgs + & $exePath --urls $Urls +} +else { + Write-Host "Running Journal.WebGateway ($Configuration Dev Server)..." -ForegroundColor Cyan + Write-Host "Project: $gatewayProject" -ForegroundColor DarkGray + Write-Host "URLs: $Urls" -ForegroundColor DarkGray + Write-Host "JOURNAL_PROJECT_ROOT: $effectiveProjectRoot" -ForegroundColor DarkGray + + $runArgs = @( + "run", + "--project", $gatewayProject, + "-c", $Configuration, + "--no-launch-profile", + "--urls", $Urls, + "-p:RestoreIgnoreFailedSources=true", + "-p:NuGetAudit=false" + ) + + & dotnet @runArgs +} exit $LASTEXITCODE diff --git a/scripts/sync-output.ps1 b/scripts/sync-output.ps1 new file mode 100644 index 0000000..bb00429 --- /dev/null +++ b/scripts/sync-output.ps1 @@ -0,0 +1,64 @@ +param() + +$commonScript = Join-Path $PSScriptRoot "script-common.ps1" +if (-not (Test-Path $commonScript)) { + throw "Missing helper script: $commonScript" +} +. $commonScript + +$repoRoot = Resolve-JournalRepoRoot -StartPath $PSScriptRoot +$outputDir = Join-Path $repoRoot "output" + +# Ensure output exists +New-Item -ItemType Directory -Force -Path $outputDir | Out-Null + +Write-Host "Syncing all recent built assets to output directory..." -ForegroundColor Cyan + +# Helper to find the newest compiled binary +function Find-NewestBin([string]$SearchPath, [string]$Pattern) { + if (-not (Test-Path $SearchPath)) { return $null } + $files = Get-ChildItem -Path $SearchPath -Filter $Pattern -Recurse -File -ErrorAction SilentlyContinue | + Where-Object { $_.FullName -notmatch '\\obj\\' } | + Sort-Object LastWriteTime -Descending + if ($files) { return $files[0] } + return $null +} + +# 1. Front-end Web Assets +$webBuildDir = Join-Path $repoRoot "Journal.App\build" +if (Test-Path $webBuildDir) { + $webOutputDir = Join-Path $outputDir "webgateway\wwwroot" + New-Item -ItemType Directory -Force -Path $webOutputDir | Out-Null + Copy-Item -Path (Join-Path $webBuildDir "*") -Destination $webOutputDir -Recurse -Force + Write-Host "Synced web assets -> $webOutputDir" -ForegroundColor Green +} + +# 2. Sidecar +$sidecarExeName = if ([System.Environment]::OSVersion.Platform -eq "Win32NT") { "Journal.Sidecar.exe" } else { "Journal.Sidecar" } +$sidecarExe = Find-NewestBin -SearchPath (Join-Path $repoRoot "Journal.Sidecar\bin") -Pattern $sidecarExeName +if ($sidecarExe) { + Copy-Item -Path (Join-Path $sidecarExe.DirectoryName "*") -Destination $outputDir -Recurse -Force + Write-Host "Synced Journal.Sidecar -> $outputDir" -ForegroundColor Green +} + +# 3. WebGateway +$gwExeName = if ([System.Environment]::OSVersion.Platform -eq "Win32NT") { "Journal.WebGateway.exe" } else { "Journal.WebGateway" } +$gwExe = Find-NewestBin -SearchPath (Join-Path $repoRoot "Journal.WebGateway\bin") -Pattern $gwExeName +if ($gwExe) { + $gwOutputDir = Join-Path $outputDir "webgateway" + New-Item -ItemType Directory -Force -Path $gwOutputDir | Out-Null + Copy-Item -Path (Join-Path $gwExe.DirectoryName "*") -Destination $gwOutputDir -Recurse -Force + Write-Host "Synced Journal.WebGateway -> $gwOutputDir" -ForegroundColor Green +} + +# 4. Tauri Desktop App +$tauriExe = Find-NewestBin -SearchPath (Join-Path $repoRoot "Journal.App\src-tauri\target") -Pattern "*.exe" +if ($tauriExe) { + # Don't try to copy sidecar.exe again if it ended up in tauri target dir + if ($tauriExe.Name -ne "Journal.Sidecar.exe") { + Copy-Item -Path $tauriExe.FullName -Destination $outputDir -Force + Write-Host "Synced Tauri App ($($tauriExe.Name)) -> $outputDir" -ForegroundColor Green + } +} + +Write-Host "Sync complete!" -ForegroundColor Cyan