Both were at 0% coverage. Focused on what's safely testable without
touching the network or filesystem: flag validation (--architecture/
--host-arch, the same guard added in the stability pass), subcommand
dispatch and aliases, help/usage error paths, and - for i18n - full
language-detection table coverage plus a completeness check that
every catalog key has both an EN and RU entry (an English-only or
Russian-only entry would silently degrade rather than fail loudly,
so this is worth locking in). cmd/vintner: 0% -> 28.8%, i18n: 0% ->
94.1%.
vintner completion bash|zsh prints a completion script meant to be
sourced (source <(vintner completion bash)); completes subcommands
(including short aliases), download's flags, and directory arguments
for install/env --bin. Mentioned in the top-level usage text and
documented in the README.
The Nivora package doesn't auto-install these system-wide yet - it'd
need Stapler's install-completion helper, whose calling convention
isn't documented anywhere in this repo or Nivora's other packages, so
guessing at it risked a broken package build for a nice-to-have.
source <(vintner completion bash) works today regardless of install
method (Nivora, prebuilt binary, or from source).
Every wrapped tool invocation (cl/link/msbuild/etc via wine, plus the
native cmd/findstr shims) now starts its child in its own process
group and forwards SIGINT/SIGTERM to that group, escalating to
SIGKILL after a 5s grace period if it doesn't exit.
Previously, interactive Ctrl-C happened to work by accident (the
child inherited the terminal's foreground process group and got the
signal directly), but anything that signals vintner by PID alone - a
CI job's timeout, a supervisor's `kill <pid>` - never reached the
wine/wineserver tree underneath it, which got reparented to init and
kept running: wasted CPU, held file locks, stray FIFOs/temp files.
Verified two ways: a unit test (signals_test.go) that starts a
detached `sleep 30`, signals the test process itself, and checks the
child actually dies; and a real end-to-end run - killed an in-flight
`msbuild` driver build by PID mid-compile and confirmed no orphaned
msbuild/cl/link/vintner process was left behind (wineserver and its
persistent service processes are expected to survive, by design - see
pipeDrainGrace's doc comment).
Loops ExpandSelection 50 times and checks the result order never
changes, guarding against the map-iteration-order bug fixed in the
previous commit ever coming back unnoticed. Verified this actually
catches the regression by temporarily reverting the fix locally.
Found via manual audit plus a staticcheck run:
- collectDependencyClosure iterated a package's dependencies map
directly, so which package "won" a same-key collision (and the
order things got downloaded/unpacked in) could vary between runs
of the exact same download command. Sort the dependency targets
first, matching what --print-deps-tree's tree-printer already did.
Verified two consecutive --print-deps-tree runs now produce
byte-identical output.
- HTTP retry loops (manifest fetch, payload download) retried
immediately with no backoff, which just hammers a server harder
during exactly the kind of transient failure retries exist for.
Added a capped exponential backoff (1s/2s/4s/8s/10s).
- --architecture/--host-arch accepted any string silently; a typo'd
value matched nothing during package selection and surfaced as a
confusing downstream failure far from the actual mistake. Now
rejected up front with a clear error.
- pumpLines' bufio.Scanner silently stops (dropping the rest of a
tool's output) if a single line ever exceeds its buffer - narrow but
real for pathological cases like heavily templated C++ diagnostics.
Now at least reports that truncation happened instead of losing
output with no trace.
- Removed select.go's unused off() helper (staticcheck U1000).
Re-verified end-to-end after these changes: a real KMDF driver build
and a plain cl/link build both still succeed.
Renamed the GitHub repo, Go module path, binary, and default install
directory from msvc-go-wine to vintner. Updated every user-facing
string (usage text, error prefixes, README, LICENSE, CI/release
workflow) and the embedded compatibility patches' own header text to
match; the VINTNER_LANG env var replaces VSMC_GO_WINE_LANG.
Also fixes a real bug found while re-verifying the rename end-to-end:
Microsoft.Cpp.WindowsSDK.props.patch had LF-only line endings in its
hunk body while the real Microsoft-shipped file it targets is CRLF,
so `git apply` silently failed on every real install and the SDK
detection fix it's meant to provide was never actually taking effect.
Restored matching CRLF endings in the hunk (checked against the other
five patches, which already had this right). Left the patch's
internal MsvcGoWine_ExtraSdkRoots MSBuild property name alone rather
than renaming it too - changing hunk content, even just an identifier,
breaks reverse-apply idempotency for anyone re-running download
against an already-patched tree, which the fix above depends on. Added
a .remove marker so an existing install's old-named props file gets
cleaned up on the next download.
Re-verified end-to-end after the rename: general MSBuild/cl/link
still work, and a real KMDF driver build (compile, link, INF stamping,
Inf2Cat signability check) still succeeds under the renamed binary.
README also gets an accuracy pass: WDK support and the download/env
CLI flags it lists were out of date (WDK was previously listed under
"Known gaps" despite being implemented and verified), the full tool
list was missing mc/cmd/findstr, and the new command aliases and
VINTNER_LANG option are now documented.
Subcommands gain one/two-letter aliases (dl, i, e, v, h) alongside
their full names. CLI-owned chrome - top-level usage, per-subcommand
usage lines, progress messages, and the license prompt - now goes
through internal/i18n, an env-driven message catalog (MSVC_GO_WINE_LANG,
falling back to the standard LC_ALL/LC_MESSAGES/LANG locale variables)
with English and Russian translations. Deeper error text from internal
packages stays in English.
Also refreshed the top-level usage text, which hadn't kept up with
--with-wdk/--list-workloads/--list-components/--print-deps-tree.
download --with-wdk fetches the WDK headers/libs/host-tools NuGet
packages (nuget.org has no vsman-manifest entry for this content) and
lays them out where the DriverKit.BuildTools PlatformToolset expects
them. msbuildEnv wires WDKContentRoot/WDKBuildFolder through
DisableRegistryUse the same way the SDK/toolset paths already are.
Two WDK-package fixups were needed for a real driver to actually
build under Wine: the bundled build-task assembly is versioned for an
older VisualStudioVersion than ours, and the package ships no x86
host-tools directory at all (only x64/arm64), which StampInf hardcodes
a path to.
Also force TZ=UTC for msbuild invocations: StampInf stamps DriverVer
using the local wall-clock date while Inf2Cat validates it against
UTC "now", so any timezone east of UTC sees a "postdated DriverVer"
failure for most of the day.
Verified against a real KMDF sample driver (microsoft/Windows-driver-
samples' echo_2): compiles, links, INF stamps and passes Inf2Cat's
signability check with SignMode=off.
- download --list-workloads / --list-components print every workload or
component id (with its manifest title) without downloading anything, for
discovering what to pass as a package id or --with-* toggle.
- download --print-deps-tree prints the dependency tree of whatever the
current flags would actually select, sharing the exact same
arch/--ignore/Optional/Recommended filtering ExpandSelection uses so the
output matches a real download; diamond dependencies are shown once and
referenced as "(see above)" afterwards to keep it finite.
- Fixed --manifest (offline/predownloaded manifest testing) never having
worked at all: it builds a "file:" URL but the shared http.Client had no
handler registered for that scheme.
- Added a CI workflow running gofmt/vet/build/test on every push and PR;
previously only the tag-triggered release workflow existed.
msbuild (and the toolrelay.exe-less fallback path for cl/link/etc.) inherited
os.Stdout/os.Stderr directly into the wine subprocess. Wine's wineserver and
its service processes (services.exe, winedevice.exe, explorer.exe, ...)
inherit those same descriptors and keep running well after the actual build
finishes, so a caller piping our output (`| tee`, `| tail`, CI log capture)
would never see EOF and hang indefinitely - even though the real build
completed in seconds.
Both paths now pipe stdout/stderr through our own copy goroutines, wait for
the tool's own process (not pipe EOF) to determine completion, and grant a
bounded 500ms grace period to drain whatever's already buffered before
moving on. Verified against a real hang (msbuild building freetype.vcxproj
piped through `tail`) and confirmed instant return after the fix, both on
success and on a build error.
msbuild <project>.vcxproj previously failed with MSB8020 ("build tools for
vNNN cannot be found") because MSBuild's own toolset/SDK resolution reads
a different set of environment variables than cl/link/lib do directly
(VCInstallDir_<N>, VCToolsInstallDir_<N>, VsInstallRoot,
WindowsSdkDir_10, WindowsTargetPlatformVersion, DisableRegistryUse, etc) -
none of which the generic INCLUDE/LIB/WINEPATH env covered.
Added msbuildEnv, populated for every MSBuild toolset generation actually
present under MSBuild/Microsoft/VC/v*, and wired into the msbuild wrapper.
Verified end-to-end: msbuild successfully builds ocornut/imgui's
example_win32_directx11.vcxproj (retargeted from its original v141
PlatformToolset to this install's v145) - compiles all 8 sources and
links against d3d11.lib/d3dcompiler.lib/dxgi.lib, producing a valid
PE32+ executable.
A single-binary Go tool for cross compiling with the real MSVC toolchain
on Linux via Wine. Behaves as cl/link/lib/rc/midl/mt/dumpbin/msbuild/
nmake/ml/ml64/armasm/armasm64/cmd/findstr depending on the name it's
invoked as, plus download/install/env/version management subcommands.
- download: fetches the MSVC/WinSDK installer manifest, resolves package
selection and dependencies, downloads and verifies payloads, unpacks
VSIX/MSI packages, and applies a handful of compatibility patches so
VsDevCmd.bat and MSBuild's SDK detection work without a Windows
Registry (which doesn't exist under Wine).
- install: locates the installed toolchain/SDK versions, normalizes
header/library name casing, lays out per-architecture tool symlinks
with an env.json config each, and compiles a small native launcher
(toolrelay.exe) that lets mt.exe's CMake-compatibility exit code
survive Wine's own exit-code truncation.
- The wrapper runtime rewrites absolute unix paths in tool arguments into
Wine's z:\... form, runs the real .exe under wine, and rewrites the
tool's output back to plain unix paths.
Verified end-to-end against a real MSVC/WinSDK download: cl, link, mt and
the resulting hello.exe all work under Wine, including through the
toolrelay.exe relay path and with paths containing non-ASCII characters.
Offline unit tests cover the wrapper's path-rewrite/output-filter logic,
install-time header lowercasing, and download package-selection/
dependency-resolution.