mvn-tree-visualizer 1.2.0__py3-none-any.whl → 1.4.0__py3-none-any.whl
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.
Potentially problematic release.
This version of mvn-tree-visualizer might be problematic. Click here for more details.
- mvn_tree_visualizer/cli.py +155 -24
- mvn_tree_visualizer/diagram.py +15 -3
- mvn_tree_visualizer/enhanced_template.py +218 -0
- mvn_tree_visualizer/exceptions.py +25 -0
- mvn_tree_visualizer/file_watcher.py +71 -0
- mvn_tree_visualizer/get_dependencies_in_one_file.py +34 -7
- mvn_tree_visualizer/outputs/html_output.py +81 -14
- mvn_tree_visualizer/outputs/json_output.py +2 -2
- mvn_tree_visualizer/themes.py +189 -0
- mvn_tree_visualizer/validation.py +86 -0
- mvn_tree_visualizer-1.4.0.dist-info/METADATA +209 -0
- mvn_tree_visualizer-1.4.0.dist-info/RECORD +17 -0
- mvn_tree_visualizer/TEMPLATE.py +0 -61
- mvn_tree_visualizer-1.2.0.dist-info/METADATA +0 -94
- mvn_tree_visualizer-1.2.0.dist-info/RECORD +0 -13
- {mvn_tree_visualizer-1.2.0.dist-info → mvn_tree_visualizer-1.4.0.dist-info}/WHEEL +0 -0
- {mvn_tree_visualizer-1.2.0.dist-info → mvn_tree_visualizer-1.4.0.dist-info}/entry_points.txt +0 -0
- {mvn_tree_visualizer-1.2.0.dist-info → mvn_tree_visualizer-1.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,25 +3,40 @@ from typing import List, Set, Tuple
|
|
|
3
3
|
|
|
4
4
|
from jinja2 import BaseLoader, Environment
|
|
5
5
|
|
|
6
|
-
from ..
|
|
6
|
+
from ..enhanced_template import get_html_template
|
|
7
|
+
from ..themes import STANDARD_COLORS, get_theme
|
|
7
8
|
|
|
8
9
|
|
|
9
|
-
def create_html_diagram(dependency_tree: str, output_filename: str, show_versions: bool = False) -> None:
|
|
10
|
+
def create_html_diagram(dependency_tree: str, output_filename: str, show_versions: bool = False, theme: str = "minimal") -> None:
|
|
11
|
+
"""Create HTML diagram with theme support."""
|
|
12
|
+
theme_obj = get_theme(theme)
|
|
10
13
|
mermaid_diagram: str = _convert_to_mermaid(dependency_tree, show_versions)
|
|
11
|
-
|
|
14
|
+
|
|
15
|
+
# Use enhanced template with theme
|
|
16
|
+
html_template = get_html_template(theme_obj)
|
|
17
|
+
template = Environment(loader=BaseLoader).from_string(html_template)
|
|
12
18
|
rendered: str = template.render(diagram_definition=mermaid_diagram)
|
|
19
|
+
|
|
13
20
|
parent_dir: Path = Path(output_filename).parent
|
|
14
21
|
if not parent_dir.exists():
|
|
15
22
|
parent_dir.mkdir(parents=True, exist_ok=True)
|
|
16
|
-
with open(output_filename, "w") as f:
|
|
23
|
+
with open(output_filename, "w", encoding="utf-8") as f:
|
|
17
24
|
f.write(rendered)
|
|
18
25
|
|
|
19
26
|
|
|
20
27
|
def _convert_to_mermaid(dependency_tree: str, show_versions: bool = False) -> str:
|
|
21
|
-
|
|
28
|
+
"""Convert dependency tree to enhanced Mermaid diagram with styling."""
|
|
22
29
|
lines: List[str] = dependency_tree.strip().split("\n")
|
|
23
|
-
|
|
30
|
+
relationships: Set[str] = set()
|
|
31
|
+
node_styles: Set[str] = set()
|
|
24
32
|
previous_dependency: List[Tuple[str, int]] = []
|
|
33
|
+
|
|
34
|
+
# Track root and leaf nodes for styling, and store all node declarations
|
|
35
|
+
all_nodes: Set[str] = set()
|
|
36
|
+
parent_nodes: Set[str] = set()
|
|
37
|
+
child_nodes: Set[str] = set()
|
|
38
|
+
node_declarations: Set[str] = set()
|
|
39
|
+
|
|
25
40
|
for line in lines:
|
|
26
41
|
if not line:
|
|
27
42
|
continue
|
|
@@ -30,17 +45,21 @@ def _convert_to_mermaid(dependency_tree: str, show_versions: bool = False) -> st
|
|
|
30
45
|
parts: List[str] = line.split(":")
|
|
31
46
|
if len(parts) < 3:
|
|
32
47
|
continue
|
|
48
|
+
|
|
33
49
|
if len(parts) == 4:
|
|
34
50
|
group_id, artifact_id, app, version = parts
|
|
35
51
|
if show_versions:
|
|
36
52
|
node_label: str = f"{artifact_id}:{version}"
|
|
37
|
-
|
|
53
|
+
safe_node_id: str = _sanitize_node_id(f"{artifact_id}_{version}")
|
|
38
54
|
else:
|
|
39
55
|
node_label: str = artifact_id
|
|
40
|
-
|
|
56
|
+
safe_node_id: str = _sanitize_node_id(artifact_id)
|
|
57
|
+
|
|
58
|
+
node_declarations.add(f'\t{safe_node_id}["{node_label}"];')
|
|
59
|
+
all_nodes.add(safe_node_id)
|
|
41
60
|
if previous_dependency: # Re initialize the list if it wasn't empty
|
|
42
61
|
previous_dependency = []
|
|
43
|
-
previous_dependency.append((
|
|
62
|
+
previous_dependency.append((safe_node_id, 0)) # The second element is the depth
|
|
44
63
|
else:
|
|
45
64
|
depth: int = len(parts[0].split(" ")) - 1
|
|
46
65
|
if len(parts) == 6:
|
|
@@ -50,16 +69,64 @@ def _convert_to_mermaid(dependency_tree: str, show_versions: bool = False) -> st
|
|
|
50
69
|
|
|
51
70
|
if show_versions:
|
|
52
71
|
node_label: str = f"{artifact_id}:{version}"
|
|
72
|
+
safe_node_id: str = _sanitize_node_id(f"{artifact_id}_{version}")
|
|
53
73
|
else:
|
|
54
74
|
node_label: str = artifact_id
|
|
75
|
+
safe_node_id: str = _sanitize_node_id(artifact_id)
|
|
76
|
+
|
|
77
|
+
node_declarations.add(f'\t{safe_node_id}["{node_label}"];')
|
|
78
|
+
all_nodes.add(safe_node_id)
|
|
79
|
+
child_nodes.add(safe_node_id)
|
|
55
80
|
|
|
56
81
|
if previous_dependency[-1][1] < depth:
|
|
57
|
-
|
|
58
|
-
|
|
82
|
+
parent_id = previous_dependency[-1][0]
|
|
83
|
+
parent_nodes.add(parent_id)
|
|
84
|
+
relationships.add(f"\t{parent_id} --> {safe_node_id};")
|
|
85
|
+
previous_dependency.append((safe_node_id, depth))
|
|
59
86
|
else:
|
|
60
87
|
# remove all dependencies that are deeper or equal to the current depth
|
|
61
88
|
while previous_dependency and previous_dependency[-1][1] >= depth:
|
|
62
89
|
previous_dependency.pop()
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
90
|
+
parent_id = previous_dependency[-1][0]
|
|
91
|
+
parent_nodes.add(parent_id)
|
|
92
|
+
relationships.add(f"\t{parent_id} --> {safe_node_id};")
|
|
93
|
+
previous_dependency.append((safe_node_id, depth))
|
|
94
|
+
|
|
95
|
+
# Add styling classes
|
|
96
|
+
root_nodes = all_nodes - child_nodes
|
|
97
|
+
leaf_nodes = all_nodes - parent_nodes
|
|
98
|
+
|
|
99
|
+
# Add node styling
|
|
100
|
+
for node in root_nodes:
|
|
101
|
+
node_styles.add(f"\tclass {node} rootNode;")
|
|
102
|
+
for node in leaf_nodes:
|
|
103
|
+
node_styles.add(f"\tclass {node} leafNode;")
|
|
104
|
+
for node in parent_nodes.intersection(child_nodes):
|
|
105
|
+
node_styles.add(f"\tclass {node} intermediateNode;")
|
|
106
|
+
|
|
107
|
+
# Build the complete diagram with standardized colors
|
|
108
|
+
diagram_parts = [
|
|
109
|
+
"graph LR",
|
|
110
|
+
*sorted(node_declarations),
|
|
111
|
+
*sorted(relationships),
|
|
112
|
+
"",
|
|
113
|
+
f"classDef rootNode fill:{STANDARD_COLORS['root_node']}20,stroke:{STANDARD_COLORS['root_node']},stroke-width:3px,color:#000;",
|
|
114
|
+
f"classDef leafNode fill:{STANDARD_COLORS['leaf_node']}20,stroke:{STANDARD_COLORS['leaf_node']},stroke-width:2px,color:#000;",
|
|
115
|
+
f"classDef intermediateNode fill:{STANDARD_COLORS['intermediate_node']}20,stroke:{STANDARD_COLORS['intermediate_node']},stroke-width:2px,color:#000;",
|
|
116
|
+
"",
|
|
117
|
+
*sorted(node_styles),
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
return "\n".join(diagram_parts)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _sanitize_node_id(node_id: str) -> str:
|
|
124
|
+
"""Sanitize node ID for Mermaid compatibility."""
|
|
125
|
+
# Replace special characters that could break Mermaid syntax
|
|
126
|
+
import re
|
|
127
|
+
|
|
128
|
+
sanitized = re.sub(r"[^a-zA-Z0-9_]", "_", node_id)
|
|
129
|
+
# Ensure it starts with a letter or underscore
|
|
130
|
+
if sanitized and not sanitized[0].isalpha() and sanitized[0] != "_":
|
|
131
|
+
sanitized = "_" + sanitized
|
|
132
|
+
return sanitized or "node"
|
|
@@ -21,9 +21,9 @@ def create_json_output(dependency_tree: str, output_filename: str, show_versions
|
|
|
21
21
|
if len(parts) == 4:
|
|
22
22
|
group_id, artifact_id, _, version = parts
|
|
23
23
|
if show_versions:
|
|
24
|
-
node_id: str = f"{
|
|
24
|
+
node_id: str = f"{artifact_id}:{version}"
|
|
25
25
|
else:
|
|
26
|
-
node_id: str =
|
|
26
|
+
node_id: str = artifact_id
|
|
27
27
|
node: Dict[str, Any] = {"id": node_id, "children": []}
|
|
28
28
|
tree = node
|
|
29
29
|
node_stack = [(node, 0)] # Reset stack with root node at depth 0
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""Theme configurations for mvn-tree-visualizer diagrams."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Theme:
|
|
7
|
+
"""Base theme configuration class."""
|
|
8
|
+
|
|
9
|
+
def __init__(
|
|
10
|
+
self,
|
|
11
|
+
name: str,
|
|
12
|
+
mermaid_theme: str = "default",
|
|
13
|
+
background_color: str = "#ffffff",
|
|
14
|
+
custom_css: str = "",
|
|
15
|
+
mermaid_config: Dict[str, Any] = None,
|
|
16
|
+
):
|
|
17
|
+
self.name = name
|
|
18
|
+
self.mermaid_theme = mermaid_theme
|
|
19
|
+
self.background_color = background_color
|
|
20
|
+
self.custom_css = custom_css
|
|
21
|
+
self.mermaid_config = mermaid_config or {}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Standard color scheme for consistency across themes
|
|
25
|
+
# Root nodes: Blue shades, Intermediate nodes: Orange shades, Leaf nodes: Green shades
|
|
26
|
+
STANDARD_COLORS = {
|
|
27
|
+
"root_node": "#3B82F6", # Blue for root nodes
|
|
28
|
+
"intermediate_node": "#F59E0B", # Orange for intermediate nodes
|
|
29
|
+
"leaf_node": "#10B981", # Green for leaf nodes
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# Predefined themes
|
|
33
|
+
THEMES = {
|
|
34
|
+
"minimal": Theme(
|
|
35
|
+
name="minimal",
|
|
36
|
+
mermaid_theme="neutral",
|
|
37
|
+
background_color="#ffffff",
|
|
38
|
+
custom_css="""
|
|
39
|
+
body {
|
|
40
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
41
|
+
margin: 0;
|
|
42
|
+
padding: 20px;
|
|
43
|
+
background-color: #ffffff;
|
|
44
|
+
color: #000000;
|
|
45
|
+
line-height: 1.6;
|
|
46
|
+
height: 100vh;
|
|
47
|
+
box-sizing: border-box;
|
|
48
|
+
}
|
|
49
|
+
#graphDiv {
|
|
50
|
+
background-color: #ffffff;
|
|
51
|
+
border: 1px solid #000000;
|
|
52
|
+
padding: 20px;
|
|
53
|
+
margin-bottom: 20px;
|
|
54
|
+
height: calc(100vh - 120px);
|
|
55
|
+
overflow: hidden;
|
|
56
|
+
}
|
|
57
|
+
.controls {
|
|
58
|
+
margin-bottom: 20px;
|
|
59
|
+
display: flex;
|
|
60
|
+
gap: 10px;
|
|
61
|
+
flex-wrap: wrap;
|
|
62
|
+
align-items: center;
|
|
63
|
+
}
|
|
64
|
+
.control-group {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
gap: 8px;
|
|
68
|
+
}
|
|
69
|
+
.control-label {
|
|
70
|
+
font-size: 12px;
|
|
71
|
+
font-weight: normal;
|
|
72
|
+
color: #000000;
|
|
73
|
+
text-transform: uppercase;
|
|
74
|
+
}
|
|
75
|
+
.toggle-btn {
|
|
76
|
+
background-color: #000000;
|
|
77
|
+
color: white;
|
|
78
|
+
border: none;
|
|
79
|
+
padding: 8px 16px;
|
|
80
|
+
cursor: pointer;
|
|
81
|
+
font-family: inherit;
|
|
82
|
+
font-size: 12px;
|
|
83
|
+
text-transform: uppercase;
|
|
84
|
+
letter-spacing: 1px;
|
|
85
|
+
transition: opacity 0.2s;
|
|
86
|
+
}
|
|
87
|
+
.toggle-btn:hover {
|
|
88
|
+
opacity: 0.8;
|
|
89
|
+
}
|
|
90
|
+
""",
|
|
91
|
+
mermaid_config={
|
|
92
|
+
"theme": "neutral",
|
|
93
|
+
"themeVariables": {
|
|
94
|
+
"primaryColor": STANDARD_COLORS["root_node"],
|
|
95
|
+
"primaryTextColor": "#000000",
|
|
96
|
+
"primaryBorderColor": "#000000",
|
|
97
|
+
"lineColor": "#000000",
|
|
98
|
+
"secondaryColor": "#f5f5f5",
|
|
99
|
+
"tertiaryColor": "#ffffff",
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
),
|
|
103
|
+
"dark": Theme(
|
|
104
|
+
name="dark",
|
|
105
|
+
mermaid_theme="forest",
|
|
106
|
+
background_color="#2d3748",
|
|
107
|
+
custom_css="""
|
|
108
|
+
body {
|
|
109
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
110
|
+
margin: 0;
|
|
111
|
+
padding: 20px;
|
|
112
|
+
background-color: #2d3748;
|
|
113
|
+
color: #f7fafc;
|
|
114
|
+
line-height: 1.6;
|
|
115
|
+
height: 100vh;
|
|
116
|
+
box-sizing: border-box;
|
|
117
|
+
}
|
|
118
|
+
#graphDiv {
|
|
119
|
+
background-color: #2d3748;
|
|
120
|
+
border: 1px solid #e2e8f0;
|
|
121
|
+
padding: 20px;
|
|
122
|
+
margin-bottom: 20px;
|
|
123
|
+
height: calc(100vh - 120px);
|
|
124
|
+
overflow: hidden;
|
|
125
|
+
}
|
|
126
|
+
.controls {
|
|
127
|
+
margin-bottom: 20px;
|
|
128
|
+
display: flex;
|
|
129
|
+
gap: 10px;
|
|
130
|
+
flex-wrap: wrap;
|
|
131
|
+
align-items: center;
|
|
132
|
+
}
|
|
133
|
+
.control-group {
|
|
134
|
+
display: flex;
|
|
135
|
+
align-items: center;
|
|
136
|
+
gap: 8px;
|
|
137
|
+
}
|
|
138
|
+
.control-label {
|
|
139
|
+
font-size: 12px;
|
|
140
|
+
font-weight: normal;
|
|
141
|
+
color: #f7fafc;
|
|
142
|
+
text-transform: uppercase;
|
|
143
|
+
}
|
|
144
|
+
.toggle-btn {
|
|
145
|
+
background-color: #f7fafc;
|
|
146
|
+
color: #2d3748;
|
|
147
|
+
border: none;
|
|
148
|
+
padding: 8px 16px;
|
|
149
|
+
cursor: pointer;
|
|
150
|
+
font-family: inherit;
|
|
151
|
+
font-size: 12px;
|
|
152
|
+
text-transform: uppercase;
|
|
153
|
+
letter-spacing: 1px;
|
|
154
|
+
transition: opacity 0.2s;
|
|
155
|
+
}
|
|
156
|
+
.toggle-btn:hover {
|
|
157
|
+
opacity: 0.8;
|
|
158
|
+
}
|
|
159
|
+
""",
|
|
160
|
+
mermaid_config={
|
|
161
|
+
"theme": "forest",
|
|
162
|
+
"themeVariables": {
|
|
163
|
+
"primaryColor": STANDARD_COLORS["root_node"],
|
|
164
|
+
"primaryTextColor": "#ffffff",
|
|
165
|
+
"primaryBorderColor": "#e2e8f0",
|
|
166
|
+
"lineColor": "#a0aec0",
|
|
167
|
+
"secondaryColor": "#4a5568",
|
|
168
|
+
"tertiaryColor": "#2d3748",
|
|
169
|
+
"background": "#2d3748",
|
|
170
|
+
"mainBkg": "#4a5568",
|
|
171
|
+
"nodeBkg": "#4a5568",
|
|
172
|
+
"clusterBkg": "#2d3748",
|
|
173
|
+
"edgeLabelBackground": "#2d3748",
|
|
174
|
+
"nodeTextColor": "#ffffff",
|
|
175
|
+
"textColor": "#ffffff",
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
),
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def get_theme(theme_name: str) -> Theme:
|
|
183
|
+
"""Get a theme by name, fallback to minimal if not found."""
|
|
184
|
+
return THEMES.get(theme_name, THEMES["minimal"])
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def get_available_themes() -> list[str]:
|
|
188
|
+
"""Get list of available theme names."""
|
|
189
|
+
return list(THEMES.keys())
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Validation utilities for mvn-tree-visualizer."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from .exceptions import DependencyFileNotFoundError, OutputGenerationError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def find_dependency_files(directory: str, filename: str) -> list[str]:
|
|
10
|
+
"""Find all dependency files in the directory tree."""
|
|
11
|
+
found_files = []
|
|
12
|
+
for dirpath, _, filenames in os.walk(directory):
|
|
13
|
+
if filename in filenames:
|
|
14
|
+
found_files.append(os.path.join(dirpath, filename))
|
|
15
|
+
return found_files
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def print_maven_help() -> None:
|
|
19
|
+
"""Print helpful Maven commands for generating dependency files."""
|
|
20
|
+
print("\n💡 To generate a Maven dependency file, try one of these commands:")
|
|
21
|
+
print(" mvn dependency:tree -DoutputFile=maven_dependency_file")
|
|
22
|
+
print(" mvn dependency:tree > maven_dependency_file")
|
|
23
|
+
print(" mvn dependency:tree -DoutputFile=maven_dependency_file -DoutputType=text")
|
|
24
|
+
print("\n📍 Make sure you're in a directory with a pom.xml file.")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def validate_directory(directory: str) -> None:
|
|
28
|
+
"""Validate that the directory exists and is accessible."""
|
|
29
|
+
if not os.path.exists(directory):
|
|
30
|
+
raise DependencyFileNotFoundError(f"Directory '{directory}' does not exist.\nPlease check the path and try again.")
|
|
31
|
+
|
|
32
|
+
if not os.path.isdir(directory):
|
|
33
|
+
raise DependencyFileNotFoundError(f"'{directory}' is not a directory.\nPlease provide a valid directory path.")
|
|
34
|
+
|
|
35
|
+
if not os.access(directory, os.R_OK):
|
|
36
|
+
raise DependencyFileNotFoundError(f"Cannot read from directory '{directory}'.\nPlease check your permissions and try again.")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def validate_dependency_files(directory: str, filename: str) -> list[str]:
|
|
40
|
+
"""Validate that dependency files exist and are readable."""
|
|
41
|
+
validate_directory(directory)
|
|
42
|
+
|
|
43
|
+
dependency_files = find_dependency_files(directory, filename)
|
|
44
|
+
|
|
45
|
+
if not dependency_files:
|
|
46
|
+
abs_directory = os.path.abspath(directory)
|
|
47
|
+
raise DependencyFileNotFoundError(
|
|
48
|
+
f"No '{filename}' files found in '{abs_directory}' or its subdirectories.\n\n"
|
|
49
|
+
f"📂 Searched in: {abs_directory}\n"
|
|
50
|
+
f"🔍 Looking for: {filename}\n"
|
|
51
|
+
f"\n💡 To generate a Maven dependency file, run:"
|
|
52
|
+
f"\n mvn dependency:tree -DoutputFile={filename}"
|
|
53
|
+
f"\n\n📍 Make sure you're in a directory with a pom.xml file."
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Validate that files are readable
|
|
57
|
+
unreadable_files = []
|
|
58
|
+
for file_path in dependency_files:
|
|
59
|
+
if not os.access(file_path, os.R_OK):
|
|
60
|
+
unreadable_files.append(file_path)
|
|
61
|
+
|
|
62
|
+
if unreadable_files:
|
|
63
|
+
files_list = "\n".join(f" - {f}" for f in unreadable_files)
|
|
64
|
+
raise DependencyFileNotFoundError(
|
|
65
|
+
f"Found {len(dependency_files)} dependency file(s), but cannot read {len(unreadable_files)} of them:\n"
|
|
66
|
+
f"{files_list}\n\n"
|
|
67
|
+
f"Please check file permissions and try again."
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
return dependency_files
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def validate_output_directory(output_file: str) -> None:
|
|
74
|
+
"""Validate that the output directory exists and is writable."""
|
|
75
|
+
output_dir = Path(output_file).parent
|
|
76
|
+
|
|
77
|
+
if not output_dir.exists():
|
|
78
|
+
try:
|
|
79
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
80
|
+
except PermissionError:
|
|
81
|
+
raise OutputGenerationError(f"Cannot create output directory '{output_dir}'.\nPlease check your permissions and try again.")
|
|
82
|
+
except Exception as e:
|
|
83
|
+
raise OutputGenerationError(f"Failed to create output directory '{output_dir}': {e}")
|
|
84
|
+
|
|
85
|
+
if not os.access(output_dir, os.W_OK):
|
|
86
|
+
raise OutputGenerationError(f"Cannot write to output directory '{output_dir}'.\nPlease check your permissions and try again.")
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mvn-tree-visualizer
|
|
3
|
+
Version: 1.4.0
|
|
4
|
+
Summary: A simple command line tool to visualize the dependency tree of a Maven project in a graphical format.
|
|
5
|
+
Project-URL: source, https://github.com/dyka3773/mvn-tree-visualizer
|
|
6
|
+
Author-email: Iraklis Konsoulas <dyka3773@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: cli,command-line,dependency,graph,maven,mermaid,tool,tree,visualization
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
Requires-Python: >=3.13
|
|
17
|
+
Requires-Dist: jinja2>=3.1.6
|
|
18
|
+
Requires-Dist: watchdog>=6.0.0
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# Maven Dependency Tree Visualizer
|
|
22
|
+
|
|
23
|
+
[](https://badge.fury.io/py/mvn-tree-visualizer)
|
|
24
|
+

|
|
25
|
+

|
|
26
|
+
[](https://pepy.tech/project/mvn-tree-visualizer)
|
|
27
|
+
[](https://github.com/dyka3773/mvn-tree-visualizer/actions)
|
|
28
|
+
[](https://github.com/astral-sh/ruff)
|
|
29
|
+
|
|
30
|
+
A simple command-line tool to visualize the dependency tree of a Maven project in a graphical and interactive format.
|
|
31
|
+
|
|
32
|
+
This tool was born out of the frustration of not being able to easily visualize the dependency tree of a Maven project. The `mvn dependency:tree` command is great, but the output can be hard to read, especially for large projects. This tool aims to solve that problem by providing a simple way to generate an interactive diagram or a structured JSON output of the dependency tree.
|
|
33
|
+
|
|
34
|
+
## Table of Contents
|
|
35
|
+
- [Features](#features)
|
|
36
|
+
- [Installation](#installation)
|
|
37
|
+
- [How to Use](#how-to-use)
|
|
38
|
+
- [Examples](#examples)
|
|
39
|
+
- [Options](#options)
|
|
40
|
+
- [Performance](#performance)
|
|
41
|
+
- [Troubleshooting](#troubleshooting)
|
|
42
|
+
- [Contributing](#contributing)
|
|
43
|
+
- [License](#license)
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
Install the package from PyPI:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install mvn-tree-visualizer
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Features
|
|
54
|
+
|
|
55
|
+
- **🌐 Multiple Output Formats:**
|
|
56
|
+
- **HTML:** Generates an interactive HTML diagram of your dependency tree using Mermaid.js.
|
|
57
|
+
- **JSON:** Creates a structured JSON representation of the dependency tree, perfect for scripting or integration with other tools.
|
|
58
|
+
- **🎨 Theme System:** Choose from 2 built-in themes (minimal, dark) for clean and consistent diagram styling.
|
|
59
|
+
- **🔄 Watch Mode:** Automatically regenerates diagrams when Maven dependency files change using the `--watch` flag.
|
|
60
|
+
- **📋 Version Display:** Show or hide dependency versions in both HTML and JSON outputs using the `--show-versions` flag.
|
|
61
|
+
- **⚡ Easy to Use:** A simple command-line interface that gets the job done with minimal configuration.
|
|
62
|
+
- **📂 File Merging:** Automatically finds and merges multiple `maven_dependency_file` files from different subdirectories.
|
|
63
|
+
- **🎨 Customizable Output:** Specify the output file name and location.
|
|
64
|
+
- **💾 Enhanced Downloads:** Download diagrams as SVG or high-resolution PNG directly from the HTML page.
|
|
65
|
+
- **🖱️ Interactive Features:** Hover tooltips, click-to-highlight connections, pan/zoom controls, and keyboard shortcuts.
|
|
66
|
+
|
|
67
|
+
## How to Use
|
|
68
|
+
|
|
69
|
+
### Step 1: Generate the dependency file
|
|
70
|
+
|
|
71
|
+
Run the following command in your terminal at the root of your Maven project. This will generate a file named `maven_dependency_file` in each module's `target` directory.
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
mvn dependency:tree -DoutputFile=maven_dependency_file -DappendOutput=true
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
> **💡 Tip:** You can add other options like `-Dincludes="org.example"` to filter the dependencies.
|
|
78
|
+
|
|
79
|
+
### Step 2: Visualize the dependency tree
|
|
80
|
+
|
|
81
|
+
Use the `mvn-tree-visualizer` command to generate the diagram.
|
|
82
|
+
|
|
83
|
+
#### HTML Output (Interactive Diagram)
|
|
84
|
+
```bash
|
|
85
|
+
mvn_tree_visualizer --filename "maven_dependency_file" --output "diagram.html" --format html
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### JSON Output (Structured Data)
|
|
89
|
+
```bash
|
|
90
|
+
mvn_tree_visualizer --filename "maven_dependency_file" --output "dependencies.json" --format json
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### With Version Information
|
|
94
|
+
```bash
|
|
95
|
+
mvn_tree_visualizer --filename "maven_dependency_file" --output "diagram.html" --show-versions
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### With Custom Themes
|
|
99
|
+
```bash
|
|
100
|
+
# Dark theme for low-light environments
|
|
101
|
+
mvn_tree_visualizer --filename "maven_dependency_file" --output "diagram.html" --theme dark
|
|
102
|
+
|
|
103
|
+
# Default minimal theme (clean monospace design)
|
|
104
|
+
mvn_tree_visualizer --filename "maven_dependency_file" --output "diagram.html"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### JSON Output with Versions
|
|
108
|
+
```bash
|
|
109
|
+
mvn_tree_visualizer --filename "maven_dependency_file" --output "dependencies.json" --format json --show-versions
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### Watch Mode (Auto-regeneration)
|
|
113
|
+
```bash
|
|
114
|
+
mvn_tree_visualizer --filename "maven_dependency_file" --output "diagram.html" --watch
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
> **💡 Tip:** In watch mode, the tool will monitor for changes to your Maven dependency files and automatically regenerate the diagram. Perfect for development workflows! Press `Ctrl+C` to stop watching.
|
|
118
|
+
|
|
119
|
+
### Step 3: View the output
|
|
120
|
+
|
|
121
|
+
- **HTML:** Open the generated `diagram.html` file in your web browser to view the interactive dependency tree.
|
|
122
|
+
- **JSON:** Use the `dependencies.json` file in your scripts or other tools.
|
|
123
|
+
|
|
124
|
+
## Examples
|
|
125
|
+
|
|
126
|
+
Check out the [`examples/`](examples/) directory for sample Maven dependency files and their outputs:
|
|
127
|
+
|
|
128
|
+
- **Simple Project**: Basic Spring Boot application with common dependencies
|
|
129
|
+
- **Complex Project**: Realistic microservice with comprehensive dependencies
|
|
130
|
+
|
|
131
|
+
Each example includes:
|
|
132
|
+
- Sample Maven dependency tree file
|
|
133
|
+
- Generated HTML and JSON outputs
|
|
134
|
+
- Usage instructions
|
|
135
|
+
|
|
136
|
+
## Options
|
|
137
|
+
|
|
138
|
+
| Option | Description | Default |
|
|
139
|
+
|--------|-------------|---------|
|
|
140
|
+
| `--filename` | The name of the file containing the Maven dependency tree | `maven_dependency_file` |
|
|
141
|
+
| `--output` | The name of the output file | `diagram.html` |
|
|
142
|
+
| `--format` | The output format (`html` or `json`) | `html` |
|
|
143
|
+
| `--theme` | Theme for HTML diagrams (`minimal`, `dark`) | `minimal` |
|
|
144
|
+
| `--show-versions` | Show dependency versions in the diagram | `False` |
|
|
145
|
+
| `--watch` | Watch for file changes and auto-regenerate diagram | `False` |
|
|
146
|
+
| `--directory` | The directory to scan for the Maven dependency file(s) | current directory |
|
|
147
|
+
| `--keep-tree` | Keep the intermediate `dependency_tree.txt` file | `False` |
|
|
148
|
+
| `--help` | Show the help message and exit | - |
|
|
149
|
+
|
|
150
|
+
### Theme Options
|
|
151
|
+
|
|
152
|
+
- **`minimal`**: Clean monospace design with simple black borders (default)
|
|
153
|
+
- **`dark`**: Same minimal styling but with white text on black background
|
|
154
|
+
|
|
155
|
+
📖 **See the complete [Theme Documentation](docs/THEMES.md) for detailed information about themes and interactive features.**
|
|
156
|
+
|
|
157
|
+
## Performance
|
|
158
|
+
|
|
159
|
+
**For Large Projects:**
|
|
160
|
+
- Consider filtering dependencies at the Maven level using `-Dincludes` or `-Dexcludes` parameters
|
|
161
|
+
- The tool can handle projects with hundreds of dependencies efficiently
|
|
162
|
+
|
|
163
|
+
**Memory Usage:**
|
|
164
|
+
- Memory usage scales with the number of dependencies
|
|
165
|
+
- Typical projects (50-200 dependencies) use minimal memory
|
|
166
|
+
- Very large projects (1000+ dependencies) may require more memory
|
|
167
|
+
|
|
168
|
+
## Troubleshooting
|
|
169
|
+
|
|
170
|
+
### Common Issues
|
|
171
|
+
|
|
172
|
+
**"No dependency files found"**
|
|
173
|
+
- The tool now provides detailed guidance including:
|
|
174
|
+
- Exact directory searched and filename expected
|
|
175
|
+
- Maven commands to generate dependency files
|
|
176
|
+
- Instructions to ensure you're in a directory with pom.xml
|
|
177
|
+
|
|
178
|
+
**"Empty or invalid output"**
|
|
179
|
+
- Enhanced error messages now include:
|
|
180
|
+
- Specific error details (encoding, permissions, empty files)
|
|
181
|
+
- Validation of file content and format
|
|
182
|
+
- Suggestions for fixing common parsing issues
|
|
183
|
+
|
|
184
|
+
**"Browser doesn't display the diagram"**
|
|
185
|
+
- Ensure you're opening the HTML file in a modern browser
|
|
186
|
+
- Check browser console for JavaScript errors
|
|
187
|
+
- Try a different browser (Chrome, Firefox, Safari)
|
|
188
|
+
|
|
189
|
+
**"Permission denied errors"**
|
|
190
|
+
- Improved diagnostics for:
|
|
191
|
+
- Directory read/write permissions
|
|
192
|
+
- File access issues
|
|
193
|
+
- Output directory creation problems
|
|
194
|
+
|
|
195
|
+
### Getting Help
|
|
196
|
+
|
|
197
|
+
- Check the [examples](examples/) directory for working samples
|
|
198
|
+
- Review the [issues](https://github.com/dyka3773/mvn-tree-visualizer/issues) page
|
|
199
|
+
- Create a new issue with your Maven dependency file sample
|
|
200
|
+
|
|
201
|
+
## Contributing
|
|
202
|
+
|
|
203
|
+
Contributions are welcome! If you have any ideas, suggestions, or bug reports, please open an issue or submit a pull request.
|
|
204
|
+
|
|
205
|
+
Please read our [CONTRIBUTING.md](CONTRIBUTING.md) file for more details.
|
|
206
|
+
|
|
207
|
+
## License
|
|
208
|
+
|
|
209
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
mvn_tree_visualizer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
mvn_tree_visualizer/__main__.py,sha256=yIQFAdWjthKAFbSzzRuz5_YGlK0c6BnR2ypjNRDq180,82
|
|
3
|
+
mvn_tree_visualizer/cli.py,sha256=Gufk14zH74lqSTz2o2KPPEmNLvOHKHLyno-eSyXqahw,8504
|
|
4
|
+
mvn_tree_visualizer/diagram.py,sha256=UfvP_J4Im4JQLe3EWlY3TsP4tua3oYk5NiCGbZNQwoA,933
|
|
5
|
+
mvn_tree_visualizer/enhanced_template.py,sha256=I35fNkZrlA5jYdyjPW0jU4FH4FF2HEagtwcUX6fcmMc,7050
|
|
6
|
+
mvn_tree_visualizer/exceptions.py,sha256=R4nnJ0xrOpd84GfPD9rFSDk40etDLoph7iZpj1CCR0c,543
|
|
7
|
+
mvn_tree_visualizer/file_watcher.py,sha256=JtmV1KW08_Az-XqpKhcd342WpxV1vUW-Dge9lodjjJY,2284
|
|
8
|
+
mvn_tree_visualizer/get_dependencies_in_one_file.py,sha256=nXhEhU-dI7tXa3TpoW1pv2t86t1K0yppSw8FYDtmTlQ,1973
|
|
9
|
+
mvn_tree_visualizer/themes.py,sha256=91asg9VIqa7q2sUmgRD-Fw5wJ6kKsVWlPJ-bX9kGZhw,5469
|
|
10
|
+
mvn_tree_visualizer/validation.py,sha256=UQ194gHiVS8UnJpp90sCM-Vjn3aeXT6scdwOplAoaSE,3689
|
|
11
|
+
mvn_tree_visualizer/outputs/html_output.py,sha256=Y0IY-UF0UMTa5w8mVFoLidgcW6BUBTxASO0iRo26hH4,5531
|
|
12
|
+
mvn_tree_visualizer/outputs/json_output.py,sha256=cXntw9ndE_BcrmFnuV61cEwZaRMp9Ev0SxaK1SUedlw,2037
|
|
13
|
+
mvn_tree_visualizer-1.4.0.dist-info/METADATA,sha256=AIAeZ3goQMeRVtZDxJLIRnlw37nBL1kCMHHRnjk2XuM,8756
|
|
14
|
+
mvn_tree_visualizer-1.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
15
|
+
mvn_tree_visualizer-1.4.0.dist-info/entry_points.txt,sha256=Mu3QZhrlvbYuCxqmluVGi2efgKjkQY6T8Opf-vdb7hU,68
|
|
16
|
+
mvn_tree_visualizer-1.4.0.dist-info/licenses/LICENSE,sha256=4zi6unpe17RUDMBu7ebh14jdbyvyeT-UA3n8Zl7aW74,1075
|
|
17
|
+
mvn_tree_visualizer-1.4.0.dist-info/RECORD,,
|