Migrate file I/O tasks to multithreadable task API#12914
Merged
JanProvaznik merged 56 commits intodotnet:mainfrom Jan 26, 2026
Merged
Migrate file I/O tasks to multithreadable task API#12914JanProvaznik merged 56 commits intodotnet:mainfrom
JanProvaznik merged 56 commits intodotnet:mainfrom
Conversation
…n status Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com>
…s section Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com>
- Updated FileState.cs to accept TaskEnvironment parameter - Migrated 7 File I/O tasks to IMultiThreadableTask: * Copy - added attribute, interface, TaskEnvironment property and updated path/environment access * Delete - migrated with proper path resolution * MakeDir - migrated with path deduplication * RemoveDir - migrated with directory operations * Touch - migrated with file timestamp operations * ReadLinesFromFile - migrated for file reading * WriteLinesToFile - migrated for file writing - All tasks use MSBuildMultiThreadableTaskAttribute for routing - All tasks implement IMultiThreadableTask for TaskEnvironment access - Tasks use TaskEnvironment.GetAbsolutePath() for thread-safe path resolution - Tasks use TaskEnvironment.GetEnvironmentVariable() for thread-safe environment access Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR converts several file I/O tasks to support multi-threaded execution by implementing IMultiThreadableTask and using TaskEnvironment for thread-safe path resolution. The changes replace static path resolution methods with instance-based TaskEnvironment.GetAbsolutePath() calls to ensure proper path handling in concurrent scenarios.
Key Changes:
- Added
IMultiThreadableTaskinterface and[MSBuildMultiThreadableTask]attribute to 7 file I/O task classes - Introduced
TaskEnvironmentproperty to all modified tasks for thread-safe operations - Modified
FileStateconstructor to requireTaskEnvironmentparameter and use it for path resolution
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Tasks/Touch.cs | Added multithreading support; uses TaskEnvironment for path resolution in TouchFile method |
| src/Tasks/RemoveDir.cs | Added multithreading support; resolves paths using TaskEnvironment in Execute and RemoveDirectory methods |
| src/Tasks/MakeDir.cs | Added multithreading support; uses TaskEnvironment for path resolution and deduplication |
| src/Tasks/FileState.cs | Modified constructor to require TaskEnvironment parameter; uses it for absolute path resolution in Lazy initialization |
| src/Tasks/FileIO/WriteLinesToFile.cs | Added multithreading support; uses TaskEnvironment for path resolution instead of FileUtilities.NormalizePath |
| src/Tasks/FileIO/ReadLinesFromFile.cs | Added multithreading support; resolves file paths using TaskEnvironment before file operations |
| src/Tasks/Delete.cs | Added multithreading support; uses TaskEnvironment for path resolution in delete operations |
| src/Tasks/Copy.cs | Added multithreading support; uses TaskEnvironment for path resolution, environment variables, and FileState construction; changed PathsAreIdentical from static to instance method |
AR-May
approved these changes
Dec 19, 2025
Member
AR-May
left a comment
There was a problem hiding this comment.
LGTM, but I would like one more review to ensure there is no behavior change in multi process mode.
AR-May
added a commit
that referenced
this pull request
Jan 21, 2026
### Context PRs #12914 and #12868 showed that we need to be able to fix and normalize `AbsolutePath`. Corresponding methods for strings live in `FileUtilities.cs` that is a Shared file and cannot reference Framework classes like `AbsolutePath`. ### Changes Made - Moved some related functions to FrameworkFileUtilities class. - Added the needed functions for `AbsolutePath` ### Testing unit tests
johnazule
pushed a commit
to johnazule/msbuild
that referenced
this pull request
Jan 22, 2026
…#13079) ### Context PRs dotnet#12914 and dotnet#12868 showed that we need to be able to fix and normalize `AbsolutePath`. Corresponding methods for strings live in `FileUtilities.cs` that is a Shared file and cannot reference Framework classes like `AbsolutePath`. ### Changes Made - Moved some related functions to FrameworkFileUtilities class. - Added the needed functions for `AbsolutePath` ### Testing unit tests
AR-May
reviewed
Jan 23, 2026
AR-May
reviewed
Jan 23, 2026
rainersigwald
approved these changes
Jan 23, 2026
Member
|
[celebrate] Yuliia Kovalova reacted to your message:
…________________________________
From: Jan Provazník ***@***.***>
Sent: Monday, January 26, 2026 9:36:11 AM
To: dotnet/msbuild ***@***.***>
Cc: Yuliia Kovalova ***@***.***>; Review requested ***@***.***>
Subject: Re: [dotnet/msbuild] Migrate file I/O tasks to multithreadable task API (PR #12914)
Merged #12914<#12914> into main.
—
Reply to this email directly, view it on GitHub<#12914 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AWYM53WTVD6AU4AVU3GUXOL4IXNYXAVCNFSM6AAAAACOUJ74G2VHI2DSMVQWIX3LMV45UABCJFZXG5LFIV3GK3TUJZXXI2LGNFRWC5DJN5XDWMRSGI4DINZZGM3TOMQ>.
You are receiving this because your review was requested.Message ID: ***@***.***>
|
This was referenced Jan 26, 2026
This was referenced Jan 27, 2026
SimaTian
pushed a commit
that referenced
this pull request
Feb 5, 2026
### Context Migrates the Unzip task to use the `TaskEnvironment` API for thread-safe path resolution, following the pattern established in #12914. This enables the task to run safely in MSBuild's multithreaded execution model. ### Changes Made - Add `IMultiThreadableTask` interface and `[MSBuildMultiThreadableTask]` attribute to `Unzip` class - Add `TaskEnvironment` property - Replace `Path.GetFullPath()` with `TaskEnvironment.GetAbsolutePath()` for: - Destination folder creation (inside try block for proper error handling) - Source file path resolution (wrapped in try-catch to continue processing on invalid paths) - Keep `Path.GetFullPath()` in the `Extract` method for DirectoryInfo-based paths where it's cleaner - Update all unit tests to provide `TaskEnvironmentHelper.CreateForTest()` when instantiating the task ### Testing - All 14 Unzip unit tests pass - Updated all test instantiations to provide `TaskEnvironmentHelper.CreateForTest()` ### Notes - The `GetAbsolutePath` calls are wrapped in try-catch blocks to handle exceptions from invalid paths gracefully - The zip-slip exploit protection continues to use `Path.GetFullPath()` on `DirectoryInfo.FullName` as it's cleaner for paths that are already absolute <!-- START COPILOT CODING AGENT SUFFIX --> <!-- START COPILOT ORIGINAL PROMPT --> <details> <summary>Original prompt</summary> > Migrate the Unzip task to use TaskEnvironment API based on the pattern used here: #12914 > > Make sure to preserve correctness, performance and that the tests pass </details> <!-- START COPILOT CODING AGENT TIPS --> --- 💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey). --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com>
JanProvaznik
added a commit
that referenced
this pull request
Feb 5, 2026
### Context Follows PR #12914 pattern. `DirectoryInfo`/`FileInfo` internally use `Path.GetFullPath()` which relies on process-global current working directory—not thread-safe when tasks run in parallel. The `TaskEnvironment.GetAbsolutePath()` API provides thread-safe path resolution using the task's execution context. ### Changes Made **ZipDirectory.cs** - Implement `IMultiThreadableTask`, add `[MSBuildMultiThreadableTask]` attribute - Add `TaskEnvironment` property - Use `TaskEnvironment.GetAbsolutePath()` to resolve paths, then create `DirectoryInfo`/`FileInfo` with the absolute path - Keep `BuildEngine3.Yield()`/`Reacquire()` calls (still needed for concurrency control) **ZipDirectory_Tests.cs** - Set `TaskEnvironment = TaskEnvironmentHelper.CreateForTest()` on all test instances ### Testing All 9 ZipDirectory tests pass. ### Notes Preserves existing behavior including error handling flow where exceptions during zip creation log an error and return via `!Log.HasLoggedErrors`. Uses `.FullName` in error messages to match original behavior. <!-- START COPILOT CODING AGENT SUFFIX --> <!-- START COPILOT ORIGINAL PROMPT --> <details> <summary>Original prompt</summary> > Migrate the ZipDirectory task to use TaskEnvironment API based on the pattern used here: #12914 > > Make sure to preserve correctness, performance and that the tests pass </details> <!-- START COPILOT CODING AGENT TIPS --> --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com>
JanProvaznik
added a commit
that referenced
this pull request
Feb 6, 2026
Thanks for asking me to work on this. I will get started on it and keep this PR's description up to date as I form a plan and make progress. <!-- START COPILOT ORIGINAL PROMPT --> <details> <summary>Original prompt</summary> > Migrate the DownloadFile task to use TaskEnvironment API based on the pattern used here: #12914 > > Make sure to preserve correctness, performance and that the tests pass </details> <!-- START COPILOT CODING AGENT TIPS --> --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com>
JanProvaznik
added a commit
to JanProvaznik/msbuild
that referenced
this pull request
Feb 25, 2026
### Context Migrates the Unzip task to use the `TaskEnvironment` API for thread-safe path resolution, following the pattern established in dotnet#12914. This enables the task to run safely in MSBuild's multithreaded execution model. ### Changes Made - Add `IMultiThreadableTask` interface and `[MSBuildMultiThreadableTask]` attribute to `Unzip` class - Add `TaskEnvironment` property - Replace `Path.GetFullPath()` with `TaskEnvironment.GetAbsolutePath()` for: - Destination folder creation (inside try block for proper error handling) - Source file path resolution (wrapped in try-catch to continue processing on invalid paths) - Keep `Path.GetFullPath()` in the `Extract` method for DirectoryInfo-based paths where it's cleaner - Update all unit tests to provide `TaskEnvironmentHelper.CreateForTest()` when instantiating the task ### Testing - All 14 Unzip unit tests pass - Updated all test instantiations to provide `TaskEnvironmentHelper.CreateForTest()` ### Notes - The `GetAbsolutePath` calls are wrapped in try-catch blocks to handle exceptions from invalid paths gracefully - The zip-slip exploit protection continues to use `Path.GetFullPath()` on `DirectoryInfo.FullName` as it's cleaner for paths that are already absolute <!-- START COPILOT CODING AGENT SUFFIX --> <!-- START COPILOT ORIGINAL PROMPT --> <details> <summary>Original prompt</summary> > Migrate the Unzip task to use TaskEnvironment API based on the pattern used here: dotnet#12914 > > Make sure to preserve correctness, performance and that the tests pass </details> <!-- START COPILOT CODING AGENT TIPS --> --- 💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey). --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com>
JanProvaznik
added a commit
to JanProvaznik/msbuild
that referenced
this pull request
Feb 25, 2026
### Context Follows PR dotnet#12914 pattern. `DirectoryInfo`/`FileInfo` internally use `Path.GetFullPath()` which relies on process-global current working directory—not thread-safe when tasks run in parallel. The `TaskEnvironment.GetAbsolutePath()` API provides thread-safe path resolution using the task's execution context. ### Changes Made **ZipDirectory.cs** - Implement `IMultiThreadableTask`, add `[MSBuildMultiThreadableTask]` attribute - Add `TaskEnvironment` property - Use `TaskEnvironment.GetAbsolutePath()` to resolve paths, then create `DirectoryInfo`/`FileInfo` with the absolute path - Keep `BuildEngine3.Yield()`/`Reacquire()` calls (still needed for concurrency control) **ZipDirectory_Tests.cs** - Set `TaskEnvironment = TaskEnvironmentHelper.CreateForTest()` on all test instances ### Testing All 9 ZipDirectory tests pass. ### Notes Preserves existing behavior including error handling flow where exceptions during zip creation log an error and return via `!Log.HasLoggedErrors`. Uses `.FullName` in error messages to match original behavior. <!-- START COPILOT CODING AGENT SUFFIX --> <!-- START COPILOT ORIGINAL PROMPT --> <details> <summary>Original prompt</summary> > Migrate the ZipDirectory task to use TaskEnvironment API based on the pattern used here: dotnet#12914 > > Make sure to preserve correctness, performance and that the tests pass </details> <!-- START COPILOT CODING AGENT TIPS --> --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com>
JanProvaznik
added a commit
to JanProvaznik/msbuild
that referenced
this pull request
Feb 25, 2026
Thanks for asking me to work on this. I will get started on it and keep this PR's description up to date as I form a plan and make progress. <!-- START COPILOT ORIGINAL PROMPT --> <details> <summary>Original prompt</summary> > Migrate the DownloadFile task to use TaskEnvironment API based on the pattern used here: dotnet#12914 > > Make sure to preserve correctness, performance and that the tests pass </details> <!-- START COPILOT CODING AGENT TIPS --> --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: JanProvaznik <25267098+JanProvaznik@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fixes #12484
This PR migrates several file I/O tasks to use the new multithreadable task API by implementing the \IMultiThreadableTask\ interface and using \TaskEnvironment\ for thread-safe path resolution. The aim is to be maximally compatible with prior behavior in terms of where it would throw
Changes
The following tasks now implement \IMultiThreadableTask\ and use \TaskEnvironment.GetAbsolutePath()\ instead of \Path.GetFullPath():
Why
\Path.GetFullPath()\ uses process-global state (current working directory) which is not thread-safe when multiple tasks run in parallel. The \TaskEnvironment.GetAbsolutePath()\ method provides thread-safe path resolution by using the task's execution context.
This enables these tasks to be safely executed in parallel when MSBuild's multithreading is enabled.