From 96b62a691ad79d665fecdcff0b5ff938f0e21fc0 Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Mon, 25 Nov 2019 12:49:48 -0800 Subject: [PATCH] (GH-2) Allow changing of requested tool version Previously, the Module wouldn't check to see what version of a Tool was installed. As a result, when a tool was already installed, even if a newer version was requested, it wouldn't be installed. This is really down to the underlying tool and how it works, but smarts have now been put into the module, to check installed version, against what is requested, so that an uninstall is first executed, and then the requested version is installed. --- .../DotNetToolOperation.cs | 9 + .../DotNetToolPackage.cs | 9 + .../DotNetToolPackageInstaller.cs | 167 +++++++++++------- 3 files changed, 120 insertions(+), 65 deletions(-) create mode 100644 Source/Cake.DotNetTool.Module/DotNetToolOperation.cs create mode 100644 Source/Cake.DotNetTool.Module/DotNetToolPackage.cs diff --git a/Source/Cake.DotNetTool.Module/DotNetToolOperation.cs b/Source/Cake.DotNetTool.Module/DotNetToolOperation.cs new file mode 100644 index 0000000..daee620 --- /dev/null +++ b/Source/Cake.DotNetTool.Module/DotNetToolOperation.cs @@ -0,0 +1,9 @@ +namespace Cake.DotNetTool.Module +{ + public enum DotNetToolOperation + { + Install, + Uninstall, + Update + } +} \ No newline at end of file diff --git a/Source/Cake.DotNetTool.Module/DotNetToolPackage.cs b/Source/Cake.DotNetTool.Module/DotNetToolPackage.cs new file mode 100644 index 0000000..3fb06d8 --- /dev/null +++ b/Source/Cake.DotNetTool.Module/DotNetToolPackage.cs @@ -0,0 +1,9 @@ +namespace Cake.DotNetTool.Module +{ + public sealed class DotNetToolPackage + { + public string Id { get; set; } + public string Version { get; set; } + public string ShortCode { get; set; } + } +} \ No newline at end of file diff --git a/Source/Cake.DotNetTool.Module/DotNetToolPackageInstaller.cs b/Source/Cake.DotNetTool.Module/DotNetToolPackageInstaller.cs index c3b39da..675477a 100644 --- a/Source/Cake.DotNetTool.Module/DotNetToolPackageInstaller.cs +++ b/Source/Cake.DotNetTool.Module/DotNetToolPackageInstaller.cs @@ -108,16 +108,42 @@ public IReadOnlyCollection Install(PackageReference package, PackageType } // First we need to check if the Tool is already installed - var installedToolNames = GetInstalledTools(toolLocation); + var installedTools = GetInstalledTools(toolLocation); _log.Debug("Checking for tool: {0}", package.Package.ToLowerInvariant()); - if(installedToolNames.Contains(package.Package.ToLowerInvariant())) + + var installedTool = installedTools.FirstOrDefault(t => t.Id.ToLowerInvariant() == package.Package.ToLowerInvariant()); + + if (installedTool != null) { - _log.Information("Tool {0} is already installed, so nothing to do here.", package.Package); + // The tool is already installed, so need to check if requested version is the same as + // what is already installed + string requestedVersion = null; + + if (package.Parameters.ContainsKey("version")) + { + requestedVersion = package.Parameters["version"].First(); + } + + if (requestedVersion == null) + { + _log.Warning("Tool {0} is already installed, and no specific version has been requested via pre-processor directive, so leaving current version installed.", package.Package); + } + else if (requestedVersion.ToLowerInvariant() != installedTool.Version.ToLowerInvariant()) + { + _log.Warning("Tool {0} is already installed, but a different version has been requested. Uninstall/install will now be performed...", package.Package); + RunDotNetTool(package, toolsFolderDirectoryPath, DotNetToolOperation.Uninstall); + RunDotNetTool(package, toolsFolderDirectoryPath, DotNetToolOperation.Install); + } + else + { + _log.Information("Tool {0} is already installed, with required version.", package.Package); + } } else { - InstallTool(package, toolsFolderDirectoryPath); + // The tool isn't already installed, go ahead and install it + RunDotNetTool(package, toolsFolderDirectoryPath, DotNetToolOperation.Install); } var result = _contentResolver.GetFiles(package, type); @@ -130,7 +156,7 @@ public IReadOnlyCollection Install(PackageReference package, PackageType return result; } - private List GetInstalledTools(string toolLocation) + private List GetInstalledTools(string toolLocation) { var toolLocationArgument = string.Empty; if(toolLocation != "global") @@ -144,7 +170,7 @@ private List GetInstalledTools(string toolLocation) if(!toolLocationDirectory.Exists) { _log.Debug("Specified installation location doesn't currently exist."); - return new List(); + return new List(); } } else @@ -162,7 +188,7 @@ private List GetInstalledTools(string toolLocation) isInstalledProcess.WaitForExit(); var installedTools = isInstalledProcess.GetStandardOutput().ToList(); - var installedToolNames = new List(); + var installedToolNames = new List(); string pattern = @"(?[^\s]+)\s+(?[^\s]+)\s+(?[^`s])"; @@ -171,7 +197,12 @@ private List GetInstalledTools(string toolLocation) foreach (Match match in Regex.Matches(installedTool, pattern, RegexOptions.IgnoreCase)) { _log.Debug("Adding tool {0}", match.Groups["packageName"].Value); - installedToolNames.Add(match.Groups["packageName"].Value); + installedToolNames.Add(new DotNetToolPackage + { + Id = match.Groups["packageName"].Value, + Version = match.Groups["packageVersion"].Value, + ShortCode = match.Groups["packageShortCode"].Value + }); } } @@ -179,14 +210,14 @@ private List GetInstalledTools(string toolLocation) return installedToolNames; } - private void InstallTool(PackageReference package, DirectoryPath toolsFolderDirectoryPath) + private void RunDotNetTool(PackageReference package, DirectoryPath toolsFolderDirectoryPath, DotNetToolOperation operation) { // Install the tool.... - _log.Debug("Installing dotnet tool: {0}...", package.Package); + _log.Debug("Running dotnet tool with operation {0}: {1}...", operation, package.Package); var process = _processRunner.Start( "dotnet", new ProcessSettings { - Arguments = GetArguments(package, _log, toolsFolderDirectoryPath), + Arguments = GetArguments(package, operation, _log, toolsFolderDirectoryPath), RedirectStandardOutput = true, Silent = _log.Verbosity < Verbosity.Diagnostic, NoWorkingDirectory = true }); @@ -201,14 +232,17 @@ private void InstallTool(PackageReference package, DirectoryPath toolsFolderDire _log.Verbose(Verbosity.Diagnostic, "Output:\r\n{0}", output); } } + private static ProcessArgumentBuilder GetArguments( PackageReference definition, + DotNetToolOperation operation, ICakeLog log, DirectoryPath toolDirectoryPath) { var arguments = new ProcessArgumentBuilder(); - arguments.Append("tool install"); + arguments.Append("tool"); + arguments.Append(Enum.GetName(typeof(DotNetToolOperation), operation).ToLowerInvariant()); arguments.AppendQuoted(definition.Package); if(definition.Parameters.ContainsKey("global")) @@ -221,67 +255,70 @@ private static ProcessArgumentBuilder GetArguments( arguments.AppendQuoted(toolDirectoryPath.FullPath); } - if (definition.Address != null) + if (operation != DotNetToolOperation.Uninstall) { - arguments.Append("--add-source"); - arguments.AppendQuoted(definition.Address.AbsoluteUri); - } + if (definition.Address != null) + { + arguments.Append("--add-source"); + arguments.AppendQuoted(definition.Address.AbsoluteUri); + } - // Version - if (definition.Parameters.ContainsKey("version")) - { - arguments.Append("--version"); - arguments.Append(definition.Parameters["version"].First()); - } + // Version + if (definition.Parameters.ContainsKey("version")) + { + arguments.Append("--version"); + arguments.Append(definition.Parameters["version"].First()); + } - // Config File - if(definition.Parameters.ContainsKey("configfile")) - { - arguments.Append("--configfile"); - arguments.AppendQuoted(definition.Parameters["configfile"].First()); - } + // Config File + if(definition.Parameters.ContainsKey("configfile")) + { + arguments.Append("--configfile"); + arguments.AppendQuoted(definition.Parameters["configfile"].First()); + } - // Whether to ignore failed sources - if(definition.Parameters.ContainsKey("ignore-failed-sources")) - { - arguments.Append("--ignore-failed-sources"); - } + // Whether to ignore failed sources + if(definition.Parameters.ContainsKey("ignore-failed-sources")) + { + arguments.Append("--ignore-failed-sources"); + } - // Framework - if (definition.Parameters.ContainsKey("framework")) - { - arguments.Append("--framework"); - arguments.Append(definition.Parameters["framework"].First()); - } + // Framework + if (definition.Parameters.ContainsKey("framework")) + { + arguments.Append("--framework"); + arguments.Append(definition.Parameters["framework"].First()); + } - switch(log.Verbosity) - { - case Verbosity.Quiet: - arguments.Append("--verbosity"); - arguments.Append("quiet"); - break; - case Verbosity.Minimal: - arguments.Append("--verbosity"); - arguments.Append("minimal"); - break; - case Verbosity.Normal: - arguments.Append("--verbosity"); - arguments.Append("normal"); - break; - case Verbosity.Verbose: - arguments.Append("--verbosity"); - arguments.Append("detailed"); - break; - case Verbosity.Diagnostic: - arguments.Append("--verbosity"); - arguments.Append("diagnostic"); - break; - default: + switch(log.Verbosity) + { + case Verbosity.Quiet: + arguments.Append("--verbosity"); + arguments.Append("quiet"); + break; + case Verbosity.Minimal: + arguments.Append("--verbosity"); + arguments.Append("minimal"); + break; + case Verbosity.Normal: arguments.Append("--verbosity"); - arguments.Append("normal"); - break; + arguments.Append("normal"); + break; + case Verbosity.Verbose: + arguments.Append("--verbosity"); + arguments.Append("detailed"); + break; + case Verbosity.Diagnostic: + arguments.Append("--verbosity"); + arguments.Append("diagnostic"); + break; + default: + arguments.Append("--verbosity"); + arguments.Append("normal"); + break; + } } - + return arguments; } }