| 30 | |
| 31 | @dataclass |
| 32 | class SSHHost: |
| 33 | patterns: List[str] = field(default_factory=list) |
| 34 | options: List[SSHOption] = field(default_factory=list) |
| 35 | start_line: int = -1 |
| 36 | end_line: int = -1 |
| 37 | raw_lines: List[str] = field(default_factory=list) |
| 38 | |
| 39 | @classmethod |
| 40 | def from_raw_lines(cls, lines: List[str]) -> "SSHHost": |
| 41 | host = cls() |
| 42 | found_host_line = False |
| 43 | for line in lines: |
| 44 | stripped = line.strip() |
| 45 | if not stripped or stripped.startswith("#"): |
| 46 | host.raw_lines.append(line) |
| 47 | continue |
| 48 | |
| 49 | if stripped.lower().startswith("host ") and not found_host_line: |
| 50 | patterns = stripped.split(None, 1)[1].split() |
| 51 | host.patterns = patterns |
| 52 | host.raw_lines.append(line) |
| 53 | found_host_line = True |
| 54 | continue |
| 55 | elif stripped.lower().startswith("host ") and found_host_line: |
| 56 | raise ValueError( |
| 57 | "Multiple Host declarations found within a single raw host block." |
| 58 | ) |
| 59 | |
| 60 | m = re.match(r"^(\S+)\s+(.+)$", stripped) |
| 61 | if m: |
| 62 | key, value = m.group(1), m.group(2) |
| 63 | indentation = line[: len(line) - len(line.lstrip())] |
| 64 | host.options.append( |
| 65 | SSHOption(key=key, value=value, indentation=indentation) |
| 66 | ) |
| 67 | host.raw_lines.append(line) |
| 68 | else: |
| 69 | host.raw_lines.append(line) |
| 70 | |
| 71 | if not found_host_line: |
| 72 | raise ValueError("No Host declaration found in raw host block.") |
| 73 | |
| 74 | return host |
| 75 | |
| 76 | def get_option(self, key: str) -> Optional[str]: |
| 77 | for opt in self.options: |
| 78 | if opt.key.lower() == key.lower(): |
| 79 | return opt.value |
| 80 | return None |
| 81 | |
| 82 | def set_option(self, key: str, value: str) -> None: |
| 83 | for opt in self.options: |
| 84 | if opt.key.lower() == key.lower(): |
| 85 | opt.value = value |
| 86 | return |
| 87 | self.options.append(SSHOption(key=key, value=value)) |
| 88 | |
| 89 | def remove_option(self, key: str) -> bool: |
no outgoing calls
no test coverage detected