Test backup patterns and return list of matched files. Pass max_files=None for internal flows that must process the complete match set, such as backup creation and restore cleanup.
(self, metadata: Dict[str, Any], max_files: Optional[int] = 1000)
| 241 | return translated_patterns |
| 242 | |
| 243 | async def test_patterns(self, metadata: Dict[str, Any], max_files: Optional[int] = 1000) -> List[Dict[str, Any]]: |
| 244 | """Test backup patterns and return list of matched files. |
| 245 | |
| 246 | Pass max_files=None for internal flows that must process the complete |
| 247 | match set, such as backup creation and restore cleanup. |
| 248 | """ |
| 249 | include_patterns = metadata.get("include_patterns", []) |
| 250 | exclude_patterns = metadata.get("exclude_patterns", []) |
| 251 | include_hidden = metadata.get("include_hidden", True) |
| 252 | |
| 253 | # Convert to patterns string for pathspec |
| 254 | patterns_string = self._patterns_to_string(include_patterns, exclude_patterns) |
| 255 | |
| 256 | # Parse patterns using pathspec |
| 257 | pattern_lines = [line.strip() for line in patterns_string.split('\n') if line.strip() and not line.strip().startswith('#')] |
| 258 | |
| 259 | if not pattern_lines: |
| 260 | return [] |
| 261 | |
| 262 | # Get explicit patterns for hidden file handling |
| 263 | explicit_patterns = self._get_explicit_patterns(include_patterns) |
| 264 | |
| 265 | has_limit = max_files is not None |
| 266 | matched_files = [] |
| 267 | processed_count = 0 |
| 268 | |
| 269 | try: |
| 270 | spec = PathSpec.from_lines("gitwildmatch", pattern_lines) |
| 271 | |
| 272 | # Walk through base directories |
| 273 | for base_pattern_path, base_real_path in self.base_paths.items(): |
| 274 | if not os.path.exists(base_real_path): |
| 275 | continue |
| 276 | |
| 277 | for root, dirs, files_list in os.walk(base_real_path): |
| 278 | # Filter hidden directories if not included, BUT allow explicit ones |
| 279 | if not include_hidden: |
| 280 | dirs_to_keep = [] |
| 281 | for d in dirs: |
| 282 | if not d.startswith('.'): |
| 283 | dirs_to_keep.append(d) |
| 284 | else: |
| 285 | # Check if this hidden directory is explicitly included |
| 286 | dir_path = os.path.join(root, d) |
| 287 | pattern_path = self._unresolve_path(dir_path) |
| 288 | if self._is_explicitly_included(pattern_path, explicit_patterns): |
| 289 | dirs_to_keep.append(d) |
| 290 | dirs[:] = dirs_to_keep |
| 291 | |
| 292 | for file in files_list: |
| 293 | if has_limit and processed_count >= max_files: |
| 294 | break |
| 295 | |
| 296 | file_path = os.path.join(root, file) |
| 297 | pattern_path = self._unresolve_path(file_path) |
| 298 | |
| 299 | # Skip hidden files if not included, BUT allow explicit ones |
| 300 | if not include_hidden and file.startswith('.'): |
no test coverage detected