Download scripts/parse_cisco_ospf.py from gesh75/multivendor-cli-configurator: direct link, hf CLI and curl.
- Browser
- Download file 3.1 kB
-
https://huggingface.co/spaces/gesh75/multivendor-cli-configurator/resolve/main/scripts/parse_cisco_ospf.py
- Command line
-
hf download hf://spaces/gesh75/multivendor-cli-configurator/scripts/parse_cisco_ospf.py
-
curl -L -o parse_cisco_ospf.py https://huggingface.co/spaces/gesh75/multivendor-cli-configurator/resolve/main/scripts/parse_cisco_ospf.py
3.1 kB
| #!/usr/bin/env python3 | |
| """ | |
| Cisco IOS IP Routing: OSPF Command Reference parser. | |
| Same bold-backtick format as the Arista EOS User Guide but Cisco-flavored. | |
| All 113 commands → vendor=Cisco, os=ios, cat=OSPF (no recat needed — they're all OSPF). | |
| """ | |
| import re, json, pathlib | |
| from collections import Counter | |
| SRC = pathlib.Path(__file__).parent / "sources" / "cisco-ios-ospf-reference.md" | |
| OUT = pathlib.Path(__file__).parent / "cisco_ospf.json" | |
| TITLE_RE = re.compile(r"^\*\*`([^`]+)`\*\*\s*$") | |
| def parse(): | |
| text = SRC.read_text(encoding="utf-8", errors="ignore") | |
| lines = text.split("\n") | |
| out = [] | |
| section_hdr = "OSPF" | |
| pending_title = None | |
| i, n = 0, len(lines) | |
| while i < n: | |
| line = lines[i] | |
| m = re.match(r"^#{2,3}\s+(.+?)\s*$", line) | |
| if m: | |
| section_hdr = m.group(1).strip() | |
| i += 1; continue | |
| m = TITLE_RE.match(line) | |
| if m: | |
| pending_title = m.group(1).strip() | |
| i += 1; continue | |
| if line.strip().startswith("```"): | |
| block = [] | |
| i += 1 | |
| while i < n and not lines[i].strip().startswith("```"): | |
| block.append(lines[i]); i += 1 | |
| i += 1 | |
| # Description (markdown blockquote) | |
| desc = "" | |
| j = i | |
| while j < n and j < i + 6: | |
| ln = lines[j].strip() | |
| if not ln: j += 1; continue | |
| qm = re.match(r"^>\s*(.+?)\s*$", lines[j]) | |
| if qm: | |
| parts = [qm.group(1)] | |
| k = j + 1 | |
| while k < n: | |
| qq = re.match(r"^>\s*(.+?)\s*$", lines[k]) | |
| if qq: parts.append(qq.group(1)); k += 1 | |
| else: break | |
| desc = " ".join(parts).strip() | |
| break | |
| cleaned = [l for l in block if l.strip()] | |
| if not cleaned: | |
| pending_title = None; continue | |
| cmd = "\n".join(cleaned).rstrip() | |
| first = cleaned[0].strip() | |
| # Skip obvious output samples | |
| if re.match(r"^(Active|Up|Down|Login:|Username:|--More--|Area\s+\d|i\s*\[)", first): | |
| pending_title = None; continue | |
| title = pending_title or first[:80] | |
| out.append({ | |
| "os":"ios","role":"router","vendor":"Cisco","cat":"OSPF", | |
| "title": title[:80], | |
| "cmd": cmd, | |
| "desc": (desc or section_hdr)[:280], | |
| }) | |
| pending_title = None | |
| continue | |
| i += 1 | |
| return out | |
| def main(): | |
| items = parse() | |
| # dedupe within this source | |
| seen = set(); deduped = [] | |
| for it in items: | |
| key = re.sub(r"\s+", " ", it["cmd"]).lower() | |
| if key in seen: continue | |
| seen.add(key); deduped.append(it) | |
| OUT.write_text(json.dumps(deduped, indent=1, ensure_ascii=False)) | |
| print(f"wrote {len(deduped)} Cisco OSPF entries → {OUT}") | |
| print("titles sample:", [c["title"][:50] for c in deduped[:5]]) | |
| if __name__ == "__main__": | |
| main() | |