-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmerge_codebase_to_xml.py
More file actions
154 lines (120 loc) · 4.72 KB
/
Copy pathmerge_codebase_to_xml.py
File metadata and controls
154 lines (120 loc) · 4.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import argparse
import logging
from pathlib import Path
import xml.etree.ElementTree as ET
from xml.dom import minidom
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
EXTENSIONS = {".py", ".ts", ".jsx", ".js", ".tsx"}
def parse_arguments() -> argparse.Namespace:
"""
Parse command-line arguments.
Supports --input-dir, --output-file, and multiple --file arguments.
"""
parser = argparse.ArgumentParser(
description="Merge specified code files into a single XML file."
)
parser.add_argument(
"--input-dir",
type=Path,
help="Path to the input directory to scan."
)
parser.add_argument(
"--file",
type=Path,
action='append',
help="Path to an individual file to include. Can be used multiple times."
)
parser.add_argument(
"--output-file",
type=Path,
required=True,
help="Path to the output XML file."
)
args = parser.parse_args()
if not args.input_dir and not args.file:
parser.error("At least one of --input-dir or --file must be specified.")
return args
def get_target_files(input_dir: Path, extensions: set[str]) -> list[Path]:
"""
Recursively get all files in input_dir with the specified extensions.
"""
return [p for p in input_dir.rglob('*') if p.suffix.lower() in extensions]
def filter_files_by_extension(files: list[Path], extensions: set[str]) -> list[Path]:
"""
Filter the provided list of files by the specified extensions.
"""
filtered_files = []
for file in files:
if file.suffix.lower() in extensions:
if file.is_file():
filtered_files.append(file.resolve())
else:
logging.warning(f"'{file}' is not a valid file and will be skipped.")
return filtered_files
def create_xml_structure(files: set[Path]) -> ET.Element:
"""
Create an XML structure with the given files.
Each file is represented as a <file> element with <filename>, <filepath>, and <contents> sub-elements.
"""
root = ET.Element("codebase")
for file_path in files:
file_element = ET.SubElement(root, "file")
filename_element = ET.SubElement(file_element, "filename")
filename_element.text = file_path.name
filepath_element = ET.SubElement(file_element, "filepath")
filepath_element.text = str(file_path.resolve())
contents_element = ET.SubElement(file_element, "contents")
try:
contents = file_path.read_text(encoding="utf-8")
except Exception as e:
contents = f"Error reading file: {e}"
contents_element.text = contents
return root
def prettify_xml(elem: ET.Element) -> str:
"""
Return a pretty-printed XML string for the Element.
"""
rough_string = ET.tostring(elem, "utf-8")
reparsed = minidom.parseString(rough_string)
return reparsed.toprettyxml(indent=" ")
def main():
args = parse_arguments()
output_file = args.output_file
all_target_files: set[Path] = set()
# Process input directory if provided
if args.input_dir:
input_dir = args.input_dir
logging.info(f"Scanning directory: {input_dir} for files with extensions: {EXTENSIONS}")
target_files = get_target_files(input_dir, EXTENSIONS)
logging.info(f"Found {len(target_files)} files in directory.")
all_target_files.update(target_files)
# Process individual files if provided
if args.file:
individual_files = filter_files_by_extension(args.file, EXTENSIONS)
logging.info(f"Adding {len(individual_files)} individual files.")
all_target_files.update(individual_files)
logging.info(f"Total unique files to process: {len(all_target_files)}")
if not all_target_files:
logging.warning("No files to process. Exiting.")
return
logging.info("Creating XML structure...")
xml_root = create_xml_structure(all_target_files)
logging.info("Generating pretty XML...")
pretty_xml = prettify_xml(xml_root)
# Ensure the output directory exists
output_dir = output_file.parent
if not output_dir.exists():
try:
output_dir.mkdir(parents=True, exist_ok=True)
logging.info(f"Created output directory: {output_dir}")
except Exception as e:
logging.error(f"Error creating output directory '{output_dir}': {e}")
return
logging.info(f"Writing to output file: {output_file}")
try:
output_file.write_text(pretty_xml, encoding="utf-8")
logging.info("XML file creation complete.")
except Exception as e:
logging.error(f"Error writing to output file '{output_file}': {e}")
if __name__ == "__main__":
main()