Files
metaverseDubai/scripts/STANDARDS.md
2026-07-07 03:43:19 -07:00

420 lines
9.7 KiB
Markdown

# Script Standards - Dubai Metaverse
## Overview
This document defines standards and best practices for all scripts in the Dubai Metaverse project. All scripts should follow these guidelines for consistency, maintainability, and reliability.
## Script Template
### Bash Script Template
```bash
#!/bin/bash
#
# Script Name: script_name.sh
# Description: Brief description of what the script does
# Usage: ./script_name.sh [options] [arguments]
# Author: [Author Name]
# Date: 2024-11-21
# Version: 1.0
#
# Exit codes:
# 0: Success
# 1: General error
# 2: Invalid arguments
# 3: Missing dependencies
# 4: Permission denied
# 5: File/directory not found
set -euo pipefail # Exit on error, undefined vars, pipe failures
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
LOG_FILE="${LOG_FILE:-$PROJECT_ROOT/logs/script_name.log}"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Logging function
log() {
local level="${1:-INFO}"
shift
local message="$*"
local timestamp=$(date +'%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
}
# Error handling
error_exit() {
log "ERROR" "$*"
exit 1
}
# Warning function
warning() {
log "WARNING" "$*"
}
# Success function
success() {
log "SUCCESS" "$*"
}
# Validate prerequisites
validate_prerequisites() {
local missing_deps=()
# Check required commands
local required_commands=("git" "python3")
for cmd in "${required_commands[@]}"; do
if ! command -v "$cmd" &> /dev/null; then
missing_deps+=("$cmd")
fi
done
if [ ${#missing_deps[@]} -gt 0 ]; then
error_exit "Missing required commands: ${missing_deps[*]}"
fi
# Check required files
local required_files=("$PROJECT_ROOT/README.md")
for file in "${required_files[@]}"; do
if [ ! -f "$file" ]; then
error_exit "Required file not found: $file"
fi
done
# Check environment
if [ -z "${REQUIRED_ENV_VAR:-}" ]; then
warning "Environment variable REQUIRED_ENV_VAR not set"
fi
}
# Print usage information
usage() {
cat << EOF
Usage: $0 [OPTIONS] [ARGUMENTS]
Description:
Brief description of what the script does
Options:
-h, --help Show this help message
-v, --verbose Enable verbose output
-q, --quiet Suppress non-error output
-d, --dry-run Perform a dry run without making changes
Arguments:
arg1 Description of first argument
arg2 Description of second argument
Examples:
$0 --verbose arg1 arg2
$0 --dry-run
Exit codes:
0 Success
1 General error
2 Invalid arguments
3 Missing dependencies
EOF
}
# Parse command line arguments
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
usage
exit 0
;;
-v|--verbose)
VERBOSE=true
shift
;;
-q|--quiet)
QUIET=true
shift
;;
-d|--dry-run)
DRY_RUN=true
shift
;;
*)
error_exit "Unknown option: $1. Use --help for usage."
;;
esac
done
}
# Main function
main() {
log "INFO" "Starting script_name.sh"
# Parse arguments
parse_args "$@"
# Validate prerequisites
validate_prerequisites
# Create log directory if it doesn't exist
mkdir -p "$(dirname "$LOG_FILE")"
# Script logic here
log "INFO" "Performing main operations..."
# Example: Check if running as root (if needed)
# if [ "$EUID" -eq 0 ]; then
# error_exit "This script should not be run as root"
# fi
# Example: Check if file exists
# if [ ! -f "$file" ]; then
# error_exit "File not found: $file"
# fi
# Example: Execute command with error handling
# if ! command_to_run; then
# error_exit "Command failed: command_to_run"
# fi
success "Script completed successfully"
}
# Run main if script is executed directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi
```
### Python Script Template
```python
#!/usr/bin/env python3
"""
Script Name: script_name.py
Description: Brief description of what the script does
Usage: python3 script_name.py [options] [arguments]
Author: [Author Name]
Date: 2024-11-21
Version: 1.0
"""
import sys
import os
import argparse
import logging
from pathlib import Path
from typing import List, Optional
# Configuration
SCRIPT_DIR = Path(__file__).parent.resolve()
PROJECT_ROOT = SCRIPT_DIR.parent.resolve()
LOG_FILE = PROJECT_ROOT / "logs" / "script_name.log"
# Setup logging
logging.basicConfig(
level=logging.INFO,
format='[%(asctime)s] [%(levelname)s] %(message)s',
handlers=[
logging.FileHandler(LOG_FILE),
logging.StreamHandler(sys.stdout)
]
)
logger = logging.getLogger(__name__)
def validate_prerequisites() -> None:
"""Validate that all prerequisites are met."""
missing_deps = []
# Check required commands
required_commands = ["git", "python3"]
for cmd in required_commands:
if not shutil.which(cmd):
missing_deps.append(cmd)
if missing_deps:
logger.error(f"Missing required commands: {', '.join(missing_deps)}")
sys.exit(3)
# Check required files
required_files = [PROJECT_ROOT / "README.md"]
for file in required_files:
if not file.exists():
logger.error(f"Required file not found: {file}")
sys.exit(5)
def parse_args() -> argparse.Namespace:
"""Parse command line arguments."""
parser = argparse.ArgumentParser(
description="Brief description of what the script does",
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
"-v", "--verbose",
action="store_true",
help="Enable verbose output"
)
parser.add_argument(
"-q", "--quiet",
action="store_true",
help="Suppress non-error output"
)
parser.add_argument(
"-d", "--dry-run",
action="store_true",
help="Perform a dry run without making changes"
)
parser.add_argument(
"arg1",
help="Description of first argument"
)
return parser.parse_args()
def main() -> int:
"""Main function."""
logger.info("Starting script_name.py")
try:
# Parse arguments
args = parse_args()
# Validate prerequisites
validate_prerequisites()
# Create log directory if it doesn't exist
LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
# Script logic here
logger.info("Performing main operations...")
# Example: Check if file exists
# file_path = Path("example.txt")
# if not file_path.exists():
# logger.error(f"File not found: {file_path}")
# return 1
logger.info("Script completed successfully")
return 0
except KeyboardInterrupt:
logger.warning("Script interrupted by user")
return 130
except Exception as e:
logger.error(f"Unexpected error: {e}", exc_info=True)
return 1
if __name__ == "__main__":
sys.exit(main())
```
## Standards
### Error Handling
1. **Always use `set -euo pipefail`** in bash scripts
2. **Handle errors explicitly** - don't ignore failures
3. **Provide meaningful error messages**
4. **Use appropriate exit codes**
5. **Log all errors** to log file
### Logging
1. **Log all important operations**
2. **Use consistent log format**: `[timestamp] [level] message`
3. **Log levels**: INFO, WARNING, ERROR, SUCCESS
4. **Log to both file and console** (tee)
5. **Create log directory** if it doesn't exist
### Input Validation
1. **Validate all user input**
2. **Check prerequisites** before execution
3. **Verify file/directory existence**
4. **Check command availability**
5. **Validate environment variables**
### Documentation
1. **Include header with description**
2. **Document all functions**
3. **Provide usage information**
4. **Include examples**
5. **Document exit codes**
### Code Quality
1. **Use meaningful variable names**
2. **Add comments for complex logic**
3. **Keep functions focused and small**
4. **Avoid hardcoded paths** (use variables)
5. **Follow consistent formatting**
## Exit Codes
Standard exit codes for all scripts:
- `0`: Success
- `1`: General error
- `2`: Invalid arguments
- `3`: Missing dependencies
- `4`: Permission denied
- `5`: File/directory not found
- `130`: Interrupted by user (Ctrl+C)
## Testing
### Before Committing
1. **Test with valid inputs**
2. **Test with invalid inputs**
3. **Test error conditions**
4. **Test edge cases**
5. **Verify exit codes**
### Test Checklist
- [ ] Script runs without errors
- [ ] Error handling works correctly
- [ ] Logging functions properly
- [ ] Help/usage information displays
- [ ] Exit codes are correct
- [ ] No hardcoded paths
- [ ] Documentation is complete
## Best Practices
1. **Fail fast** - Check prerequisites early
2. **Be idempotent** - Scripts should be safe to run multiple times
3. **Provide feedback** - Inform user of progress
4. **Clean up** - Remove temporary files
5. **Be portable** - Avoid platform-specific code when possible
## Examples
See existing scripts for examples:
- `scripts/setup/setup_project.sh` - Setup script example
- `scripts/validation/validate_project.sh` - Validation script example
- `scripts/data/import_osm_data.py` - Python script example
---
**Last Updated**: 2024
**Version**: 1.0