Intro
dotnet tool 是从 .NET Core 2.1 开始支持的命令行工具,在使用 dotnet tool 比较多了的时候,想要更新所有的 dotnet tool 就比较麻烦,而目前 .NET SDK 还不支持,也有一些人希望能够支持一次更新所有的 dotnet tool 这样我们就不需要一个一个地去更新了
Implement
实现思路比较简单,获取所有的 dotnet tool 并逐个进行更新.
我们可以通过 dotnet tool list -g
command 来获取我们安装的所有的 dotnet global tool,输出结果如下:
第一行是一个标题,第二行是分隔线,从第三行开始是 dotnet tool 数据
第一列是 NuGet package id, 第二列是 package version, 第三列是 dotnet tool 对应的命令,我们可以获取 dotnet tool list -g
输出并从第三行开始读取数据,只需要读取第一列数据的 package id 即可
获取所有 dotnet tool list 的代码如下:
// get dotnet path
var dotnetPath = ApplicationHelper.GetDotnetPath();
// execute `dotnet tool list -g` to get all dotnet tool
var dotnetToolListOutput = await CommandExecutor.ExecuteAndCaptureAsync(dotnetPath, "tool list -g");
// output
Console.WriteLine("`dotnet tool list -g` output:");
Console.WriteLine(dotnetToolListOutput.StandardOut);
拿到输出结果之后,我们就可以得到 dotnet tool list 并开始逐个更新了,实现如下:
var dotnetToolList = dotnetToolListOutput.StandardOut.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
if (dotnetToolList.Length > 2)
{
foreach (var tool in dotnetToolList[2..])
{
var toolId = tool.Split(' ', StringSplitOptions.RemoveEmptyEntries)[0].Trim();
if (fullToolName.Equals(toolId))
{
continue;
}
Console.WriteLine($"update tool {toolId}...");
try
{
await CommandExecutor.ExecuteAsync(dotnetPath, $"tool update -g {toolId}");
Console.WriteLine($"update tool {toolId} completed");
}
catch (Exception ex)
{
Console.WriteLine($"update tool {toolId} failed: {ex}");
}
}
}
至此我们的核心逻辑就基本完成了,实现效果如下:
如果要发布还要准备一下 nuget package 的一些信息
<PropertyGroup>
<IsPackable>true</IsPackable>
<PackAsTool>true</PackAsTool>
<ToolCommandName>dotnet-update-all-tools</ToolCommandName>
<PackageId>dotnet-update-all-tools</PackageId>
<Version>1.0.0</Version>
</PropertyGroup>
PackAsTool
意味着我们要打包一个 dotnet tool
ToolCommandName
是我们 tool 安装后对应的执行命令
More
上面的 ApplicationHelper.GetDotnetPath()
实现是通过扫描 PATH
找到可执行的dotne path,有些 platform 上需要 full path 才能工作,实现可以参考:https://github.com/WeihanLi/WeihanLi.Common/blob/86b6acc10f50df5867c590ca10039c1e7a8bb740/src/WeihanLi.Common/Helpers/ApplicationHelper.cs#L61
CommandExecutor
实现是起了一个进程并捕获进程输出,可以参考:https://github.com/WeihanLi/WeihanLi.Common/blob/86b6acc10f50df5867c590ca10039c1e7a8bb740/src/WeihanLi.Common/Helpers/CommandExecutor.cs#L45
最终的 dotnet tool
在 System.CommandLine
的基础上包装了一下,以为了更好的体验和扩展的方便
var command = new Command(toolName);
command.SetHandler(async () =>
{
// 前面的逻辑在这里
});
await command.InvokeAsync(args);
自此我们的 dotnet tool 就完成了
可以通过下面的命令来进行安装
dotnet tool install --global dotnet-update-all-tools
安装好之后执行 dotnet-update-all-tools
即可更新所有的 dotnet tool 了。