diff --git a/AppInspector.CLI/CLICmdOptions.cs b/AppInspector.CLI/CLICmdOptions.cs index a9e2d820..59c0db15 100644 --- a/AppInspector.CLI/CLICmdOptions.cs +++ b/AppInspector.CLI/CLICmdOptions.cs @@ -43,6 +43,9 @@ public class CLIGetTagsCommandOptions : CLICommandOptions [Option("file-timeout", Required = false, HelpText = "If set, maximum amount of time in milliseconds to allow for processing each file.", Default = 0)] public int FileTimeOut { get; set; } = 0; + [Option("processing-timeout", Required = false, HelpText = "If set, maximum amount of time in milliseconds to allow for processing overall.", Default = 0)] + public int ProcessingTimeOut { get; set; } = 0; + [Option("single-threaded", Required = false, HelpText = "Disables parallel processing.")] public bool SingleThread { get; set; } @@ -80,6 +83,9 @@ public class CLIAnalyzeCmdOptions : CLICommandOptions [Option("file-timeout", Required = false, HelpText = "If set, maximum amount of time in milliseconds to allow for processing each file.", Default = 0)] public int FileTimeOut { get; set; } = 0; + [Option("processing-timeout", Required = false, HelpText = "If set, maximum amount of time in milliseconds to allow for processing overall.", Default = 0)] + public int ProcessingTimeOut { get; set; } = 0; + [Option("single-threaded", Required = false, HelpText = "Disables parallel processing.")] public bool SingleThread { get; set; } diff --git a/AppInspector.CLI/Program.cs b/AppInspector.CLI/Program.cs index 44d4db81..993e5e8d 100644 --- a/AppInspector.CLI/Program.cs +++ b/AppInspector.CLI/Program.cs @@ -278,7 +278,8 @@ private static int RunGetTagsCommand(CLIGetTagsCommandOptions cliOptions) Log = cliOptions.Log, SingleThread = cliOptions.SingleThread, NoShowProgress = cliOptions.NoShowProgressBar, - FileTimeOut = cliOptions.FileTimeOut + FileTimeOut = cliOptions.FileTimeOut, + ProcessingTimeOut = cliOptions.ProcessingTimeOut }); GetTagsResult getTagsResult = command.GetResult(); @@ -290,8 +291,6 @@ private static int RunGetTagsCommand(CLIGetTagsCommandOptions cliOptions) private static int RunAnalyzeCommand(CLIAnalyzeCmdOptions cliOptions) { - AnalyzeResult.ExitCode exitCode = AnalyzeResult.ExitCode.CriticalError; - AnalyzeCommand command = new AnalyzeCommand(new AnalyzeOptions() { SourcePath = cliOptions.SourcePath ?? "", @@ -303,20 +302,18 @@ private static int RunAnalyzeCommand(CLIAnalyzeCmdOptions cliOptions) Log = cliOptions.Log, SingleThread = cliOptions.SingleThread, NoShowProgress = cliOptions.NoShowProgressBar, - FileTimeOut = cliOptions.FileTimeOut + FileTimeOut = cliOptions.FileTimeOut, + ProcessingTimeOut = cliOptions.ProcessingTimeOut }); AnalyzeResult analyzeResult = command.GetResult(); - exitCode = analyzeResult.ResultCode; ResultsWriter.Write(analyzeResult, cliOptions); - return (int)exitCode; + return (int)analyzeResult.ResultCode; } private static int RunTagDiffCommand(CLITagDiffCmdOptions cliOptions) { - TagDiffResult.ExitCode exitCode = TagDiffResult.ExitCode.CriticalError; - TagDiffCommand command = new TagDiffCommand(new TagDiffOptions() { SourcePath1 = cliOptions.SourcePath1 ?? "", @@ -330,16 +327,13 @@ private static int RunTagDiffCommand(CLITagDiffCmdOptions cliOptions) }); TagDiffResult tagDiffResult = command.GetResult(); - exitCode = tagDiffResult.ResultCode; ResultsWriter.Write(tagDiffResult, cliOptions); - return (int)exitCode; + return (int)tagDiffResult.ResultCode; } private static int RunTagTestCommand(CLITagTestCmdOptions cliOptions) { - TagTestResult.ExitCode exitCode = TagTestResult.ExitCode.CriticalError; - TagTestCommand command = new TagTestCommand(new TagTestOptions() { SourcePath = cliOptions.SourcePath, @@ -351,16 +345,13 @@ private static int RunTagTestCommand(CLITagTestCmdOptions cliOptions) }); TagTestResult tagTestCommand = command.GetResult(); - exitCode = tagTestCommand.ResultCode; ResultsWriter.Write(tagTestCommand, cliOptions); - return (int)exitCode; + return (int)tagTestCommand.ResultCode; } private static int RunExportTagsCommand(CLIExportTagsCmdOptions cliOptions) { - ExportTagsResult.ExitCode exitCode = ExportTagsResult.ExitCode.CriticalError; - ExportTagsCommand command = new ExportTagsCommand(new ExportTagsOptions() { IgnoreDefaultRules = cliOptions.IgnoreDefaultRules, @@ -370,16 +361,13 @@ private static int RunExportTagsCommand(CLIExportTagsCmdOptions cliOptions) }); ExportTagsResult exportTagsResult = command.GetResult(); - exitCode = exportTagsResult.ResultCode; ResultsWriter.Write(exportTagsResult, cliOptions); - return (int)exitCode; + return (int)exportTagsResult.ResultCode; } private static int RunVerifyRulesCommand(CLIVerifyRulesCmdOptions cliOptions) { - VerifyRulesResult.ExitCode exitCode = VerifyRulesResult.ExitCode.CriticalError; - VerifyRulesCommand command = new VerifyRulesCommand(new VerifyRulesOptions() { VerifyDefaultRules = cliOptions.VerifyDefaultRules, @@ -390,16 +378,13 @@ private static int RunVerifyRulesCommand(CLIVerifyRulesCmdOptions cliOptions) }); VerifyRulesResult exportTagsResult = command.GetResult(); - exitCode = exportTagsResult.ResultCode; ResultsWriter.Write(exportTagsResult, cliOptions); - return (int)exitCode; + return (int)exportTagsResult.ResultCode; } private static int RunPackRulesCommand(CLIPackRulesCmdOptions cliOptions) { - PackRulesResult.ExitCode exitCode = PackRulesResult.ExitCode.CriticalError; - PackRulesCommand command = new PackRulesCommand(new PackRulesOptions() { RepackDefaultRules = cliOptions.RepackDefaultRules, @@ -409,10 +394,9 @@ private static int RunPackRulesCommand(CLIPackRulesCmdOptions cliOptions) }); PackRulesResult exportTagsResult = command.GetResult(); - exitCode = exportTagsResult.ResultCode; ResultsWriter.Write(exportTagsResult, cliOptions); - return (int)exitCode; + return (int)exportTagsResult.ResultCode; } #endregion RunCmdsWriteResults diff --git a/AppInspector/Commands/AnalyzeCommand.cs b/AppInspector/Commands/AnalyzeCommand.cs index 91a4ab9c..c447bdd9 100644 --- a/AppInspector/Commands/AnalyzeCommand.cs +++ b/AppInspector/Commands/AnalyzeCommand.cs @@ -30,6 +30,7 @@ public class AnalyzeOptions : CommandOptions public bool TreatEverythingAsCode { get; set; } = false; public bool NoShowProgress { get; set; } = true; public int FileTimeOut { get; set; } = 0; + public int ProcessingTimeOut { get; set; } = 0; } /// @@ -42,7 +43,8 @@ public enum ExitCode Success = 0, NoMatches = 1, CriticalError = Utils.ExitCode.CriticalError, //ensure common value for final exit log mention - Canceled = 3 + Canceled = 3, + TimedOut = 4 } [JsonProperty(Order = 2, PropertyName = "resultCode")] @@ -447,6 +449,8 @@ public AnalyzeResult GetResult() AppVersion = Utils.GetVersionString() }; + var timedOut = false; + if (!_options.NoShowProgress) { var done = false; @@ -504,7 +508,7 @@ public AnalyzeResult GetResult() sw.Start(); _ = Task.Factory.StartNew(() => { - PopulateRecords(new CancellationToken(), _options, fileQueue); + DoProcessing(fileQueue); done = true; }); @@ -525,7 +529,7 @@ public AnalyzeResult GetResult() } else { - PopulateRecords(new CancellationToken(), _options, GetFileEntries(_options)); + DoProcessing(GetFileEntries(_options)); } //wrapup result status @@ -547,7 +551,39 @@ public AnalyzeResult GetResult() analyzeResult.ResultCode = AnalyzeResult.ExitCode.Success; } + if (timedOut) + { + analyzeResult.ResultCode = AnalyzeResult.ExitCode.TimedOut; + } + return analyzeResult; + + void DoProcessing(IEnumerable fileEntries) + { + if (_options.ProcessingTimeOut > 0) + { + using var cts = new CancellationTokenSource(); + var t = Task.Run(() => PopulateRecords(cts.Token, _options, fileEntries), cts.Token); + if (!t.Wait(new TimeSpan(0, 0, 0, 0, _options.ProcessingTimeOut))) + { + timedOut = true; + WriteOnce.Error($"Processing timed out."); + cts.Cancel(); + if (_metaDataHelper is not null) + { + // Populate skips for all the entries we didn't process + foreach (var entry in fileEntries.Where(x => !_metaDataHelper.Files.Any(y => x.FullPath == y.FileName))) + { + _metaDataHelper.Files.Add(new FileRecord() { AccessTime = entry.AccessTime, CreateTime = entry.CreateTime, ModifyTime = entry.ModifyTime, FileName = entry.FullPath, Status = ScanState.TimeOutSkipped }); + } + } + } + } + else + { + PopulateRecords(new CancellationToken(), _options, fileEntries); + } + } } } } \ No newline at end of file diff --git a/AppInspector/Commands/GetTagsCommand.cs b/AppInspector/Commands/GetTagsCommand.cs index 9ff83afc..065f61ba 100644 --- a/AppInspector/Commands/GetTagsCommand.cs +++ b/AppInspector/Commands/GetTagsCommand.cs @@ -30,6 +30,7 @@ public class GetTagsCommandOptions : CommandOptions public bool TreatEverythingAsCode { get; set; } = false; public bool NoShowProgress { get; set; } = true; public int FileTimeOut { get; set; } = 0; + public int ProcessingTimeOut { get; set; } } /// @@ -42,7 +43,8 @@ public enum ExitCode Success = 0, NoMatches = 1, CriticalError = Utils.ExitCode.CriticalError, //ensure common value for final exit log mention - Canceled = 3 + Canceled = 3, + TimedOut = 4 } [JsonProperty(Order = 2, PropertyName = "resultCode")] @@ -444,6 +446,8 @@ public GetTagsResult GetResult() AppVersion = Utils.GetVersionString() }; + var timedOut = false; + if (!_options.NoShowProgress) { var done = false; @@ -501,7 +505,7 @@ public GetTagsResult GetResult() sw.Start(); _ = Task.Factory.StartNew(() => { - PopulateRecords(new CancellationToken(), _options, fileQueue); + DoProcessing(fileQueue); done = true; }); @@ -521,7 +525,7 @@ public GetTagsResult GetResult() } else { - PopulateRecords(new CancellationToken(), _options, GetFileEntries(_options)); + DoProcessing(GetFileEntries(_options)); } //wrapup result status @@ -543,7 +547,39 @@ public GetTagsResult GetResult() getTagsResult.ResultCode = GetTagsResult.ExitCode.Success; } + if (timedOut) + { + getTagsResult.ResultCode = GetTagsResult.ExitCode.TimedOut; + } + return getTagsResult; + + void DoProcessing(IEnumerable fileEntries) + { + if (_options.ProcessingTimeOut > 0) + { + using var cts = new CancellationTokenSource(); + var t = Task.Run(() => PopulateRecords(cts.Token, _options, fileEntries), cts.Token); + if (!t.Wait(new TimeSpan(0, 0, 0, 0, _options.ProcessingTimeOut))) + { + timedOut = true; + WriteOnce.Error($"Processing timed out."); + cts.Cancel(); + if (_metaDataHelper is not null) + { + // Populate skips for all the entries we didn't process + foreach (var entry in fileEntries.Where(x => !_metaDataHelper.Files.Any(y => x.FullPath == y.FileName))) + { + _metaDataHelper.Files.Add(new FileRecord() { AccessTime = entry.AccessTime, CreateTime = entry.CreateTime, ModifyTime = entry.ModifyTime, FileName = entry.FullPath, Status = ScanState.TimeOutSkipped }); + } + } + } + } + else + { + PopulateRecords(new CancellationToken(), _options, fileEntries); + } + } } } } \ No newline at end of file diff --git a/AppInspector/FileRecord.cs b/AppInspector/FileRecord.cs index 8e4b1fef..50f3c448 100644 --- a/AppInspector/FileRecord.cs +++ b/AppInspector/FileRecord.cs @@ -19,6 +19,7 @@ public enum ScanState Skipped, TimedOut, Analyzed, - Affected + Affected, + TimeOutSkipped } }