feat: Add grammar fetch and comparison tooling
- Add fetch_bind_grammar.py for MCP-based grammar file retrieval - Add compare_bind_versions.py for version differences analysis - Add process_mcp_result.py for handling base64-encoded MCP output - Create upstream directory structure with fetching instructions - Document grammar file locations and structure
This commit is contained in:
179
scripts/fetch_bind_grammar.py
Normal file
179
scripts/fetch_bind_grammar.py
Normal file
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Fetch BIND9 grammar files from Gitea mirror repository for version comparison.
|
||||
|
||||
This script uses the Gitea MCP tools to fetch grammar files from the official
|
||||
BIND9 mirror at git.valid.dk/Mirrors/bind9 for specified version tags.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
|
||||
|
||||
# Grammar files to fetch from doc/misc/
|
||||
GRAMMAR_FILES = [
|
||||
"options",
|
||||
"forward.zoneopt",
|
||||
"hint.zoneopt",
|
||||
"in-view.zoneopt",
|
||||
"mirror.zoneopt",
|
||||
"primary.zoneopt",
|
||||
"redirect.zoneopt",
|
||||
"secondary.zoneopt",
|
||||
"static-stub.zoneopt",
|
||||
"stub.zoneopt",
|
||||
"delegation-only.zoneopt",
|
||||
"rndc.grammar",
|
||||
]
|
||||
|
||||
# Support files
|
||||
SUPPORT_FILES = [
|
||||
"parsegrammar.py",
|
||||
"checkgrammar.py",
|
||||
]
|
||||
|
||||
|
||||
def fetch_file_content(owner: str, repo: str, ref: str, file_path: str) -> str:
|
||||
"""
|
||||
Fetch file content from Gitea repository.
|
||||
|
||||
This would use mcp_gitea-mcp_get_file_content in the actual MCP environment.
|
||||
For standalone usage, returns placeholder.
|
||||
"""
|
||||
# In MCP environment, this would call:
|
||||
# mcp_gitea-mcp_get_file_content(owner=owner, repo=repo, ref=ref, filePath=file_path)
|
||||
print(f"Would fetch: {owner}/{repo}@{ref}:{file_path}")
|
||||
return ""
|
||||
|
||||
|
||||
def save_grammar_file(content: str, version: str, filename: str, output_dir: Path):
|
||||
"""Save fetched grammar file to local directory."""
|
||||
version_dir = output_dir / version / "grammar"
|
||||
version_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
file_path = version_dir / filename
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
print(f"Saved: {file_path}")
|
||||
|
||||
|
||||
def fetch_version_grammars(owner: str, repo: str, tag: str, output_dir: Path):
|
||||
"""Fetch all grammar files for a specific version tag."""
|
||||
print(f"\n=== Fetching grammar files for {tag} ===")
|
||||
|
||||
# Create metadata
|
||||
metadata = {
|
||||
"version": tag,
|
||||
"repository": f"{owner}/{repo}",
|
||||
"files": [],
|
||||
}
|
||||
|
||||
# Fetch grammar files
|
||||
for grammar_file in GRAMMAR_FILES:
|
||||
try:
|
||||
file_path = f"doc/misc/{grammar_file}"
|
||||
content = fetch_file_content(owner, repo, tag, file_path)
|
||||
|
||||
if content:
|
||||
save_grammar_file(content, tag, grammar_file, output_dir)
|
||||
metadata["files"].append({
|
||||
"name": grammar_file,
|
||||
"path": file_path,
|
||||
"type": "grammar"
|
||||
})
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not fetch {grammar_file}: {e}")
|
||||
|
||||
# Fetch support files
|
||||
for support_file in SUPPORT_FILES:
|
||||
try:
|
||||
file_path = f"doc/misc/{support_file}"
|
||||
content = fetch_file_content(owner, repo, tag, file_path)
|
||||
|
||||
if content:
|
||||
save_grammar_file(content, tag, support_file, output_dir)
|
||||
metadata["files"].append({
|
||||
"name": support_file,
|
||||
"path": file_path,
|
||||
"type": "support"
|
||||
})
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not fetch {support_file}: {e}")
|
||||
|
||||
# Save metadata
|
||||
metadata_file = output_dir / tag / "metadata.json"
|
||||
with open(metadata_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(metadata, f, indent=2)
|
||||
|
||||
print(f"Metadata saved: {metadata_file}")
|
||||
return metadata
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Fetch BIND9 grammar files from Gitea mirror"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--owner",
|
||||
default="Mirrors",
|
||||
help="Repository owner (default: Mirrors)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--repo",
|
||||
default="bind9",
|
||||
help="Repository name (default: bind9)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--tags",
|
||||
nargs="+",
|
||||
default=["v9.18.44", "v9.20.18"],
|
||||
help="Version tags to fetch (default: v9.18.44 v9.20.18)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-dir",
|
||||
type=Path,
|
||||
default=Path("bind9-grammar/upstream"),
|
||||
help="Output directory for grammar files"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
print("BIND9 Grammar Fetcher")
|
||||
print("=" * 60)
|
||||
print(f"Repository: {args.owner}/{args.repo}")
|
||||
print(f"Tags: {', '.join(args.tags)}")
|
||||
print(f"Output: {args.output_dir}")
|
||||
|
||||
# Fetch grammars for each version
|
||||
results = {}
|
||||
for tag in args.tags:
|
||||
try:
|
||||
metadata = fetch_version_grammars(
|
||||
args.owner,
|
||||
args.repo,
|
||||
tag,
|
||||
args.output_dir
|
||||
)
|
||||
results[tag] = metadata
|
||||
except Exception as e:
|
||||
print(f"Error fetching {tag}: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# Save overall summary
|
||||
summary_file = args.output_dir / "fetch_summary.json"
|
||||
with open(summary_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(results, f, indent=2)
|
||||
|
||||
print(f"\n=== Fetch complete ===")
|
||||
print(f"Summary: {summary_file}")
|
||||
print(f"Fetched {len(results)} versions")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user