Skip to content

Commit 0651ef2

Browse files
committed
No more container build
* Remove docker container worktree logic (will use VSCode agent worktrees) * Remove spinup, teardown * Added tracing and logging for debug version of FieldWorks
1 parent aa4332a commit 0651ef2

19 files changed

+369
-1582
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
---
2+
applyTo: "**/*"
3+
name: "debugging.instructions"
4+
description: "Runtime debugging and tracing guidance for FieldWorks"
5+
---
6+
7+
# Debugging and Tracing
8+
9+
## Purpose & Scope
10+
- Enable developers to capture actionable runtime diagnostics in Debug builds.
11+
- Cover trace switches, listeners, and crash evidence collection for FieldWorks desktop.
12+
13+
## Quick Start: Enable Trace Log
14+
1) Copy the snippet below into `Output/Debug/FieldWorks.exe.config` (or create it by copying `Src/AppForTests.config`).
15+
2) Ensure `%temp%` is writable; set `AssertUiEnabled=false` to avoid modal assertion dialogs.
16+
3) Restart `FieldWorks.exe`; traces will append to `%temp%/FieldWorks.trace.log`.
17+
18+
```xml
19+
<system.diagnostics>
20+
<trace autoflush="false">
21+
<listeners>
22+
<clear />
23+
<add name="FwTraceListener"
24+
type="SIL.LCModel.Utils.EnvVarTraceListener, SIL.LCModel.Utils"
25+
initializeData="assertuienabled='false' assertexceptionenabled='false' logfilename='%temp%/FieldWorks.trace.log'" />
26+
</listeners>
27+
</trace>
28+
<switches>
29+
<add name="ShowPendingMsgs" value="3" />
30+
<add name="XCore.Mediator_InvokeTrace" value="3" />
31+
<add name="XWorks_Timing" value="3" />
32+
<add name="XWorks_LinkListener" value="3" />
33+
</switches>
34+
</system.diagnostics>
35+
```
36+
- Switch levels: 0 Off, 1 Error, 2 Warning, 3 Info, 4 Verbose.
37+
- Log file path is configurable via `logfilename`; environment variable expansion (`%temp%`) is supported by `EnvVarTraceListener`.
38+
39+
## Trace Switch Reference
40+
- `ShowPendingMsgs`: XCore pending message queue tracing.
41+
- `XCore.Mediator_InvokeTrace`: Mediator invoke and job queue tracing.
42+
- `XWorks_Timing`: Timing hooks in xWorks (RecordList, etc.).
43+
- `XWorks_LinkListener`: LinkListener diagnostics.
44+
- Additional Trace.WriteLine hooks exist in Debug-only helpers (`DebugProcs`, etc.).
45+
46+
## Assertions and UI
47+
- `EnvVarTraceListener` honors `AssertUiEnabled` and `AssertExceptionEnabled` environment variables.
48+
- Set `AssertUiEnabled=false` to suppress modal assertion dialogs; exceptions are thrown only if `assertexceptionenabled` remains `true`.
49+
50+
## Dev switch (auto config)
51+
- FieldWorks now supports a swappable diagnostics config via `FieldWorks.Diagnostics.config`.
52+
- Default is quiet. `build.ps1` now enables the dev diagnostics config automatically for Debug builds unless you override `/p:UseDevTraceConfig`. You can also force it via `UseDevTraceConfig=true` or by setting environment variable `FW_TRACE_LOG` before the build; the dev diagnostics file is copied as `FieldWorks.Diagnostics.config` in the output.
53+
- Dev log location: `Output/Debug/FieldWorks.trace.log` (relative to the app folder) so it’s easy to collect alongside binaries.
54+
- Dev config logs to `%temp%/FieldWorks.trace.log` and turns on the core switches above. Edit `Src/Common/FieldWorks/FieldWorks.Diagnostics.dev.config` to change log path or switches.
55+
56+
## Crash Evidence
57+
- Check `%LOCALAPPDATA%\CrashDumps` for `FieldWorks.exe.*.dmp` (enable Windows Error Reporting local dumps if missing).
58+
- Windows Event Viewer → Windows Logs → Application contains `.NET Runtime` and `Application Error` entries.
59+
60+
## Proposed Improvements (dev-only)
61+
- Add `Docs/FieldWorks.trace.sample.config` with the snippet above for easy reuse.
62+
- Introduce a dev flag (`UseDevTraceConfig=true` or `FW_TRACE_LOG` env var) that copies the dev diagnostics file next to `FieldWorks.exe` in Debug builds so tracing is on by default for local runs.
63+
- Document standard trace switches in `Docs/logging.md` and keep `EnvVarTraceListener` as the default listener for dev traces.

.github/copilot-instructions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
| Task | Reference |
4141
| --- | --- |
4242
| Build/test rules | `.github/instructions/build.instructions.md`, `.github/instructions/testing.instructions.md` |
43+
| Debugging | `.github/instructions/debugging.instructions.md` |
4344
| Managed / Native / Installer guidance | `.github/instructions/managed.instructions.md`, `.github/instructions/native.instructions.md`, `.github/instructions/installer.instructions.md` |
4445
| Security & PowerShell rules | `.github/instructions/security.instructions.md`, `.github/instructions/powershell.instructions.md` |
4546
| **Serena MCP (symbol tools)** | `.github/instructions/serena.instructions.md` |

.github/instructions/build.instructions.md

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,20 +81,17 @@ Run: msbuild Build\Src\NativeBuild\NativeBuild.csproj
8181
- On Linux/macOS: Use `./build.sh` and ensure `msbuild`, `dotnet`, and native build tools are installed.
8282
- Environment variables (`fwrt`, `Platform=x64`, etc.) are set by `SetupInclude.targets` during build.
8383

84-
## Worktree and Container Policy
84+
## Concurrent Builds & Smart Kill
8585

86-
FieldWorks uses **git worktrees** for parallel development and **Docker containers** for build isolation:
86+
FieldWorks supports concurrent builds in **git worktrees** (e.g., VS Code Background Agents) on the same machine.
8787

88-
| Location | Build Method | Reason |
89-
|----------|--------------|--------|
90-
| Main repo checkout | Host via `.\build.ps1` | Direct access to COM/registry |
91-
| Worktree (`worktrees/agent-N`) | Container via `.\build.ps1` | COM/registry isolation |
88+
To prevent conflicts where one build kills another's MSBuild nodes (which hold file locks on `FwBuildTasks.dll`), `build.ps1` uses a **Smart Kill** strategy:
89+
1. **Scope**: Only kills processes in the current user session.
90+
2. **Filter**: Only kills processes (msbuild, dotnet, vstest) that:
91+
- Have the current worktree path in their command line.
92+
- Have loaded a DLL from the current worktree.
9293

93-
**`.\build.ps1` and `.\test.ps1` handle this automatically:**
94-
- Detects worktree paths matching `worktrees/agent-N`
95-
- Checks if container `fw-agent-N` is running
96-
- Respawns build inside container if available
97-
- Use `-NoDocker` to override and build on host
94+
**Result**: You can run `.\build.ps1` in `worktrees/agent-1` and `worktrees/agent-2` simultaneously without interference.
9895

9996
### Intermediate Output Locations
10097

.vscode/launch.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
"cwd": "${workspaceFolder}\\Output\\Debug",
1010
"console": "externalTerminal",
1111
"justMyCode": false,
12-
"preLaunchTask": "Build Debug"
1312
},
1413
{
1514
"name": "Debug NUnit Tests",

AGENTS.md

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,16 @@ dotnet test Src/<Component>.Tests/<Component>.Tests.csproj
4545
Native C++ (Phase 2) must build before managed code (Phases 3+). The traversal build in `FieldWorks.proj` handles this automatically.
4646

4747
### COM/Registry Isolation
48-
Changes affecting COM registration or the Windows registry must:
49-
- Include appropriate tests
50-
- Work inside Docker containers (see `scripts/spin-up-agents.ps1`)
51-
- Never assume host machine registry state
52-
53-
### NuGet Package Cache (Hybrid Architecture)
54-
Containers use a hybrid caching strategy:
55-
- **SHARED** (on named volume `fw-nuget-cache`):
56-
- `C:\NuGetCache\packages\` - global-packages (download once, all agents read)
57-
- `C:\NuGetCache\http-cache\` - HTTP cache (feed metadata)
58-
- **ISOLATED** (container-local):
59-
- `C:\Temp\` - temp/NuGetScratch (extraction operations)
60-
61-
Host builds use `packages/` in the repo (via `nuget.config`).
62-
63-
Containers use **Hyper-V isolation** to fix the Windows Docker `MoveFile()` bug ([moby/moby#38256](https://github.com/moby/moby/issues/38256)). See `DOCKER.md` and `.cache/NUGET_CONTAINER_CACHE_ANALYSIS.md` for details.
48+
FieldWorks uses **Registration-Free COM** (manifest-only) for most components.
49+
- Registry isolation is generally not required for standard builds.
50+
- Worktrees run on the host by default.
51+
52+
### NuGet Package Cache (Host Isolation)
53+
Worktrees running on the host use a shared package cache but isolated scratch folders:
54+
- **SHARED**: `C:\ProgramData\FieldWorks\NuGetCache` (packages/http-cache)
55+
- **ISOLATED**: `.nuget-scratch` and `.temp` inside the worktree folder
56+
57+
Host builds use `packages/` in the repo (via `nuget.config`) unless overridden by environment variables.
6458

6559
### Localization
6660
- Use `.resx` files for localizable strings

Build/Agent/FwBuildHelpers.psm1

Lines changed: 52 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -24,58 +24,40 @@
2424

2525
$moduleRoot = $PSScriptRoot
2626

27-
# Container helpers (detection, path resolution, execution)
28-
Import-Module (Join-Path $moduleRoot "FwContainerHelpers.psm1") -Force
29-
3027
# Build environment (VS setup, MSBuild, VSTest)
3128
Import-Module (Join-Path $moduleRoot "FwBuildEnvironment.psm1") -Force
3229

3330
# =============================================================================
3431
# Process Management Functions
3532
# =============================================================================
3633

37-
function Stop-ContainerBuildProcesses {
38-
param(
39-
[string]$ContainerName
40-
)
41-
42-
if (-not $ContainerName) { return }
43-
44-
$cleanupCommand = @"
45-
`$processNames = @('dotnet', 'msbuild', 'VBCSCompiler', 'vstest.console', 'testhost', 'FieldWorks', 'cl', 'link', 'lib', 'nmake', 'cvtres', 'rc', 'midl', 'tracker', 'vctip', 'ml64')
46-
foreach (`$name in `$processNames) {
47-
Get-Process -Name `$name -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
48-
}
49-
Start-Sleep -Milliseconds 300
50-
"@
51-
52-
Write-Host "Closing build processes in container '$ContainerName'..." -ForegroundColor Yellow
53-
docker exec $ContainerName powershell -NoProfile -Command $cleanupCommand 2>$null
54-
}
55-
5634
function Stop-ConflictingProcesses {
5735
<#
5836
.SYNOPSIS
5937
Stops processes that could interfere with builds/tests.
6038
.DESCRIPTION
6139
Kills build- and test-related processes that can hold locks on artifacts
62-
such as FwBuildTasks.dll. Defaults to the current session; optionally
63-
kills across sessions when running inside containers. When invoked on the
64-
host, can also preemptively clean running agent containers to avoid
65-
cross-locks on shared temp locations.
40+
such as FwBuildTasks.dll. Defaults to the current session.
41+
42+
Implements "Smart Kill" strategy:
43+
1. Identifies processes by name (msbuild, dotnet, etc.)
44+
2. Filters by current session ID
45+
3. If RepoRoot is provided, filters by:
46+
- Command line containing RepoRoot path
47+
- Loaded modules (DLLs) within RepoRoot path
48+
49+
This allows concurrent builds in different worktrees to coexist without
50+
killing each other's MSBuild nodes.
6651
#>
6752
param(
68-
[switch]$AllSessions,
69-
[switch]$CrossContainers,
7053
[string[]]$AdditionalProcessNames = @(),
71-
[switch]$IncludeOmniSharp
54+
[switch]$IncludeOmniSharp,
55+
[string]$RepoRoot
7256
)
7357

7458
$conflicts = @(
75-
# Managed build/test hosts
76-
"dotnet", "msbuild", "VBCSCompiler", "vstest.console", "testhost", "FieldWorks",
77-
# Native toolchain
78-
"cl", "link", "lib", "nmake", "cvtres", "rc", "midl", "tracker", "vctip", "ml64"
59+
# Managed build/test hosts (Persistent lockers)
60+
"dotnet", "msbuild", "VBCSCompiler", "vstest.console", "testhost", "FieldWorks"
7961
)
8062

8163
if ($IncludeOmniSharp) {
@@ -94,8 +76,42 @@ function Stop-ConflictingProcesses {
9476
Get-Process -Name $name -ErrorAction SilentlyContinue
9577
}
9678

97-
if (-not $AllSessions) {
98-
$processes = $processes | Where-Object { $_.SessionId -eq $currentSessionId }
79+
# Always filter by current session
80+
$processes = $processes | Where-Object { $_.SessionId -eq $currentSessionId }
81+
82+
# Filter by RepoRoot (Smart Kill) - only kill processes locking files in this repo
83+
if ($RepoRoot) {
84+
$processesToKill = @()
85+
$RepoRoot = $RepoRoot.TrimEnd('\').TrimEnd('/')
86+
87+
foreach ($p in $processes) {
88+
if ($p.Id -eq $PID) { continue } # Don't kill self
89+
90+
$isRelated = $false
91+
92+
# 1. Check Command Line (fast)
93+
try {
94+
$cim = Get-CimInstance Win32_Process -Filter "ProcessId = $($p.Id)" -ErrorAction SilentlyContinue
95+
if ($cim.CommandLine -and $cim.CommandLine.IndexOf($RepoRoot, [System.StringComparison]::OrdinalIgnoreCase) -ge 0) {
96+
$isRelated = $true
97+
}
98+
} catch {}
99+
100+
# 2. Check Modules (slower, but catches MSBuild nodes holding DLLs)
101+
if (-not $isRelated) {
102+
try {
103+
# Check if any loaded module is within the RepoRoot
104+
if ($p.Modules | Where-Object { $_.FileName -and $_.FileName.StartsWith($RepoRoot, [System.StringComparison]::OrdinalIgnoreCase) }) {
105+
$isRelated = $true
106+
}
107+
} catch {}
108+
}
109+
110+
if ($isRelated) {
111+
$processesToKill += $p
112+
}
113+
}
114+
$processes = $processesToKill
99115
}
100116

101117
if ($processes) {
@@ -108,16 +124,6 @@ function Stop-ConflictingProcesses {
108124

109125
Start-Sleep -Milliseconds 500
110126
}
111-
112-
if ($CrossContainers -and -not (Test-InsideContainer)) {
113-
$agentNum = Get-WorktreeAgentNumber
114-
if ($null -ne $agentNum) {
115-
$containerName = "fw-agent-$agentNum"
116-
if (Test-DockerContainerRunning -ContainerName $containerName) {
117-
Stop-ContainerBuildProcesses -ContainerName $containerName
118-
}
119-
}
120-
}
121127
}
122128

123129
function Test-IsFileLockError {
@@ -154,8 +160,6 @@ function Invoke-WithFileLockRetry {
154160
param(
155161
[Parameter(Mandatory)][ScriptBlock]$Action,
156162
[Parameter(Mandatory)][string]$Context,
157-
[switch]$AllSessions,
158-
[switch]$CrossContainers,
159163
[switch]$IncludeOmniSharp,
160164
[int]$MaxAttempts = 2
161165
)
@@ -170,7 +174,7 @@ function Invoke-WithFileLockRetry {
170174
if ($attempt -lt $MaxAttempts -and (Test-IsFileLockError -ErrorRecord $_)) {
171175
$nextAttempt = $attempt + 1
172176
Write-Host "[WARN] $Context hit a file lock. Cleaning and retrying (attempt $nextAttempt of $MaxAttempts)..." -ForegroundColor Yellow
173-
Stop-ConflictingProcesses -AllSessions:$AllSessions -CrossContainers:$CrossContainers -IncludeOmniSharp:$IncludeOmniSharp
177+
Stop-ConflictingProcesses -IncludeOmniSharp:$IncludeOmniSharp
174178
Start-Sleep -Seconds 2
175179
$retry = $true
176180
}
@@ -298,13 +302,6 @@ function Test-GitTrackedFile {
298302

299303
# Re-export functions from sub-modules plus local functions
300304
Export-ModuleMember -Function @(
301-
# From FwContainerHelpers.psm1
302-
'Test-InsideContainer',
303-
'Get-WorktreeAgentNumber',
304-
'Test-DockerContainerRunning',
305-
'Get-ContainerWorkDir',
306-
'Invoke-InContainer',
307-
'New-ContainerArgumentString',
308305
# From FwBuildEnvironment.psm1
309306
'Initialize-VsDevEnvironment',
310307
'Get-MSBuildPath',

0 commit comments

Comments
 (0)