Files
giglez/scripts/safe_install.sh
T
leetcrypt 9f73595b20 feat: RTL_433 protocol database import - iteration 1/5
- 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.
2026-02-14 18:55:55 -08:00

469 lines
12 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 "$@"