9.7 KiB
9.7 KiB
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
#!/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
#!/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
- Always use
set -euo pipefailin bash scripts - Handle errors explicitly - don't ignore failures
- Provide meaningful error messages
- Use appropriate exit codes
- Log all errors to log file
Logging
- Log all important operations
- Use consistent log format:
[timestamp] [level] message - Log levels: INFO, WARNING, ERROR, SUCCESS
- Log to both file and console (tee)
- Create log directory if it doesn't exist
Input Validation
- Validate all user input
- Check prerequisites before execution
- Verify file/directory existence
- Check command availability
- Validate environment variables
Documentation
- Include header with description
- Document all functions
- Provide usage information
- Include examples
- Document exit codes
Code Quality
- Use meaningful variable names
- Add comments for complex logic
- Keep functions focused and small
- Avoid hardcoded paths (use variables)
- Follow consistent formatting
Exit Codes
Standard exit codes for all scripts:
0: Success1: General error2: Invalid arguments3: Missing dependencies4: Permission denied5: File/directory not found130: Interrupted by user (Ctrl+C)
Testing
Before Committing
- Test with valid inputs
- Test with invalid inputs
- Test error conditions
- Test edge cases
- 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
- Fail fast - Check prerequisites early
- Be idempotent - Scripts should be safe to run multiple times
- Provide feedback - Inform user of progress
- Clean up - Remove temporary files
- Be portable - Avoid platform-specific code when possible
Examples
See existing scripts for examples:
scripts/setup/setup_project.sh- Setup script examplescripts/validation/validate_project.sh- Validation script examplescripts/data/import_osm_data.py- Python script example
Last Updated: 2024
Version: 1.0