140 lines
3.9 KiB
Python
140 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Metadata Validation Utility
|
|
|
|
This script validates metadata files in the gallery source directories,
|
|
checking for proper YAML/JSON syntax and common field validation.
|
|
"""
|
|
|
|
import sys
|
|
import json
|
|
import yaml
|
|
from pathlib import Path
|
|
from typing import Dict, Any, List
|
|
|
|
|
|
def validate_metadata_file(file_path: Path) -> tuple[bool, List[str]]:
|
|
"""
|
|
Validate a single metadata file.
|
|
|
|
Args:
|
|
file_path: Path to the metadata file
|
|
|
|
Returns:
|
|
Tuple of (is_valid, error_messages)
|
|
"""
|
|
errors = []
|
|
|
|
if not file_path.exists():
|
|
errors.append(f"File does not exist: {file_path}")
|
|
return False, errors
|
|
|
|
try:
|
|
with file_path.open('r', encoding='utf-8') as f:
|
|
suffix_lower = file_path.suffix.lower()
|
|
if suffix_lower in ['.yaml', '.yml']:
|
|
data = yaml.safe_load(f)
|
|
elif suffix_lower == '.json':
|
|
data = json.load(f)
|
|
else:
|
|
errors.append(f"Unsupported file format: {file_path}")
|
|
return False, errors
|
|
|
|
if data is None:
|
|
errors.append(f"Empty metadata file: {file_path}")
|
|
return False, errors
|
|
|
|
# Basic validation
|
|
if not isinstance(data, dict):
|
|
errors.append(f"Metadata must be a dictionary: {file_path}")
|
|
return False, errors
|
|
|
|
# Check for common issues
|
|
if 'title' in data and not isinstance(data['title'], str):
|
|
errors.append(f"Title must be a string: {file_path}")
|
|
|
|
if 'tags' in data and not isinstance(data['tags'], list):
|
|
errors.append(f"Tags must be a list: {file_path}")
|
|
|
|
if 'author' in data and not isinstance(data['author'], dict):
|
|
errors.append(f"Author must be a dictionary: {file_path}")
|
|
|
|
except (yaml.YAMLError, json.JSONDecodeError) as e:
|
|
errors.append(f"Parse error in {file_path}: {e}")
|
|
return False, errors
|
|
except Exception as e:
|
|
errors.append(f"Unexpected error reading {file_path}: {e}")
|
|
return False, errors
|
|
|
|
return len(errors) == 0, errors
|
|
|
|
|
|
def find_metadata_files(root_dir: Path) -> List[Path]:
|
|
"""
|
|
Find all metadata files in a directory tree.
|
|
|
|
Args:
|
|
root_dir: Root directory to search
|
|
|
|
Returns:
|
|
List of metadata file paths
|
|
"""
|
|
metadata_files = []
|
|
|
|
for pattern in ['**/*.yaml', '**/*.yml', '**/*.json']:
|
|
for file_path in root_dir.glob(pattern):
|
|
if file_path.name.startswith('meta.') or file_path.stem != file_path.name:
|
|
metadata_files.append(file_path)
|
|
|
|
return metadata_files
|
|
|
|
|
|
def main():
|
|
"""Main validation function."""
|
|
if len(sys.argv) != 2:
|
|
print("Usage: python validate_metadata.py <directory>")
|
|
sys.exit(1)
|
|
|
|
root_dir = Path(sys.argv[1])
|
|
|
|
if not root_dir.exists():
|
|
print(f"Error: Directory does not exist: {root_dir}")
|
|
sys.exit(1)
|
|
|
|
if not root_dir.is_dir():
|
|
print(f"Error: Not a directory: {root_dir}")
|
|
sys.exit(1)
|
|
|
|
print(f"Validating metadata files in: {root_dir}")
|
|
print("-" * 50)
|
|
|
|
metadata_files = find_metadata_files(root_dir)
|
|
|
|
if not metadata_files:
|
|
print("No metadata files found.")
|
|
return
|
|
|
|
total_files = len(metadata_files)
|
|
valid_files = 0
|
|
|
|
for file_path in metadata_files:
|
|
is_valid, errors = validate_metadata_file(file_path)
|
|
|
|
if is_valid:
|
|
print(f"✓ {file_path.relative_to(root_dir)}")
|
|
valid_files += 1
|
|
else:
|
|
print(f"✗ {file_path.relative_to(root_dir)}")
|
|
for error in errors:
|
|
print(f" - {error}")
|
|
|
|
print("-" * 50)
|
|
print(f"Summary: {valid_files}/{total_files} files valid")
|
|
|
|
if valid_files != total_files:
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|