diff --git a/.anvil.lock b/.anvil.lock
index 6b9924dd..649f032b 100644
--- a/.anvil.lock
+++ b/.anvil.lock
@@ -1,7 +1,7 @@
version = 1
tool = "anvil"
-tool_version = "0.11.0"
-catalog_checksum = "sha256:8902caf297ad65a158418bd2ab41801a95c600c99b6140d51c9e7a440000cffa"
+tool_version = "0.11.1"
+catalog_checksum = "sha256:b5e3da36fa7754d780c43c77e2cff46232de54a440b0798c91f085d2830eee3c"
[[file]]
path = ".anvil/container/Dockerfile.dockerignore"
@@ -125,7 +125,7 @@ checksum = "sha256:7aa0560dc9088b33e80cd55aee0a25090cbd3d3610652afd3734d0ca52ee7
[[file]]
path = "justfiles/anvil/checks/llvm-cov.just"
-checksum = "sha256:662c85b748f87a0a294e34588ab294851562896739b5cc11f9ad895699e06a94"
+checksum = "sha256:5c4d7454b67503ce68a4d68df1783989f5afabc763df5e343bf7abddf974c387"
[[file]]
path = "justfiles/anvil/checks/loom.just"
diff --git a/Cargo.lock b/Cargo.lock
index d5bb99c6..3fcbcc21 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -415,7 +415,7 @@ dependencies = [
[[package]]
name = "cargo-anvil"
-version = "0.11.0"
+version = "0.11.1"
dependencies = [
"assert_cmd",
"clap",
diff --git a/crates/cargo-anvil/CHANGELOG.md b/crates/cargo-anvil/CHANGELOG.md
index 7705b6f2..9d74c8f4 100644
--- a/crates/cargo-anvil/CHANGELOG.md
+++ b/crates/cargo-anvil/CHANGELOG.md
@@ -2,6 +2,13 @@
## [Unreleased]
+## [0.11.1] - 2026-09-21
+
+- 🐛 Bug Fixes
+
+ - normalize shell-quoted coverage arguments
+ - parse single-quoted llvm-cov paths
+
## [0.11.0] - 2026-09-17
- 🐛 Bug Fixes
diff --git a/crates/cargo-anvil/Cargo.toml b/crates/cargo-anvil/Cargo.toml
index dc3d34d4..05b80759 100644
--- a/crates/cargo-anvil/Cargo.toml
+++ b/crates/cargo-anvil/Cargo.toml
@@ -3,7 +3,7 @@
[package]
name = "cargo-anvil"
-version = "0.11.0"
+version = "0.11.1"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
diff --git a/crates/cargo-anvil/README.md b/crates/cargo-anvil/README.md
index 13e5ed12..e5a2e9a9 100644
--- a/crates/cargo-anvil/README.md
+++ b/crates/cargo-anvil/README.md
@@ -400,7 +400,7 @@ More detailed design and operational guidance is available in the
This crate was developed as part of The Oxidizer Project. Browse this crate's source code.
- [__cargo_doc2readme_dependencies_info]: ggGmYW0CYXZlMC43LjNhdIQblRYhli3L8qob_NSi_WYo69wbWnMVqZw3jJwb3u56HnT6RDphYvRhcoQbBALu36V1VAYbFUDdfp-8dCobobFjKbRep8AbYNMPgi_aMhFhZIGDa2NhcmdvLWFudmlsZjAuMTEuMGtjYXJnb19hbnZpbA
+ [__cargo_doc2readme_dependencies_info]: ggGmYW0CYXZlMC43LjNhdIQblRYhli3L8qob_NSi_WYo69wbWnMVqZw3jJwb3u56HnT6RDphYvRhcoQbBALu36V1VAYbFUDdfp-8dCobobFjKbRep8AbYNMPgi_aMhFhZIGDa2NhcmdvLWFudmlsZjAuMTEuMWtjYXJnb19hbnZpbA
[__link0]: https://github.com/casey/just
[__link1]: https://rust-lang.github.io/rustfmt/
[__link10]: https://embarkstudios.github.io/cargo-deny/
@@ -419,9 +419,9 @@ This crate was developed as part of The Oxidizer Project. Br
[__link22]: https://mutants.rs/
[__link23]: https://crates.io/crates/cargo-hack
[__link24]: https://crates.io/crates/cargo-coverage-gate
- [__link25]: https://docs.rs/cargo-anvil/0.11.0/cargo_anvil/?search=Catalog::anvil
- [__link26]: https://docs.rs/cargo-anvil/0.11.0/cargo_anvil/?search=Artifact
- [__link27]: https://docs.rs/cargo-anvil/0.11.0/cargo_anvil/fn.run_app.html
+ [__link25]: https://docs.rs/cargo-anvil/0.11.1/cargo_anvil/?search=Catalog::anvil
+ [__link26]: https://docs.rs/cargo-anvil/0.11.1/cargo_anvil/?search=Artifact
+ [__link27]: https://docs.rs/cargo-anvil/0.11.1/cargo_anvil/fn.run_app.html
[__link3]: https://crates.io/crates/cargo-sort
[__link4]: https://crates.io/crates/cargo-heather
[__link5]: https://crates.io/crates/cargo-ensure-no-cyclic-deps
diff --git a/crates/cargo-anvil/templates/justfiles/anvil/checks/llvm-cov.just b/crates/cargo-anvil/templates/justfiles/anvil/checks/llvm-cov.just
index 99e1cb19..a4531ecb 100644
--- a/crates/cargo-anvil/templates/justfiles/anvil/checks/llvm-cov.just
+++ b/crates/cargo-anvil/templates/justfiles/anvil/checks/llvm-cov.just
@@ -131,7 +131,7 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
}
$command = [regex]::Match(
$failedProcess.Groups['command'].Value,
- '(?s)^(?:"(?[^"]+)"|(?\S+))\s+export\s+(?.*)$'
+ '(?s)^(?:"(?[^"]+)"|''(?[^'']+)''|(?\S+))\s+export\s+(?.*)$'
)
if (-not $command.Success) {
Write-Warning 'anvil-llvm-cov: the failed process was not an llvm-cov export command'
@@ -139,6 +139,8 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
}
$llvmCov = if ($command.Groups['quoted'].Success) {
$command.Groups['quoted'].Value
+ } elseif ($command.Groups['singleQuoted'].Success) {
+ $command.Groups['singleQuoted'].Value
} else {
$command.Groups['bare'].Value
}
@@ -147,10 +149,15 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
return $reportExitCode
}
$responsePath = [System.IO.Path]::GetFullPath("$OutputPath.llvm-cov.rsp")
+ $responseArguments = [regex]::Replace(
+ $command.Groups['arguments'].Value,
+ "'(?[^']*)'",
+ { param($match) '"' + $match.Groups['value'].Value.Replace('"', '\"') + '"' }
+ )
try {
[System.IO.File]::WriteAllText(
$responsePath,
- $command.Groups['arguments'].Value,
+ $responseArguments,
[System.Text.UTF8Encoding]::new($false)
)
Write-Host 'anvil-llvm-cov: retrying Windows error 206 with an LLVM response file'
diff --git a/crates/cargo-anvil/tests/recipe_contracts.rs b/crates/cargo-anvil/tests/recipe_contracts.rs
index ae618668..d87229ef 100644
--- a/crates/cargo-anvil/tests/recipe_contracts.rs
+++ b/crates/cargo-anvil/tests/recipe_contracts.rs
@@ -359,9 +359,16 @@ if ($args -contains 'bolero' -and $args -contains 'list') {
exit [int]$env:FAKE_BOLERO_LIST_EXIT
}
if ($args -contains 'llvm-cov' -and $args -contains 'report' -and $env:FAKE_LLVM_COV_REPORT_206) {
- $command = "$([char]34)$($env:FAKE_LLVM_COV_PATH)$([char]34) export -format=lcov -instr-profile=fake.profdata -object fake-object.exe"
+ $quote = if ($env:FAKE_LLVM_COV_SINGLE_QUOTES) { [char]39 } else { [char]34 }
+ $arguments = if ($env:FAKE_LLVM_COV_SINGLE_QUOTES) {
+ "'-format=lcov' '-instr-profile=fake.profdata' '-object' 'fake-object.exe'"
+ } else {
+ '-format=lcov -instr-profile=fake.profdata -object fake-object.exe'
+ }
+ $command = "$quote$($env:FAKE_LLVM_COV_PATH)$quote export $arguments"
if ($env:FAKE_LLVM_COV_MULTILINE) {
- $command = $command.Replace(' -object', "`n-object")
+ $objectArgument = if ($env:FAKE_LLVM_COV_SINGLE_QUOTES) { " '-object'" } else { ' -object' }
+ $command = $command.Replace($objectArgument, "`n$($objectArgument.TrimStart())")
}
Write-Output (
"error: failed to generate report: could not execute process $([char]96)$command$([char]96) " +
@@ -2372,6 +2379,10 @@ fn coverage_reports_use_requested_package_scope() {
#[cfg(all(windows, not(target_arch = "aarch64")))]
#[test]
+#[expect(
+ clippy::too_many_lines,
+ reason = "one end-to-end fixture covers successful and failed response-file retries"
+)]
fn windows_coverage_report_retries_error_206_with_response_file() {
if !tools_available() {
return;
@@ -2399,7 +2410,10 @@ fn windows_coverage_report_retries_error_206_with_response_file() {
Add-Content -LiteralPath $env:FAKE_LLVM_COV_LOG -Value ($Remaining -join ' ')\n\
$response = $Remaining | Where-Object { $_.StartsWith('@') } | Select-Object -First 1\n\
if (-not $response) { exit 2 }\n\
- Add-Content -LiteralPath $env:FAKE_LLVM_COV_RESPONSE_LOG -Value (Get-Content -LiteralPath $response.Substring(1) -Raw)\n\
+ $responseContent = Get-Content -LiteralPath $response.Substring(1) -Raw\n\
+ if ($responseContent -match \"'\") { exit 3 }\n\
+ if ($responseContent -notmatch '-instr-profile=fake.profdata') { exit 4 }\n\
+ Add-Content -LiteralPath $env:FAKE_LLVM_COV_RESPONSE_LOG -Value $responseContent\n\
Write-Output 'TN:'\n\
if ($env:FAKE_LLVM_COV_EXIT) { exit [int]$env:FAKE_LLVM_COV_EXIT }\n\
exit 0\n",
@@ -2412,6 +2426,7 @@ fn windows_coverage_report_retries_error_206_with_response_file() {
("FAKE_SECOND_PACKAGE_NAME", OsStr::new("measured")),
("FAKE_LLVM_COV_REPORT_206", OsStr::new("1")),
("FAKE_LLVM_COV_MULTILINE", OsStr::new("1")),
+ ("FAKE_LLVM_COV_SINGLE_QUOTES", OsStr::new("1")),
("FAKE_LLVM_COV_PATH", llvm_cov.as_os_str()),
("FAKE_LLVM_COV_LOG", llvm_cov_log.as_os_str()),
("FAKE_LLVM_COV_RESPONSE_LOG", response_log.as_os_str()),
@@ -2428,7 +2443,11 @@ fn windows_coverage_report_retries_error_206_with_response_file() {
assert_eq!(invocations.lines().count(), 2, "invocations:\n{invocations}");
assert_eq!(invocations.matches("export @").count(), 2, "invocations:\n{invocations}");
let responses = fs::read_to_string(&response_log).unwrap();
- assert_eq!(responses.matches("-object fake-object.exe").count(), 2, "responses:\n{responses}");
+ assert_eq!(
+ responses.matches("\n\"-object\" \"fake-object.exe\"").count(),
+ 2,
+ "both reports must preserve the multiline command shape:\n{responses}"
+ );
for config in ["all-features", "no-default"] {
let report = tmp.path().join(format!("target/coverage/lcov-{config}.info"));
assert_eq!(fs::read_to_string(report).unwrap().trim(), "TN:");
@@ -2455,6 +2474,12 @@ fn windows_coverage_report_retries_error_206_with_response_file() {
],
);
assert_failed(&failed, "failed response-file fallback");
+ let invocations = fs::read_to_string(&llvm_cov_log).unwrap();
+ assert_eq!(
+ invocations.lines().count(),
+ 3,
+ "both quote styles must reach llvm-cov:\n{invocations}"
+ );
let failed_report = tmp.path().join("target/coverage/lcov-all-features.info");
assert!(!failed_report.exists(), "failed response-file fallback must remove partial report");
assert!(
diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap b/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap
index 86e4f837..75056f9c 100644
--- a/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap
+++ b/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap
@@ -2858,7 +2858,7 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
}
$command = [regex]::Match(
$failedProcess.Groups['command'].Value,
- '(?s)^(?:"(?[^"]+)"|(?\S+))\s+export\s+(?.*)$'
+ '(?s)^(?:"(?[^"]+)"|''(?[^'']+)''|(?\S+))\s+export\s+(?.*)$'
)
if (-not $command.Success) {
Write-Warning 'anvil-llvm-cov: the failed process was not an llvm-cov export command'
@@ -2866,6 +2866,8 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
}
$llvmCov = if ($command.Groups['quoted'].Success) {
$command.Groups['quoted'].Value
+ } elseif ($command.Groups['singleQuoted'].Success) {
+ $command.Groups['singleQuoted'].Value
} else {
$command.Groups['bare'].Value
}
@@ -2874,10 +2876,15 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
return $reportExitCode
}
$responsePath = [System.IO.Path]::GetFullPath("$OutputPath.llvm-cov.rsp")
+ $responseArguments = [regex]::Replace(
+ $command.Groups['arguments'].Value,
+ "'(?[^']*)'",
+ { param($match) '"' + $match.Groups['value'].Value.Replace('"', '\"') + '"' }
+ )
try {
[System.IO.File]::WriteAllText(
$responsePath,
- $command.Groups['arguments'].Value,
+ $responseArguments,
[System.Text.UTF8Encoding]::new($false)
)
Write-Host 'anvil-llvm-cov: retrying Windows error 206 with an LLVM response file'
diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap b/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap
index edbb39d9..29ecea51 100644
--- a/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap
+++ b/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap
@@ -2971,7 +2971,7 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
}
$command = [regex]::Match(
$failedProcess.Groups['command'].Value,
- '(?s)^(?:"(?[^"]+)"|(?\S+))\s+export\s+(?.*)$'
+ '(?s)^(?:"(?[^"]+)"|''(?[^'']+)''|(?\S+))\s+export\s+(?.*)$'
)
if (-not $command.Success) {
Write-Warning 'anvil-llvm-cov: the failed process was not an llvm-cov export command'
@@ -2979,6 +2979,8 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
}
$llvmCov = if ($command.Groups['quoted'].Success) {
$command.Groups['quoted'].Value
+ } elseif ($command.Groups['singleQuoted'].Success) {
+ $command.Groups['singleQuoted'].Value
} else {
$command.Groups['bare'].Value
}
@@ -2987,10 +2989,15 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
return $reportExitCode
}
$responsePath = [System.IO.Path]::GetFullPath("$OutputPath.llvm-cov.rsp")
+ $responseArguments = [regex]::Replace(
+ $command.Groups['arguments'].Value,
+ "'(?[^']*)'",
+ { param($match) '"' + $match.Groups['value'].Value.Replace('"', '\"') + '"' }
+ )
try {
[System.IO.File]::WriteAllText(
$responsePath,
- $command.Groups['arguments'].Value,
+ $responseArguments,
[System.Text.UTF8Encoding]::new($false)
)
Write-Host 'anvil-llvm-cov: retrying Windows error 206 with an LLVM response file'
diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap b/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap
index d2930f28..27a43ff4 100644
--- a/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap
+++ b/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap
@@ -1655,7 +1655,7 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
}
$command = [regex]::Match(
$failedProcess.Groups['command'].Value,
- '(?s)^(?:"(?[^"]+)"|(?\S+))\s+export\s+(?.*)$'
+ '(?s)^(?:"(?[^"]+)"|''(?[^'']+)''|(?\S+))\s+export\s+(?.*)$'
)
if (-not $command.Success) {
Write-Warning 'anvil-llvm-cov: the failed process was not an llvm-cov export command'
@@ -1663,6 +1663,8 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
}
$llvmCov = if ($command.Groups['quoted'].Success) {
$command.Groups['quoted'].Value
+ } elseif ($command.Groups['singleQuoted'].Success) {
+ $command.Groups['singleQuoted'].Value
} else {
$command.Groups['bare'].Value
}
@@ -1671,10 +1673,15 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
return $reportExitCode
}
$responsePath = [System.IO.Path]::GetFullPath("$OutputPath.llvm-cov.rsp")
+ $responseArguments = [regex]::Replace(
+ $command.Groups['arguments'].Value,
+ "'(?[^']*)'",
+ { param($match) '"' + $match.Groups['value'].Value.Replace('"', '\"') + '"' }
+ )
try {
[System.IO.File]::WriteAllText(
$responsePath,
- $command.Groups['arguments'].Value,
+ $responseArguments,
[System.Text.UTF8Encoding]::new($false)
)
Write-Host 'anvil-llvm-cov: retrying Windows error 206 with an LLVM response file'
diff --git a/justfiles/anvil/checks/llvm-cov.just b/justfiles/anvil/checks/llvm-cov.just
index 99e1cb19..a4531ecb 100644
--- a/justfiles/anvil/checks/llvm-cov.just
+++ b/justfiles/anvil/checks/llvm-cov.just
@@ -131,7 +131,7 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
}
$command = [regex]::Match(
$failedProcess.Groups['command'].Value,
- '(?s)^(?:"(?[^"]+)"|(?\S+))\s+export\s+(?.*)$'
+ '(?s)^(?:"(?[^"]+)"|''(?[^'']+)''|(?\S+))\s+export\s+(?.*)$'
)
if (-not $command.Success) {
Write-Warning 'anvil-llvm-cov: the failed process was not an llvm-cov export command'
@@ -139,6 +139,8 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
}
$llvmCov = if ($command.Groups['quoted'].Success) {
$command.Groups['quoted'].Value
+ } elseif ($command.Groups['singleQuoted'].Success) {
+ $command.Groups['singleQuoted'].Value
} else {
$command.Groups['bare'].Value
}
@@ -147,10 +149,15 @@ anvil-llvm-cov: anvil-llvm-cov-validate-prereqs anvil-impact
return $reportExitCode
}
$responsePath = [System.IO.Path]::GetFullPath("$OutputPath.llvm-cov.rsp")
+ $responseArguments = [regex]::Replace(
+ $command.Groups['arguments'].Value,
+ "'(?[^']*)'",
+ { param($match) '"' + $match.Groups['value'].Value.Replace('"', '\"') + '"' }
+ )
try {
[System.IO.File]::WriteAllText(
$responsePath,
- $command.Groups['arguments'].Value,
+ $responseArguments,
[System.Text.UTF8Encoding]::new($false)
)
Write-Host 'anvil-llvm-cov: retrying Windows error 206 with an LLVM response file'