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,42 @@ 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 expand_brace_pattern (pattern : str ) -> List [str ]:
128
+ """
129
+ Expands brace expressions (e.g., {a,b,c}) into separate patterns.
130
+ """
131
+ brace_regex = re .compile (r"\{([^{}]+)\}" )
132
+
133
+ # Expand all brace groups
134
+ expanded_patterns = [pattern ]
135
+ while any ("{" in p for p in expanded_patterns ):
136
+ new_patterns = []
137
+ for pat in expanded_patterns :
138
+ match = brace_regex .search (pat )
139
+ if match :
140
+ options = match .group (1 ).split ("," ) # Extract values inside {}
141
+ prefix , suffix = pat [:match .start ()], pat [match .end ():]
142
+ new_patterns .extend ([prefix + opt + suffix for opt in options ])
143
+ else :
144
+ new_patterns .append (pat )
145
+ expanded_patterns = new_patterns
146
+
147
+ return expanded_patterns
148
+
126
149
def find_files (self , path : str ) -> List [str ]:
127
150
"""
128
151
Finds supported manifest files in the given path.
129
152
130
153
Args:
131
- path: Path to search for manifest files
154
+ path: Path to search for manifest files.
132
155
133
156
Returns:
134
- List of found manifest file paths
157
+ List of found manifest file paths.
135
158
"""
136
159
log .debug ("Starting Find Files" )
137
160
start_time = time .time ()
138
- files = set ()
161
+ files : Set [ str ] = set ()
139
162
140
163
# Get supported patterns from the API
141
164
try :
@@ -149,28 +172,28 @@ def find_files(self, path: str) -> List[str]:
149
172
for ecosystem in patterns :
150
173
ecosystem_patterns = patterns [ecosystem ]
151
174
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 )
175
+ original_pattern = ecosystem_patterns [file_name ]["pattern" ]
176
+
177
+ # Expand brace patterns
178
+ expanded_patterns = Core . expand_brace_pattern ( original_pattern )
179
+
180
+ for pattern in expanded_patterns :
181
+ case_insensitive_pattern = Core . to_case_insensitive_regex ( pattern )
182
+ file_path = os .path .join ( path , "**" , case_insensitive_pattern )
183
+
184
+ log . debug ( f"Globbing { file_path } " )
185
+ glob_start = time . time ()
186
+ glob_files = glob ( file_path , recursive = True )
187
+
188
+ for glob_file in glob_files :
189
+ if os . path . isfile ( glob_file ):
190
+ files . add ( glob_file )
191
+
192
+ glob_end = time . time ()
193
+ log .debug (f"Globbing took { glob_end - glob_start :.4f } seconds " )
194
+
195
+ log .debug (f"Total files found: { len ( files )} " )
196
+ return sorted (files )
174
197
175
198
def get_supported_patterns (self ) -> Dict :
176
199
"""
0 commit comments