44using System . Linq ;
55using System . Reflection ;
66using System . Reflection . PortableExecutable ;
7+ using System . Text . RegularExpressions ;
78
89using Microsoft . Extensions . FileSystemGlobbing ;
910using Microsoft . Extensions . FileSystemGlobbing . Abstractions ;
@@ -12,10 +13,10 @@ namespace Coverlet.Core.Helpers
1213{
1314 internal static class InstrumentationHelper
1415 {
15- public static string [ ] GetDependencies ( string module )
16+ public static string [ ] GetCoverableModules ( string module )
1617 {
1718 IEnumerable < string > modules = Directory . GetFiles ( Path . GetDirectoryName ( module ) , "*.dll" ) ;
18- modules = modules . Where ( a => IsAssembly ( a ) && Path . GetFileName ( a ) != Path . GetFileName ( module ) ) ;
19+ modules = modules . Where ( m => IsAssembly ( m ) && Path . GetFileName ( m ) != Path . GetFileName ( module ) ) ;
1920 return modules . ToArray ( ) ;
2021 }
2122
@@ -65,7 +66,8 @@ public static void RestoreOriginalModule(string module, string identifier)
6566 // See: https://github.com/tonerdo/coverlet/issues/25
6667 var retryStrategy = CreateRetryStrategy ( ) ;
6768
68- RetryHelper . Retry ( ( ) => {
69+ RetryHelper . Retry ( ( ) =>
70+ {
6971 File . Copy ( backupPath , module , true ) ;
7072 File . Delete ( backupPath ) ;
7173 } , retryStrategy , 10 ) ;
@@ -76,34 +78,81 @@ public static void DeleteHitsFile(string path)
7678 // Retry hitting the hits file - retry up to 10 times, since the file could be locked
7779 // See: https://github.com/tonerdo/coverlet/issues/25
7880 var retryStrategy = CreateRetryStrategy ( ) ;
79-
8081 RetryHelper . Retry ( ( ) => File . Delete ( path ) , retryStrategy , 10 ) ;
8182 }
8283
83- public static IEnumerable < string > GetExcludedFiles ( IEnumerable < string > excludeRules ,
84- string parentDir = null )
84+ public static bool IsModuleExcluded ( string module , string [ ] filters )
85+ {
86+ if ( filters == null || ! filters . Any ( ) )
87+ return false ;
88+
89+ module = Path . GetFileNameWithoutExtension ( module ) ;
90+ bool isMatch = false ;
91+
92+ foreach ( var filter in filters )
93+ {
94+ if ( ! IsValidFilterExpression ( filter ) )
95+ continue ;
96+
97+ string pattern = filter . Substring ( 1 , filter . IndexOf ( ']' ) - 1 ) ;
98+ pattern = WildcardToRegex ( pattern ) ;
99+
100+ var regex = new Regex ( pattern ) ;
101+ isMatch = regex . IsMatch ( module ) ;
102+ }
103+
104+ return isMatch ;
105+ }
106+
107+ public static bool IsTypeExcluded ( string type , string [ ] filters )
108+ {
109+ if ( filters == null || ! filters . Any ( ) )
110+ return false ;
111+
112+ bool isMatch = false ;
113+
114+ foreach ( var filter in filters )
115+ {
116+ if ( ! IsValidFilterExpression ( filter ) )
117+ continue ;
118+
119+ string pattern = filter . Substring ( filter . IndexOf ( ']' ) + 1 ) ;
120+ pattern = WildcardToRegex ( pattern ) ;
121+
122+ var regex = new Regex ( pattern ) ;
123+ isMatch = regex . IsMatch ( type ) ;
124+ }
125+
126+ return isMatch ;
127+ }
128+
129+ public static string [ ] GetExcludedFiles ( string [ ] excludes )
85130 {
86131 const string RELATIVE_KEY = nameof ( RELATIVE_KEY ) ;
87- parentDir = string . IsNullOrWhiteSpace ( parentDir ) ? Directory . GetCurrentDirectory ( ) : parentDir ;
132+ string parentDir = Directory . GetCurrentDirectory ( ) ;
88133
89- if ( excludeRules == null || ! excludeRules . Any ( ) ) return Enumerable . Empty < string > ( ) ;
134+ if ( excludes == null || ! excludes . Any ( ) ) return Array . Empty < string > ( ) ;
90135
91- var matcherDict = new Dictionary < string , Matcher > ( ) { { RELATIVE_KEY , new Matcher ( ) } } ;
92- foreach ( var excludeRule in excludeRules )
136+ var matcherDict = new Dictionary < string , Matcher > ( ) { { RELATIVE_KEY , new Matcher ( ) } } ;
137+ foreach ( var excludeRule in excludes )
93138 {
94- if ( Path . IsPathRooted ( excludeRule ) ) {
139+ if ( Path . IsPathRooted ( excludeRule ) )
140+ {
95141 var root = Path . GetPathRoot ( excludeRule ) ;
96- if ( ! matcherDict . ContainsKey ( root ) ) {
142+ if ( ! matcherDict . ContainsKey ( root ) )
143+ {
97144 matcherDict . Add ( root , new Matcher ( ) ) ;
98145 }
99146 matcherDict [ root ] . AddInclude ( excludeRule . Substring ( root . Length ) ) ;
100- } else {
147+ }
148+ else
149+ {
101150 matcherDict [ RELATIVE_KEY ] . AddInclude ( excludeRule ) ;
102151 }
103152 }
104153
105154 var files = new List < string > ( ) ;
106- foreach ( var entry in matcherDict )
155+ foreach ( var entry in matcherDict )
107156 {
108157 var root = entry . Key ;
109158 var matcher = entry . Value ;
@@ -114,20 +163,7 @@ public static IEnumerable<string> GetExcludedFiles(IEnumerable<string> excludeRu
114163 files . AddRange ( currentFiles ) ;
115164 }
116165
117- return files . Distinct ( ) ;
118- }
119-
120- private static bool IsAssembly ( string filePath )
121- {
122- try
123- {
124- AssemblyName . GetAssemblyName ( filePath ) ;
125- return true ;
126- }
127- catch
128- {
129- return false ;
130- }
166+ return files . Distinct ( ) . ToArray ( ) ;
131167 }
132168
133169 private static string GetBackupPath ( string module , string identifier )
@@ -149,6 +185,52 @@ TimeSpan retryStrategy()
149185
150186 return retryStrategy ;
151187 }
188+
189+ private static bool IsValidFilterExpression ( string filter )
190+ {
191+ if ( ! filter . StartsWith ( "[" ) )
192+ return false ;
193+
194+ if ( ! filter . Contains ( "]" ) )
195+ return false ;
196+
197+ if ( filter . Count ( f => f == '[' ) > 1 )
198+ return false ;
199+
200+ if ( filter . Count ( f => f == ']' ) > 1 )
201+ return false ;
202+
203+ if ( filter . IndexOf ( ']' ) < filter . IndexOf ( '[' ) )
204+ return false ;
205+
206+ if ( filter . IndexOf ( ']' ) - filter . IndexOf ( '[' ) == 1 )
207+ return false ;
208+
209+ if ( new Regex ( @"[^\w*]" ) . IsMatch ( filter . Replace ( "[" , "" ) . Replace ( "]" , "" ) ) )
210+ return false ;
211+
212+ return true ;
213+ }
214+
215+ private static string WildcardToRegex ( string pattern )
216+ {
217+ return "^" + Regex . Escape ( pattern ) .
218+ Replace ( "\\ *" , ".*" ) .
219+ Replace ( "\\ ?" , "." ) + "$" ;
220+ }
221+
222+ private static bool IsAssembly ( string filePath )
223+ {
224+ try
225+ {
226+ AssemblyName . GetAssemblyName ( filePath ) ;
227+ return true ;
228+ }
229+ catch
230+ {
231+ return false ;
232+ }
233+ }
152234 }
153235}
154236
0 commit comments