Skip to content

Commit 05099b7

Browse files
committed
added cancellation support
1 parent 01fb4bf commit 05099b7

2 files changed

Lines changed: 42 additions & 31 deletions

File tree

src/LineCount.cs

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,42 @@ namespace LineCount;
1212
// The excessive exception handling is necessitated by the fact that thrown exceptions don't carry any information about the file that caused them, rendering top-level exception handling infeasible.
1313
public static class LineCount
1414
{
15-
public static async Task<ReportResult> Run(string path, LineCountData data, string[] excludeDirectories, string[] excludeFiles)
15+
public static async Task<ReportResult?> Run(string path, LineCountData data, string[] excludeDirectories, string[] excludeFiles, CancellationToken cancellationToken = default)
1616
{
17-
path = Path.TrimEndingDirectorySeparator(path);
18-
19-
var excludeFilePatterns = PathPatterns.Create(path, excludeFiles);
20-
var excludeDirectoryPatterns = PathPatterns.Create(path, excludeDirectories);
21-
22-
return await GetLineCount(path, data, excludeFilePatterns, excludeDirectoryPatterns);
17+
try
18+
{
19+
path = Path.TrimEndingDirectorySeparator(path);
20+
21+
var excludeFilePatterns = PathPatterns.Create(path, excludeFiles);
22+
var excludeDirectoryPatterns = PathPatterns.Create(path, excludeDirectories);
23+
24+
return await GetLineCount(path, data, excludeFilePatterns, excludeDirectoryPatterns, cancellationToken);
25+
}
26+
catch (OperationCanceledException)
27+
{
28+
return null;
29+
}
2330
}
2431

25-
static async Task<ReportResult> GetLineCount(string path, LineCountData data, PathPatterns excludeFilePatterns, PathPatterns excludeDirectoryPatterns)
32+
static async Task<ReportResult> GetLineCount(string path, LineCountData data, PathPatterns excludeFilePatterns, PathPatterns excludeDirectoryPatterns, CancellationToken cancellationToken = default)
2633
{
2734
try
2835
{
2936
FileAttributes attributes = File.GetAttributes(path);
3037

3138
if(!attributes.HasFlag(FileAttributes.Directory))
3239
{
33-
return await GetSingleFileLineCount(path, data);
40+
return await GetSingleFileLineCount(path, data, cancellationToken);
3441
}
3542

36-
var filesReportResult = await CountInFiles(path, data, excludeFilePatterns);
43+
var filesReportResult = await CountInFiles(path, data, excludeFilePatterns, cancellationToken);
3744

3845
if(!filesReportResult.TryGetValue(out var filesReport))
3946
{
4047
return filesReportResult;
4148
}
4249

43-
var directoriesReportResult = await CountInDirectories(path, data, excludeFilePatterns, excludeDirectoryPatterns);
50+
var directoriesReportResult = await CountInDirectories(path, data, excludeFilePatterns, excludeDirectoryPatterns, cancellationToken);
4451

4552
if (!directoriesReportResult.TryGetValue(out var directoriesReport))
4653
{
@@ -75,7 +82,7 @@ static async Task<ReportResult> GetLineCount(string path, LineCountData data, Pa
7582
}
7683
}
7784

78-
static async Task<ReportResult> CountInDirectories(string path, LineCountData data, PathPatterns excludeFilePatterns, PathPatterns excludeDirectoryPatterns)
85+
static async Task<ReportResult> CountInDirectories(string path, LineCountData data, PathPatterns excludeFilePatterns, PathPatterns excludeDirectoryPatterns, CancellationToken cancellationToken = default)
7986
{
8087
List<Task<ReportResult>> directorytasks = [];
8188

@@ -88,7 +95,7 @@ static async Task<ReportResult> CountInDirectories(string path, LineCountData da
8895
continue;
8996
}
9097

91-
var task = GetLineCount(directory, data, excludeFilePatterns, excludeDirectoryPatterns);
98+
var task = GetLineCount(directory, data, excludeFilePatterns, excludeDirectoryPatterns, cancellationToken);
9299
directorytasks.Add(task);
93100
}
94101
}
@@ -137,7 +144,7 @@ static async Task<ReportResult> CountInDirectories(string path, LineCountData da
137144
return new LineCountReport(lineCount, fileCount);
138145
}
139146

140-
static async Task<ReportResult> CountInFiles(string path, LineCountData data, PathPatterns excludeFilePatterns)
147+
static async Task<ReportResult> CountInFiles(string path, LineCountData data, PathPatterns excludeFilePatterns, CancellationToken cancellationToken = default)
141148
{
142149
List<Task<Result<FileStats, IError>>> filetasks = [];
143150

@@ -152,7 +159,7 @@ static async Task<ReportResult> CountInFiles(string path, LineCountData data, Pa
152159
continue;
153160
}
154161

155-
Task<Result<FileStats, IError>> task = GetSingleFileLineCount(file, data)
162+
Task<Result<FileStats, IError>> task = GetSingleFileLineCount(file, data, cancellationToken)
156163
.ContinueWith(task => task.Result.Map(report => new FileStats(file, report.Lines)));
157164
filetasks.Add(task);
158165
}
@@ -217,23 +224,23 @@ static IEnumerable<string> GetFilterFilePaths(string path, LineCountData data)
217224
return Directory.EnumerateFiles(path, data.Filter).Select(Path.GetFullPath);
218225
}
219226

220-
static Task<LineCountReport> GetSingleFileLineCountReport(string path, LineCountData data)
227+
static Task<LineCountReport> GetSingleFileLineCountReport(string path, LineCountData data, CancellationToken cancellationToken = default)
221228
{
222229
return (data.FilterType switch
223230
{
224-
FilterType.None => GetFileLineCount(path),
225-
FilterType.Filtered => GetFilteredFileLineCount(path, line => data.LineFilter!.IsMatch(line)),
226-
FilterType.FilteredExcept => GetFilteredFileLineCount(path, line => !data.ExcludeLineFilter!.IsMatch(line)),
227-
FilterType.FilteredBoth => GetFilteredFileLineCount(path, line => data.LineFilter!.IsMatch(line) && !data.ExcludeLineFilter!.IsMatch(line)),
231+
FilterType.None => GetFileLineCount(path, cancellationToken),
232+
FilterType.Filtered => GetFilteredFileLineCount(path, line => data.LineFilter!.IsMatch(line), cancellationToken),
233+
FilterType.FilteredExcept => GetFilteredFileLineCount(path, line => !data.ExcludeLineFilter!.IsMatch(line), cancellationToken),
234+
FilterType.FilteredBoth => GetFilteredFileLineCount(path, line => data.LineFilter!.IsMatch(line) && !data.ExcludeLineFilter!.IsMatch(line), cancellationToken),
228235
_ => throw new InvalidOperationException($"CountType.{data.FilterType} not recognized"),
229236
}).ContinueWith(task => new LineCountReport(task.Result));
230237
}
231238

232-
static async Task<ReportResult> GetSingleFileLineCount(string path, LineCountData data)
239+
static async Task<ReportResult> GetSingleFileLineCount(string path, LineCountData data, CancellationToken cancellationToken = default)
233240
{
234241
try
235242
{
236-
return await GetSingleFileLineCountReport(path, data);
243+
return await GetSingleFileLineCountReport(path, data, cancellationToken);
237244
}
238245
catch (FileNotFoundException)
239246
{
@@ -277,41 +284,45 @@ static async Task<ReportResult> GetSingleFileLineCount(string path, LineCountDat
277284
}
278285
}
279286

280-
public static async Task<int> GetFilteredFileLineCount(string path, Predicate<string> filter)
287+
public static async Task<int> GetFilteredFileLineCount(string path, Predicate<string> filter, CancellationToken cancellationToken = default)
281288
{
282289
using FileStream stream = File.OpenRead(path);
283290
using StreamReader reader = new StreamReader(stream);
284291

285-
string? line = await reader.ReadLineAsync();
292+
string? line = await reader.ReadLineAsync(cancellationToken);
286293
int count = 0;
287294

288-
while (line is not null)
295+
while (line is not null && !cancellationToken.IsCancellationRequested)
289296
{
290297
if (filter(line))
291298
{
292299
count++;
293300
}
294301

295-
line = await reader.ReadLineAsync();
302+
line = await reader.ReadLineAsync(cancellationToken);
296303
}
297304

305+
cancellationToken.ThrowIfCancellationRequested();
306+
298307
return count;
299308
}
300309

301-
public static async Task<int> GetFileLineCount(string path)
310+
public static async Task<int> GetFileLineCount(string path, CancellationToken cancellationToken = default)
302311
{
303312
using FileStream stream = File.OpenRead(path);
304313
using StreamReader reader = new StreamReader(stream);
305314

306-
string? line = await reader.ReadLineAsync();
315+
string? line = await reader.ReadLineAsync(cancellationToken);
307316
int count = 0;
308317

309-
while (line is not null)
318+
while (line is not null && !cancellationToken.IsCancellationRequested)
310319
{
311320
count++;
312-
line = await reader.ReadLineAsync();
321+
line = await reader.ReadLineAsync(cancellationToken);
313322
}
314323

324+
cancellationToken.ThrowIfCancellationRequested();
325+
315326
return count;
316327
}
317328
}

src/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
Console.WriteLine();
6262
}
6363

64-
result.Match(
64+
result?.Match(
6565
report => Logger.LogReport(report, format),
6666
error => Logger.LogError(error)
6767
);

0 commit comments

Comments
 (0)