Created
October 11, 2025 10:39
-
-
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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