Extract toolchain archives into a staging folder and gate on the executable - #4940
Conversation
…utable ExtractTask now extracts into a sibling staging folder and moves it into place once every archive is extracted, so a build killed mid-extraction leaves no destination folder behind. The slicec and protoc extraction steps are now skipped only when the extracted executable exists, so a folder left without its executable is re-extracted on the next build instead of failing the following Copy with MSB3030. Fixes icerpc#4800
There was a problem hiding this comment.
🔵 Needs a closer look
Orphaned .extracting folders can remain after an interrupted extraction.
Pull request overview
This PR hardens toolchain archive extraction against interrupted builds.
Changes:
- Extracts archives into a staging directory before replacement.
- Re-extracts when
slicecorprotocis missing.
File summaries
| File | Summary |
|---|---|
src/IceRpc.Slice.Tools/IceRpc.Slice.Tools.csproj |
Gates extraction on slicec and needs staging cleanup handling. |
src/IceRpc.Protobuf.Tools/IceRpc.Protobuf.Tools.csproj |
Gates extraction on protoc and needs staging cleanup handling. |
build/ExtractTask.cs |
Implements staged extraction and cleanup. |
Review details
Suppressed comments (2)
src/IceRpc.Protobuf.Tools/IceRpc.Protobuf.Tools.csproj:97
- If the process is hard-killed after extraction has completed into
<destination>.extractingbut beforeDirectory.Move, the previous destination can still containprotoc. On the next build this condition is false, soExtractTasknever runs its staging cleanup and the complete or partial duplicate.extractingfolder remains indefinitely. Include the staging path in the condition or run a cleanup target independently of the executable check.
Condition="!Exists('$(MSBuildThisFileDirectory)obj/protoc-$(ProtobufVersion)-osx-aarch_64/bin/protoc')" />
src/IceRpc.Slice.Tools/IceRpc.Slice.Tools.csproj:110
- If the process is hard-killed after extraction has completed into
<destination>.extractingbut beforeDirectory.Move, the previous destination can still containslicec. On the next build this condition is false, soExtractTasknever runs its staging cleanup and the complete or partial duplicate.extractingfolder remains indefinitely. Include the staging path in the condition or run a cleanup target independently of the executable check.
Condition="!Exists('$(MSBuildThisFileDirectory)obj/slicec-$(SlicecVersion)-%(SlicecPlatform.Identity)/%(SlicecPlatform.Exe)')" />
- Files reviewed: 3/3 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
🤖 Claude: On the "Orphaned The premise that the destination can still contain the executable while a stale staging folder exists does not hold. Verified with a build-level check that reproduces the exact state described (a complete The only leftover still possible is a staging folder for a toolchain version that was bumped between the kill and the next build. It accumulates the same way the per-version zips and extracted folders already do in |
Co-authored-by: Bernard Normier <bernard@zeroc.com>
ExtractTaskunzipped the slicec and protoc archives straight into their finalobj/folder, and the extraction stepwas skipped whenever that folder existed. A build killed mid-extraction (hard kill, disk full, power loss) therefore
left a partial folder that was never re-extracted: the following
Copyfailed with MSB3030, or copied a truncatedexecutable, until the developer removed
obj/by hand.This PR makes the extraction all-or-nothing and self-healing:
ExtractTaskextracts into a sibling<folder>.extractingstaging folder and moves it into place once every archiveis extracted. The staging folder is removed on failure and replaced on the next run.
without its executable is re-extracted on the next build instead of failing the following
Copy.Verified locally on macOS: a zip with a corrupt entry no longer leaves a destination folder behind, Unix executable
permissions are still preserved, a slicec or protoc folder whose executable was deleted heals on rebuild, and the
full solution builds. The task only uses netstandard 2.0 APIs, which is what
RoslynCodeTaskFactorycompiles against.Fixes #4800
What's Changed entry
None — build-system change to how this repository downloads its own toolchain; no user-facing impact.