mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-10-21 13:54:39 +00:00
fix(tauri): prevent Windows event-loop refcount corruption (#996)
## Summary
Fix repeated Windows heap-corruption crashes in the installed Tauri
build. The pinned runtime exposes clonable, thread-safe handles whose
unsafe context graph contains Tao's non-atomic `Rc<EventLoopRunner>`.
IPC-worker clone/drop traffic races the event loop's reference count and
can free the runner prematurely.
- Use `Arc` for that internal Windows runner counter, retaining
main-thread confinement of runner state and the target's existing public
threading contract.
- Add an isolated regression using the real pinned Wry runtime's public
handle API, with a negative control that reverses only this counter in a
temporary crate copy.
- Add the Windows regression to CI and document the captured failures,
compatibility rationale and removal criteria.
This is a local compatibility correction for the runtime CodeNomad
ships. [tao#1290](https://github.com/tauri-apps/tao/pull/1290) proposed
the same counter change but was closed **without merging**, because the
underlying contract violation is Tauri moving/cloning the non-Send
target. That distinction is recorded explicitly. Related reports:
[tauri#15408](https://github.com/tauri-apps/tauri/issues/15408) and
[tauri#15793](https://github.com/tauri-apps/tauri/issues/15793).
## Validation
- `node scripts/test-tauri-runner-refcount.mjs --baseline`: **9 native
crashes / 10 negative-control processes; 5 / 5 corrected passes**,
800,000 handle clones plus teardown per process.
- `node scripts/test-tauri-input-deadlock.mjs --baseline`: keydown,
keyup, char, syschar, IME and instrumented IME-boundary checks pass; the
original/reverted negative controls reproduce their expected deadlocks.
- `cargo build --locked --release -p codenomad-tauri`: passes.
- `rustfmt --check` on the new fixture and `node --check` on its runner:
pass.
- Corrected release executable installed locally on the affected Windows
machine, retaining the existing resources and updater verification
public key; original executable and matching new symbols archived
locally.
The runtime reproduction needs no JavaScript or web page. The Virtua
0.53.5 upgrade is absent from the crashing `3394fc7f` build. Sustained
application use remains additional validation beyond the bounded native
regression.
This commit is contained in:
parent
fc16d250cf
commit
54958f4e83
12 changed files with 305 additions and 10 deletions
3
.github/workflows/pr-build.yml
vendored
3
.github/workflows/pr-build.yml
vendored
|
|
@ -525,6 +525,9 @@ jobs:
|
|||
- name: Reproduce and prevent Tao input deadlocks
|
||||
run: node scripts/test-tauri-input-deadlock.mjs --baseline
|
||||
|
||||
- name: Reproduce and prevent Windows runtime handle corruption
|
||||
run: node scripts/test-tauri-runner-refcount.mjs --baseline
|
||||
|
||||
# Exercise the selected-CLI contract on the reported macOS ARM64 platform as
|
||||
# well as both other hosts, independently of unrelated server-suite failures.
|
||||
tests-opencode-compatibility:
|
||||
|
|
|
|||
|
|
@ -133,6 +133,8 @@
|
|||
|
||||
- Tauri's Tao Windows input backport lives in `packages/tauri-app/vendor/`; preserve upstream provenance and avoid message pumping under input mutexes. Run `node scripts/test-tauri-input-deadlock.mjs --baseline` on Windows when changing it. See `packages/tauri-app/vendor/README.md` for provenance and override removal criteria.
|
||||
|
||||
- The pinned Tauri runtime clones native handles on worker threads, including Tao's Windows event-loop target. Its internal runner counter must remain atomic; this does not authorize off-main-thread access to the runner state or make Tao's target Send/Sync. Run `node scripts/test-tauri-runner-refcount.mjs --baseline` after changes to this compatibility fix. The isolated regression uses the actual Wry runtime without an application profile or OpenCode; see `dev-docs/TAURI_WINDOWS_RUNNER_REFCOUNT.md` and the vendor provenance (the referenced upstream proposal was not merged).
|
||||
|
||||
- Tao's macOS zoom getter must remain read-only: synchronous temporary style-mask changes on borderless windows generate geometry-event feedback and can starve startup navigation. Keep the exact upstream tao#1182 backport beside the Windows fix, with its provenance in `packages/tauri-app/vendor/README.md`. Run `node scripts/test-tauri-macos-window.mjs --baseline` in a graphical macOS session and retain the ARM64 CI regression. Do not disable window persistence or change the application chrome as a workaround.
|
||||
|
||||
- Bundled runtime maintenance keeps `.node-version` exact and proposes only same-major LTS upgrades as regular, non-draft PRs without automatic merge. The scheduled npm CLI/dependency audit is warning-only: never independently replace bundled npm, auto-fix dependencies, merge or publish from that check. Audit failure is not a clean assessment; application runtime changes require reviewed builds/releases. See `dev-docs/RUNTIME_MAINTENANCE.md`.
|
||||
|
|
|
|||
85
dev-docs/TAURI_WINDOWS_RUNNER_REFCOUNT.md
Normal file
85
dev-docs/TAURI_WINDOWS_RUNNER_REFCOUNT.md
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
# Windows Tauri runtime handle corruption
|
||||
|
||||
## Captured failure
|
||||
|
||||
The installed Windows build `0.20.1-dev-20261017-3394fc7f` crashed repeatedly
|
||||
on 2026-10-18 at 00:19:50, 00:36:49 and 00:52:27 local time. Windows reported
|
||||
`STATUS_HEAP_CORRUPTION` (`0xc0000374`) in `ntdll!RtlFreeHeap`.
|
||||
|
||||
The first two minidumps have the same application call chain. The leading
|
||||
application offsets are `+0xbb9f28`, `+0x1043`, `+0x1165`, `+0x2e87b`,
|
||||
`+0x2ec26`, `+0x611cf8`, followed by the native event callback and Win32
|
||||
subclass/message dispatch. Disassembly shows the failing release reached via
|
||||
a non-atomic reference-count decrement (`dec`, without `lock`). The installed
|
||||
release's matching PDB was not published; these offsets are evidence, not
|
||||
claimed symbol names.
|
||||
|
||||
The original dumps remain in the machine's Windows CrashDumps directory and
|
||||
must not be committed or uploaded: they can contain application memory.
|
||||
|
||||
The installed build pins Virtua 0.51.0. The later Virtua 0.53.5 change (#991)
|
||||
is absent from it. The native reproducer below does not load any JavaScript.
|
||||
|
||||
## Cause and bounded correction
|
||||
|
||||
`tauri-runtime-wry` 2.10.1's clonable context contains
|
||||
`DispatcherMainThreadContext::window_target`. Its unsafe Send/Sync context
|
||||
permits public runtime handles to move between threads, but cloning/dropping
|
||||
the Windows target updates Tao's `Rc<EventLoopRunner>` non-atomically.
|
||||
IPC-related handle traffic can therefore free the runner while the event loop
|
||||
still owns it. A different ordering can leave a leaked reference instead.
|
||||
|
||||
References: tauri-apps/tauri#15408 and #15793. The same two-file counter change
|
||||
was proposed in tauri-apps/tao#1290, **closed without merging** because Tao's
|
||||
target is not intended to cross threads. The violation is in the runtime's
|
||||
unsafe wrapper; CodeNomad's reproducer needs no unsafe Send wrapper of its own.
|
||||
|
||||
For the pinned runtime CodeNomad vendors a narrow compatibility correction:
|
||||
the Windows runner's shared ownership uses `Arc`. Only reference counting
|
||||
becomes thread-safe; runner state remains main-thread-only, and the window
|
||||
target's public threading contract is not widened. Other platforms and existing
|
||||
Windows input/macOS zoom backports retain their behavior.
|
||||
|
||||
## Regression
|
||||
|
||||
Run on Windows:
|
||||
|
||||
```sh
|
||||
node scripts/test-tauri-runner-refcount.mjs --baseline
|
||||
node scripts/test-tauri-input-deadlock.mjs --baseline
|
||||
```
|
||||
|
||||
The new fixture creates the real Wry runtime and performs 800,000 public
|
||||
runtime-handle clones/drops on eight workers, followed by teardown. It opens
|
||||
no visible window and uses no web page, CodeNomad data, backend or daemon.
|
||||
Every corrected run must exit successfully. The optional negative control
|
||||
copies the same crate and lockfile, reverses only the counter correction,
|
||||
and requires a native fault within ten isolated processes. A surviving
|
||||
negative-control process is reported explicitly, not counted as a fault.
|
||||
|
||||
Initial diagnosis: the original build failed in all three stress runs;
|
||||
the corrected build completed all five runs (four million clones total).
|
||||
Debugger inspection of a failing native fixture reached `alloc::rc::Rc::drop_slow`
|
||||
from a worker thread. The input regression is required alongside this test
|
||||
because the existing Windows backport shares `event_loop.rs`.
|
||||
|
||||
The final scripted negative control reproduced nine native crashes out of ten
|
||||
processes (one survived); all five corrected processes passed. The input suite
|
||||
also passed keydown, keyup, char, syschar, IME and the instrumented IME-boundary
|
||||
case, while each corresponding original/reverted negative control reproduced
|
||||
its expected deadlock. The release application builds with the same vendor fix.
|
||||
|
||||
## Local installation
|
||||
|
||||
A release binary built from this worktree with the corrected counter was
|
||||
installed on the affected machine after normal window shutdown. Existing
|
||||
resources and the updater verification public key were retained. Its embedded
|
||||
application version is `0.20.1-dev-20261018-1f132dbb-heapfix` (the Windows PE
|
||||
version resource still reports the package version, `0.20.1`). SHA-256:
|
||||
|
||||
`0e8dce026bd3db3d48d77a4a82820e527e1425d8357214be8851e4ab8e15cea3`
|
||||
|
||||
The original executable and matching symbols for the corrected build were
|
||||
archived locally before replacement. This is a local repair, not a published
|
||||
release; sustained application use is additional validation beyond the bounded
|
||||
native regression.
|
||||
9
packages/tauri-app/Cargo.lock
generated
9
packages/tauri-app/Cargo.lock
generated
|
|
@ -565,6 +565,15 @@ dependencies = [
|
|||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codenomad-windows-runner-fixture"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"tauri-runtime",
|
||||
"tauri-runtime-wry",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.7"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
[workspace]
|
||||
members = ["src-tauri", "tests/windows-input", "tests/macos-window", "tests/panel-extension"]
|
||||
members = ["src-tauri", "tests/windows-input", "tests/windows-runner-refcount", "tests/macos-window", "tests/panel-extension"]
|
||||
default-members = ["src-tauri"]
|
||||
resolver = "2"
|
||||
|
||||
|
|
|
|||
10
packages/tauri-app/tests/windows-runner-refcount/Cargo.toml
Normal file
10
packages/tauri-app/tests/windows-runner-refcount/Cargo.toml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "codenomad-windows-runner-fixture"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
tauri-runtime = "=2.10.1"
|
||||
tauri-runtime-wry = "=2.10.1"
|
||||
windows-sys = { version = "0.59", features = ["Win32_System_Diagnostics_Debug"] }
|
||||
14
packages/tauri-app/tests/windows-runner-refcount/build.rs
Normal file
14
packages/tauri-app/tests/windows-runner-refcount/build.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
fn main() {
|
||||
if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("windows") {
|
||||
// Cargo can reuse this compiled build script between the temporary
|
||||
// negative control and the checkout. Resolve the current path at run time.
|
||||
let manifest = std::path::PathBuf::from(
|
||||
std::env::var("CARGO_MANIFEST_DIR")
|
||||
.expect("Cargo provides the current manifest directory"),
|
||||
)
|
||||
.join("../../src-tauri/examples/window_constraints_windows.manifest");
|
||||
println!("cargo:rerun-if-changed={}", manifest.display());
|
||||
println!("cargo:rustc-link-arg=/MANIFEST:EMBED");
|
||||
println!("cargo:rustc-link-arg=/MANIFESTINPUT:{}", manifest.display());
|
||||
}
|
||||
}
|
||||
52
packages/tauri-app/tests/windows-runner-refcount/src/main.rs
Normal file
52
packages/tauri-app/tests/windows-runner-refcount/src/main.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
//! Exercises the real Tauri runtime's safe Send + Clone handle across workers.
|
||||
//! No CodeNomad profile, backend, shared daemon, web page or visible window.
|
||||
#[cfg(not(windows))]
|
||||
fn main() {
|
||||
eprintln!("This regression requires Windows");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn main() {
|
||||
use std::{
|
||||
hint::black_box,
|
||||
sync::{Arc, Barrier},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
use tauri_runtime::Runtime;
|
||||
use tauri_runtime_wry::Wry;
|
||||
use windows_sys::Win32::System::Diagnostics::Debug::{SetErrorMode, SEM_NOGPFAULTERRORBOX};
|
||||
|
||||
// A negative control must exit without opening a Windows error dialog.
|
||||
unsafe {
|
||||
SetErrorMode(SEM_NOGPFAULTERRORBOX);
|
||||
}
|
||||
thread::spawn(|| {
|
||||
thread::sleep(Duration::from_secs(30));
|
||||
eprintln!("FAIL: runtime handle regression watchdog");
|
||||
std::process::exit(2);
|
||||
});
|
||||
let runtime = Wry::<()>::new(Default::default()).expect("create isolated Wry runtime");
|
||||
let gate = Arc::new(Barrier::new(9));
|
||||
let workers: Vec<_> = (0..8)
|
||||
.map(|_| {
|
||||
let handle = runtime.handle();
|
||||
let gate = gate.clone();
|
||||
thread::spawn(move || {
|
||||
gate.wait();
|
||||
for _ in 0..100_000 {
|
||||
// IPC performs this same safe runtime-handle clone/drop traffic.
|
||||
drop(black_box(handle.clone()));
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
println!("START: concurrent Tauri runtime handle cloning");
|
||||
gate.wait();
|
||||
for worker in workers {
|
||||
worker.join().expect("runtime worker failed");
|
||||
}
|
||||
drop(runtime);
|
||||
println!("PASS: 800000 runtime handle clones and clean teardown");
|
||||
}
|
||||
43
packages/tauri-app/vendor/README.md
vendored
43
packages/tauri-app/vendor/README.md
vendored
|
|
@ -1,8 +1,9 @@
|
|||
# Tao native window backports
|
||||
|
||||
`tao-0.34.6/` is the published Apache-2.0 crate (license included), with only
|
||||
the four Windows source files from upstream [tao#1215] and the macOS
|
||||
`is_zoomed` function from [tao#1182] changed. It is selected
|
||||
`tao-0.34.6/` is the published Apache-2.0 crate (license included), with
|
||||
the Windows input backport from upstream [tao#1215], the macOS
|
||||
`is_zoomed` function from [tao#1182], and the local Windows runner refcount
|
||||
compatibility correction below. It is selected
|
||||
by the Tauri workspace's `[patch.crates-io]`; there is no registry-cache mutation
|
||||
or build-time patching. All platforms keep the same dependency/API version.
|
||||
|
||||
|
|
@ -49,12 +50,44 @@ events, including reads during geometry capture, and exercises maximize/restore,
|
|||
fixed-size and decorated windows. Its original-crate negative control reproduces
|
||||
the feedback loop.
|
||||
|
||||
Remove the override only after both native backports are available in the
|
||||
resolved supported release and both native regressions pass.
|
||||
Remove the override only after the resolved dependencies cover the input,
|
||||
read-only zoom and runner lifetime fixes and their native regressions pass.
|
||||
|
||||
[tao#1215]: https://github.com/tauri-apps/tao/pull/1215
|
||||
[tao#1182]: https://github.com/tauri-apps/tao/pull/1182
|
||||
|
||||
## Windows runtime handle lifetime
|
||||
|
||||
The pinned `tauri-runtime-wry` 2.10.1 exposes `Send + Sync + Clone` runtime
|
||||
handles whose unsafe context graph contains Tao's non-atomic
|
||||
`Rc<EventLoopRunner>`. Safe handle clones/drops on IPC workers race the main
|
||||
thread's reference count, freeing the runner prematurely or leaking it.
|
||||
|
||||
The local correction changes **only this internal shared counter** to `Arc`
|
||||
in `event_loop.rs` and `event_loop/runner.rs`. It neither makes
|
||||
`EventLoopWindowTarget` Send/Sync nor permits worker access to the runner's
|
||||
`Cell`/`RefCell` state. Tauri's existing main-thread access discipline remains.
|
||||
|
||||
Provenance: [tauri#15408](https://github.com/tauri-apps/tauri/issues/15408),
|
||||
[tauri#15793](https://github.com/tauri-apps/tauri/issues/15793) and the proposal
|
||||
[tao#1290](https://github.com/tauri-apps/tao/pull/1290). **That PR was closed
|
||||
unmerged**: the maintainer correctly identified Tauri's cross-thread use of a
|
||||
non-Send window target as the contract violation. This is a deliberate local
|
||||
compatibility correction for the runtime we ship, not a claimed upstream merge
|
||||
or a general guarantee that Tao window targets are safe to use across threads.
|
||||
|
||||
`node scripts/test-tauri-runner-refcount.mjs --baseline` calls the real pinned
|
||||
Wry runtime's safe public handle API on eight workers. The negative control
|
||||
reverts only the counter in a temporary crate copy and requires a native fault;
|
||||
the corrected build must finish every run and tear down cleanly. It uses no
|
||||
CodeNomad profile, page, backend or OpenCode service. Individual negative-control
|
||||
processes can survive a race that leaks instead of freeing early.
|
||||
|
||||
Keep this correction until the resolved Tauri runtime no longer races Tao's
|
||||
reference count (or the resolved Tao implementation safely handles that traffic).
|
||||
Qualify removal with the same regression and the existing Windows input tests.
|
||||
Captured crash evidence is recorded in `dev-docs/TAURI_WINDOWS_RUNNER_REFCOUNT.md`.
|
||||
|
||||
## Updater Windows launch handoff
|
||||
|
||||
`tauri-plugin-updater-2.12.0/` is the published MIT/Apache-2.0 crate (licenses
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ use std::{
|
|||
ffi::c_void,
|
||||
marker::PhantomData,
|
||||
mem, panic,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
|
|
@ -198,7 +197,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
thread::spawn(move || wait_thread(thread_id, HWND(send_thread_msg_target as _)));
|
||||
let wait_thread_id = get_wait_thread_id();
|
||||
|
||||
let runner_shared = Rc::new(EventLoopRunner::new(thread_msg_target, wait_thread_id));
|
||||
let runner_shared = Arc::new(EventLoopRunner::new(thread_msg_target, wait_thread_id));
|
||||
|
||||
let thread_msg_sender = subclass_event_target_window(thread_msg_target, runner_shared.clone());
|
||||
raw_input::register_all_mice_and_keyboards_for_raw_input(thread_msg_target, Default::default());
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use std::{
|
|||
cell::{Cell, RefCell},
|
||||
collections::{HashSet, VecDeque},
|
||||
mem, panic,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
|
|
@ -24,7 +24,10 @@ use crate::{
|
|||
window::WindowId,
|
||||
};
|
||||
|
||||
pub(crate) type EventLoopRunnerShared<T> = Rc<EventLoopRunner<T>>;
|
||||
// The pinned Tauri runtime clones/drops this handle through unsafe Send/Sync
|
||||
// contexts on worker threads. Only the reference count may cross threads;
|
||||
// the runner's interior remains confined to the event-loop thread.
|
||||
pub(crate) type EventLoopRunnerShared<T> = Arc<EventLoopRunner<T>>;
|
||||
pub(crate) struct EventLoopRunner<T: 'static> {
|
||||
// The event loop's win32 handles
|
||||
thread_msg_target: HWND,
|
||||
|
|
|
|||
85
scripts/test-tauri-runner-refcount.mjs
Normal file
85
scripts/test-tauri-runner-refcount.mjs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
// Real Wry handle cloning. No CodeNomad profile, backend, page or shared daemon.
|
||||
import assert from "node:assert/strict"
|
||||
import { spawnSync } from "node:child_process"
|
||||
import { cp, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"
|
||||
import os from "node:os"
|
||||
import path from "node:path"
|
||||
import { fileURLToPath } from "node:url"
|
||||
|
||||
assert.equal(process.platform, "win32", "Run this native regression on Windows")
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
||||
const workspace = path.join(root, "packages/tauri-app")
|
||||
const fixture = "tests/windows-runner-refcount"
|
||||
const target = path.resolve(process.env.CARGO_TARGET_DIR || path.join(workspace, "target"))
|
||||
const env = { ...process.env, CARGO_TARGET_DIR: target }
|
||||
delete env.NODE_OPTIONS
|
||||
delete env.CODENOMAD_NATIVE_PARENT
|
||||
const binary = path.join(target, "release/codenomad-windows-runner-fixture.exe")
|
||||
|
||||
function cargo(args, cwd = workspace) {
|
||||
const result = spawnSync("cargo", args, { cwd, env, encoding: "utf8", timeout: 600_000, maxBuffer: 8 * 1024 * 1024, windowsHide: true })
|
||||
assert.equal(result.error, undefined, String(result.error))
|
||||
assert.equal(result.status, 0, result.stdout + result.stderr)
|
||||
return result.stdout
|
||||
}
|
||||
function run(fixed, count) {
|
||||
let crashes = 0
|
||||
for (let index = 0; index < count; index++) {
|
||||
const result = spawnSync(binary, [], { env, encoding: "utf8", timeout: 35_000, windowsHide: true })
|
||||
assert.equal(result.error, undefined, String(result.error))
|
||||
assert.match(result.stdout, /START: concurrent Tauri runtime handle cloning/)
|
||||
if (fixed) {
|
||||
assert.equal(result.status, 0, result.stdout + result.stderr)
|
||||
assert.match(result.stdout, /PASS: 800000 runtime handle clones and clean teardown/)
|
||||
} else if (result.status !== 0) {
|
||||
// Native heap/access failures and Rust's abort on an invalid Rc refcount.
|
||||
assert.ok([0xc000001d, 0xc0000005, 0xc0000374, 0xc0000409].includes(result.status >>> 0),
|
||||
`Expected the native refcount failure, got ${result.status}: ${result.stdout}${result.stderr}`)
|
||||
crashes++
|
||||
} else {
|
||||
// A refcount race can leak rather than free early. One surviving process
|
||||
// is not a clean baseline; the bounded negative-control series must crash.
|
||||
assert.match(result.stdout, /PASS: 800000 runtime handle clones and clean teardown/)
|
||||
}
|
||||
console.log(`${fixed ? "fixed PASS" : result.status === 0 ? "negative control survived" : "negative control crash reproduced"} ${index + 1}/${count}: 0x${(result.status >>> 0).toString(16)}`)
|
||||
}
|
||||
if (!fixed) assert.ok(crashes > 0, "Negative control did not reproduce the native race")
|
||||
}
|
||||
function replaceOnce(source, before, after) {
|
||||
assert.equal(source.split(before).length, 2, `Expected one counter boundary: ${before}`)
|
||||
return source.replace(before, after)
|
||||
}
|
||||
|
||||
if (process.argv.includes("--baseline")) {
|
||||
const temporaryRoot = path.join(os.tmpdir(), "opencode")
|
||||
await mkdir(temporaryRoot, { recursive: true })
|
||||
const baseline = await mkdtemp(path.join(temporaryRoot, "tauri-runner-baseline-"))
|
||||
try {
|
||||
await cp(path.join(workspace, fixture), path.join(baseline, fixture), { recursive: true })
|
||||
await cp(path.join(workspace, "vendor/tao-0.34.6"), path.join(baseline, "tao"), { recursive: true })
|
||||
await cp(path.join(workspace, "Cargo.lock"), path.join(baseline, "Cargo.lock"))
|
||||
const manifest = "src-tauri/examples/window_constraints_windows.manifest"
|
||||
await mkdir(path.dirname(path.join(baseline, manifest)), { recursive: true })
|
||||
await cp(path.join(workspace, manifest), path.join(baseline, manifest))
|
||||
await writeFile(path.join(baseline, "Cargo.toml"), `[workspace]\nmembers = ["${fixture}"]\nresolver = "2"\n[patch.crates-io]\ntao = { path = "tao" }\n`)
|
||||
// Reverse only this correction in a temporary copy. Existing input and macOS
|
||||
// backports, dependencies and the public Wry API exercised remain identical.
|
||||
const runner = path.join(baseline, "tao/src/platform_impl/windows/event_loop/runner.rs")
|
||||
let source = await readFile(runner, "utf8")
|
||||
source = replaceOnce(source, " sync::Arc,", " rc::Rc,")
|
||||
source = replaceOnce(source, "= Arc<EventLoopRunner<T>>;", "= Rc<EventLoopRunner<T>>;")
|
||||
await writeFile(runner, source)
|
||||
const loopFile = path.join(baseline, "tao/src/platform_impl/windows/event_loop.rs")
|
||||
await writeFile(loopFile, replaceOnce(await readFile(loopFile, "utf8"),
|
||||
"let runner_shared = Arc::new(", "let runner_shared = std::rc::Rc::new("))
|
||||
cargo(["build", "--release", "-p", "codenomad-windows-runner-fixture"], baseline)
|
||||
run(false, 10)
|
||||
} finally { await rm(baseline, { recursive: true, force: true }) }
|
||||
}
|
||||
|
||||
const metadata = JSON.parse(cargo(["metadata", "--locked", "--format-version", "1"]))
|
||||
const tao = metadata.packages.filter(item => item.name === "tao")
|
||||
assert.equal(tao.length, 1)
|
||||
assert.equal(path.resolve(tao[0].manifest_path), path.join(workspace, "vendor/tao-0.34.6/Cargo.toml"))
|
||||
cargo(["build", "--locked", "--release", "-p", "codenomad-windows-runner-fixture"])
|
||||
run(true, 5)
|
||||
Loading…
Add table
Add a link
Reference in a new issue