public static IDictionary <string, long> Process(IEnumerable <NPath> pathsToFormat, FormatContext formatContext, Func <FormatItem, bool> cancellableBeforeFormatCallback = null) { if (formatContext == null) { formatContext = new FormatContext(); } if ((formatContext.Options & FormatOptions.DryRun) != 0) { throw new NotImplementedException("DryRun not supported yet"); } var formatted = new Dictionary <string, long>(); var formatItems = new List <FormatItem>(); foreach (var path in pathsToFormat) { FormatItem item; if (!File.Exists(path)) { formatContext.Logger.Error($"File {path} doesn't exist'"); continue; } try { item = FormatItem.TryCreate(new NPath(path), formatContext); } catch (Exception inner) { var outer = new Exception($"Fatal occurred while configuring formatting for '{path}' (see inner exception for details)", inner); outer.Data["pathToFormat"] = path.ToString(); throw outer; } if (item == null) { continue; } if (!CheckHeader(item)) { continue; } formatItems.Add(item); if (cancellableBeforeFormatCallback != null && cancellableBeforeFormatCallback.Invoke(item)) { return(formatted); } } if (formatItems.Any()) { // avoid requiring ThisPackageRoot if we are only using the Generic formatter, which has no external // tooling dependencies if (formatItems.SelectMany(fi => fi.Formatters).Any(f => f != FormatterType.Generic)) { EnsureFilePermissionsOnUnixLikeOS(formatContext.ThisPackageRoot); } // FUTURE: this is a good spot to group by formatter, then let the formatter segment (for example, // uncrustify would want to segment by associated .ini file), so we can do batching with response // files to avoid per-file process spawn overhead. var sw = Stopwatch.StartNew(); foreach (var formatItem in formatItems) { if (cancellableBeforeFormatCallback != null && cancellableBeforeFormatCallback.Invoke(formatItem)) { break; } if (Process(formatItem)) { formatted[formatItem.Path] = File.GetLastWriteTime(formatItem.Path).Ticks; } } sw.Stop(); formatContext.Logger.Debug($"Formatted {formatItems.Count} files. Took {sw.ElapsedMilliseconds}ms"); } return(formatted); }