Skip to content

Commit 1f41970

Browse files
rjwaltersclaude
andcommitted
feat: add Maven to Elide converter script
Add Python script to convert Maven projects to Elide pkl format. This converter: - Parses pom.xml to extract project info and dependencies - Resolves versions from dependency management sections - Maps standard Maven source directories - Generates elide.pkl in Elide's expected format Supports single-module Maven projects without custom plugins. Works best for simple library projects. Tested with google/gson and validates that: - Main source compilation succeeds (83 files) - Dependencies are properly resolved - Build artifacts are created in .dev/artifacts/ Known limitations: - Multi-module projects need to run converter in each module - Test dependencies from parent POM may not resolve - Custom Maven plugins are not supported Example usage: python3 scripts/maven-to-elide.py pom.xml elide build 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 8ec8275 commit 1f41970

File tree

1 file changed

+174
-0
lines changed

1 file changed

+174
-0
lines changed

scripts/maven-to-elide.py

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Maven to Elide Converter
4+
5+
Converts single-module Maven projects to Elide pkl format.
6+
Works for simple Maven projects without custom plugins.
7+
8+
Usage: python3 maven-to-elide.py [path-to-pom.xml]
9+
"""
10+
11+
import xml.etree.ElementTree as ET
12+
import sys
13+
import os
14+
from pathlib import Path
15+
16+
17+
def parse_maven_pom(pom_path):
18+
"""Parse Maven pom.xml and extract relevant information."""
19+
tree = ET.parse(pom_path)
20+
root = tree.getroot()
21+
22+
# Handle Maven namespace
23+
ns = {'mvn': 'http://maven.apache.org/POM/4.0.0'}
24+
if root.tag.startswith('{'):
25+
# Extract namespace from root tag
26+
ns['mvn'] = root.tag[1:root.tag.index('}')]
27+
28+
# Extract project info
29+
def find_text(path, default=''):
30+
elem = root.find(path, ns)
31+
return elem.text if elem is not None else default
32+
33+
project_info = {
34+
'groupId': find_text('.//mvn:groupId'),
35+
'artifactId': find_text('.//mvn:artifactId'),
36+
'version': find_text('.//mvn:version'),
37+
'name': find_text('.//mvn:name'),
38+
'description': find_text('.//mvn:description'),
39+
}
40+
41+
# Use artifactId as name if name is not specified
42+
if not project_info['name']:
43+
project_info['name'] = project_info['artifactId']
44+
45+
# Build dependency management version map
46+
version_map = {}
47+
dep_mgmt = root.findall('.//mvn:dependencyManagement/mvn:dependencies/mvn:dependency', ns)
48+
for dep in dep_mgmt:
49+
group = dep.find('mvn:groupId', ns)
50+
artifact = dep.find('mvn:artifactId', ns)
51+
version = dep.find('mvn:version', ns)
52+
if group is not None and artifact is not None and version is not None:
53+
key = f"{group.text}:{artifact.text}"
54+
version_map[key] = version.text
55+
56+
# Extract dependencies
57+
dependencies = {'compile': [], 'test': []}
58+
deps = root.findall('.//mvn:dependencies/mvn:dependency', ns)
59+
60+
for dep in deps:
61+
group = dep.find('mvn:groupId', ns)
62+
artifact = dep.find('mvn:artifactId', ns)
63+
version = dep.find('mvn:version', ns)
64+
scope = dep.find('mvn:scope', ns)
65+
66+
if group is not None and artifact is not None:
67+
coordinate = f"{group.text}:{artifact.text}"
68+
69+
# Determine version: use explicit version, or look up in dependency management
70+
dep_version = None
71+
if version is not None and version.text:
72+
dep_version = version.text
73+
elif coordinate in version_map:
74+
dep_version = version_map[coordinate]
75+
76+
# Only add dependency if we have a version
77+
if dep_version:
78+
coordinate += f":{dep_version}"
79+
scope_key = 'test' if scope is not None and scope.text == 'test' else 'compile'
80+
dependencies[scope_key].append(coordinate)
81+
else:
82+
print(f"Warning: Skipping {coordinate} (no version found)", file=sys.stderr)
83+
84+
return project_info, dependencies
85+
86+
87+
def generate_elide_pkl(project_info, dependencies, output_path):
88+
"""Generate elide.pkl file from Maven project information."""
89+
90+
pkl_content = f'''amends "elide:project.pkl"
91+
92+
name = "{project_info['artifactId']}"
93+
description = "{project_info['description'] or project_info['name']}"
94+
95+
'''
96+
97+
# Add dependencies section if there are any
98+
if dependencies['compile'] or dependencies['test']:
99+
pkl_content += 'dependencies {\n'
100+
pkl_content += ' maven {\n'
101+
102+
if dependencies['compile']:
103+
pkl_content += ' packages {\n'
104+
for dep in dependencies['compile']:
105+
pkl_content += f' "{dep}"\n'
106+
pkl_content += ' }\n'
107+
108+
if dependencies['test']:
109+
pkl_content += ' testPackages {\n'
110+
for dep in dependencies['test']:
111+
pkl_content += f' "{dep}"\n'
112+
pkl_content += ' }\n'
113+
114+
pkl_content += ' }\n'
115+
pkl_content += '}\n\n'
116+
117+
# Add source mappings
118+
pkl_content += '''sources {
119+
["main"] = "src/main/java/**/*.java"
120+
["test"] = "src/test/java/**/*.java"
121+
}
122+
'''
123+
124+
# Write to file
125+
with open(output_path, 'w') as f:
126+
f.write(pkl_content)
127+
128+
return pkl_content
129+
130+
131+
def main():
132+
"""Main entry point."""
133+
if len(sys.argv) > 1:
134+
pom_path = sys.argv[1]
135+
else:
136+
pom_path = 'pom.xml'
137+
138+
if not os.path.exists(pom_path):
139+
print(f"Error: {pom_path} not found", file=sys.stderr)
140+
sys.exit(1)
141+
142+
try:
143+
# Parse Maven POM
144+
print(f"Parsing {pom_path}...")
145+
project_info, dependencies = parse_maven_pom(pom_path)
146+
147+
# Determine output path (same directory as pom.xml)
148+
pom_dir = os.path.dirname(os.path.abspath(pom_path))
149+
output_path = os.path.join(pom_dir, 'elide.pkl')
150+
151+
# Generate elide.pkl
152+
print(f"Generating {output_path}...")
153+
content = generate_elide_pkl(project_info, dependencies, output_path)
154+
155+
print(f"\n✓ Successfully created {output_path}")
156+
print(f"\nProject: {project_info['name']}")
157+
print(f"Compile dependencies: {len(dependencies['compile'])}")
158+
print(f"Test dependencies: {len(dependencies['test'])}")
159+
160+
print("\nGenerated elide.pkl:")
161+
print("=" * 60)
162+
print(content)
163+
print("=" * 60)
164+
165+
except ET.ParseError as e:
166+
print(f"Error parsing pom.xml: {e}", file=sys.stderr)
167+
sys.exit(1)
168+
except Exception as e:
169+
print(f"Error: {e}", file=sys.stderr)
170+
sys.exit(1)
171+
172+
173+
if __name__ == '__main__':
174+
main()

0 commit comments

Comments
 (0)