Description
Describe the bug
In theory, installing NET tools post-8.0.200 should repeat reliably with Tool 'my.tool' was reinstalled with the stable version...
.
If you do this across a Windows Docker context, the NET tool install fails if repeated. This appears to suggest the NET tool install code is not properly checking for some filesystem state, as 'normal' file operations on that folder work correctly, and in theory Docker has simply copied the contents across from Windows filesystem A to B.
Thanks in advance for your attention.
To Reproduce
- Install Cake.Tool to a custom tool install folder e.g.
.\cake
- Create a Docker image from a base Windows image that does the following:
- Installs the NET SDK from CI-CD powershell
- Copies the current folder (and thus the installed tool in
cake
subfolder) to a folder in the Docker image
- Run the Docker image as a container
- Attempt to reinstall the tool at the copied location inside the container multiple times
Expected results:
Tool consistently reinstalls correctly.
Actual results:
Tool install fails with exception detailed below.
Workaround:
Excluding the toolpath folder from the Docker context i.e. in the below example a .dockerignore
containing cake/
fixes the issue, demonstrating the issue is with the presence of the folder and how the NET tool installer tries to alter it. Of course, this means the tool has to be re-downloaded and re-installed, wasting time.
Exceptions (if any)
Unhandled exception: System.IO.IOException: Cannot create 'C:\BUILD\cake\.store\cake.tool\4.0.0' because a file or directory with the same name already exists.
at System.IO.FileSystem.MoveDirectory(String sourceFullPath, String destFullPath, Boolean _)
at System.IO.FileSystem.MoveDirectory(String sourceFullPath, String destFullPath)
at Microsoft.DotNet.Cli.Utils.FileAccessRetrier.RetryOnMoveAccessFailure(Action action)
at Microsoft.DotNet.Cli.TransactionalAction.EnlistmentNotification.Rollback(Enlistment enlistment)
at System.Transactions.VolatileEnlistmentAborting.EnterState(InternalEnlistment enlistment)
at System.Transactions.TransactionStateAborted.EnterState(InternalTransaction tx)
at System.Transactions.Transaction.Rollback()
at System.Transactions.TransactionScope.InternalDispose()
at System.Transactions.TransactionScope.Dispose()
at Microsoft.DotNet.Cli.TransactionalAction.Run[T](Func`1 action, Action commit, Action rollback)
at Microsoft.DotNet.Cli.TransactionalAction.Run(Action action, Action commit, Action rollback)
at Microsoft.DotNet.Tools.Tool.Install.ToolInstallGlobalOrToolPathCommand.RunWithHandlingUninstallError(Action uninstallAction)
at Microsoft.DotNet.Tools.Tool.Install.ToolInstallGlobalOrToolPathCommand.Execute()
at System.CommandLine.Invocation.InvocationPipeline.Invoke(ParseResult parseResult)
at Microsoft.DotNet.Cli.Program.ProcessArgs(String[] args, TimeSpan startupTime, ITelemetry telemetryClient)
Further technical details
Detailed command line for reproduction, with indenting for readability:
Local environment:
$SdkInstallDir = "./dotnet-sdk"
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/dotnet/install-scripts/main/src/dotnet-install.ps1" -OutFile "$SdkInstallDir/dotnet-install.ps1"
& $SdkInstallDir/dotnet-install.ps1 -JsonFile 'global.json' -InstallDir $SdkInstallDir
$env:DOTNET_ROOT = $SdkInstallDir
dotnet --list-sdks
8.0.202 [D:\repro\dotnet-sdk\sdk]
8.0.303 [D:\repro\dotnet-sdk\sdk]
docker version
Client: Mirantis Container Runtime
Version: 20.10.9
API version: 1.41
Go version: go1.16.12m2
Git commit: 591094d
Built: 12/21/2021 21:34:30
OS/Arch: windows/amd64
Context: default
Experimental: true
Server: Mirantis Container Runtime
Engine:
Version: 20.10.9
API version: 1.41 (minimum version 1.24)
Go version: go1.16.12m2
Git commit: 9b96ce992b
Built: 12/21/2021 21:33:06
OS/Arch: windows/amd64
Experimental: false
dotnet --info
.NET SDK:
Version: 8.0.303
Commit: 29ab8e3268
Workload version: 8.0.300-manifests.4e94be9c
MSBuild version: 17.10.4+10fbfbf2e
Runtime Environment:
OS Name: Windows
OS Version: 10.0.20348
OS Platform: Windows
RID: win-x64
Base Path: D:\repro\dotnet-sdk\sdk\8.0.303\
.NET workloads installed:
There are no installed workloads to display.
Host:
Version: 8.0.7
Architecture: x64
Commit: 2aade6beb0
.NET SDKs installed:
8.0.202 [D:\repro\dotnet-sdk\sdk]
8.0.303 [D:\repro\dotnet-sdk\sdk]
.NET runtimes installed:
Microsoft.AspNetCore.App 8.0.3 [D:\repro\dotnet-sdk\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.7 [D:\repro\dotnet-sdk\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 8.0.3 [D:\repro\dotnet-sdk\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.7 [D:\repro\dotnet-sdk\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 8.0.3 [D:\repro\dotnet-sdk\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 8.0.7 [D:\repro\dotnet-sdk\shared\Microsoft.WindowsDesktop.App]
Other architectures found:
None
Environment variables:
DOTNET_ROOT [D:\repro\dotnet-sdk]
global.json file:
D:\repro\global.json
Learn more:
https://aka.ms/dotnet/info
Download .NET:
https://aka.ms/dotnet/download
$cakeDir = Join-Path $PSScriptRoot "cake"
dotnet tool install Cake.Tool --tool-path $cakeDir --version 4.0.0
Tool 'cake.tool' was reinstalled with the stable version (version '4.0.0').
& docker.exe build --file RecipeWindowsDockerfileCode --tag "sdk_testing_code:8.0.303" .
Sending build context to Docker daemon 155.9MB
Step 1/7 : FROM mcr.microsoft.com/dotnet/framework/runtime:4.8.1-20240514-windowsservercore-ltsc2022
---> f2814b275efe
Step 2/7 : ENV DOT_NET_VERSION=${DOT_NET_VERSION} DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 DOTNET_CLI_TELEMETRY_OPTOUT=1 DOTNET_NOLOGO=1 DOTNET_ROOT=C:\\Dotnet\\x64
---> Running in b56f3298722a
Removing intermediate container b56f3298722a
---> 09ef8892ea83
Step 3/7 : ADD https://raw.githubusercontent.com/dotnet/install-scripts/main/src/dotnet-install.ps1 C:\\TEMP\\dotnet-install.ps1
Downloading 54.69kB
---> d7b611251bd4
Step 4/7 : RUN setx /m PATH "C:\Dotnet\x64;%PATH%" && powershell -File C:\\TEMP\\dotnet-install.ps1 -Channel LTS -Version 8.0.303 -InstallDir C:\\Dotnet\\x64 -Architecture x64 -NoPath
---> Running in 136070dc18e6
SUCCESS: Specified value was saved.
dotnet-install: Downloaded file https://dotnetcli.azureedge.net/dotnet/Sdk/8.0.303/dotnet-sdk-8.0.303-win-x64.zip size is 291718357 bytes.
dotnet-install: Either downloaded or local package size can not be measured. One of them may be corrupted.
dotnet-install: Extracting the archive.
dotnet-install: Binaries of dotnet can be found in C:\Dotnet\x64\
dotnet-install: Note that the script does not resolve dependencies during installation.
dotnet-install: To check the list of dependencies, go to https://learn.microsoft.com/dotnet/core/install/windows#dependencies
dotnet-install: Installed version is 8.0.303
dotnet-install: Installation finished
Removing intermediate container 136070dc18e6
---> 3d3be5bff89a
Step 5/7 : RUN mkdir C:\\BUILD
---> Running in 2bd0c97695e5
Removing intermediate container 2bd0c97695e5
---> d53645c7a679
Step 6/7 : WORKDIR C:/BUILD
---> Running in 392f23ba8e2f
Removing intermediate container 392f23ba8e2f
---> af7420fc7fcb
Step 7/7 : COPY / C:/BUILD/
---> 5eb5fd19d95a
Successfully built 5eb5fd19d95a
Successfully tagged sdk_testing_code:8.0.303
& docker.exe run --rm sdk_testing_code:8.0.303 powershell -File C:\BUILD\main.ps1
Docker environment:
dotnet --info
.NET SDK:
Version: 8.0.303
Commit: 29ab8e3268
Workload version: 8.0.300-manifests.c915c39d
MSBuild version: 17.10.4+10fbfbf2e
Runtime Environment:
OS Name: Windows
OS Version: 10.0.20348
OS Platform: Windows
RID: win-x64
Base Path: C:\Dotnet\x64\sdk\8.0.303\
.NET workloads installed:
There are no installed workloads to display.
Host:
Version: 8.0.7
Architecture: x64
Commit: 2aade6beb0
.NET SDKs installed:
8.0.303 [C:\Dotnet\x64\sdk]
.NET runtimes installed:
Microsoft.AspNetCore.App 8.0.7 [C:\Dotnet\x64\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 8.0.7 [C:\Dotnet\x64\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 8.0.7 [C:\Dotnet\x64\shared\Microsoft.WindowsDesktop.App]
Other architectures found:
None
Environment variables:
DOTNET_ROOT [C:\Dotnet\x64]
global.json file:
C:\BUILD\global.json
Learn more:
https://aka.ms/dotnet/info
Download .NET:
https://aka.ms/dotnet/download
& dotnet tool install Cake.Tool --tool-path $cakeDir --version 4.0.0
Tool 'cake.tool' was reinstalled with the stable version (version '4.0.0').
& dotnet tool install Cake.Tool --tool-path $cakeDir --version 4.0.0
Unhandled exception: System.IO.IOException: Cannot create 'C:\BUILD\cake\.store\cake.tool\4.0.0' because a file or directory with the same name already exists.
at System.IO.FileSystem.MoveDirectory(String sourceFullPath, String destFullPath, Boolean _)
at System.IO.FileSystem.MoveDirectory(String sourceFullPath, String destFullPath)
at Microsoft.DotNet.Cli.Utils.FileAccessRetrier.RetryOnMoveAccessFailure(Action action)
at Microsoft.DotNet.Cli.TransactionalAction.EnlistmentNotification.Rollback(Enlistment enlistment)
at System.Transactions.VolatileEnlistmentAborting.EnterState(InternalEnlistment enlistment)
at System.Transactions.TransactionStateAborted.EnterState(InternalTransaction tx)
at System.Transactions.Transaction.Rollback()
at System.Transactions.TransactionScope.InternalDispose()
at System.Transactions.TransactionScope.Dispose()
at Microsoft.DotNet.Cli.TransactionalAction.Run[T](Func`1 action, Action commit, Action rollback)
at Microsoft.DotNet.Cli.TransactionalAction.Run(Action action, Action commit, Action rollback)
at Microsoft.DotNet.Tools.Tool.Install.ToolInstallGlobalOrToolPathCommand.RunWithHandlingUninstallError(Action uninstallAction)
at Microsoft.DotNet.Tools.Tool.Install.ToolInstallGlobalOrToolPathCommand.Execute()
at System.CommandLine.Invocation.InvocationPipeline.Invoke(ParseResult parseResult)
at Microsoft.DotNet.Cli.Program.ProcessArgs(String[] args, TimeSpan startupTime, ITelemetry telemetryClient)