25
25
import com .scanoss .dto .ScanFileResult ;
26
26
import com .scanoss .exceptions .ScannerException ;
27
27
import com .scanoss .exceptions .WinnowingException ;
28
- import com .scanoss .processor .FileProcessor ;
29
- import com .scanoss .processor .ScanFileProcessor ;
30
- import com .scanoss .processor .WfpFileProcessor ;
28
+ import com .scanoss .filters .FilterConfig ;
29
+ import com .scanoss .filters .factories .FileFilterFactory ;
30
+ import com .scanoss .filters .factories .FolderFilterFactory ;
31
+ import com .scanoss .processor .*;
31
32
import com .scanoss .rest .ScanApi ;
32
- import com .scanoss .settings .Settings ;
33
+ import com .scanoss .settings .ScanossSettings ;
33
34
import com .scanoss .utils .JsonUtils ;
34
- import lombok .Builder ;
35
- import lombok .Getter ;
36
- import lombok .NonNull ;
35
+ import lombok .*;
37
36
import lombok .extern .slf4j .Slf4j ;
38
37
39
38
import java .io .File ;
49
48
import java .util .concurrent .ExecutorService ;
50
49
import java .util .concurrent .Executors ;
51
50
import java .util .concurrent .Future ;
51
+ import java .util .function .Predicate ;
52
52
53
53
import static com .scanoss .ScanossConstants .*;
54
54
64
64
public class Scanner {
65
65
@ Builder .Default
66
66
private Boolean skipSnippets = Boolean .FALSE ; // Skip snippet generations
67
+
67
68
@ Builder .Default
68
69
private Boolean allExtensions = Boolean .FALSE ; // Fingerprint all file extensions
70
+
69
71
@ Builder .Default
70
72
private Boolean obfuscate = Boolean .FALSE ; // Obfuscate file path
73
+
71
74
@ Builder .Default
72
75
private Boolean hpsm = Boolean .FALSE ; // Enable High Precision Snippet Matching data collection
76
+
73
77
@ Builder .Default
74
78
private Boolean hiddenFilesFolders = Boolean .FALSE ; // Enable Scanning of hidden files/folders
79
+
75
80
@ Builder .Default
76
81
private Boolean allFolders = Boolean .FALSE ; // Enable Scanning of all folders (except hidden)
82
+
77
83
@ Builder .Default
78
84
private Integer numThreads = DEFAULT_WORKER_THREADS ; // Number of parallel threads to use when processing a folder
85
+
79
86
@ Builder .Default
80
87
private Duration timeout = Duration .ofSeconds (DEFAULT_TIMEOUT ); // API POST timeout
88
+
81
89
@ Builder .Default
82
90
private Integer retryLimit = DEFAULT_HTTP_RETRY_LIMIT ; // Retry limit for posting scan requests
83
- private String url ; // Alternative scanning URL
84
- private String apiKey ; // API key
85
- private String scanFlags ; // Scan flags to pass to the API
86
- private String sbomType ; // SBOM type (identify/ignore)
87
- private String sbom ; // SBOM to supply while scanning
88
- private int snippetLimit ; // Size limit for a single line of generated snippet
89
- private String customCert ; // Custom certificate
90
- private Proxy proxy ; // Proxy
91
- private Winnowing winnowing ;
92
- private ScanApi scanApi ;
93
- private ScanFileProcessor scanFileProcessor ;
94
- private WfpFileProcessor wfpFileProcessor ;
95
- private Settings settings ;
96
- private ScannerPostProcessor postProcessor ;
91
+
92
+ private final String url ; // Alternative scanning URL
93
+ private final String apiKey ; // API key
94
+ private final String scanFlags ; // Scan flags to pass to the APIç
95
+ private final String sbomType ; // SBOM type (identify/ignore)
96
+ private final String sbom ; // SBOM to supply while scanning
97
+ private final int snippetLimit ; // Size limit for a single line of generated snippet
98
+ private final String customCert ; // Custom certificate
99
+ private final Proxy proxy ; // Proxy
100
+ private final Winnowing winnowing ;
101
+ private final ScanApi scanApi ;
102
+ private final ScanFileProcessor scanFileProcessor ;
103
+ private final WfpFileProcessor wfpFileProcessor ;
104
+ private final ScanossSettings settings ;
105
+ private final ScannerPostProcessor postProcessor ;
106
+ private final FilterConfig filterConfig ;
107
+ private Predicate <Path > fileFilter ;
108
+ private Predicate <Path > folderFilter ;
109
+
110
+ //TODO: Once this Lombok PR is merged https://github.com/projectlombok/lombok/pull/3723#pullrequestreview-2617412643
111
+ // Update Lombok dependency
112
+ public static class ScannerBuilder {
113
+ private ScannerBuilder folderFilter (Predicate <Path > folderFilter ) {
114
+ return this ;
115
+ }
116
+ private ScannerBuilder fileFilter (Predicate <Path > fileFilter ) {
117
+ return this ;
118
+ }
119
+ }
97
120
98
121
@ SuppressWarnings ("unused" )
99
122
private Scanner (Boolean skipSnippets , Boolean allExtensions , Boolean obfuscate , Boolean hpsm ,
@@ -102,7 +125,9 @@ private Scanner(Boolean skipSnippets, Boolean allExtensions, Boolean obfuscate,
102
125
Integer snippetLimit , String customCert , Proxy proxy ,
103
126
Winnowing winnowing , ScanApi scanApi ,
104
127
ScanFileProcessor scanFileProcessor , WfpFileProcessor wfpFileProcessor ,
105
- Settings settings , ScannerPostProcessor postProcessor
128
+ ScanossSettings settings , ScannerPostProcessor postProcessor , FilterConfig filterConfig ,
129
+ Predicate <Path > fileFilter ,
130
+ Predicate <Path > folderFilter
106
131
) {
107
132
this .skipSnippets = skipSnippets ;
108
133
this .allExtensions = allExtensions ;
@@ -134,9 +159,20 @@ private Scanner(Boolean skipSnippets, Boolean allExtensions, Boolean obfuscate,
134
159
this .wfpFileProcessor = Objects .requireNonNullElseGet (wfpFileProcessor , () -> WfpFileProcessor .builder ()
135
160
.winnowing (this .winnowing )
136
161
.build ());
137
- this .settings = Objects .requireNonNullElseGet (settings , () -> Settings .builder ().build ());
162
+ this .settings = Objects .requireNonNullElseGet (settings , () -> ScanossSettings .builder ().build ());
138
163
this .postProcessor = Objects .requireNonNullElseGet (postProcessor , () ->
139
- ScannerPostProcessor .builder ().build ()); }
164
+ ScannerPostProcessor .builder ().build ());
165
+
166
+ this .filterConfig = Objects .requireNonNullElseGet (filterConfig , () -> FilterConfig .builder ()
167
+ .allFolders (allFolders )
168
+ .allExtensions (allExtensions )
169
+ .hiddenFilesFolders (hiddenFilesFolders )
170
+ .gitIgnorePatterns (this .settings .getScanningIgnorePattern ())
171
+ .build ());
172
+
173
+ this .fileFilter = Objects .requireNonNullElseGet (fileFilter , () -> FileFilterFactory .build (this .filterConfig ));
174
+ this .folderFilter = Objects .requireNonNullElseGet (folderFilter , () -> FolderFilterFactory .build (this .filterConfig ));
175
+ }
140
176
141
177
/**
142
178
* Generate a WFP/Fingerprint for the given file
@@ -157,70 +193,6 @@ public String wfpFile(@NonNull String filename) throws ScannerException, Winnowi
157
193
return this .winnowing .wfpForFile (filename , filename );
158
194
}
159
195
160
- /**
161
- * Determine if a folder should be processed or not
162
- *
163
- * @param name folder/directory to review
164
- * @return <code>true</code> if the folder should be skipped, <code>false</code> otherwise
165
- */
166
- private Boolean filterFolder (String name ) {
167
- String nameLower = name .toLowerCase ();
168
- if (!hiddenFilesFolders && name .startsWith ("." ) && !name .equals ("." )) {
169
- log .trace ("Skipping hidden folder: {}" , name );
170
- return true ;
171
- }
172
- boolean ignore = false ;
173
- if (!allFolders ) { // skip this check if all folders is selected
174
- for (String ending : ScanossConstants .FILTERED_DIRS ) {
175
- if (nameLower .endsWith (ending )) {
176
- log .trace ("Skipping folder due to ending: {} - {}" , name , ending );
177
- ignore = true ;
178
- }
179
- }
180
- if (!ignore ){
181
- for (String ending : ScanossConstants .FILTERED_DIR_EXT ) {
182
- if (nameLower .endsWith (ending )) {
183
- log .trace ("Skipping folder due to ending: {} - {}" , name , ending );
184
- ignore = true ;
185
- }
186
- }
187
- }
188
- }
189
- return ignore ;
190
- }
191
-
192
- /**
193
- * Determine if a file should be processed or not
194
- *
195
- * @param name filename to review
196
- * @return <code>true</code> if the file should be skipped, <code>false</code> otherwise
197
- */
198
- private Boolean filterFile (String name ) {
199
- // Skip hidden files unless explicitly asked to read them
200
- if (!hiddenFilesFolders && name .startsWith ("." )) {
201
- log .trace ("Skipping hidden file: {}" , name );
202
- return true ;
203
- }
204
- // Process all file extensions if requested
205
- if (this .allExtensions ) {
206
- log .trace ("Processing all file extensions: {}" , name );
207
- return false ;
208
- }
209
- // Skip some specific files
210
- if (ScanossConstants .FILTERED_FILES .contains (name )) {
211
- log .trace ("Skipping specific file: {}" , name );
212
- return true ;
213
- }
214
- // Skip specific file endings/extensions
215
- for (String ending : ScanossConstants .FILTERED_EXTENSIONS ) {
216
- if (name .endsWith (ending )) {
217
- log .trace ("Skipping file due to ending: {} - {}" , name , ending );
218
- return true ;
219
- }
220
- }
221
- return false ;
222
- }
223
-
224
196
/**
225
197
* Strip the leading string from the specified path
226
198
*
@@ -262,17 +234,16 @@ public List<String> processFolder(@NonNull String folder, FileProcessor processo
262
234
Files .walkFileTree (Paths .get (folder ), new SimpleFileVisitor <>() {
263
235
@ Override
264
236
public FileVisitResult preVisitDirectory (Path file , BasicFileAttributes attrs ) {
265
- String nameLower = file . getFileName (). toString (). toLowerCase ();
266
- if ( attrs . isDirectory () && filterFolder ( nameLower )) {
237
+ if ( folderFilter . test ( file )) {
238
+ log . debug ( "Processing file: {}" , file . getFileName (). toString ());
267
239
return FileVisitResult .SKIP_SUBTREE ; // Skip the rest of this directory tree
268
240
}
269
241
return FileVisitResult .CONTINUE ;
270
242
}
271
243
272
244
@ Override
273
245
public FileVisitResult visitFile (Path file , BasicFileAttributes attrs ) {
274
- String nameLower = file .getFileName ().toString ().toLowerCase ();
275
- if (attrs .isRegularFile () && !filterFile (nameLower ) && attrs .size () > 0 ) {
246
+ if (attrs .isRegularFile () && !fileFilter .test (file ) && attrs .size () > 0 ) {
276
247
String filename = file .toString ();
277
248
Future <String > future = executorService .submit (() -> processor .process (filename , stripDirectory (folder , filename )));
278
249
futures .add (future );
@@ -321,7 +292,8 @@ public List<String> processFileList(@NonNull String root, @NonNull List<String>
321
292
Path path = Path .of (file );
322
293
boolean skipDir = false ;
323
294
for (Path p : path ) {
324
- if (filterFolder (p .toString ().toLowerCase ())) { // should we skip this folder or not
295
+ // should we skip this folder or not
296
+ if (this .folderFilter .test (p )) { // should we skip this folder or not
325
297
skipDir = true ;
326
298
break ;
327
299
}
@@ -330,7 +302,7 @@ public List<String> processFileList(@NonNull String root, @NonNull List<String>
330
302
continue ; // skip this file as the folder is not allowed
331
303
}
332
304
String nameLower = path .getFileName ().toString ().toLowerCase ();
333
- if (!filterFile ( nameLower )) {
305
+ if (!this . fileFilter . test ( path )) {
334
306
Path fullPath = Path .of (root , file );
335
307
File f = fullPath .toFile ();
336
308
if (f .exists () && f .isFile () && f .length () > 0 && ! Files .isSymbolicLink (fullPath )) {
0 commit comments