Skip to content

Instantly share code, notes, and snippets.

@HSGamer
Created October 11, 2025 10:39
Show Gist options
  • Select an option

  • Save HSGamer/335fd3f40b599c18467ed0579d03b817 to your computer and use it in GitHub Desktop.

Select an option

Save HSGamer/335fd3f40b599c18467ed0579d03b817 to your computer and use it in GitHub Desktop.
AI-generated script to add <name> to pom.xml based on its <artifactId>
#!/usr/bin/env python3
"""
Script to add <name> element in POM.xml based on artifactId.
Replaces a prefix in the artifactId with a new value and formats it as a proper name.
Automatically finds all pom.xml files in current directory and subdirectories.
Preserves XML formatting and indentation.
Only affects the root artifactId, not those in parent, dependencies, etc.
Skips files that already have a <name> tag.
"""
import argparse
import sys
import re
from pathlib import Path
def parse_arguments():
"""Parse command line arguments."""
parser = argparse.ArgumentParser(
description="Add <name> element in POM.xml based on artifactId",
epilog="Example: script.py uni-hologram UniHologram\n"
' If artifactId is "uni-hologram-picker", name becomes "UniHologram Picker"\n'
" The script will auto-detect all pom.xml files in current and subfolders\n"
" Files that already have a <name> tag will be skipped",
)
parser.add_argument(
"old_prefix",
type=str,
help='The prefix to replace in the artifactId (e.g., "uni-hologram")',
)
parser.add_argument(
"new_prefix", type=str, help='The new prefix value (e.g., "UniHologram")'
)
parser.add_argument(
"--dir",
type=str,
default=".",
help="Directory to search for pom.xml files (default: current directory)",
)
return parser.parse_args()
def capitalize_words(text):
"""Capitalize each word separated by hyphens, converting to space-separated."""
words = text.split("-")
return " ".join(word.capitalize() for word in words if word)
def find_pom_files(directory):
"""Recursively find all pom.xml files in directory and subdirectories."""
search_path = Path(directory)
if not search_path.exists():
raise FileNotFoundError(f"Directory not found: {directory}")
pom_files = list(search_path.rglob("pom.xml"))
return pom_files
def has_root_name_tag(content):
"""Check if POM already has a root-level <name> tag."""
lines = content.split("\n")
in_project = False
nested_tags = [
"parent",
"dependencies",
"dependencyManagement",
"build",
"plugins",
"profiles",
"modules",
"repositories",
"pluginRepositories",
"distributionManagement",
]
in_nested = False
nested_depth = 0
for line in lines:
# Check if we're entering project tag
if re.search(r"<(?:\w+:)?project[\s>]", line):
in_project = True
continue
if not in_project:
continue
# Track nested sections we want to skip
for tag in nested_tags:
if re.search(rf"<(?:\w+:)?{tag}[\s>]", line):
in_nested = True
nested_depth += 1
if re.search(rf"</(?:\w+:)?{tag}>", line):
nested_depth -= 1
if nested_depth <= 0:
in_nested = False
nested_depth = 0
# If we're not in a nested section, look for name tag
if not in_nested:
if re.search(r"<(?:\w+:)?name>", line):
return True
return False
def extract_root_artifact_id(content):
"""Extract only the root artifactId from POM content (not in parent, dependencies, etc)."""
lines = content.split("\n")
in_project = False
nested_tags = [
"parent",
"dependencies",
"dependencyManagement",
"build",
"plugins",
"profiles",
"modules",
"repositories",
"pluginRepositories",
"distributionManagement",
]
in_nested = False
nested_depth = 0
for i, line in enumerate(lines):
# Check if we're entering project tag
if re.search(r"<(?:\w+:)?project[\s>]", line):
in_project = True
continue
if not in_project:
continue
# Track nested sections we want to skip
for tag in nested_tags:
if re.search(rf"<(?:\w+:)?{tag}[\s>]", line):
in_nested = True
nested_depth += 1
if re.search(rf"</(?:\w+:)?{tag}>", line):
nested_depth -= 1
if nested_depth <= 0:
in_nested = False
nested_depth = 0
# If we're not in a nested section, look for artifactId
if not in_nested:
artifact_match = re.search(
r"<(?:\w+:)?artifactId>\s*([^<]+?)\s*</(?:\w+:)?artifactId>", line
)
if artifact_match:
return artifact_match.group(1).strip(), i
return None, -1
def get_indentation(line):
"""Get the indentation from a line."""
match = re.match(r"^(\s*)", line)
if match:
return match.group(1)
return " " # Default to 4 spaces
def update_single_pom(pom_path, old_prefix, new_prefix):
"""Add the <name> element in a single POM.xml file."""
# Read the file content
with open(pom_path, "r", encoding="utf-8") as f:
content = f.read()
# Check if file already has a root-level name tag
if has_root_name_tag(content):
return {"skipped": True, "reason": "already_has_name"}
lines = content.split("\n")
# Extract root artifactId and its line number
artifact_id, artifact_line_num = extract_root_artifact_id(content)
if not artifact_id:
raise ValueError("No root <artifactId> element found in POM")
# Check if artifactId starts with old prefix
if not artifact_id.startswith(old_prefix):
return None # Skip this file
# Remove old prefix and any following hyphen
remaining = artifact_id[len(old_prefix) :]
if remaining.startswith("-"):
remaining = remaining[1:]
# Build new name: new_prefix + remaining parts (capitalized)
if remaining:
remaining_capitalized = capitalize_words(remaining)
new_name = f"{new_prefix} {remaining_capitalized}"
else:
new_name = new_prefix
# Get indentation from artifactId line
indent = get_indentation(lines[artifact_line_num])
# Insert new name tag after artifactId
new_name_tag = f"{indent}<name>{new_name}</name>"
lines.insert(artifact_line_num + 1, new_name_tag)
# Write back to file
with open(pom_path, "w", encoding="utf-8") as f:
f.write("\n".join(lines))
return {"artifact_id": artifact_id, "new_name": new_name}
def main():
"""Main function."""
try:
args = parse_arguments()
# Find all pom.xml files
pom_files = find_pom_files(args.dir)
if not pom_files:
print(f"No pom.xml files found in {args.dir} or its subdirectories")
return 1
print(f"Found {len(pom_files)} pom.xml file(s)\n")
# Process each pom.xml file
success_count = 0
error_count = 0
skipped_count = 0
for pom_path in pom_files:
try:
result = update_single_pom(pom_path, args.old_prefix, args.new_prefix)
if result is None:
# File was skipped because artifactId doesn't match
with open(pom_path, "r", encoding="utf-8") as f:
content = f.read()
artifact_id, _ = extract_root_artifact_id(content)
artifact_id = artifact_id or "unknown"
print(f"⊘ Skipped: {pom_path}")
print(
f' (artifactId "{artifact_id}" does not start with "{args.old_prefix}")'
)
skipped_count += 1
elif isinstance(result, dict) and result.get("skipped"):
# File was skipped because it already has a name tag
print(f"⊘ Skipped: {pom_path}")
print(f" (already has a <name> tag)")
skipped_count += 1
else:
print(f"✓ Successfully updated: {pom_path}")
print(f" artifactId: {result['artifact_id']}")
print(f" name: {result['new_name']}")
success_count += 1
print()
except Exception as e:
print(f"✗ Error processing {pom_path}: {e}")
error_count += 1
print()
# Summary
print("=" * 60)
print(f"Summary:")
print(f" ✓ Successfully updated: {success_count}")
print(f" ⊘ Skipped: {skipped_count}")
print(f" ✗ Errors: {error_count}")
print(f" Total files found: {len(pom_files)}")
return 0 if error_count == 0 else 1
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
return 1
if __name__ == "__main__":
sys.exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment