Skip to content

Commit fb3b5b1

Browse files
committed
work
lint issues update spec update spec Add support for other extensions on Windows as future possibility
1 parent 0cf2676 commit fb3b5b1

1 file changed

Lines changed: 57 additions & 13 deletions

File tree

accepted/2024/support-nuget-authentication-plugins-dotnet-tools.md

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,15 @@ Currently, NuGet maintains `netfx` folder for plugins that will be invoked in `.
2626
| .NET Core | %UserProfile%/.nuget/plugins/netcore |
2727
| .NET Framework | %UserProfile%/.nuget/plugins/netfx |
2828

29-
This proposal introduces a new workflow for both plugin authors and consumers:
30-
- Plugin authors will now have the ability to publish their NuGet plugins as .NET Tools.
29+
This proposal introduces a new workflow for plugin authors, consumers, and NuGet Client tooling:
30+
- Plugin authors will now be able to publish their NuGet plugins as .NET Tools.
31+
The only requirement is that the .NET Tool command name should begin with `nuget-plugin-`.
3132
- Consumers can install these NuGet plugins as [global .NET tools](https://learn.microsoft.com/dotnet/core/tools/global-tools-how-to-use#use-the-tool-as-a-global-tool).
32-
Upon installation, these global .NET tools are added to the PATH. This allows NuGet to easily determine which file in the package should be run at runtime.
33+
- Upon installation, these global .NET tools are added to the PATH by the .NET SDK.
34+
This allows NuGet to easily determine which file in the package should be run at runtime.
35+
It does this by scanning the `PATH` environment variable for plugins whose file name begins with `nuget-plugin-`.
36+
On Windows, NuGet will look for plugins with a `.exe` extension, whereas on Linux/Mac, it will look for plugins with the executable bit set.
37+
These plugins are launched in a separate process, which aligns with the current design.
3338

3439
## Motivation
3540

@@ -128,9 +133,9 @@ It also simplifies the installation process by removing the necessity for plugin
128133

129134
To distribute a NuGet cross platform plugin as a .NET Tool, plugin authors need to follow these steps:
130135

131-
- Follow [NuGet cross platform plugins](https://learn.microsoft.com/nuget/reference/extensibility/nuget-cross-platform-plugins) guidance.
132-
- Ensure that the NuGet package name or the `ToolCommandName` property value begins with `nuget-plugin-*`.
133-
- Execute `dotnet pack` to generate the package.
136+
- Follow [NuGet cross platform plugins](https://learn.microsoft.com/nuget/reference/extensibility/nuget-cross-platform-plugins) guidance.
137+
- Ensure that the .NET Tool command name begins with `nuget-plugin-*`.
138+
- Execute `dotnet pack` to generate the package.
134139

135140
```xml
136141
<PackAsTool>true</PackAsTool>
@@ -176,17 +181,28 @@ The plugins specified in the `NUGET_DOTNET_TOOLS_PLUGIN_PATHS` environment varia
176181
The primary reason for this is that plugins installed as .NET tools can be executed in both .NET Framework and .NET Core tooling.
177182
If customers prefer to install NuGet plugins as a [tool-path global tool](https://learn.microsoft.com/dotnet/core/tools/global-tools-how-to-use#use-the-tool-as-a-global-tool-installed-in-a-custom-location), they can set the `NUGET_DOTNET_TOOLS_PLUGIN_PATHS` environment variable.This variable should point to the location of the .NET Tool executable that the NuGet Client tooling can invoke when needed.
178183

179-
Considering the varying ways different platforms handle file casing, the implementation could convert all file names to lowercase before checking for a file.
180-
Specifically, it should look for files whose names begin with `nuget-plugin-*` by scanning all the directories in the PATH environment variable.
181-
On Windows, NuGet should search for files with the `.exe` extension. On other platforms, it should look for files with the executable bit set.
182-
`NuGet.exe` currently [scans all directories in the PATH environment variable](https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Clients/NuGet.CommandLine/MsBuildUtility.cs#L708-L736) to find `MSBuild.exe`.
184+
NuGet should search for files whose names begin with `nuget-plugin-*` by scanning all the directories in the `PATH` environment variable.
185+
To ensure compatibility across different platforms, the implementation could convert all file names to lowercase before checking for a file.
186+
187+
- On Windows, NuGet should search for plugins using the `.exe` extension.
188+
The `PATHEXT` environment variable in Windows specifies the file extensions that the operating system considers to be executable.
189+
When you enter a command without specifying an extension, Windows will look for files with the extensions listed in `PATHEXT` in the directories specified by the `PATH` environment variable.
190+
For example, if `PATHEXT` is set to `.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC`, and you enter the command `myprogram`, Windows will search for `myprogram.com`, `myprogram.exe`, `myprogram.bat`, and so on, in that order, in the directories listed in your `PATH` environment variable.
191+
It will execute the first match it finds.
192+
Given that .NET Tools are console applications, they should have the `.exe` extension on Windows to be considered valid plugins if the naming convention is followed.
193+
194+
- Similarly, on other platforms, NuGet should search for plugins with the executable bit set to identify them as valid plugins.
195+
This is because on Mac and Linux, executable files typically don't have extensions.
196+
Given that .NET Tools, when installed on Linux and Mac, have a native shim with an executable bit set, they should be considered valid plugins if the naming convention is followed.
197+
198+
Currently, `NuGet.exe` [scans all directories in the `PATH` environment variable](https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Clients/NuGet.CommandLine/MsBuildUtility.cs#L708-L736) to find `MSBuild.exe`.
183199

184200
#### Plugin execution
185201

186202
In the [current implementation](https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.Protocol/Plugins/PluginFactory.cs#L155-L181), NuGet launches the `.exe` file in a separate process when running on the .NET Framework.
187203
On the other hand, when running on .NET, NuGet executes the `dotnet plugin-in.dll` command in a separate process.
188204

189-
The plan is to slightly adjust this implementation. NuGet will launch the `.exe` file in a separate process when running on Windows, irrespective of whether the runtime is .NET Framework or .NET.
205+
The plan is to slightly adjust this implementation. NuGet will launch the `.exe` file in a separate process when running on Windows, irrespective of whether the runtime is .NET Framework or .NET.
190206
For non-Windows platforms, if the file does not have an extension, it will launch the executable directly in a separate process.
191207
If the file has a `.dll` extension, it will continue to execute the `dotnet nuget-plugin-name.dll` command in a separate process.
192208

@@ -207,6 +223,10 @@ See the `Future Possibilities` section for more details.
207223
- The discoverability of NuGet plugins published as .NET Tools is challenging for users because the `dotnet tool search` command only filters based on the `PackageType` being `DotnetTool`.
208224
Please refer to the `Future Possibilities` section for more related information.
209225

226+
- On Windows, NuGet searches for plugins using the `.exe` extension.
227+
This is the case even though Windows recognizes all extensions configured in `PATHEXT` as executables.
228+
For more information, please refer to the `Future Possibilities` section.
229+
210230
## Rationale and alternatives
211231

212232
### Installing NuGet plugins as tool-path .NET Tools
@@ -266,7 +286,7 @@ However, NuGet plugins and .NET tools share the similarity of being console appl
266286
This approach is similar to the alternative design that [Andy Zivkovic](https://github.com/zivkan) kindly proposed in [[Feature]: Make NuGet credential providers installable via the dotnet cli](https://github.com/NuGet/Home/issues/11325).
267287
The recommendation was developing a command like `dotnet nuget credential-provider install Microsoft.Azure.Artifacts.CredentialProvider`.
268288

269-
### Technical explanation
289+
#### Technical explanation
270290

271291
If none of the above environment variables are set, NuGet will default to the conventional method of discovering plugins from predefined directories.
272292
In the [current implementation](https://github.com/NuGet/NuGet.Client/blob/8b658e2eee6391936887b9fd1b39f7918d16a9cb/src/NuGet.Core/NuGet.Protocol/Plugins/PluginDiscoveryUtility.cs#L65-L77), the NuGet code looks for plugin files in the `netfx` directory when running on .NET Framework, and in the `netcore` directory when running on .NET Core. This implementation should be updated to include the new `any` directory.
@@ -327,7 +347,7 @@ drwxr-xr-x 5 {user} 4096 Feb 10 08:21 .store
327347
**Disadvantages:**
328348

329349
- The ideal workflow for repositories accessing private NuGet feeds, such as Azure DevOps, is to easily search for NuGet plugins and install them as global tool.
330-
However, this approach suggests installing the plugin as a tool-path .NET tool.
350+
However, this approach suggests installing the plugin as a tool-path .NET tool.
331351
Customers can opt to install NuGet plugins as a global tool instead of a tool-path tool.
332352
To do this, they need to set the `NUGET_DOTNET_TOOLS_PLUGIN_PATHS` environment variable.
333353
This variable should point to the location of the .NET Tool executable, which the NuGet Client tooling can invoke when needed.
@@ -448,3 +468,27 @@ This might be because the new package type, `CredentialProvider`, which I added
448468
If the `dotnet pack` command could generate a .nupkg for .NET Tool with multiple package types, we could introduce a new `dotnet nuget plugin search` command.
449469
This command would act as a wrapper for the `dotnet tool search` command, further refining the results based on the additional package type, such as `CredentialProvider`.
450470
These package types can be found in the `.nuspec` metadata file of the generated nupkg.
471+
472+
### Support for other extensions on Windows.
473+
474+
- In the future, we could consider supporting extensions other than `.exe` configured in `PATHEXT` as executables.
475+
To achieve this, NuGet would need to identify the correct executable or interpretter to run a particular file.
476+
For example, to execute a PowerShell script, NuGet would need to launch the process as shown below.
477+
However, the challenge lies in identifying the appropriate executable for each type of file, which is not an immediate requirement.
478+
479+
```cs
480+
var processInfo = new System.Diagnostics.ProcessStartInfo
481+
{
482+
FileName = "powershell.exe",
483+
Arguments = @"& 'C:\Path\To\Your\Script.ps1'",
484+
RedirectStandardOutput = true,
485+
UseShellExecute = false,
486+
CreateNoWindow = true
487+
};
488+
489+
var process = System.Diagnostics.Process.Start(processInfo);
490+
491+
// To read the output (if any):
492+
string output = process.StandardOutput.ReadToEnd();
493+
process.WaitForExit();
494+
```

0 commit comments

Comments
 (0)