8
8
using System . Collections . Concurrent ;
9
9
using System . Text ;
10
10
using System . Security . Cryptography ;
11
- using System . Text . RegularExpressions ;
12
11
13
12
namespace Semmle . BuildAnalyser
14
13
{
15
14
/// <summary>
16
15
/// Main implementation of the build analysis.
17
16
/// </summary>
18
- internal sealed partial class BuildAnalysis : IDisposable
17
+ internal sealed class BuildAnalysis : IDisposable
19
18
{
20
19
private readonly AssemblyCache assemblyCache ;
21
20
private readonly ProgressMonitor progressMonitor ;
@@ -29,7 +28,7 @@ internal sealed partial class BuildAnalysis : IDisposable
29
28
private readonly Options options ;
30
29
private readonly DirectoryInfo sourceDir ;
31
30
private readonly DotNet dotnet ;
32
- private readonly Lazy < IEnumerable < string > > allFiles ;
31
+ private readonly FileContent fileContent ;
33
32
private readonly TemporaryDirectory packageDirectory ;
34
33
35
34
@@ -58,7 +57,9 @@ public BuildAnalysis(Options options, ProgressMonitor progressMonitor)
58
57
59
58
this . progressMonitor . FindingFiles ( options . SrcDir ) ;
60
59
61
- this . allFiles = new ( ( ) => GetFiles ( "*.*" ) ) ;
60
+ packageDirectory = new TemporaryDirectory ( ComputeTempDirectory ( sourceDir . FullName ) ) ;
61
+
62
+ this . fileContent = new FileContent ( packageDirectory , progressMonitor , ( ) => GetFiles ( "*.*" ) ) ;
62
63
this . allSources = GetFiles ( "*.cs" ) . ToArray ( ) ;
63
64
var allProjects = GetFiles ( "*.csproj" ) ;
64
65
var solutions = options . SolutionFile is not null
@@ -75,7 +76,7 @@ public BuildAnalysis(Options options, ProgressMonitor progressMonitor)
75
76
progressMonitor . LogInfo ( $ ".NET runtime location selected: { runtimeLocation } ") ;
76
77
dllDirNames . Add ( runtimeLocation ) ;
77
78
78
- if ( UseAspNetDlls ( ) && runtime . GetAspRuntime ( ) is string aspRuntime )
79
+ if ( fileContent . UseAspNetDlls && runtime . GetAspRuntime ( ) is string aspRuntime )
79
80
{
80
81
progressMonitor . LogInfo ( $ "ASP.NET runtime location selected: { aspRuntime } ") ;
81
82
dllDirNames . Add ( aspRuntime ) ;
@@ -87,8 +88,6 @@ public BuildAnalysis(Options options, ProgressMonitor progressMonitor)
87
88
UseReference ( typeof ( object ) . Assembly . Location ) ;
88
89
}
89
90
90
- packageDirectory = new TemporaryDirectory ( ComputeTempDirectory ( sourceDir . FullName ) ) ;
91
-
92
91
if ( options . UseNuGet )
93
92
{
94
93
dllDirNames . Add ( packageDirectory . DirInfo . FullName ) ;
@@ -230,11 +229,6 @@ private void ResolveConflicts()
230
229
/// <param name="sourceFile">The source file.</param>
231
230
private void UseSource ( FileInfo sourceFile ) => sources [ sourceFile . FullName ] = sourceFile . Exists ;
232
231
233
- /// <summary>
234
- /// All files in the source directory.
235
- /// </summary>
236
- private IEnumerable < string > AllFiles => allFiles . Value ;
237
-
238
232
/// <summary>
239
233
/// The list of resolved reference files.
240
234
/// </summary>
@@ -335,73 +329,9 @@ private void Restore(IEnumerable<string> targets, string? pathToNugetConfig = nu
335
329
}
336
330
}
337
331
338
- private static string GetGroup ( ReadOnlySpan < char > input , ValueMatch valueMatch , string groupPrefix )
339
- {
340
- var match = input . Slice ( valueMatch . Index , valueMatch . Length ) ;
341
- var includeIndex = match . IndexOf ( groupPrefix , StringComparison . InvariantCultureIgnoreCase ) ;
342
- if ( includeIndex == - 1 )
343
- {
344
- return string . Empty ;
345
- }
346
-
347
- match = match . Slice ( includeIndex + groupPrefix . Length + 1 ) ;
348
-
349
- var quoteIndex1 = match . IndexOf ( "\" " ) ;
350
- var quoteIndex2 = match . Slice ( quoteIndex1 + 1 ) . IndexOf ( "\" " ) ;
351
-
352
- return match . Slice ( quoteIndex1 + 1 , quoteIndex2 ) . ToString ( ) . ToLowerInvariant ( ) ;
353
- }
354
-
355
- private static bool IsGroupMatch ( ReadOnlySpan < char > line , Regex regex , string groupPrefix , string value )
356
- {
357
- foreach ( var valueMatch in regex . EnumerateMatches ( line ) )
358
- {
359
- // We can't get the group from the ValueMatch, so doing it manually:
360
- if ( GetGroup ( line , valueMatch , groupPrefix ) == value . ToLowerInvariant ( ) )
361
- {
362
- return true ;
363
- }
364
- }
365
- return false ;
366
- }
367
-
368
- /// <summary>
369
- /// Returns true if any file in the source directory indicates that ASP.NET is used.
370
- /// The following heuristic is used to decide, if ASP.NET is used:
371
- /// If any file in the source directory contains something like (this will most like be a .csproj file)
372
- /// <Project Sdk="Microsoft.NET.Sdk.Web">
373
- /// <FrameworkReference Include="Microsoft.AspNetCore.App"/>
374
- /// </summary>
375
- private bool UseAspNetDlls ( )
376
- {
377
- foreach ( var file in AllFiles )
378
- {
379
- try
380
- {
381
- using var sr = new StreamReader ( file ) ;
382
- ReadOnlySpan < char > line ;
383
- while ( ( line = sr . ReadLine ( ) ) != null )
384
- {
385
- if ( IsGroupMatch ( line , ProjectSdk ( ) , "Sdk" , "Microsoft.NET.Sdk.Web" ) ||
386
- IsGroupMatch ( line , FrameworkReference ( ) , "Include" , "Microsoft.AspNetCore.App" ) )
387
- {
388
- return true ;
389
- }
390
- }
391
- }
392
- catch ( Exception ex )
393
- {
394
- progressMonitor . FailedToReadFile ( file , ex ) ;
395
- }
396
- }
397
- return false ;
398
- }
399
332
400
333
private void DownloadMissingPackages ( IEnumerable < string > restoreTargets )
401
334
{
402
- var alreadyDownloadedPackages = Directory . GetDirectories ( packageDirectory . DirInfo . FullName ) . Select ( d => Path . GetFileName ( d ) . ToLowerInvariant ( ) ) . ToHashSet ( ) ;
403
- var notYetDownloadedPackages = new HashSet < string > ( ) ;
404
-
405
335
var nugetConfigs = GetFiles ( "nuget.config" , recurseSubdirectories : true ) . ToArray ( ) ;
406
336
string ? nugetConfig = null ;
407
337
if ( nugetConfigs . Length > 1 )
@@ -418,32 +348,7 @@ private void DownloadMissingPackages(IEnumerable<string> restoreTargets)
418
348
nugetConfig = nugetConfigs . FirstOrDefault ( ) ;
419
349
}
420
350
421
- foreach ( var file in AllFiles )
422
- {
423
- try
424
- {
425
- using var sr = new StreamReader ( file ) ;
426
- ReadOnlySpan < char > line ;
427
- while ( ( line = sr . ReadLine ( ) ) != null )
428
- {
429
- foreach ( var valueMatch in PackageReference ( ) . EnumerateMatches ( line ) )
430
- {
431
- // We can't get the group from the ValueMatch, so doing it manually:
432
- var packageName = GetGroup ( line , valueMatch , "Include" ) ;
433
- if ( ! string . IsNullOrEmpty ( packageName ) && ! alreadyDownloadedPackages . Contains ( packageName ) )
434
- {
435
- notYetDownloadedPackages . Add ( packageName ) ;
436
- }
437
- }
438
- }
439
- }
440
- catch ( Exception ex )
441
- {
442
- progressMonitor . FailedToReadFile ( file , ex ) ;
443
- }
444
- }
445
-
446
- foreach ( var package in notYetDownloadedPackages )
351
+ foreach ( var package in fileContent . NotYetDownloadedPackages )
447
352
{
448
353
progressMonitor . NugetInstall ( package ) ;
449
354
using var tempDir = new TemporaryDirectory ( ComputeTempDirectory ( package ) ) ;
@@ -487,15 +392,5 @@ private void AnalyseSolutions(IEnumerable<string> solutions)
487
392
}
488
393
489
394
public void Dispose ( ) => packageDirectory ? . Dispose ( ) ;
490
-
491
- [ GeneratedRegex ( "<PackageReference\\ s+Include=\" (.*?)\" .*/?>" , RegexOptions . IgnoreCase | RegexOptions . Compiled | RegexOptions . Singleline ) ]
492
- private static partial Regex PackageReference ( ) ;
493
-
494
- [ GeneratedRegex ( "<FrameworkReference\\ s+Include=\" (.*?)\" .*/?>" , RegexOptions . IgnoreCase | RegexOptions . Compiled | RegexOptions . Singleline ) ]
495
- private static partial Regex FrameworkReference ( ) ;
496
-
497
- [ GeneratedRegex ( "<Project\\ s+Sdk=\" (.*?)\" .*/?>" , RegexOptions . IgnoreCase | RegexOptions . Compiled | RegexOptions . Singleline ) ]
498
- private static partial Regex ProjectSdk ( ) ;
499
-
500
395
}
501
396
}
0 commit comments