/// <summary> /// This is the function that actually does the searching. It creates threads and searches and then /// waits for all the results to be sent. /// </summary> public void internalSearch() { String searchDirectory = mSearchParams.SearchDirectory; if (mRegex != null) { List <String> fileList = DirectoryCache.get().getFileList(); if (fileList != null) { Stats.TotalFilesToSearch = fileList.Count; Logger.get().AddInfoFormat("{0} files to search", Stats.TotalFilesToSearch); try { // Set up the parallel lambda expression. The parameters were trial and error trying to get the fastest execution fileList.AsParallel().WithExecutionMode(ParallelExecutionMode.ForceParallelism).WithDegreeOfParallelism(63) .WithCancellation(Stats.CancellationTokenSource.Token) .WithMergeOptions(ParallelMergeOptions.FullyBuffered).ForAll(file => { // Check for cancellation, this speeds up the cancel after the button is clicked. if (!Stats.CancellationTokenSource.IsCancellationRequested) { if (mSearchParams.FileNameSearch) { if (mRegex.IsMatch(file)) { SearchResultList list = new SearchResultList(PathExt.GetRelativePath(searchDirectory, file)); saveResults(list); } } else { searchFile(file); } } }); } catch (OperationCanceledException) { // Cancelling is not an error, why do they throw an exception? } catch (Exception ex) { Logger.get().AddError(ex.Message); } } else { SearchResultList results = new SearchResultList(DirectoryCache.get().ErrorMessage); mPendingResults.Add(results); } } waitForResultsToBeSent(); }
public override void Execute(params string[] args) { if (CheckHelpAndVersion(args)) { return; } DemoParsingSetupInfo setupInfo = new DemoParsingSetupInfo(); ParseArgs(args, setupInfo); // check the values in setupInfo // enable --time implicitly if there are no other options if (setupInfo.ExecutableOptions == 0) { if (TryGetOption(OptTime.DefaultAliases[0], out var option)) { option.Enable(null); option.AfterParse(setupInfo); } else { throw new ArgProcessProgrammerException("listdemo option not passed to demo sub-command."); } } // if (setupInfo.OverWriteDemos && !setupInfo.WritesNewDemos) <- I could add a check for this, is it necessary? if (setupInfo.OverWriteDemos && setupInfo.EditsDemos && setupInfo.OverwritePrompt) { Utils.Warning("Warning:"); Console.WriteLine($" '{OptOverwrite.DefaultAliases[0]}' enabled, this will edit demos and may cause corruption!"); Console.Write("Are you sure you want to continue? "); string?inp = null; while (inp != "y") { Console.Write("[y/n]"); inp = Console.ReadLine()?.Trim().ToLower(); if (inp == "n") { return; } } } // flatten directories/files into just files foreach (FileSystemInfo fileSystemInfo in _argPaths) { switch (fileSystemInfo) { case FileInfo fi: _demoPaths.Add(fi); break; case DirectoryInfo di: _demoPaths.UnionWith(Directory.GetFiles(di.FullName, "*.dem", setupInfo.ShouldSearchForDemosRecursively ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly) .Select(s => new FileInfo(s))); break; default: throw new ArgumentOutOfRangeException(); } } if (_demoPaths.Count == 0) { if (_argPaths.Any(fsi => fsi is DirectoryInfo)) { throw new ArgProcessUserException($"no demos found, maybe try searching subfolders using '{OptRecursive.DefaultAliases[0]}'."); } throw new ArgProcessUserException("no demos found!"); } // Shorten the paths of the demos if possible, the shared path between the first and last paths will give // the overall shared path of everything. If it's empty then we know the demos span multiple drives. string commonParent = Utils.SharedPathSubstring(_demoPaths.Min.FullName, _demoPaths.Max.FullName); IEnumerable <(FileInfo demoPath, string displayName)> paths = _demoPaths.Select(demoPath => ( demoPath, commonParent == "" ? demoPath.FullName : PathExt.GetRelativePath(commonParent, demoPath.FullName) )); using DemoParsingInfo parsingInfo = new DemoParsingInfo(setupInfo, paths.ToImmutableList()); Process(parsingInfo); }