import os import shlex import pathlib class SplitFileTarget: def __init__(self, slice_start_idx, test_path, lines, name): self.slice_start_idx = slice_start_idx self.test_path = test_path self.lines = lines self.name = name def copyFrom(self, source, leading_lines=False): lines_before = self.lines[: self.slice_start_idx + 1] self.lines = self.lines[self.slice_start_idx + 1 :] slice_end_idx = None for i, l in enumerate(self.lines): if SplitFileTarget._get_split_line_path(l) != None: slice_end_idx = i break if slice_end_idx is not None: lines_after = self.lines[slice_end_idx:] else: lines_after = [] with open(source, "r") as f: source_lines = f.readlines() if leading_lines: # Strip the leading blank lines added by split-file --leading-lines source_lines = source_lines[self.slice_start_idx + 1 :] new_lines = lines_before + source_lines + lines_after with open(self.test_path, "w") as f: for l in new_lines: f.write(l) def __str__(self): return f"slice {self.name} in {self.test_path}" @staticmethod def get_target_dir(commands, test_path): # posix=True breaks Windows paths because \ is treated as an escaping character for cmd in commands: split = shlex.split(cmd, posix=False) if "split-file" not in split: continue start_idx = split.index("split-file") split = split[start_idx:] # Skip flags like --leading-lines leading_lines = "--leading-lines" in split args = [s for s in split[1:] if not s.startswith("-")] if len(args) < 2: continue p = unquote(args[0].strip()) if not test_path.samefile(p): continue return (unquote(args[1].strip()), leading_lines) return None @staticmethod def create(path, commands, test_path, target_dir): path = pathlib.Path(path) with open(test_path, "r") as f: lines = f.readlines() for i, l in enumerate(lines): p = SplitFileTarget._get_split_line_path(l) if p and path.samefile(os.path.join(target_dir, p)): idx = i break else: return None return SplitFileTarget(idx, test_path, lines, p) @staticmethod def _get_split_line_path(l): if len(l) < 6: return None if l.startswith("//"): l = l[2:] else: l = l[1:] if l.startswith("--- "): l = l[4:] else: return None return l.rstrip() def unquote(s): if len(s) > 1 and s[0] == s[-1] and (s[0] == '"' or s[0] == "'"): return s[1:-1] return s def propagate_split_files(test_path, updated_files, commands): test_path = pathlib.Path(test_path) result = SplitFileTarget.get_target_dir(commands, test_path) if not result: return updated_files split_target_dir, leading_lines = result new = [] for file in updated_files: target = SplitFileTarget.create(file, commands, test_path, split_target_dir) if target: target.copyFrom(file, leading_lines) new.append(str(target)) else: new.append(file) return new