Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions claude.md
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,7 @@ the comment there about not caching "nothing staged" asks for.
### Key Patterns

- Tool discovery uses wildcard path matching (`WildcardFileFinder`) to find executables in common install locations. A wildcard whose matches are all version-named folders takes the highest version; anything else takes the most recently written
- Inside WSL, which `BuildServerDetector.IsWsl` reports and `Detected` does not count as a build server, a tool with no copy in the distribution is resolved from its Windows definition and started through WSL's interop (`Wsl/`: `WslInterop`, `WslHost`, `WslPaths`; `OsSettingsResolver.TryFindOnHost`). The host's variables come from one `cmd.exe /u /c set`, its drives from `/proc/mounts` and the name of the distribution's share from one `wslpath -w /`. Paths are translated in process, not by `wslpath` per path, because `ResolvedTool.GetArguments` runs for every failing pair, opened or not. A program on the host's PATH is found from one listing of each host directory on it (`WslHost.TryFindOnPath`), a stat on a Windows drive from inside WSL being most of a millisecond. What this side holds for such a tool is WSL's `/init` standing in for it: `ps` lists it as `/init <exe> <exe> <args>` (`WslInterop.StripProxy`), ending it does not close a windowed tool, so `ResolvedTool.CanKill` is false and `DiffRunner.Kill` leaves it alone, and it ends with the terminal session while the window stays. It is started with all three streams redirected and closed (`WslInterop.Start`), or it would hold the pipe `dotnet test` reads. Not offered: the viewer (the host's loopback is not the distribution's under WSL's default networking), a Windows executable that is a `.cmd`, and Vim and Neovim. `DiffEngine_WslWindowsTools=false` turns it off. None of it can run in CI: `WslHostTests` stand a temp directory in for the drive, and the launch itself was run by hand in an Ubuntu distribution under WSL 2, with Beyond Compare, WinMerge and P4Merge
- Tool order can be customized via `DiffEngine_ToolOrder` environment variable
- `DisabledChecker` respects `DiffEngine_Disabled` env var
- `ViewerClient` remembers a port found unowned for ten minutes (`RecheckUnownedAfter`), and the library's telling sends - settle, retire, move, delete, the first inline or diff send - skip the connect while that stands. A refused loopback connection costs two seconds on Windows (firewall stealth mode drops the reset), and a green run settles once per inline verification, which was six minutes for a class of 188 inline tests. Probes (`IsOwned`), the hosts and `InlineQueueClient` always ask and correct the memory; so does `SettleAppliedInline`, being one send per accept. Asking, on Windows, is the operating system's listener table first (`ListenerTable`, shared with `PiperClient`): no listener on the port means nobody to connect to, said without the two seconds, and a listener or a table that cannot be read leaves the connect to answer. So the first telling send of a test process, the launch gate's probe and each of its polls no longer wait to be refused. By port alone, whichever address, since the table is only believed when it says nobody is there. Not for a port that accepted a connection in the last second (`TrustOwnerFor`), because reading the table is reading every connection the machine has, and a run of settles to a live owner would pay more for each than the connect costs. The table is Windows' listeners alone, by `GetExtendedTcpTable` (`ListenerTable.Listeners`), falling back to .NET's list of every connection where that call is not there: 0.32 ms beside 3,000 connections where it was 13. What the table found empty is asked about again after a second (`RecheckUnlistedAfter`), so a tray started after a test process is found; the ten minutes is only for what a connect found. And only a refusal or an unanswered connect is remembered as nobody being there (`NobodyThere`). A viewer launch that failed gives its `MaxInstance` slot back
Expand Down
25 changes: 25 additions & 0 deletions docs/diff-tool.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,31 @@ File | Settings | Manage Layers | This computer | Edit Layer | Build, Execution,
<img src="rider-ignore-spawned.png" alt="Disable R# orphaned processes detection" width="500">


## Windows Subsystem for Linux

A test run inside a [WSL](https://learn.microsoft.com/en-us/windows/wsl/about) distribution can use a diff tool installed on Windows, as well as one installed in the distribution.

For each tool the distribution is searched first. A tool not found there is looked for on Windows: in the directories listed for it under [Supported Tools](#supported-tools), then on the `PATH`, which WSL extends with the Windows one. It is started through WSL's [interoperability with Windows](https://learn.microsoft.com/en-us/windows/wsl/filesystems#run-windows-tools-from-linux), and handed both files as Windows paths:

* A file on a mounted drive by its drive letter: `/mnt/c/code/Tests.Method.received.txt` as `C:\code\Tests.Method.received.txt`.
* A file inside the distribution as a share: `/home/user/code/Tests.Method.received.txt` as `\\wsl.localhost\Ubuntu\home\user\code\Tests.Method.received.txt`.

The [tool order](/docs/diff-tool.order.md) applies as it does anywhere else, so a Windows tool earlier in the order is used ahead of a tool in the distribution that is later in it.

`DiffEngine_{ToolName}` can point at the Windows copy of a tool, written either as the distribution sees the directory (`/mnt/c/Program Files/WinMerge`) or as Windows does (`C:\Program Files\WinMerge`).

What differs from a test run on Windows:

* A Windows tool is not closed when its test passes. WSL runs a Windows program through a process of its own, and ending that process does not close the program's window. For the same reason a tool that does not auto refresh is given a second window when the same comparison fails again, where on Windows its window is replaced.
* Visual Studio Code is started by its `code` launcher, which WSL places on the `PATH`, and opens both files through its WSL extension. A tool that is a script on Windows (`.cmd`) cannot be started from a distribution.
* Vim and Neovim are only used from the distribution, since they run in the terminal they are started from.
* [DiffEngineTray](/docs/tray.md) is not supported from inside a distribution.

To use only the tools in the distribution, set an environment variable `DiffEngine_WslWindowsTools` with the value `false`.

A distribution is treated as a developer machine and not as a build server: see [BuildServerDetector](/readme.md#wsl).


## Supported Tools:

Tools location is automatically detected. If a tool installed in a custom location, it can be manually configured using an environment variable, that points to the executable. The environment variable format is `DiffEngine_{ToolName}`.
Expand Down
25 changes: 25 additions & 0 deletions docs/mdsource/diff-tool.source.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,31 @@ File | Settings | Manage Layers | This computer | Edit Layer | Build, Execution,
<img src="rider-ignore-spawned.png" alt="Disable R# orphaned processes detection" width="500">


## Windows Subsystem for Linux

A test run inside a [WSL](https://learn.microsoft.com/en-us/windows/wsl/about) distribution can use a diff tool installed on Windows, as well as one installed in the distribution.

For each tool the distribution is searched first. A tool not found there is looked for on Windows: in the directories listed for it under [Supported Tools](#supported-tools), then on the `PATH`, which WSL extends with the Windows one. It is started through WSL's [interoperability with Windows](https://learn.microsoft.com/en-us/windows/wsl/filesystems#run-windows-tools-from-linux), and handed both files as Windows paths:

* A file on a mounted drive by its drive letter: `/mnt/c/code/Tests.Method.received.txt` as `C:\code\Tests.Method.received.txt`.
* A file inside the distribution as a share: `/home/user/code/Tests.Method.received.txt` as `\\wsl.localhost\Ubuntu\home\user\code\Tests.Method.received.txt`.

The [tool order](/docs/diff-tool.order.md) applies as it does anywhere else, so a Windows tool earlier in the order is used ahead of a tool in the distribution that is later in it.

`DiffEngine_{ToolName}` can point at the Windows copy of a tool, written either as the distribution sees the directory (`/mnt/c/Program Files/WinMerge`) or as Windows does (`C:\Program Files\WinMerge`).

What differs from a test run on Windows:

* A Windows tool is not closed when its test passes. WSL runs a Windows program through a process of its own, and ending that process does not close the program's window. For the same reason a tool that does not auto refresh is given a second window when the same comparison fails again, where on Windows its window is replaced.
* Visual Studio Code is started by its `code` launcher, which WSL places on the `PATH`, and opens both files through its WSL extension. A tool that is a script on Windows (`.cmd`) cannot be started from a distribution.
* Vim and Neovim are only used from the distribution, since they run in the terminal they are started from.
* [DiffEngineTray](/docs/tray.md) is not supported from inside a distribution.

To use only the tools in the distribution, set an environment variable `DiffEngine_WslWindowsTools` with the value `false`.

A distribution is treated as a developer machine and not as a build server: see [BuildServerDetector](/readme.md#wsl).


## Supported Tools:

Tools location is automatically detected. If a tool installed in a custom location, it can be manually configured using an environment variable, that points to the executable. The environment variable format is `DiffEngine_{ToolName}`.
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ var isBitbucketPipelines = BuildServerDetector.IsBitbucketPipelines;

### WSL

Running under [WSL](https://learn.microsoft.com/en-us/windows/wsl/about) is not treated as a build server, since a WSL session is usually a developer machine. `BuildServerDetector.IsWsl` reports it, and `BuildServerDetector.Detected` ignores it.
Running under [WSL](https://learn.microsoft.com/en-us/windows/wsl/about) is not treated as a build server, since a WSL session is usually a developer machine. `BuildServerDetector.IsWsl` reports it, and `BuildServerDetector.Detected` ignores it. Diff tools are launched there, the ones installed on Windows included: see [Windows Subsystem for Linux](/docs/diff-tool.md#windows-subsystem-for-linux).

A build that runs its tests inside WSL from a Windows build agent is the case to watch. The variables the build server sets exist on the Windows side, and WSL only passes across the ones named in [WSLENV](https://learn.microsoft.com/en-us/windows/wsl/filesystems#share-environment-variables-between-windows-and-wsl-with-wslenv). So inside WSL nothing is detected, and diff tools are launched on the build agent.

Expand Down
2 changes: 1 addition & 1 deletion readme.source.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ snippet: BuildServerDetectorProps

### WSL

Running under [WSL](https://learn.microsoft.com/en-us/windows/wsl/about) is not treated as a build server, since a WSL session is usually a developer machine. `BuildServerDetector.IsWsl` reports it, and `BuildServerDetector.Detected` ignores it.
Running under [WSL](https://learn.microsoft.com/en-us/windows/wsl/about) is not treated as a build server, since a WSL session is usually a developer machine. `BuildServerDetector.IsWsl` reports it, and `BuildServerDetector.Detected` ignores it. Diff tools are launched there, the ones installed on Windows included: see [Windows Subsystem for Linux](/docs/diff-tool.md#windows-subsystem-for-linux).

A build that runs its tests inside WSL from a Windows build agent is the case to watch. The variables the build server sets exist on the Windows side, and WSL only passes across the ones named in [WSLENV](https://learn.microsoft.com/en-us/windows/wsl/filesystems#share-environment-variables-between-windows-and-wsl-with-wslenv). So inside WSL nothing is detected, and diff tools are launched on the build agent.

Expand Down
Loading
Loading