9f73595b20
- Expanded protocol database from 18 → 299 signatures (16.6x increase) - Imported 281 protocols from RTL_433 open-source database (286 total devices) - Created automated import script: scripts/import_rtl433_protocols.py - Generated rtl433_protocols_imported.py with timing/frequency/modulation data - Updated protocol_database.py to include RTL433_PROTOCOLS - All 26 tests passing Breakdown by category: - Weather: 116 protocols - Sensors: 36 protocols - TPMS: 25 protocols - Security: 23 protocols - Home Automation: 18 protocols - Other: 50+ protocols Frequency coverage: - 433.92 MHz: 248 protocols - 315.00 MHz: 32 protocols - 915.00 MHz: 1 protocol This provides comprehensive coverage of Sub-GHz IoT devices for accurate identification from raw RF captures.
469 lines
12 KiB
Bash
Executable File
469 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
||
###############################################################################
|
||
# Safe Package Installation Script
|
||
#
|
||
# Provides safe python -m pip installation with:
|
||
# - Virtual environment detection/creation
|
||
# - Dependency resolution
|
||
# - Version compatibility checking
|
||
# - Rollback on failure
|
||
# - Security scanning
|
||
#
|
||
# Usage:
|
||
# ./scripts/safe_install.sh [package_name] [version]
|
||
# ./scripts/safe_install.sh -r requirements.txt
|
||
# ./scripts/safe_install.sh --all # Install all project dependencies
|
||
###############################################################################
|
||
|
||
set -e # Exit on error
|
||
|
||
# Colors for output
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# Script directory
|
||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||
|
||
# Configuration
|
||
VENV_DIR="$PROJECT_ROOT/venv"
|
||
REQUIREMENTS_FILE="$PROJECT_ROOT/requirements.txt"
|
||
BACKUP_DIR="$PROJECT_ROOT/.pip_backups"
|
||
|
||
###############################################################################
|
||
# Helper Functions
|
||
###############################################################################
|
||
|
||
print_header() {
|
||
echo -e "${BLUE}========================================${NC}"
|
||
echo -e "${BLUE}$1${NC}"
|
||
echo -e "${BLUE}========================================${NC}"
|
||
}
|
||
|
||
print_success() {
|
||
echo -e "${GREEN}✓ $1${NC}"
|
||
}
|
||
|
||
print_error() {
|
||
echo -e "${RED}✗ $1${NC}"
|
||
}
|
||
|
||
print_warning() {
|
||
echo -e "${YELLOW}⚠ $1${NC}"
|
||
}
|
||
|
||
print_info() {
|
||
echo -e "${BLUE}ℹ $1${NC}"
|
||
}
|
||
|
||
###############################################################################
|
||
# Virtual Environment Management
|
||
###############################################################################
|
||
|
||
check_venv() {
|
||
if [[ "$VIRTUAL_ENV" != "" ]]; then
|
||
print_success "Virtual environment active: $VIRTUAL_ENV"
|
||
return 0
|
||
else
|
||
print_warning "No virtual environment active"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
create_venv() {
|
||
print_header "Creating Virtual Environment"
|
||
|
||
if [ -d "$VENV_DIR" ]; then
|
||
print_info "Virtual environment already exists at: $VENV_DIR"
|
||
read -p "Recreate it? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||
print_info "Removing old virtual environment..."
|
||
rm -rf "$VENV_DIR"
|
||
else
|
||
return 0
|
||
fi
|
||
fi
|
||
|
||
print_info "Creating new virtual environment..."
|
||
python3 -m venv "$VENV_DIR"
|
||
|
||
if [ $? -eq 0 ]; then
|
||
print_success "Virtual environment created at: $VENV_DIR"
|
||
print_info "Activate it with: source $VENV_DIR/bin/activate"
|
||
return 0
|
||
else
|
||
print_error "Failed to create virtual environment"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
activate_venv() {
|
||
if [ ! -d "$VENV_DIR" ]; then
|
||
print_warning "Virtual environment not found at: $VENV_DIR"
|
||
read -p "Create it now? (Y/n): " -n 1 -r
|
||
echo
|
||
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
|
||
create_venv || return 1
|
||
else
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
# Check if already activated
|
||
if check_venv; then
|
||
return 0
|
||
fi
|
||
|
||
print_info "Activating virtual environment..."
|
||
source "$VENV_DIR/bin/activate"
|
||
|
||
if check_venv; then
|
||
print_success "Virtual environment activated"
|
||
return 0
|
||
else
|
||
print_error "Failed to activate virtual environment"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
###############################################################################
|
||
# Pip Safety Checks
|
||
###############################################################################
|
||
|
||
check_pip() {
|
||
print_header "Checking pip"
|
||
|
||
# Use python -m pip to bypass any aliases
|
||
if ! python -m pip --version &> /dev/null; then
|
||
print_error "pip not found"
|
||
print_info "Installing pip..."
|
||
|
||
# Try to install pip
|
||
if command -v python3 &> /dev/null; then
|
||
python3 -m ensurepip --upgrade
|
||
else
|
||
print_error "Python 3 not found. Please install Python 3 first."
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
# Check pip version
|
||
pip_version=$(python -m pip --version | awk '{print $2}')
|
||
print_success "pip version: $pip_version"
|
||
|
||
# Upgrade pip if needed
|
||
print_info "Upgrading pip to latest version..."
|
||
python -m pip install --upgrade pip
|
||
|
||
return 0
|
||
}
|
||
|
||
create_backup() {
|
||
print_header "Creating Backup"
|
||
|
||
mkdir -p "$BACKUP_DIR"
|
||
|
||
timestamp=$(date +%Y%m%d_%H%M%S)
|
||
backup_file="$BACKUP_DIR/installed_packages_$timestamp.txt"
|
||
|
||
print_info "Saving current package list to: $backup_file"
|
||
python -m pip freeze > "$backup_file"
|
||
|
||
print_success "Backup created"
|
||
echo "$backup_file"
|
||
}
|
||
|
||
check_conflicts() {
|
||
local package=$1
|
||
|
||
print_header "Checking for Conflicts"
|
||
|
||
# Use pip-conflict-checker if available
|
||
if command -v pip-conflict-checker &> /dev/null; then
|
||
pip-conflict-checker "$package"
|
||
else
|
||
# Basic check using pip
|
||
print_info "Running dependency check..."
|
||
python -m pip install --dry-run "$package" 2>&1 | grep -i "conflict\|incompatible" || true
|
||
fi
|
||
}
|
||
|
||
###############################################################################
|
||
# Installation Functions
|
||
###############################################################################
|
||
|
||
safe_install_package() {
|
||
local package=$1
|
||
local version=$2
|
||
|
||
# Construct package spec
|
||
if [ -n "$version" ]; then
|
||
package_spec="$package==$version"
|
||
else
|
||
package_spec="$package"
|
||
fi
|
||
|
||
print_header "Installing: $package_spec"
|
||
|
||
# Create backup
|
||
backup_file=$(create_backup)
|
||
|
||
# Check for conflicts
|
||
check_conflicts "$package_spec"
|
||
|
||
# Ask for confirmation
|
||
read -p "Proceed with installation? (Y/n): " -n 1 -r
|
||
echo
|
||
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
||
print_warning "Installation cancelled"
|
||
return 1
|
||
fi
|
||
|
||
# Install
|
||
print_info "Installing $package_spec..."
|
||
|
||
if python -m pip install "$package_spec"; then
|
||
print_success "Successfully installed $package_spec"
|
||
|
||
# Verify installation
|
||
print_info "Verifying installation..."
|
||
python -m pip show "$package" &> /dev/null
|
||
|
||
if [ $? -eq 0 ]; then
|
||
print_success "Package verified"
|
||
return 0
|
||
else
|
||
print_error "Package installation verification failed"
|
||
rollback "$backup_file"
|
||
return 1
|
||
fi
|
||
else
|
||
print_error "Installation failed"
|
||
rollback "$backup_file"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
install_from_requirements() {
|
||
local req_file=$1
|
||
|
||
if [ ! -f "$req_file" ]; then
|
||
print_error "Requirements file not found: $req_file"
|
||
return 1
|
||
fi
|
||
|
||
print_header "Installing from: $req_file"
|
||
|
||
# Create backup
|
||
backup_file=$(create_backup)
|
||
|
||
# Count packages
|
||
package_count=$(grep -c -v '^#' "$req_file" | grep -c -v '^$' || echo 0)
|
||
print_info "Found $package_count packages to install"
|
||
|
||
# Show packages
|
||
print_info "Packages to install:"
|
||
grep -v '^#' "$req_file" | grep -v '^$' | sed 's/^/ - /'
|
||
|
||
# Ask for confirmation
|
||
read -p "Proceed with installation? (Y/n): " -n 1 -r
|
||
echo
|
||
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
||
print_warning "Installation cancelled"
|
||
return 1
|
||
fi
|
||
|
||
# Install
|
||
print_info "Installing packages..."
|
||
|
||
if python -m pip install -r "$req_file"; then
|
||
print_success "All packages installed successfully"
|
||
return 0
|
||
else
|
||
print_error "Installation failed"
|
||
rollback "$backup_file"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
rollback() {
|
||
local backup_file=$1
|
||
|
||
print_header "Rolling Back"
|
||
|
||
if [ ! -f "$backup_file" ]; then
|
||
print_error "Backup file not found: $backup_file"
|
||
return 1
|
||
fi
|
||
|
||
print_warning "Rolling back to previous state..."
|
||
|
||
# Uninstall all current packages
|
||
python -m pip freeze | xargs python -m pip uninstall -y
|
||
|
||
# Reinstall from backup
|
||
python -m pip install -r "$backup_file"
|
||
|
||
if [ $? -eq 0 ]; then
|
||
print_success "Rollback completed"
|
||
return 0
|
||
else
|
||
print_error "Rollback failed"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
###############################################################################
|
||
# Dependency Resolution
|
||
###############################################################################
|
||
|
||
resolve_dependencies() {
|
||
print_header "Resolving Dependencies"
|
||
|
||
# Use pip-tools if available
|
||
if command -v pip-compile &> /dev/null; then
|
||
print_info "Using pip-tools to resolve dependencies..."
|
||
pip-compile --upgrade --generate-hashes requirements.in
|
||
else
|
||
print_warning "pip-tools not installed. Install with: python -m pip install pip-tools"
|
||
print_info "Basic dependency check:"
|
||
python -m pip check
|
||
fi
|
||
}
|
||
|
||
###############################################################################
|
||
# Security Scanning
|
||
###############################################################################
|
||
|
||
security_scan() {
|
||
print_header "Security Scanning"
|
||
|
||
# Use safety if available
|
||
if command -v safety &> /dev/null; then
|
||
print_info "Running safety check..."
|
||
safety check --json | jq '.'
|
||
else
|
||
print_warning "safety not installed. Install with: python -m pip install safety"
|
||
print_info "Skipping security scan"
|
||
fi
|
||
}
|
||
|
||
###############################################################################
|
||
# Main Logic
|
||
###############################################################################
|
||
|
||
show_help() {
|
||
cat << EOF
|
||
Safe Package Installation Script
|
||
|
||
Usage:
|
||
$0 [OPTIONS] [PACKAGE] [VERSION]
|
||
|
||
Options:
|
||
--help Show this help message
|
||
--create-venv Create virtual environment only
|
||
--activate-venv Activate virtual environment (source this script)
|
||
--check Check pip and environment
|
||
--all Install all project dependencies
|
||
-r FILE Install from requirements file
|
||
--resolve Resolve dependencies (requires pip-tools)
|
||
--scan Run security scan (requires safety)
|
||
--backup Create backup of current packages
|
||
--rollback FILE Rollback to backup file
|
||
|
||
Examples:
|
||
# Create and activate virtual environment
|
||
$0 --create-venv
|
||
source venv/bin/activate
|
||
|
||
# Install a single package
|
||
$0 requests
|
||
|
||
# Install specific version
|
||
$0 requests 2.28.0
|
||
|
||
# Install from requirements.txt
|
||
$0 -r requirements.txt
|
||
$0 --all # Uses default requirements.txt
|
||
|
||
# Check environment
|
||
$0 --check
|
||
|
||
# Security scan
|
||
$0 --scan
|
||
|
||
EOF
|
||
}
|
||
|
||
main() {
|
||
# Parse arguments
|
||
case "$1" in
|
||
--help|-h)
|
||
show_help
|
||
exit 0
|
||
;;
|
||
--create-venv)
|
||
create_venv
|
||
exit $?
|
||
;;
|
||
--check)
|
||
activate_venv || exit 1
|
||
check_pip
|
||
print_info "Python version: $(python --version)"
|
||
print_info "Installed packages:"
|
||
python -m pip list
|
||
exit 0
|
||
;;
|
||
--all)
|
||
activate_venv || exit 1
|
||
check_pip || exit 1
|
||
install_from_requirements "$REQUIREMENTS_FILE"
|
||
exit $?
|
||
;;
|
||
-r)
|
||
activate_venv || exit 1
|
||
check_pip || exit 1
|
||
install_from_requirements "$2"
|
||
exit $?
|
||
;;
|
||
--resolve)
|
||
activate_venv || exit 1
|
||
resolve_dependencies
|
||
exit $?
|
||
;;
|
||
--scan)
|
||
activate_venv || exit 1
|
||
security_scan
|
||
exit $?
|
||
;;
|
||
--backup)
|
||
activate_venv || exit 1
|
||
create_backup
|
||
exit $?
|
||
;;
|
||
--rollback)
|
||
activate_venv || exit 1
|
||
rollback "$2"
|
||
exit $?
|
||
;;
|
||
"")
|
||
show_help
|
||
exit 1
|
||
;;
|
||
*)
|
||
# Install package
|
||
activate_venv || exit 1
|
||
check_pip || exit 1
|
||
safe_install_package "$1" "$2"
|
||
exit $?
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# Run main
|
||
main "$@"
|