Skip to content

Commit 4df6f2b

Browse files
committed
Pass ToolCommand to ShellShimRepository
This will support creating script / symlink shims for "dotnet" runner type
1 parent 04c82cb commit 4df6f2b

File tree

5 files changed

+69
-46
lines changed

5 files changed

+69
-46
lines changed

src/Cli/dotnet/Commands/Tool/Install/ToolInstallGlobalOrToolPathCommand.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ private int ExecuteInstallCommand(PackageId packageId)
181181
{
182182
RunWithHandlingUninstallError(() =>
183183
{
184-
shellShimRepository.RemoveShim(oldPackageNullable.Command.Name);
184+
shellShimRepository.RemoveShim(oldPackageNullable.Command);
185185
toolPackageUninstaller.Uninstall(oldPackageNullable.PackageDirectory);
186186
}, packageId);
187187
}
@@ -217,7 +217,7 @@ private int ExecuteInstallCommand(PackageId packageId)
217217
}
218218
string appHostSourceDirectory = _shellShimTemplateFinder.ResolveAppHostSourceDirectoryAsync(_architectureOption, framework, RuntimeInformation.ProcessArchitecture).Result;
219219

220-
shellShimRepository.CreateShim(newInstalledPackage.Command.Executable, newInstalledPackage.Command.Name, newInstalledPackage.PackagedShims);
220+
shellShimRepository.CreateShim(newInstalledPackage.Command, newInstalledPackage.PackagedShims);
221221

222222
foreach (string w in newInstalledPackage.Warnings)
223223
{

src/Cli/dotnet/Commands/Tool/Uninstall/ToolUninstallGlobalOrToolPathCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public override int Execute()
7272
{
7373
TransactionalAction.Run(() =>
7474
{
75-
shellShimRepository.RemoveShim(package.Command.Name);
75+
shellShimRepository.RemoveShim(package.Command);
7676

7777
toolPackageUninstaller.Uninstall(package.PackageDirectory);
7878
});

src/Cli/dotnet/ShellShim/IShellShimRepository.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33

44
#nullable disable
55

6+
using Microsoft.DotNet.Cli.ToolPackage;
67
using Microsoft.DotNet.Cli.Utils;
78
using Microsoft.Extensions.EnvironmentAbstractions;
89

910
namespace Microsoft.DotNet.Cli.ShellShim;
1011

1112
internal interface IShellShimRepository
1213
{
13-
void CreateShim(FilePath targetExecutablePath, ToolCommandName commandName, IReadOnlyList<FilePath> packagedShims = null);
14+
void CreateShim(ToolCommand toolCommand, IReadOnlyList<FilePath> packagedShims = null);
1415

15-
void RemoveShim(ToolCommandName commandName);
16+
void RemoveShim(ToolCommand toolCommand);
1617
}

src/Cli/dotnet/ShellShim/ShellShimRepository.cs

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#nullable disable
55

6+
using Microsoft.DotNet.Cli.ToolPackage;
67
using Microsoft.DotNet.Cli.Utils;
78
using Microsoft.Extensions.EnvironmentAbstractions;
89

@@ -20,19 +21,19 @@ internal class ShellShimRepository(
2021
private readonly IAppHostShellShimMaker _appHostShellShimMaker = appHostShellShimMaker ?? new AppHostShellShimMaker(appHostSourceDirectory: appHostSourceDirectory);
2122
private readonly IFilePermissionSetter _filePermissionSetter = filePermissionSetter ?? new FilePermissionSetter();
2223

23-
public void CreateShim(FilePath targetExecutablePath, ToolCommandName commandName, IReadOnlyList<FilePath> packagedShims = null)
24+
public void CreateShim(ToolCommand toolCommand, IReadOnlyList<FilePath> packagedShims = null)
2425
{
25-
if (string.IsNullOrEmpty(targetExecutablePath.Value))
26+
if (string.IsNullOrEmpty(toolCommand.Executable.Value))
2627
{
2728
throw new ShellShimException(CliStrings.CannotCreateShimForEmptyExecutablePath);
2829
}
2930

30-
if (ShimExists(commandName))
31+
if (ShimExists(toolCommand))
3132
{
3233
throw new ShellShimException(
3334
string.Format(
3435
CliStrings.ShellShimConflict,
35-
commandName));
36+
toolCommand.Name));
3637
}
3738

3839
TransactionalAction.Run(
@@ -45,16 +46,16 @@ public void CreateShim(FilePath targetExecutablePath, ToolCommandName commandNam
4546
_fileSystem.Directory.CreateDirectory(_shimsDirectory.Value);
4647
}
4748

48-
if (TryGetPackagedShim(packagedShims, commandName, out FilePath? packagedShim))
49+
if (TryGetPackagedShim(packagedShims, toolCommand.Name, out FilePath? packagedShim))
4950
{
50-
_fileSystem.File.Copy(packagedShim.Value.Value, GetShimPath(commandName).Value);
51-
_filePermissionSetter.SetUserExecutionPermission(GetShimPath(commandName).Value);
51+
_fileSystem.File.Copy(packagedShim.Value.Value, GetShimPath(toolCommand.Name).Value);
52+
_filePermissionSetter.SetUserExecutionPermission(GetShimPath(toolCommand.Name).Value);
5253
}
5354
else
5455
{
5556
_appHostShellShimMaker.CreateApphostShellShim(
56-
targetExecutablePath,
57-
GetShimPath(commandName));
57+
toolCommand.Executable,
58+
GetShimPath(toolCommand.Name));
5859
}
5960
}
6061
catch (FilePermissionSettingException ex)
@@ -67,30 +68,30 @@ public void CreateShim(FilePath targetExecutablePath, ToolCommandName commandNam
6768
throw new ShellShimException(
6869
string.Format(
6970
CliStrings.FailedToCreateShellShim,
70-
commandName,
71+
toolCommand.Name,
7172
ex.Message
7273
),
7374
ex);
7475
}
7576
},
7677
rollback: () =>
7778
{
78-
foreach (var file in GetShimFiles(commandName).Where(f => _fileSystem.File.Exists(f.Value)))
79+
foreach (var file in GetShimFiles(toolCommand).Where(f => _fileSystem.File.Exists(f.Value)))
7980
{
8081
File.Delete(file.Value);
8182
}
8283
});
8384
}
8485

85-
public void RemoveShim(ToolCommandName commandName)
86+
public void RemoveShim(ToolCommand toolCommand)
8687
{
8788
var files = new Dictionary<string, string>();
8889
TransactionalAction.Run(
8990
action: () =>
9091
{
9192
try
9293
{
93-
foreach (var file in GetShimFiles(commandName).Where(f => _fileSystem.File.Exists(f.Value)))
94+
foreach (var file in GetShimFiles(toolCommand).Where(f => _fileSystem.File.Exists(f.Value)))
9495
{
9596
var tempPath = Path.Combine(_fileSystem.Directory.CreateTemporarySubdirectory(), Path.GetRandomFileName());
9697
FileAccessRetrier.RetryOnMoveAccessFailure(() => _fileSystem.File.Move(file.Value, tempPath));
@@ -102,7 +103,7 @@ public void RemoveShim(ToolCommandName commandName)
102103
throw new ShellShimException(
103104
string.Format(
104105
CliStrings.FailedToRemoveShellShim,
105-
commandName.ToString(),
106+
toolCommand.Name.ToString(),
106107
ex.Message
107108
),
108109
ex);
@@ -134,38 +135,38 @@ private class RootObject
134135
public StartupOptions startupOptions { get; set; }
135136
}
136137

137-
private bool ShimExists(ToolCommandName commandName)
138+
private bool ShimExists(ToolCommand toolCommand)
138139
{
139-
return GetShimFiles(commandName).Any(p => _fileSystem.File.Exists(p.Value));
140+
return GetShimFiles(toolCommand).Any(p => _fileSystem.File.Exists(p.Value));
140141
}
141142

142-
private IEnumerable<FilePath> GetShimFiles(ToolCommandName commandName)
143+
private IEnumerable<FilePath> GetShimFiles(ToolCommand toolCommand)
143144
{
144-
yield return GetShimPath(commandName);
145+
yield return GetShimPath(toolCommand);
145146
}
146147

147-
private FilePath GetShimPath(ToolCommandName commandName)
148+
private FilePath GetShimPath(ToolCommand toolCommand)
148149
{
149150
if (OperatingSystem.IsWindows())
150151
{
151-
return _shimsDirectory.WithFile(commandName.Value + ".exe");
152+
return _shimsDirectory.WithFile(toolCommand.Name.Value + ".exe");
152153
}
153154
else
154155
{
155-
return _shimsDirectory.WithFile(commandName.Value);
156+
return _shimsDirectory.WithFile(toolCommand.Name.Value);
156157
}
157158
}
158159

159160
private bool TryGetPackagedShim(
160161
IReadOnlyList<FilePath> packagedShims,
161-
ToolCommandName commandName,
162+
ToolCommand toolCommand,
162163
out FilePath? packagedShim)
163164
{
164165
packagedShim = null;
165166

166167
if (packagedShims != null && packagedShims.Count > 0)
167168
{
168-
FilePath[] candidatepackagedShim = [.. packagedShims.Where(s => string.Equals(Path.GetFileName(s.Value), Path.GetFileName(GetShimPath(commandName).Value)))];
169+
FilePath[] candidatepackagedShim = [.. packagedShims.Where(s => string.Equals(Path.GetFileName(s.Value), Path.GetFileName(GetShimPath(toolCommand).Value)))];
169170

170171
if (candidatepackagedShim.Length > 1)
171172
{

test/dotnet.Tests/ShellShimTests/ShellShimRepositoryTests.cs

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ public void GivenAnExecutablePathItCanGenerateShimFile()
3232
ShellShimRepository shellShimRepository = ConfigBasicTestDependencyShellShimRepository(pathToShim);
3333
var shellCommandName = nameof(ShellShimRepositoryTests) + Path.GetRandomFileName();
3434

35-
shellShimRepository.CreateShim(outputDll, new ToolCommandName(shellCommandName));
35+
var command = new ToolCommand(new ToolCommandName(shellCommandName), "dotnet", outputDll);
36+
37+
shellShimRepository.CreateShim(command);
3638

3739
var stdOut = ExecuteInShell(shellCommandName, pathToShim);
3840

@@ -53,7 +55,8 @@ public void GivenAnExecutableAndRelativePathToShimPathItCanGenerateShimFile()
5355
ShellShimRepository shellShimRepository = ConfigBasicTestDependencyShellShimRepository(relativePathToShim);
5456
var shellCommandName = nameof(ShellShimRepositoryTests) + Path.GetRandomFileName();
5557

56-
shellShimRepository.CreateShim(outputDll, new ToolCommandName(shellCommandName));
58+
var command = new ToolCommand(new ToolCommandName(shellCommandName), "dotnet", outputDll);
59+
shellShimRepository.CreateShim(command);
5760

5861
var stdOut = ExecuteInShell(shellCommandName, relativePathToShim);
5962

@@ -75,11 +78,13 @@ public void GivenAnExecutablePathItCanGenerateShimFileInTransaction()
7578
var shellShimRepository = ConfigBasicTestDependencyShellShimRepository(pathToShim);
7679
var shellCommandName = nameof(ShellShimRepositoryTests) + Path.GetRandomFileName();
7780

81+
var command = new ToolCommand(new ToolCommandName(shellCommandName), "dotnet", outputDll);
82+
7883
using (var transactionScope = new TransactionScope(
7984
TransactionScopeOption.Required,
8085
TimeSpan.Zero))
8186
{
82-
shellShimRepository.CreateShim(outputDll, new ToolCommandName(shellCommandName));
87+
shellShimRepository.CreateShim(command);
8388
transactionScope.Complete();
8489
}
8590

@@ -96,8 +101,9 @@ public void GivenAnExecutablePathDirectoryThatDoesNotExistItCanGenerateShimFile(
96101
var extraNonExistDirectory = Path.GetRandomFileName();
97102
var shellShimRepository = new ShellShimRepository(new DirectoryPath(Path.Combine(testFolder, extraNonExistDirectory)), GetAppHostTemplateFromStage2());
98103
var shellCommandName = nameof(ShellShimRepositoryTests) + Path.GetRandomFileName();
104+
var command = new ToolCommand(new ToolCommandName(shellCommandName), "dotnet", outputDll);
99105

100-
Action a = () => shellShimRepository.CreateShim(outputDll, new ToolCommandName(shellCommandName));
106+
Action a = () => shellShimRepository.CreateShim(command);
101107

102108
a.Should().NotThrow<DirectoryNotFoundException>();
103109
}
@@ -112,8 +118,9 @@ public void GivenAShimItPassesThroughArguments(string arguments, string[] expect
112118
var pathToShim = GetNewCleanFolderUnderTempRoot();
113119
var shellShimRepository = ConfigBasicTestDependencyShellShimRepository(pathToShim);
114120
var shellCommandName = nameof(ShellShimRepositoryTests) + Path.GetRandomFileName();
121+
var command = new ToolCommand(new ToolCommandName(shellCommandName), "dotnet", outputDll);
115122

116-
shellShimRepository.CreateShim(outputDll, new ToolCommandName(shellCommandName));
123+
shellShimRepository.CreateShim(command);
117124

118125
var stdOut = ExecuteInShell(shellCommandName, pathToShim, arguments);
119126

@@ -142,13 +149,15 @@ public void GivenAShimConflictItWillRollback(bool testMockBehaviorIsInSync)
142149
shellShimRepository = ConfigBasicTestDependencyShellShimRepository(pathToShim);
143150
}
144151

152+
var command = new ToolCommand(new ToolCommandName(shellCommandName), "dotnet", new FilePath("dummy.dll"));
153+
145154
Action a = () =>
146155
{
147156
using (var scope = new TransactionScope(
148157
TransactionScopeOption.Required,
149158
TimeSpan.Zero))
150159
{
151-
shellShimRepository.CreateShim(new FilePath("dummy.dll"), new ToolCommandName(shellCommandName));
160+
shellShimRepository.CreateShim(command);
152161

153162
scope.Complete();
154163
}
@@ -184,16 +193,21 @@ public void GivenAnExceptionItWillRollback(bool testMockBehaviorIsInSync)
184193
shellShimRepository = ConfigBasicTestDependencyShellShimRepository(pathToShim);
185194
}
186195

196+
197+
187198
Action intendedError = () => throw new ToolPackageException("simulated error");
188199

200+
201+
189202
Action a = () =>
190203
{
191204
using (var scope = new TransactionScope(
192205
TransactionScopeOption.Required,
193206
TimeSpan.Zero))
194207
{
195208
FilePath targetExecutablePath = MakeHelloWorldExecutableDll(identifier: testMockBehaviorIsInSync.ToString());
196-
shellShimRepository.CreateShim(targetExecutablePath, new ToolCommandName(shellCommandName));
209+
var command = new ToolCommand(new ToolCommandName(shellCommandName), "dotnet", targetExecutablePath);
210+
shellShimRepository.CreateShim(command);
197211

198212
intendedError();
199213
scope.Complete();
@@ -224,7 +238,9 @@ public void GivenANonexistentShimRemoveDoesNotThrow(bool testMockBehaviorIsInSyn
224238

225239
Directory.EnumerateFileSystemEntries(pathToShim).Should().BeEmpty();
226240

227-
shellShimRepository.RemoveShim(new ToolCommandName(shellCommandName));
241+
var command = new ToolCommand(new ToolCommandName(shellCommandName), "dotnet", new FilePath("dummyExe"));
242+
243+
shellShimRepository.RemoveShim(command);
228244

229245
Directory.EnumerateFileSystemEntries(pathToShim).Should().BeEmpty();
230246
}
@@ -250,11 +266,12 @@ public void GivenAnInstalledShimRemoveDeletesTheShimFiles(bool testMockBehaviorI
250266
Directory.EnumerateFileSystemEntries(pathToShim).Should().BeEmpty();
251267

252268
FilePath targetExecutablePath = MakeHelloWorldExecutableDll(identifier: testMockBehaviorIsInSync.ToString());
253-
shellShimRepository.CreateShim(targetExecutablePath, new ToolCommandName(shellCommandName));
269+
var command = new ToolCommand(new ToolCommandName(shellCommandName), "dotnet", targetExecutablePath);
270+
shellShimRepository.CreateShim(command);
254271

255272
Directory.EnumerateFileSystemEntries(pathToShim).Should().NotBeEmpty();
256273

257-
shellShimRepository.RemoveShim(new ToolCommandName(shellCommandName));
274+
shellShimRepository.RemoveShim(command);
258275

259276
Directory.EnumerateFileSystemEntries(pathToShim).Should().BeEmpty();
260277
}
@@ -280,15 +297,16 @@ public void GivenAnInstalledShimRemoveRollsbackIfTransactionIsAborted(bool testM
280297
Directory.EnumerateFileSystemEntries(pathToShim).Should().BeEmpty();
281298

282299
FilePath targetExecutablePath = MakeHelloWorldExecutableDll(identifier: testMockBehaviorIsInSync.ToString());
283-
shellShimRepository.CreateShim(targetExecutablePath, new ToolCommandName(shellCommandName));
300+
var command = new ToolCommand(new ToolCommandName(shellCommandName), "dotnet", targetExecutablePath);
301+
shellShimRepository.CreateShim(command);
284302

285303
Directory.EnumerateFileSystemEntries(pathToShim).Should().NotBeEmpty();
286304

287305
using (var scope = new TransactionScope(
288306
TransactionScopeOption.Required,
289307
TimeSpan.Zero))
290308
{
291-
shellShimRepository.RemoveShim(new ToolCommandName(shellCommandName));
309+
shellShimRepository.RemoveShim(command);
292310

293311
Directory.EnumerateFileSystemEntries(pathToShim).Should().BeEmpty();
294312
}
@@ -317,15 +335,16 @@ public void GivenAnInstalledShimRemoveCommitsIfTransactionIsCompleted(bool testM
317335
Directory.EnumerateFileSystemEntries(pathToShim).Should().BeEmpty();
318336

319337
FilePath targetExecutablePath = MakeHelloWorldExecutableDll(identifier: testMockBehaviorIsInSync.ToString());
320-
shellShimRepository.CreateShim(targetExecutablePath, new ToolCommandName(shellCommandName));
338+
var command = new ToolCommand(new ToolCommandName(shellCommandName), "dotnet", targetExecutablePath);
339+
shellShimRepository.CreateShim(command);
321340

322341
Directory.EnumerateFileSystemEntries(pathToShim).Should().NotBeEmpty();
323342

324343
using (var scope = new TransactionScope(
325344
TransactionScopeOption.Required,
326345
TimeSpan.Zero))
327346
{
328-
shellShimRepository.RemoveShim(new ToolCommandName(shellCommandName));
347+
shellShimRepository.RemoveShim(command);
329348

330349
Directory.EnumerateFileSystemEntries(pathToShim).Should().BeEmpty();
331350

@@ -354,9 +373,10 @@ public void WhenPackagedShimProvidedItCopies()
354373

355374
ShellShimRepository shellShimRepository = GetShellShimRepositoryWithMockMaker(pathToShim);
356375

376+
var command = new ToolCommand(new ToolCommandName(shellCommandName), "dotnet", new FilePath("dummy.dll"));
377+
357378
shellShimRepository.CreateShim(
358-
new FilePath("dummy.dll"),
359-
new ToolCommandName(shellCommandName),
379+
command,
360380
new[] { new FilePath(dummyShimPath) });
361381

362382
var createdShim = Directory.EnumerateFileSystemEntries(pathToShim).Single();
@@ -383,9 +403,10 @@ public void WhenMultipleSameNamePackagedShimProvidedItThrows()
383403

384404
FilePath[] filePaths = new[] { new FilePath(dummyShimPath), new FilePath("path" + dummyShimPath) };
385405

406+
var command = new ToolCommand(new ToolCommandName(shellCommandName), "dotnet", new FilePath("dummy.dll"));
407+
386408
Action a = () => shellShimRepository.CreateShim(
387-
new FilePath("dummy.dll"),
388-
new ToolCommandName(shellCommandName),
409+
command,
389410
new[] { new FilePath(dummyShimPath), new FilePath("path" + dummyShimPath) });
390411

391412
a.Should().Throw<ShellShimException>()

0 commit comments

Comments
 (0)