nginx-lens 0.1.5__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/PKG-INFO +1 -1
  2. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/commands/analyze.py +8 -1
  3. nginx_lens-0.1.6/commands/diff.py +51 -0
  4. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/commands/graph.py +52 -8
  5. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/commands/include.py +8 -1
  6. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/commands/route.py +5 -1
  7. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/commands/syntax.py +5 -2
  8. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/commands/tree.py +8 -1
  9. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/nginx_lens.egg-info/PKG-INFO +1 -1
  10. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/setup.py +1 -1
  11. nginx_lens-0.1.5/commands/diff.py +0 -39
  12. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/analyzer/__init__.py +0 -0
  13. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/analyzer/base.py +0 -0
  14. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/analyzer/conflicts.py +0 -0
  15. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/analyzer/dead_locations.py +0 -0
  16. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/analyzer/diff.py +0 -0
  17. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/analyzer/duplicates.py +0 -0
  18. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/analyzer/empty_blocks.py +0 -0
  19. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/analyzer/include.py +0 -0
  20. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/analyzer/rewrite.py +0 -0
  21. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/analyzer/route.py +0 -0
  22. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/analyzer/unused.py +0 -0
  23. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/analyzer/warnings.py +0 -0
  24. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/commands/__init__.py +0 -0
  25. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/commands/cli.py +0 -0
  26. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/commands/health.py +0 -0
  27. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/commands/logs.py +0 -0
  28. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/exporter/__init__.py +0 -0
  29. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/exporter/graph.py +0 -0
  30. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/exporter/html.py +0 -0
  31. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/exporter/markdown.py +0 -0
  32. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/nginx_lens.egg-info/SOURCES.txt +0 -0
  33. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/nginx_lens.egg-info/dependency_links.txt +0 -0
  34. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/nginx_lens.egg-info/entry_points.txt +0 -0
  35. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/nginx_lens.egg-info/requires.txt +0 -0
  36. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/nginx_lens.egg-info/top_level.txt +0 -0
  37. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/parser/__init__.py +0 -0
  38. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/parser/nginx_parser.py +0 -0
  39. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/pyproject.toml +0 -0
  40. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/setup.cfg +0 -0
  41. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/tests/test_conflicts.py +0 -0
  42. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/tests/test_duplicates.py +0 -0
  43. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/tests/test_empty_blocks.py +0 -0
  44. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/tests/test_health.py +0 -0
  45. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/tests/test_parser.py +0 -0
  46. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/upstream_checker/__init__.py +0 -0
  47. {nginx_lens-0.1.5 → nginx_lens-0.1.6}/upstream_checker/checker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nginx-lens
3
- Version: 0.1.5
3
+ Version: 0.1.6
4
4
  Summary: CLI-инструмент для анализа, визуализации и диагностики конфигураций Nginx
5
5
  Author: Daniil Astrouski
6
6
  Author-email: shelovesuastra@gmail.com
@@ -58,7 +58,14 @@ def analyze(config_path: str = typer.Argument(..., help="Путь к nginx.conf"
58
58
  Пример:
59
59
  nginx-lens analyze /etc/nginx/nginx.conf
60
60
  """
61
- tree = parse_nginx_config(config_path)
61
+ try:
62
+ tree = parse_nginx_config(config_path)
63
+ except FileNotFoundError:
64
+ console.print(f"[red]Файл {config_path} не найден. Проверьте путь к конфигу.[/red]")
65
+ return
66
+ except Exception as e:
67
+ console.print(f"[red]Ошибка при разборе {config_path}: {e}[/red]")
68
+ return
62
69
  conflicts = find_location_conflicts(tree)
63
70
  dups = find_duplicate_directives(tree)
64
71
  empties = find_empty_blocks(tree)
@@ -0,0 +1,51 @@
1
+ import typer
2
+ from rich.console import Console
3
+ from rich.table import Table
4
+ from analyzer.diff import diff_trees
5
+ from parser.nginx_parser import parse_nginx_config
6
+ import difflib
7
+
8
+ app = typer.Typer()
9
+ console = Console()
10
+
11
+ def diff(
12
+ config1: str = typer.Argument(..., help="Первый nginx.conf"),
13
+ config2: str = typer.Argument(..., help="Второй nginx.conf")
14
+ ):
15
+ """
16
+ Сравнивает две конфигурации Nginx и выводит отличия построчно side-by-side с подсветкой.
17
+
18
+ Пример:
19
+ nginx-lens diff /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
20
+ """
21
+ try:
22
+ with open(config1) as f1, open(config2) as f2:
23
+ lines1 = f1.readlines()
24
+ lines2 = f2.readlines()
25
+ except FileNotFoundError as e:
26
+ console.print(f"[red]Файл {e.filename} не найден. Проверьте путь к конфигу.[/red]")
27
+ return
28
+ except Exception as e:
29
+ console.print(f"[red]Ошибка при чтении файлов: {e}[/red]")
30
+ return
31
+ maxlen = max(len(lines1), len(lines2))
32
+ # Выравниваем длины
33
+ lines1 += [''] * (maxlen - len(lines1))
34
+ lines2 += [''] * (maxlen - len(lines2))
35
+ table = Table(show_header=True, header_style="bold blue")
36
+ table.add_column("№", style="dim", width=4)
37
+ table.add_column("Config 1", style="white")
38
+ table.add_column("№", style="dim", width=4)
39
+ table.add_column("Config 2", style="white")
40
+ for i in range(maxlen):
41
+ l1 = lines1[i].rstrip('\n')
42
+ l2 = lines2[i].rstrip('\n')
43
+ n1 = str(i+1) if l1 else ''
44
+ n2 = str(i+1) if l2 else ''
45
+ if l1 == l2:
46
+ table.add_row(n1, l1, n2, l2)
47
+ else:
48
+ style1 = "red" if l1 else "on red"
49
+ style2 = "green" if l2 else "on green"
50
+ table.add_row(f"[bold]{n1}[/bold]" if l1 else n1, f"[{style1}]{l1}[/{style1}]" if l1 or l2 else '', f"[bold]{n2}[/bold]" if l2 else n2, f"[{style2}]{l2}[/{style2}]" if l1 or l2 else '')
51
+ console.print(table)
@@ -59,17 +59,61 @@ def graph(
59
59
  console.print("[yellow]Не найдено ни одного маршрута[/yellow]")
60
60
  return
61
61
  # Красивый вывод
62
+ seen = set()
62
63
  for route in routes:
64
+ if not route or route[0][0] != 'server':
65
+ continue
66
+ key = tuple(route)
67
+ if key in seen:
68
+ continue
69
+ seen.add(key)
63
70
  t = Text()
64
- for i, (typ, val) in enumerate(route):
65
- if typ == 'server':
66
- t.append(f"server: {val}", style="bold blue")
67
- elif typ == 'location':
68
- t.append(f" -> location: {val}", style="yellow")
71
+ # Получаем label для server
72
+ server_val = route[0][1]
73
+ server_block = None
74
+ # Найти сам блок server по arg
75
+ for d in tree.directives:
76
+ if d.get('block') == 'server' and (d.get('arg','') == server_val or (not d.get('arg') and (server_val == '[no arg]' or not server_val))):
77
+ server_block = d
78
+ break
79
+ label = get_server_label(server_block) if server_block else (server_val or 'default')
80
+ t.append(f"[", style="white")
81
+ t.append(f"server: {label}", style="bold blue")
82
+ t.append("]", style="white")
83
+ for i, (typ, val) in enumerate(route[1:]):
84
+ if typ == 'location':
85
+ t.append(f" -> [", style="white")
86
+ t.append(f"location: {val}", style="yellow")
87
+ t.append("]", style="white")
69
88
  elif typ == 'proxy_pass':
70
89
  t.append(f" -> proxy_pass: {val}", style="green")
71
90
  elif typ == 'upstream':
72
- t.append(f" -> upstream: {val}", style="magenta")
91
+ t.append(f" -> [", style="white")
92
+ t.append(f"upstream: {val}", style="magenta")
93
+ t.append("]", style="white")
73
94
  elif typ == 'upstream_server':
74
- t.append(f" -> server: {val}", style="grey50")
75
- console.print(t)
95
+ t.append(f" -> [", style="white")
96
+ t.append(f"server: {val}", style="grey50")
97
+ t.append("]", style="white")
98
+ console.print(t)
99
+
100
+ def get_server_label(server_block):
101
+ arg = server_block.get('arg')
102
+ if arg and arg != '[no arg]':
103
+ return arg
104
+ # Ищем server_name
105
+ names = []
106
+ listens = []
107
+ for sub in server_block.get('directives', []):
108
+ if sub.get('directive') == 'server_name':
109
+ names += sub.get('args', '').split()
110
+ if sub.get('directive') == 'listen':
111
+ listens.append(sub.get('args', ''))
112
+ if names:
113
+ return ' '.join(names)
114
+ if listens:
115
+ return ','.join(listens)
116
+ return 'default'
117
+
118
+ if __name__ == "__main__":
119
+ app()
@@ -18,7 +18,14 @@ def include_tree(
18
18
  nginx-lens include-tree /etc/nginx/nginx.conf
19
19
  nginx-lens include-tree /etc/nginx/nginx.conf --directive server_name
20
20
  """
21
- tree = build_include_tree(config_path)
21
+ try:
22
+ tree = build_include_tree(config_path)
23
+ except FileNotFoundError:
24
+ console.print(f"[red]Файл {config_path} не найден. Проверьте путь к конфигу.[/red]")
25
+ return
26
+ except Exception as e:
27
+ console.print(f"[red]Ошибка при разборе {config_path}: {e}[/red]")
28
+ return
22
29
  rich_tree = Tree(f"[bold blue]{config_path}[/bold blue]")
23
30
  def _add(node, t):
24
31
  for k, v in t.items():
@@ -31,8 +31,12 @@ def route(
31
31
  for conf in configs:
32
32
  try:
33
33
  tree = parse_nginx_config(conf)
34
+ except FileNotFoundError:
35
+ console.print(f"[red]Файл {conf} не найден. Проверьте путь к конфигу.[/red]")
36
+ continue
34
37
  except Exception as e:
35
- continue # пропускаем битые/невалидные
38
+ console.print(f"[red]Ошибка при разборе {conf}: {e}[/red]")
39
+ continue
36
40
  res = find_route(tree, url)
37
41
  if res:
38
42
  server = res['server']
@@ -33,6 +33,9 @@ def syntax(
33
33
  if not config_path:
34
34
  console.print("[red]Не удалось найти nginx.conf. Укажите путь через -c.[/red]")
35
35
  return
36
+ if not os.path.isfile(config_path):
37
+ console.print(f"[red]Файл {config_path} не найден. Проверьте путь к конфигу.[/red]")
38
+ return
36
39
  cmd = [nginx_path, "-t", "-c", os.path.abspath(config_path)]
37
40
  try:
38
41
  result = subprocess.run(cmd, capture_output=True, text=True, check=False)
@@ -41,8 +44,8 @@ def syntax(
41
44
  return
42
45
  else:
43
46
  console.print("[red]Ошибка синтаксиса![/red]")
44
- console.print(result.stdout)
45
- console.print(result.stderr)
47
+ console.print(result.stdout)
48
+ console.print(result.stderr)
46
49
  # Парсим все ошибки
47
50
  err = result.stderr or result.stdout
48
51
  errors = list(ERRORS_RE.finditer(err))
@@ -34,7 +34,14 @@ def tree(
34
34
  nginx-lens tree /etc/nginx/nginx.conf --markdown
35
35
  nginx-lens tree /etc/nginx/nginx.conf --html
36
36
  """
37
- tree_obj = parse_nginx_config(config_path)
37
+ try:
38
+ tree_obj = parse_nginx_config(config_path)
39
+ except FileNotFoundError:
40
+ console.print(f"[red]Файл {config_path} не найден. Проверьте путь к конфигу.[/red]")
41
+ return
42
+ except Exception as e:
43
+ console.print(f"[red]Ошибка при разборе {config_path}: {e}[/red]")
44
+ return
38
45
  root = RichTree(f"[bold blue]nginx.conf[/bold blue]")
39
46
  _build_tree(tree_obj.directives, root)
40
47
  if markdown:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nginx-lens
3
- Version: 0.1.5
3
+ Version: 0.1.6
4
4
  Summary: CLI-инструмент для анализа, визуализации и диагностики конфигураций Nginx
5
5
  Author: Daniil Astrouski
6
6
  Author-email: shelovesuastra@gmail.com
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="nginx-lens",
5
- version="0.1.5",
5
+ version="0.1.6",
6
6
  description="CLI-инструмент для анализа, визуализации и диагностики конфигураций Nginx",
7
7
  author="Daniil Astrouski",
8
8
  author_email="shelovesuastra@gmail.com",
@@ -1,39 +0,0 @@
1
- import typer
2
- from rich.console import Console
3
- from rich.table import Table
4
- from analyzer.diff import diff_trees
5
- from parser.nginx_parser import parse_nginx_config
6
-
7
- app = typer.Typer()
8
- console = Console()
9
-
10
- def diff(
11
- config1: str = typer.Argument(..., help="Первый nginx.conf"),
12
- config2: str = typer.Argument(..., help="Второй nginx.conf")
13
- ):
14
- """
15
- Сравнивает две конфигурации Nginx и выводит отличия side-by-side.
16
-
17
- Пример:
18
- nginx-lens diff /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
19
- """
20
- tree1 = parse_nginx_config(config1)
21
- tree2 = parse_nginx_config(config2)
22
- diffs = diff_trees(tree1, tree2)
23
- if not diffs:
24
- console.print("[green]Конфигурации идентичны[/green]")
25
- return
26
- table = Table(show_header=True, header_style="bold blue")
27
- table.add_column("Config 1", style="red")
28
- table.add_column("Config 2", style="green")
29
- for d in diffs:
30
- path = "/".join(d['path'])
31
- if d['type'] == 'added':
32
- table.add_row("", f"+ {path}")
33
- elif d['type'] == 'removed':
34
- table.add_row(f"- {path}", "")
35
- elif d['type'] == 'changed':
36
- v1 = str(d['value1'])
37
- v2 = str(d['value2'])
38
- table.add_row(f"! {path}\n{v1}", f"! {path}\n{v2}")
39
- console.print(table)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes