2525import com .scanoss .dto .ScanFileResult ;
2626import com .scanoss .exceptions .ScannerException ;
2727import 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 .*;
3132import com .scanoss .rest .ScanApi ;
32- import com .scanoss .settings .Settings ;
33+ import com .scanoss .settings .ScanossSettings ;
3334import com .scanoss .utils .JsonUtils ;
34- import lombok .Builder ;
35- import lombok .Getter ;
36- import lombok .NonNull ;
35+ import lombok .*;
3736import lombok .extern .slf4j .Slf4j ;
3837
3938import java .io .File ;
4948import java .util .concurrent .ExecutorService ;
5049import java .util .concurrent .Executors ;
5150import java .util .concurrent .Future ;
51+ import java .util .function .Predicate ;
5252
5353import static com .scanoss .ScanossConstants .*;
5454
6464public class Scanner {
6565 @ Builder .Default
6666 private Boolean skipSnippets = Boolean .FALSE ; // Skip snippet generations
67+
6768 @ Builder .Default
6869 private Boolean allExtensions = Boolean .FALSE ; // Fingerprint all file extensions
70+
6971 @ Builder .Default
7072 private Boolean obfuscate = Boolean .FALSE ; // Obfuscate file path
73+
7174 @ Builder .Default
7275 private Boolean hpsm = Boolean .FALSE ; // Enable High Precision Snippet Matching data collection
76+
7377 @ Builder .Default
7478 private Boolean hiddenFilesFolders = Boolean .FALSE ; // Enable Scanning of hidden files/folders
79+
7580 @ Builder .Default
7681 private Boolean allFolders = Boolean .FALSE ; // Enable Scanning of all folders (except hidden)
82+
7783 @ Builder .Default
7884 private Integer numThreads = DEFAULT_WORKER_THREADS ; // Number of parallel threads to use when processing a folder
85+
7986 @ Builder .Default
8087 private Duration timeout = Duration .ofSeconds (DEFAULT_TIMEOUT ); // API POST timeout
88+
8189 @ Builder .Default
8290 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+ }
97120
98121 @ SuppressWarnings ("unused" )
99122 private Scanner (Boolean skipSnippets , Boolean allExtensions , Boolean obfuscate , Boolean hpsm ,
@@ -102,7 +125,9 @@ private Scanner(Boolean skipSnippets, Boolean allExtensions, Boolean obfuscate,
102125 Integer snippetLimit , String customCert , Proxy proxy ,
103126 Winnowing winnowing , ScanApi scanApi ,
104127 ScanFileProcessor scanFileProcessor , WfpFileProcessor wfpFileProcessor ,
105- Settings settings , ScannerPostProcessor postProcessor
128+ ScanossSettings settings , ScannerPostProcessor postProcessor , FilterConfig filterConfig ,
129+ Predicate <Path > fileFilter ,
130+ Predicate <Path > folderFilter
106131 ) {
107132 this .skipSnippets = skipSnippets ;
108133 this .allExtensions = allExtensions ;
@@ -134,9 +159,20 @@ private Scanner(Boolean skipSnippets, Boolean allExtensions, Boolean obfuscate,
134159 this .wfpFileProcessor = Objects .requireNonNullElseGet (wfpFileProcessor , () -> WfpFileProcessor .builder ()
135160 .winnowing (this .winnowing )
136161 .build ());
137- this .settings = Objects .requireNonNullElseGet (settings , () -> Settings .builder ().build ());
162+ this .settings = Objects .requireNonNullElseGet (settings , () -> ScanossSettings .builder ().build ());
138163 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+ }
140176
141177 /**
142178 * Generate a WFP/Fingerprint for the given file
@@ -157,70 +193,6 @@ public String wfpFile(@NonNull String filename) throws ScannerException, Winnowi
157193 return this .winnowing .wfpForFile (filename , filename );
158194 }
159195
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-
224196 /**
225197 * Strip the leading string from the specified path
226198 *
@@ -262,17 +234,16 @@ public List<String> processFolder(@NonNull String folder, FileProcessor processo
262234 Files .walkFileTree (Paths .get (folder ), new SimpleFileVisitor <>() {
263235 @ Override
264236 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 ());
267239 return FileVisitResult .SKIP_SUBTREE ; // Skip the rest of this directory tree
268240 }
269241 return FileVisitResult .CONTINUE ;
270242 }
271243
272244 @ Override
273245 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 ) {
276247 String filename = file .toString ();
277248 Future <String > future = executorService .submit (() -> processor .process (filename , stripDirectory (folder , filename )));
278249 futures .add (future );
@@ -321,7 +292,8 @@ public List<String> processFileList(@NonNull String root, @NonNull List<String>
321292 Path path = Path .of (file );
322293 boolean skipDir = false ;
323294 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
325297 skipDir = true ;
326298 break ;
327299 }
@@ -330,7 +302,7 @@ public List<String> processFileList(@NonNull String root, @NonNull List<String>
330302 continue ; // skip this file as the folder is not allowed
331303 }
332304 String nameLower = path .getFileName ().toString ().toLowerCase ();
333- if (!filterFile ( nameLower )) {
305+ if (!this . fileFilter . test ( path )) {
334306 Path fullPath = Path .of (root , file );
335307 File f = fullPath .toFile ();
336308 if (f .exists () && f .isFile () && f .length () > 0 && ! Files .isSymbolicLink (fullPath )) {
0 commit comments