5
5
from dataclasses import asdict
6
6
from glob import glob
7
7
from pathlib import PurePath
8
- from typing import BinaryIO , Dict , List , Tuple
9
-
8
+ from typing import BinaryIO , Dict , List , Tuple , Set
9
+ import re
10
10
from socketdev import socketdev
11
11
from socketdev .exceptions import APIFailure
12
12
from socketdev .fullscans import FullScanParams , SocketArtifact
@@ -123,19 +123,50 @@ def create_sbom_output(self, diff: Diff) -> dict:
123
123
log .error (result .get ("message" , "No error message provided" ))
124
124
return {}
125
125
126
+ @staticmethod
127
+ def to_case_insensitive_regex (pattern : str ) -> str :
128
+ """
129
+ Converts a pattern to a case-insensitive regex (optional step).
130
+ If `pattern` is a glob pattern, this step should be removed.
131
+ """
132
+ return pattern # Remove if unnecessary
133
+
134
+ @staticmethod
135
+ def expand_brace_pattern (pattern : str ) -> List [str ]:
136
+ """
137
+ Expands brace expressions (e.g., {a,b,c}) into separate patterns.
138
+ """
139
+ brace_regex = re .compile (r"\{([^{}]+)\}" )
140
+
141
+ # Expand all brace groups
142
+ expanded_patterns = [pattern ]
143
+ while any ("{" in p for p in expanded_patterns ):
144
+ new_patterns = []
145
+ for pat in expanded_patterns :
146
+ match = brace_regex .search (pat )
147
+ if match :
148
+ options = match .group (1 ).split ("," ) # Extract values inside {}
149
+ prefix , suffix = pat [:match .start ()], pat [match .end ():]
150
+ new_patterns .extend ([prefix + opt + suffix for opt in options ])
151
+ else :
152
+ new_patterns .append (pat )
153
+ expanded_patterns = new_patterns
154
+
155
+ return expanded_patterns
156
+
126
157
def find_files (self , path : str ) -> List [str ]:
127
158
"""
128
159
Finds supported manifest files in the given path.
129
160
130
161
Args:
131
- path: Path to search for manifest files
162
+ path: Path to search for manifest files.
132
163
133
164
Returns:
134
- List of found manifest file paths
165
+ List of found manifest file paths.
135
166
"""
136
167
log .debug ("Starting Find Files" )
137
168
start_time = time .time ()
138
- files = set ()
169
+ files : Set [ str ] = set ()
139
170
140
171
# Get supported patterns from the API
141
172
try :
@@ -149,28 +180,28 @@ def find_files(self, path: str) -> List[str]:
149
180
for ecosystem in patterns :
150
181
ecosystem_patterns = patterns [ecosystem ]
151
182
for file_name in ecosystem_patterns :
152
- pattern = Core . to_case_insensitive_regex ( ecosystem_patterns [file_name ]["pattern" ])
153
- file_path = f" { path } /**/ { pattern } "
154
- #log.debug(f"Globbing {file_path}")
155
- glob_start = time . time ( )
156
- glob_files = glob ( file_path , recursive = True )
157
- for glob_file in glob_files :
158
- # Only add if it's a file, not a directory
159
- if glob_file not in files and os .path .isfile ( glob_file ):
160
- files . add ( glob_file )
161
- glob_end = time . time ( )
162
- glob_total_time = glob_end - glob_start
163
- #log.debug(f"Glob for pattern {file_path} took {glob_total_time:.2f} seconds" )
164
-
165
- log . debug ( "Finished Find Files" )
166
- end_time = time . time ()
167
- total_time = end_time - start_time
168
- files_list = list ( files )
169
- if len ( files_list ) > 5 :
170
- log .debug (f"{ len ( files_list ) } Files found ( { total_time :.2f } s): { ', ' . join ( files_list [: 5 ]) } , ... " )
171
- else :
172
- log .debug (f"{ len ( files_list ) } Files found ( { total_time :.2f } s): { ', ' . join ( files_list )} " )
173
- return list (files )
183
+ original_pattern = ecosystem_patterns [file_name ]["pattern" ]
184
+
185
+ # Expand brace patterns
186
+ expanded_patterns = Core . expand_brace_pattern ( original_pattern )
187
+
188
+ for pattern in expanded_patterns :
189
+ case_insensitive_pattern = Core . to_case_insensitive_regex ( pattern )
190
+ file_path = os .path .join ( path , "**" , case_insensitive_pattern )
191
+
192
+ log . debug ( f"Globbing { file_path } " )
193
+ glob_start = time . time ()
194
+ glob_files = glob ( file_path , recursive = True )
195
+
196
+ for glob_file in glob_files :
197
+ if os . path . isfile ( glob_file ):
198
+ files . add ( glob_file )
199
+
200
+ glob_end = time . time ()
201
+ log .debug (f"Globbing took { glob_end - glob_start :.4f } seconds " )
202
+
203
+ log .debug (f"Total files found: { len ( files )} " )
204
+ return sorted (files )
174
205
175
206
def get_supported_patterns (self ) -> Dict :
176
207
"""
0 commit comments