#!/usr/bin/env python3 import json import sys import argparse import os from typing import Set, List, Dict, Any, Optional # --- Constants (mirroring those used in tag structure) --- TAGS = 'tags' NAME = 'name' TAG_TYPE = 'tagType' FOLDER = 'Folder' UDT_INSTANCE = 'UdtInstance' def load_json_file(file_path: str) -> Optional[Dict[str, Any]]: """Loads JSON data from a file path. Returns the loaded dict or None on error.""" if not os.path.exists(file_path): print(f"Error: File not found: '{file_path}'", file=sys.stderr) return None try: with open(file_path, 'r') as f: data = json.load(f) # Basic validation that it's a dictionary (expected top level) if not isinstance(data, dict): print(f"Error: Expected JSON root to be an object/dictionary in '{file_path}'", file=sys.stderr) return None return data except json.JSONDecodeError: print(f"Error: Invalid JSON format in file: '{file_path}'", file=sys.stderr) return None except IOError as e: print(f"Error reading file '{file_path}': {e}", file=sys.stderr) return None except Exception as e: print(f"An unexpected error occurred while loading '{file_path}': {e}", file=sys.stderr) return None def _find_udt_instances_recursive(items: List[Dict[str, Any]], found_names: Set[str]): """Helper function to recursively find UDT instance names within a list of tags/folders.""" # Copy logic from check_tags.py if not isinstance(items, list): return # Stop recursion for this branch for item in items: if not isinstance(item, dict): continue # Skip malformed items item_tag_type = item.get(TAG_TYPE) item_name = item.get(NAME) if item_tag_type == UDT_INSTANCE and item_name: found_names.add(item_name) elif item_tag_type == FOLDER: # Recursively check the tags within this folder folder_tags = item.get(TAGS, []) _find_udt_instances_recursive(folder_tags, found_names) def extract_udt_names(file_path: str) -> Optional[Set[str]]: """ Loads a tags JSON file and extracts the names of all UDT instances. Returns a set of names, or None if the file cannot be processed. """ print(f"Extracting UDT names from: {file_path}") data = load_json_file(file_path) if data is None: return None # Expecting a top-level object like {"tags": [...list of MCM folders...]} if TAGS not in data or not isinstance(data.get(TAGS), list): print(f"Error: '{file_path}' does not contain a top-level '{TAGS}' key with a list value.", file=sys.stderr) return None udt_names = set() top_level_tags = data[TAGS] # Start the recursive search from the list of MCM folders/tags _find_udt_instances_recursive(top_level_tags, udt_names) print(f" Found {len(udt_names)} UDT instance names.") return udt_names def main(): parser = argparse.ArgumentParser( description="Compares the set of UDT Instance names found in two tags.json files.", formatter_class=argparse.ArgumentDefaultsHelpFormatter ) parser.add_argument("file1", help="Path to the first JSON tags file (e.g., baseline).") parser.add_argument("file2", help="Path to the second JSON tags file (e.g., new result).") args = parser.parse_args() print(f"Comparing UDT Instance names in:\n File 1: {args.file1}\n File 2: {args.file2}\n") # Extract UDT names from both files names1 = extract_udt_names(args.file1) if names1 is None: sys.exit(1) names2 = extract_udt_names(args.file2) if names2 is None: sys.exit(1) # Compare the sets of names print("\n--- Comparison Results ---") if names1 == names2: print(f"Success: Both files contain the exact same {len(names1)} UDT instance names.") sys.exit(0) else: print("Difference Found: The set of UDT instance names differs between the files.") missing_in_file2 = sorted(list(names1 - names2)) added_in_file2 = sorted(list(names2 - names1)) if missing_in_file2: print(f"\nNames in '{os.path.basename(args.file1)}' but NOT in '{os.path.basename(args.file2)}' ({len(missing_in_file2)}):") for name in missing_in_file2: print(f" - {name}") if added_in_file2: print(f"\nNames in '{os.path.basename(args.file2)}' but NOT in '{os.path.basename(args.file1)}' ({len(added_in_file2)}):") for name in added_in_file2: print(f" - {name}") sys.exit(1) # Exit with a non-zero code to indicate difference if __name__ == "__main__": main()