-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcli.py
More file actions
131 lines (104 loc) Β· 4.39 KB
/
Copy pathcli.py
File metadata and controls
131 lines (104 loc) Β· 4.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"""The ``errlib`` command line interface: search, validate, index, stats, new.
Dependency-light (argparse + PyYAML) so engineers can run it anywhere::
errlib search "CrashLoopBackOff"
errlib search --tech kubernetes --severity high
errlib validate
errlib index
errlib stats
errlib new "Kubernetes Evicted Pod" --tech kubernetes --severity high
"""
from __future__ import annotations
import argparse
import sys
from . import __version__
from .index import DEFAULT_ROOT, INDEX_FILE, build_index, stats, write_index
from .new_error import create_error
from .search import search
from .validate import validate_tree
def _cmd_search(args: argparse.Namespace) -> int:
docs = build_index(args.root)
results = search(
docs,
args.query,
technology=args.tech,
tag=args.tag,
severity=args.severity,
message=args.message,
limit=args.limit,
)
if not results:
print("No matching errors found.")
return 1
for res in results:
d = res.doc
techs = ",".join(d.technologies)
print(f"[{d.severity:<8}] {d.title}")
print(f" {d.path} ({techs}) score={res.score}")
print(f"\n{len(results)} result(s).")
return 0
def _cmd_validate(args: argparse.Namespace) -> int:
issues = validate_tree(args.root)
if not issues:
count = len(build_index(args.root))
print(f"OK β {count} error document(s) valid.")
return 0
for issue in issues:
print(f"{issue.path}: {issue.message}")
print(f"\n{len(issues)} issue(s) found.", file=sys.stderr)
return 1
def _cmd_index(args: argparse.Namespace) -> int:
docs = build_index(args.root)
out = write_index(docs, args.out)
print(f"Wrote {out} ({len(docs)} documents).")
return 0
def _cmd_stats(args: argparse.Namespace) -> int:
for tech, count in stats(build_index(args.root)).items():
print(f"{tech:<16} {count}")
return 0
def _cmd_new(args: argparse.Namespace) -> int:
path = create_error(
args.title,
args.tech,
severity=args.severity,
tags=args.tags.split(",") if args.tags else None,
root=args.root,
subdir=args.subdir,
)
print(f"Created {path}")
return 0
def build_parser() -> argparse.ArgumentParser:
"""Construct the argparse CLI."""
parser = argparse.ArgumentParser(prog="errlib", description="Search the DevOps Error Library.")
parser.add_argument("--version", action="version", version=f"errlib {__version__}")
parser.add_argument("--root", default=DEFAULT_ROOT, help="Path to the errors/ tree.")
sub = parser.add_subparsers(dest="command", required=True)
p_search = sub.add_parser("search", help="Search errors by text and filters.")
p_search.add_argument("query", nargs="?", default=None, help="Free-text query.")
p_search.add_argument("--tech", help="Filter by technology.")
p_search.add_argument("--tag", help="Filter by tag.")
p_search.add_argument("--severity", help="Filter by severity.")
p_search.add_argument("--message", help="Match against the error message only.")
p_search.add_argument("--limit", type=int, default=20)
p_search.set_defaults(func=_cmd_search)
p_validate = sub.add_parser("validate", help="Validate every error document.")
p_validate.set_defaults(func=_cmd_validate)
p_index = sub.add_parser("index", help="Build the JSON search index.")
p_index.add_argument("--out", default=INDEX_FILE)
p_index.set_defaults(func=_cmd_index)
p_stats = sub.add_parser("stats", help="Show per-technology document counts.")
p_stats.set_defaults(func=_cmd_stats)
p_new = sub.add_parser("new", help="Scaffold a new error document.")
p_new.add_argument("title", help="Human error title, e.g. 'Kubernetes Evicted Pod'.")
p_new.add_argument("--tech", required=True, help="Technology, e.g. kubernetes.")
p_new.add_argument("--severity", default="medium")
p_new.add_argument("--tags", help="Comma-separated tags.")
p_new.add_argument("--subdir", help="Optional nested dir (e.g. an OpenStack service).")
p_new.set_defaults(func=_cmd_new)
return parser
def main(argv: list[str] | None = None) -> int:
"""Entry point for the ``errlib`` console script."""
parser = build_parser()
args = parser.parse_args(argv)
return int(args.func(args))
if __name__ == "__main__": # pragma: no cover
raise SystemExit(main())