|
3 | 3 | using System.Collections.ObjectModel; |
4 | 4 | using System.IO; |
5 | 5 | using System.Linq; |
| 6 | +using System.Threading; |
6 | 7 | using Newtonsoft.Json.Linq; |
7 | 8 |
|
8 | 9 | using Semmle.Util; |
@@ -36,12 +37,29 @@ private DotNet(ILogger logger, string? dotNetPath, TemporaryDirectory tempWorkin |
36 | 37 |
|
37 | 38 | public static IDotNet Make(ILogger logger, string? dotNetPath, TemporaryDirectory tempWorkingDirectory, DependabotProxy? dependabotProxy) => new DotNet(logger, dotNetPath, tempWorkingDirectory, dependabotProxy); |
38 | 39 |
|
| 40 | + private static void HandleRetryExitCode143(string dotnet, int attempt, ILogger logger) |
| 41 | + { |
| 42 | + logger.LogWarning($"Running '{dotnet} --info' failed with exit code 143. Retrying..."); |
| 43 | + var sleep = Math.Pow(2, attempt) * 1000; |
| 44 | + Thread.Sleep((int)sleep); |
| 45 | + } |
| 46 | + |
39 | 47 | private void Info() |
40 | 48 | { |
41 | | - var res = dotnetCliInvoker.RunCommand("--info", silent: false); |
42 | | - if (!res) |
| 49 | + // Allow up to four attempts (with up to three retries) to run `dotnet --info`, to mitigate transient issues |
| 50 | + for (int attempt = 0; attempt < 4; attempt++) |
43 | 51 | { |
44 | | - throw new Exception($"{dotnetCliInvoker.Exec} --info failed."); |
| 52 | + var exitCode = dotnetCliInvoker.RunCommandExitCode("--info", silent: false); |
| 53 | + switch (exitCode) |
| 54 | + { |
| 55 | + case 0: |
| 56 | + return; |
| 57 | + case 143 when attempt < 3: |
| 58 | + HandleRetryExitCode143(dotnetCliInvoker.Exec, attempt, logger); |
| 59 | + continue; |
| 60 | + default: |
| 61 | + throw new Exception($"{dotnetCliInvoker.Exec} --info failed with exit code {exitCode}."); |
| 62 | + } |
45 | 63 | } |
46 | 64 | } |
47 | 65 |
|
@@ -193,6 +211,35 @@ private static BuildScript DownloadDotNet(IBuildActions actions, ILogger logger, |
193 | 211 | return BuildScript.Failure; |
194 | 212 | } |
195 | 213 |
|
| 214 | + /// <summary> |
| 215 | + /// Returns a script for running `dotnet --info`, with retries on exit code 143. |
| 216 | + /// </summary> |
| 217 | + public static BuildScript InfoScript(IBuildActions actions, string dotnet, IDictionary<string, string>? environment, ILogger logger) |
| 218 | + { |
| 219 | + var info = new CommandBuilder(actions, null, environment). |
| 220 | + RunCommand(dotnet). |
| 221 | + Argument("--info"); |
| 222 | + var script = info.Script; |
| 223 | + for (var attempt = 0; attempt < 4; attempt++) |
| 224 | + { |
| 225 | + var attemptCopy = attempt; // Capture in local variable |
| 226 | + script = BuildScript.Bind(script, ret => |
| 227 | + { |
| 228 | + switch (ret) |
| 229 | + { |
| 230 | + case 0: |
| 231 | + return BuildScript.Success; |
| 232 | + case 143 when attemptCopy < 3: |
| 233 | + HandleRetryExitCode143(dotnet, attemptCopy, logger); |
| 234 | + return info.Script; |
| 235 | + default: |
| 236 | + return BuildScript.Failure; |
| 237 | + } |
| 238 | + }); |
| 239 | + } |
| 240 | + return script; |
| 241 | + } |
| 242 | + |
196 | 243 | /// <summary> |
197 | 244 | /// Returns a script for downloading specific .NET SDK versions, if the |
198 | 245 | /// versions are not already installed. |
@@ -292,9 +339,7 @@ BuildScript GetInstall(string pwsh) => |
292 | 339 | }; |
293 | 340 | } |
294 | 341 |
|
295 | | - var dotnetInfo = new CommandBuilder(actions, environment: MinimalEnvironment). |
296 | | - RunCommand(actions.PathCombine(path, "dotnet")). |
297 | | - Argument("--info").Script; |
| 342 | + var dotnetInfo = InfoScript(actions, actions.PathCombine(path, "dotnet"), MinimalEnvironment.ToDictionary(), logger); |
298 | 343 |
|
299 | 344 | Func<string, BuildScript> getInstallAndVerify = version => |
300 | 345 | // run `dotnet --info` after install, to check that it executes successfully |
|
0 commit comments