1+ #!/usr/bin/env python3
2+ """
3+ File Operations Module
4+ Handles file copying operations and index file management.
5+
6+ This module provides functionality for:
7+ - Copying test files with or without modification
8+ - Managing index file toctree entries
9+ - Component tracking for copied files
10+ - RST content-level filtering and file operations
11+ """
12+
13+ import os
14+ import shutil
15+ import re
16+ from file_filters import filter_rst_content
17+
18+
19+ def get_copied_components (filtered_files ):
20+ """Track which components were actually copied."""
21+ copied_components = set ()
22+ for tf in filtered_files :
23+ if tf ['component' ] not in ['other' , 'general' ]:
24+ copied_components .add (tf ['component' ])
25+ return copied_components
26+
27+
28+ def extract_component_from_toctree_entry (entry ):
29+ """Extract component name from toctree entry."""
30+ # " adc/index" → "adc"
31+ # " core/hp_tests" → "core"
32+ entry = entry .strip ()
33+ if '/' in entry :
34+ return entry .split ('/' )[0 ]
35+ return entry
36+
37+
38+ def filter_index_content (file_path , copied_components ):
39+ """Filter toctree entries in index files based on copied components."""
40+
41+ with open (file_path , 'r' , encoding = 'utf-8' ) as f :
42+ content = f .read ()
43+
44+ # Find toctree section
45+ toctree_pattern = r'(\.\. toctree::\n(?:\s+:[^\n]+\n)*\s*\n)(.*?)(\n\n|\.\.|$)'
46+ match = re .search (toctree_pattern , content , re .DOTALL )
47+
48+ if not match :
49+ return content # No toctree found
50+
51+ header = match .group (1 )
52+ entries = match .group (2 )
53+ footer = content [match .end ():]
54+
55+ # Filter toctree entries
56+ filtered_entries = []
57+ for line in entries .split ('\n ' ):
58+ if line .strip ():
59+ # Extract component from entry like "adc/index" → "adc"
60+ component = extract_component_from_toctree_entry (line )
61+ if component in copied_components :
62+ filtered_entries .append (line )
63+
64+ # Reconstruct content
65+ before_toctree = content [:match .start ()]
66+ new_entries = '\n ' .join (filtered_entries )
67+
68+ return f"{ before_toctree } { header } { new_entries } \n { footer } "
69+
70+
71+ def copy_files_unchanged (test_files , dest_dir , component_filter = None ):
72+ """Copy files without content modification."""
73+ copied_count = 0
74+ copied_components = get_copied_components (test_files ) if component_filter else None
75+
76+ for test_file in test_files :
77+ src_path = test_file ['file_path' ]
78+ dest_path = os .path .join (dest_dir , test_file ['relative_path' ])
79+
80+ # Create destination directory
81+ os .makedirs (os .path .dirname (dest_path ), exist_ok = True )
82+
83+ # Filter index files when component filtering is active
84+ if component_filter and 'index.rst' in test_file ['relative_path' ]:
85+ filtered_content = filter_index_content (src_path , copied_components )
86+ with open (dest_path , 'w' , encoding = 'utf-8' ) as f :
87+ f .write (filtered_content )
88+ else :
89+ # Copy file unchanged
90+ shutil .copy2 (src_path , dest_path )
91+
92+ copied_count += 1
93+
94+ return copied_count
95+
96+
97+ def filter_by_rbp_content (test_files , rbp_filter , dest_dir , component_filter = None , new_uids = None ):
98+ """Content-level filtering: modify files to keep only specified RBP tests or new tests."""
99+ if not rbp_filter and not new_uids :
100+ # No filters - copy files as-is
101+ return copy_files_unchanged (test_files , dest_dir , component_filter )
102+
103+ copied_count = 0
104+ copied_components = get_copied_components (test_files ) if component_filter else None
105+
106+ # Filter active - parse and modify content
107+ for test_file in test_files :
108+ dest_path = os .path .join (dest_dir , test_file ['relative_path' ])
109+
110+ # Create destination directory
111+ os .makedirs (os .path .dirname (dest_path ), exist_ok = True )
112+
113+ if test_file ['tests' ]: # File contains tests
114+ filtered_content = filter_rst_content (test_file ['file_path' ], rbp_filter , new_uids )
115+ with open (dest_path , 'w' , encoding = 'utf-8' ) as f :
116+ f .write (filtered_content )
117+ elif component_filter and 'index.rst' in test_file ['relative_path' ]:
118+ # Filter index files when component filtering is active
119+ filtered_content = filter_index_content (test_file ['file_path' ], copied_components )
120+ with open (dest_path , 'w' , encoding = 'utf-8' ) as f :
121+ f .write (filtered_content )
122+ else : # File has no tests (index, docs, etc.)
123+ shutil .copy2 (test_file ['file_path' ], dest_path )
124+
125+ copied_count += 1
126+
127+ return copied_count
0 commit comments