# 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] basename = os.path.basename(basefile) if basename.startswith('.'): #hidden .c continue items.append( (basefile, path) ) return items def write_section(self, is_includes): if is_includes: ext = 'h' tpls = [ ' ', ' %sHeader Files', ' ', ' ', ] else: ext = 'c' tpls = [ ' ', ' %sSource Files', ' ', ' ', ] 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 '