@@ -108,16 +108,42 @@ public IReadOnlyCollection<IFile> Install(PackageReference package, PackageType
108108 }
109109
110110 // First we need to check if the Tool is already installed
111- var installedToolNames = GetInstalledTools ( toolLocation ) ;
111+ var installedTools = GetInstalledTools ( toolLocation ) ;
112112
113113 _log . Debug ( "Checking for tool: {0}" , package . Package . ToLowerInvariant ( ) ) ;
114- if ( installedToolNames . Contains ( package . Package . ToLowerInvariant ( ) ) )
114+
115+ var installedTool = installedTools . FirstOrDefault ( t => t . Id . ToLowerInvariant ( ) == package . Package . ToLowerInvariant ( ) ) ;
116+
117+ if ( installedTool != null )
115118 {
116- _log . Information ( "Tool {0} is already installed, so nothing to do here." , package . Package ) ;
119+ // The tool is already installed, so need to check if requested version is the same as
120+ // what is already installed
121+ string requestedVersion = null ;
122+
123+ if ( package . Parameters . ContainsKey ( "version" ) )
124+ {
125+ requestedVersion = package . Parameters [ "version" ] . First ( ) ;
126+ }
127+
128+ if ( requestedVersion == null )
129+ {
130+ _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 ) ;
131+ }
132+ else if ( requestedVersion . ToLowerInvariant ( ) != installedTool . Version . ToLowerInvariant ( ) )
133+ {
134+ _log . Warning ( "Tool {0} is already installed, but a different version has been requested. Uninstall/install will now be performed..." , package . Package ) ;
135+ RunDotNetTool ( package , toolsFolderDirectoryPath , DotNetToolOperation . Uninstall ) ;
136+ RunDotNetTool ( package , toolsFolderDirectoryPath , DotNetToolOperation . Install ) ;
137+ }
138+ else
139+ {
140+ _log . Information ( "Tool {0} is already installed, with required version." , package . Package ) ;
141+ }
117142 }
118143 else
119144 {
120- InstallTool ( package , toolsFolderDirectoryPath ) ;
145+ // The tool isn't already installed, go ahead and install it
146+ RunDotNetTool ( package , toolsFolderDirectoryPath , DotNetToolOperation . Install ) ;
121147 }
122148
123149 var result = _contentResolver . GetFiles ( package , type ) ;
@@ -130,7 +156,7 @@ public IReadOnlyCollection<IFile> Install(PackageReference package, PackageType
130156 return result ;
131157 }
132158
133- private List < string > GetInstalledTools ( string toolLocation )
159+ private List < DotNetToolPackage > GetInstalledTools ( string toolLocation )
134160 {
135161 var toolLocationArgument = string . Empty ;
136162 if ( toolLocation != "global" )
@@ -144,7 +170,7 @@ private List<string> GetInstalledTools(string toolLocation)
144170 if ( ! toolLocationDirectory . Exists )
145171 {
146172 _log . Debug ( "Specified installation location doesn't currently exist." ) ;
147- return new List < string > ( ) ;
173+ return new List < DotNetToolPackage > ( ) ;
148174 }
149175 }
150176 else
@@ -162,7 +188,7 @@ private List<string> GetInstalledTools(string toolLocation)
162188 isInstalledProcess . WaitForExit ( ) ;
163189
164190 var installedTools = isInstalledProcess . GetStandardOutput ( ) . ToList ( ) ;
165- var installedToolNames = new List < string > ( ) ;
191+ var installedToolNames = new List < DotNetToolPackage > ( ) ;
166192
167193 string pattern = @"(?<packageName>[^\s]+)\s+(?<packageVersion>[^\s]+)\s+(?<packageShortCode>[^`s])" ;
168194
@@ -171,22 +197,27 @@ private List<string> GetInstalledTools(string toolLocation)
171197 foreach ( Match match in Regex . Matches ( installedTool , pattern , RegexOptions . IgnoreCase ) )
172198 {
173199 _log . Debug ( "Adding tool {0}" , match . Groups [ "packageName" ] . Value ) ;
174- installedToolNames . Add ( match . Groups [ "packageName" ] . Value ) ;
200+ installedToolNames . Add ( new DotNetToolPackage
201+ {
202+ Id = match . Groups [ "packageName" ] . Value ,
203+ Version = match . Groups [ "packageVersion" ] . Value ,
204+ ShortCode = match . Groups [ "packageShortCode" ] . Value
205+ } ) ;
175206 }
176207 }
177208
178209 _log . Debug ( "There are {0} dotnet tools installed" , installedToolNames . Count ) ;
179210 return installedToolNames ;
180211 }
181212
182- private void InstallTool ( PackageReference package , DirectoryPath toolsFolderDirectoryPath )
213+ private void RunDotNetTool ( PackageReference package , DirectoryPath toolsFolderDirectoryPath , DotNetToolOperation operation )
183214 {
184215 // Install the tool....
185- _log . Debug ( "Installing dotnet tool: {0}..." , package . Package ) ;
216+ _log . Debug ( "Running dotnet tool with operation {0}: {1} ..." , operation , package . Package ) ;
186217 var process = _processRunner . Start (
187218 "dotnet" ,
188219 new ProcessSettings {
189- Arguments = GetArguments ( package , _log , toolsFolderDirectoryPath ) ,
220+ Arguments = GetArguments ( package , operation , _log , toolsFolderDirectoryPath ) ,
190221 RedirectStandardOutput = true ,
191222 Silent = _log . Verbosity < Verbosity . Diagnostic ,
192223 NoWorkingDirectory = true } ) ;
@@ -201,14 +232,17 @@ private void InstallTool(PackageReference package, DirectoryPath toolsFolderDire
201232 _log . Verbose ( Verbosity . Diagnostic , "Output:\r \n {0}" , output ) ;
202233 }
203234 }
235+
204236 private static ProcessArgumentBuilder GetArguments (
205237 PackageReference definition ,
238+ DotNetToolOperation operation ,
206239 ICakeLog log ,
207240 DirectoryPath toolDirectoryPath )
208241 {
209242 var arguments = new ProcessArgumentBuilder ( ) ;
210243
211- arguments . Append ( "tool install" ) ;
244+ arguments . Append ( "tool" ) ;
245+ arguments . Append ( Enum . GetName ( typeof ( DotNetToolOperation ) , operation ) . ToLowerInvariant ( ) ) ;
212246 arguments . AppendQuoted ( definition . Package ) ;
213247
214248 if ( definition . Parameters . ContainsKey ( "global" ) )
@@ -221,67 +255,70 @@ private static ProcessArgumentBuilder GetArguments(
221255 arguments . AppendQuoted ( toolDirectoryPath . FullPath ) ;
222256 }
223257
224- if ( definition . Address != null )
258+ if ( operation != DotNetToolOperation . Uninstall )
225259 {
226- arguments . Append ( "--add-source" ) ;
227- arguments . AppendQuoted ( definition . Address . AbsoluteUri ) ;
228- }
260+ if ( definition . Address != null )
261+ {
262+ arguments . Append ( "--add-source" ) ;
263+ arguments . AppendQuoted ( definition . Address . AbsoluteUri ) ;
264+ }
229265
230- // Version
231- if ( definition . Parameters . ContainsKey ( "version" ) )
232- {
233- arguments . Append ( "--version" ) ;
234- arguments . Append ( definition . Parameters [ "version" ] . First ( ) ) ;
235- }
266+ // Version
267+ if ( definition . Parameters . ContainsKey ( "version" ) )
268+ {
269+ arguments . Append ( "--version" ) ;
270+ arguments . Append ( definition . Parameters [ "version" ] . First ( ) ) ;
271+ }
236272
237- // Config File
238- if ( definition . Parameters . ContainsKey ( "configfile" ) )
239- {
240- arguments . Append ( "--configfile" ) ;
241- arguments . AppendQuoted ( definition . Parameters [ "configfile" ] . First ( ) ) ;
242- }
273+ // Config File
274+ if ( definition . Parameters . ContainsKey ( "configfile" ) )
275+ {
276+ arguments . Append ( "--configfile" ) ;
277+ arguments . AppendQuoted ( definition . Parameters [ "configfile" ] . First ( ) ) ;
278+ }
243279
244- // Whether to ignore failed sources
245- if ( definition . Parameters . ContainsKey ( "ignore-failed-sources" ) )
246- {
247- arguments . Append ( "--ignore-failed-sources" ) ;
248- }
280+ // Whether to ignore failed sources
281+ if ( definition . Parameters . ContainsKey ( "ignore-failed-sources" ) )
282+ {
283+ arguments . Append ( "--ignore-failed-sources" ) ;
284+ }
249285
250- // Framework
251- if ( definition . Parameters . ContainsKey ( "framework" ) )
252- {
253- arguments . Append ( "--framework" ) ;
254- arguments . Append ( definition . Parameters [ "framework" ] . First ( ) ) ;
255- }
286+ // Framework
287+ if ( definition . Parameters . ContainsKey ( "framework" ) )
288+ {
289+ arguments . Append ( "--framework" ) ;
290+ arguments . Append ( definition . Parameters [ "framework" ] . First ( ) ) ;
291+ }
256292
257- switch ( log . Verbosity )
258- {
259- case Verbosity . Quiet :
260- arguments . Append ( "--verbosity" ) ;
261- arguments . Append ( "quiet" ) ;
262- break ;
263- case Verbosity . Minimal :
264- arguments . Append ( "--verbosity" ) ;
265- arguments . Append ( "minimal" ) ;
266- break ;
267- case Verbosity . Normal :
268- arguments . Append ( "--verbosity" ) ;
269- arguments . Append ( "normal" ) ;
270- break ;
271- case Verbosity . Verbose :
272- arguments . Append ( "--verbosity" ) ;
273- arguments . Append ( "detailed" ) ;
274- break ;
275- case Verbosity . Diagnostic :
276- arguments . Append ( "--verbosity" ) ;
277- arguments . Append ( "diagnostic" ) ;
278- break ;
279- default :
293+ switch ( log . Verbosity )
294+ {
295+ case Verbosity . Quiet :
296+ arguments . Append ( "--verbosity" ) ;
297+ arguments . Append ( "quiet" ) ;
298+ break ;
299+ case Verbosity . Minimal :
300+ arguments . Append ( "--verbosity" ) ;
301+ arguments . Append ( "minimal" ) ;
302+ break ;
303+ case Verbosity . Normal :
280304 arguments . Append ( "--verbosity" ) ;
281- arguments . Append ( "normal" ) ;
282- break ;
305+ arguments . Append ( "normal" ) ;
306+ break ;
307+ case Verbosity . Verbose :
308+ arguments . Append ( "--verbosity" ) ;
309+ arguments . Append ( "detailed" ) ;
310+ break ;
311+ case Verbosity . Diagnostic :
312+ arguments . Append ( "--verbosity" ) ;
313+ arguments . Append ( "diagnostic" ) ;
314+ break ;
315+ default :
316+ arguments . Append ( "--verbosity" ) ;
317+ arguments . Append ( "normal" ) ;
318+ break ;
319+ }
283320 }
284-
321+
285322 return arguments ;
286323 }
287324 }
0 commit comments