forked from vgmstream/vgmstream
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvspf.py
161 lines (128 loc) · 5.13 KB
/
vspf.py
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
155
156
157
158
159
160
161
# Visual Studio project fixer
#
# VS updates automatically project files every time a new source file is added, but they are
# a pain to maintain if aren't using VS. CL compiler supports wildcards in .vcxprojs, but VS
# doesn't and won't update the file list (and probably causes other issues). Meanwhile CMake
# creates ugly stuff with full paths that can't be added to SCC, meaning new/old users need
# to call cmake every time stuff changes around. So for now, this tool updates the expected
# file list so MS is happy and I don't have to babysit this crap.
#
# Reads/writes lines as to keep original structure (python's XML functions re-create the document).
# It's brittle though, and only works with the known structure used here.
import os, glob
TEST_OUTPUT = False
BASE_SRC_PATH = '.'
class ProjectFixer:
def __init__(self, prj_pathname):
self.prj_pathname = prj_pathname
self.prj_path = os.path.dirname(prj_pathname)
#self.prj_name = os.path.basename(prj_pathname)
self.in_lines = []
self.out_lines = []
self.is_filters = False
if prj_pathname.lower().endswith('.vcxproj'):
self.is_filters = False
elif prj_pathname.lower().endswith('.vcxproj.filters'):
self.is_filters = True
else:
raise ValueError("unsupported file")
def is_changed(self):
# no change in src means output files should be the exact same as input
return self.in_lines != self.out_lines
def read(self):
with open (self.prj_pathname, 'r', encoding='utf-8-sig') as f:
lines = f.readlines()
self.in_lines = [line.strip('\r\n') for line in lines]
def add(self, text):
self.out_lines.append(text)
def get_files(self, ext):
files = glob.glob(self.prj_path + '/**/*.' + ext, recursive=True)
items = []
for file in files:
basefile = file[len(self.prj_path) + 1 : ].replace('/', '\\')
path = ''
if '\\' in basefile:
pos = basefile.rindex('\\')
path = basefile[0 : pos + 1]
items.append( (basefile, path) )
return items
def write_section(self, is_includes):
if is_includes:
ext = 'h'
tpls = [
' <ClInclude Include="%s">',
' <Filter>%sHeader Files</Filter>',
' </ClInclude>',
' <ClInclude Include="%s" />',
]
else:
ext = 'c'
tpls = [
' <ClCompile Include="%s">',
' <Filter>%sSource Files</Filter>',
' </ClCompile>',
' <ClCompile Include="%s" />',
]
self.write_section_internal(ext, tpls)
def write_section_internal(self, ext, tpls):
files = self.get_files(ext)
for basefile, path in files:
if self.is_filters:
self.add(tpls[0] % (basefile))
self.add(tpls[1] % (path))
self.add(tpls[2])
else:
self.add(tpls[3] % (basefile))
# - VS projects are organized in sections
# - writes lines if not target section
# - when target section found (includes or compiles), redo section's files again
def process(self):
lines_itr = iter(self.in_lines)
for line in lines_itr:
self.add(line)
if '<ItemGroup' not in line:
continue
# section start
next_line = next(lines_itr)
is_includes = '<ClInclude' in next_line
is_compiles = '<ClCompile' in next_line
if is_includes or is_compiles:
# include/compile section
self.write_section(is_includes)
# consume rest of files until section end
for subline in lines_itr:
if '</ItemGroup' in subline:
self.add(subline)
break
else:
# other type
self.add(next_line)
#print("done", len(self.out_lines))
def write(self):
if not self.is_changed():
print("no changes detected for %s" % (self.prj_pathname))
return
out_name = self.prj_pathname
if TEST_OUTPUT:
out_name += '.test'
print("writting " + out_name)
with open(out_name, 'w', newline='\r\n', encoding='utf-8-sig') as f:
#f.write(codecs.BOM_UTF8)
f.write('\n'.join(self.out_lines))
def start(self):
self.read()
self.process()
self.write()
def main():
types = [
'./src/*.vcxproj',
'./src/*.vcxproj.filters'
]
for type in types:
files = glob.glob(type, recursive=True)
for file in files:
print('fixing ' + file)
ProjectFixer(file).start()
main()
#ProjectFixer('libvgmstream.vcxproj').start()
#ProjectFixer('libvgmstream.vcxproj.filters').start()