Enhance setup and testing scripts for improved package management and logging

- Updated setup.sh to check for Nala installation and provide alternative installation methods based on Ubuntu version.
- Added error handling for package installation, allowing fallback to apt if Nala fails.
- Introduced startup.sh to perform container startup checks, including system info and permissions for logs directory.
- Created test-setup.sh to validate bootstrap and setup scripts, including detailed logging of package availability and installation results.
- Implemented checks for missing packages and provided recommendations for manual installation.
- Enhanced logging for better traceability of actions and errors during setup and testing processes.
This commit is contained in:
Peter Wood
2025-05-12 13:59:15 -04:00
parent 78d64d5ee5
commit 9a941d1752
11 changed files with 1901 additions and 16 deletions

161
.github/copilot-instructions.md vendored Normal file
View File

@@ -0,0 +1,161 @@
# GitHub Copilot Instructions for Shell Repository
This document provides context and guidance for GitHub Copilot when working with this shell script and dotfiles repository.
## Repository Overview
This repository contains:
1. **Shell scripts** for system administration tasks
2. **Dotfiles** for system configuration
3. **Setup scripts** for automated environment configuration
4. **Docker-based testing framework** for validating setup across environments
## Repository Structure
- **Root directory**: Contains various utility shell scripts
- **docs/**: Documentation for individual scripts and components
- **dotfiles/**: System configuration files that get symlinked to the user's home directory
- **powershell/**: PowerShell scripts for Windows environments
- **setup/**: Setup scripts and package lists for automated environment configuration
- **.github/**: GitHub-related configuration files
## Key Files Overview
### Shell Scripts
- **bootstrap.sh**: Entry point script for automated setup
- **test-setup.sh**: Testing script for validating environment setup
- **run-docker-tests.sh**: Runner for Docker-based testing
- **update.sh**: System update scripts
- **plex.sh**: Plex Media Server management
### Configuration Files
- **setup/packages.list**: List of packages to install during setup
- **dotfiles/my-aliases.zsh**: Custom ZSH aliases
- **dotfiles/tailscale-acl.json**: Tailscale ACL configuration
### Documentation
- **README.md**: Main repository documentation
- **docs/testing.md**: Detailed documentation for the testing framework
- **dotfiles/README.md**: Documentation for dotfiles setup and usage
## Style Guidelines
When suggesting code or modifications:
1. **Shell Scripts**:
- Use `#!/bin/bash` for most scripts
- Include proper error handling with `set -e` where appropriate
- For test scripts, avoid `set -e` to allow testing all components
- Add descriptive comments for script sections
- Use colors for terminal output when appropriate (GREEN, RED, YELLOW, etc.)
- Use capitalized variable names (e.g., `USER_HOME=/home/user`)
2. **Docker Files**:
- Follow Docker best practices for layer optimization
- Use specific tags for base images rather than 'latest'
- Include proper LABEL directives for metadata
3. **Documentation**:
- Use proper Markdown formatting
- Include code examples using appropriate syntax highlighting
- Document script parameters and usage
## Testing Framework
When modifying the testing framework:
1. Make sure to test across both Ubuntu and Debian environments
2. Ensure tests continue even when individual components fail
3. Track and summarize all errors at the end of tests
4. Maintain proper error reporting and logging
### Docker Testing Enhancements
The Docker-based testing framework includes these key features:
1. **Continuous Testing**: Tests continue running even when individual package installations fail
- Achieved by removing `set -e` from test scripts
- Uses a counter to track errors rather than exiting immediately
2. **Package Testing**:
- Dynamically reads packages from `setup/packages.list`
- Tests each package individually
- Maintains an array of missing packages for final reporting
3. **Summary Reporting**:
- Provides a comprehensive summary of all failed tests
- Suggests commands to fix missing packages
- Saves detailed logs to a timestamped file in /tmp
4. **Cross-Platform Testing**:
- Tests both Ubuntu and Debian environments
- Handles platform-specific package names (e.g., `bat` vs `batcat`)
## Key Concepts
- **Shell Environment Setup**: Focuses on ZSH with Oh My Zsh and plugins
- **Docker Testing**: Validates environment setup in isolated containers
- **Dotfiles Management**: Uses symbolic links to user's home directory
- **Package Installation**: Uses apt/nala on Debian-based systems
## Main Use Cases
1. **Setting up a new development environment**: Using bootstrap.sh
2. **Managing media services**: Using plex.sh and related scripts
3. **System maintenance**: Using update.sh and backup scripts
4. **Testing configuration changes**: Using the Docker testing framework
## Code Organization Principles
1. **Modularity**: Keep scripts focused on one task
2. **Documentation**: Document all scripts and configurations
3. **Testing**: Ensure all changes are testable
4. **Cross-platform**: Support both Ubuntu and Debian where possible
## Security Practices
When suggesting security-related code:
1. **Permissions**:
- Avoid running scripts as root unless necessary
- Use `sudo` for specific commands rather than entire scripts
- Set appropriate file permissions (e.g., `chmod 600` for sensitive files)
2. **Secret Management**:
- Never include hardcoded credentials in scripts
- Use environment variables or external secret management
- Add sensitive files to .gitignore
3. **Input Validation**:
- Validate and sanitize all user inputs
- Use quotes around variables to prevent word splitting and globbing
- Implement proper error handling for invalid inputs
4. **Network Security**:
- Verify URLs before downloading (`curl`/`wget`)
- Use HTTPS instead of HTTP when possible
- Validate checksums for downloaded packages
## Contribution Guidelines
For contributors and Copilot suggestions:
1. **Script Modifications**:
- Test all changes using the Docker testing framework
- Update documentation when adding new functionality
- Maintain backward compatibility when possible
2. **New Scripts**:
- Follow the established naming conventions
- Include a header with description, usage, and author
- Add appropriate documentation to the docs/ directory
- Add any new dependencies to setup/packages.list
3. **Review Process**:
- Run tests before submitting changes
- Document what was changed and why
- Consider both Ubuntu and Debian compatibility

80
Dockerfile Normal file
View File

@@ -0,0 +1,80 @@
# Dockerfile to test bootstrap.sh and setup.sh scripts in different environments
# This allows testing the setup process in isolated containers
# Ubuntu test environment
FROM ubuntu:24.04 as ubuntu-test
LABEL description="Ubuntu test environment for shell setup scripts"
# Install minimal dependencies needed to run the test
ENV TZ=America/New_York
ENV DEBIAN_FRONTEND=noninteractive
ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \
&& apt-get update && apt-get install -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confnew" -y curl git sudo wget
# Pre-install cowsay and lolcat packages for testing
RUN apt-get update && apt-get install -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confnew" -y cowsay lolcat
# Create logs directory with proper permissions
RUN mkdir -p /logs && chmod -R 777 /logs
# Create a test user with sudo permissions
RUN useradd -ms /bin/bash testuser && \
echo "testuser ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/testuser
USER testuser
WORKDIR /home/testuser
# Create directory structure for shell setup
RUN mkdir -p /home/testuser/shell/setup
# Copy test script, startup script, and packages.list
COPY --chown=testuser:testuser test-setup.sh /home/testuser/
COPY --chown=testuser:testuser startup.sh /home/testuser/
COPY --chown=testuser:testuser setup/packages.list /home/testuser/shell/setup/
# Make scripts executable
RUN chmod +x /home/testuser/test-setup.sh
RUN chmod +x /home/testuser/startup.sh
CMD ["/bin/bash", "-c", "./startup.sh"]
# Debian test environment
FROM debian:12 as debian-test
LABEL description="Debian test environment for shell setup scripts"
# Install minimal dependencies needed to run the test
ENV TZ=America/New_York
ENV DEBIAN_FRONTEND=noninteractive
ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \
&& apt-get update && apt-get install -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confnew" -y curl git sudo wget
# Pre-install cowsay and lolcat packages for testing
RUN apt-get update && apt-get install -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confnew" -y cowsay lolcat
# Create logs directory with proper permissions
RUN mkdir -p /logs && chmod -R 777 /logs
# Create a test user with sudo permissions
RUN useradd -ms /bin/bash testuser && \
echo "testuser ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/testuser
USER testuser
WORKDIR /home/testuser
# Create directory structure for shell setup
RUN mkdir -p /home/testuser/shell/setup
# Copy test script, startup script, and packages.list
COPY --chown=testuser:testuser test-setup.sh /home/testuser/
COPY --chown=testuser:testuser startup.sh /home/testuser/
COPY --chown=testuser:testuser setup/packages.list /home/testuser/shell/setup/
# Make scripts executable
RUN chmod +x /home/testuser/test-setup.sh
RUN chmod +x /home/testuser/startup.sh
CMD ["/bin/bash", "-c", "./startup.sh"]

View File

@@ -14,6 +14,7 @@ This repository contains various shell scripts for managing media-related tasks
- [Plex Backup Script Documentation](./docs/plex-backup.md): Detailed documentation for the `backup-plex.sh` script. - [Plex Backup Script Documentation](./docs/plex-backup.md): Detailed documentation for the `backup-plex.sh` script.
- [Plex Management Script Documentation](./docs/plex-management.md): Detailed documentation for the `plex.sh` script. - [Plex Management Script Documentation](./docs/plex-management.md): Detailed documentation for the `plex.sh` script.
- [Folder Metrics Script Documentation](./docs/folder-metrics.md): Detailed documentation for the `folder-metrics.sh` script. - [Folder Metrics Script Documentation](./docs/folder-metrics.md): Detailed documentation for the `folder-metrics.sh` script.
- [Testing Framework Documentation](./docs/testing.md): Detailed documentation for the Docker-based testing system.
## Dotfiles ## Dotfiles
@@ -25,6 +26,60 @@ curl -fsSL https://raw.githubusercontent.com/acedanger/shell/main/bootstrap.sh |
For more information about the dotfiles, see [Dotfiles README](./dotfiles/README.md). For more information about the dotfiles, see [Dotfiles README](./dotfiles/README.md).
## Testing
This repository includes Docker-based testing to validate the setup process across different environments:
- **test-setup.sh**: Script that validates the bootstrap and setup process
- **run-docker-tests.sh**: Runner script that executes tests in Docker containers
- **Dockerfile**: Defines test environments (Ubuntu, Debian)
### Running Tests
Test your setup in isolated Docker containers with:
```bash
# Test in Ubuntu container
./run-docker-tests.sh ubuntu
# Test in Debian container
./run-docker-tests.sh debian
# Run full bootstrap test in Ubuntu
./run-docker-tests.sh full-ubuntu
# Run full bootstrap test in Debian
./run-docker-tests.sh full-debian
# Test in both Ubuntu and Debian
./run-docker-tests.sh all
```
#### When to Use Each Testing Option
- **Use `./run-docker-tests.sh ubuntu` or `./run-docker-tests.sh debian`** when you want to:
- Quickly validate if packages in packages.list are available and installed
- Test if your test-setup.sh script is working correctly
- Check for issues with specific components without performing a full setup
- **Use `./run-docker-tests.sh full-ubuntu` or `./run-docker-tests.sh full-debian`** when you want to:
- Test the complete bootstrap installation process end-to-end
- Validate that all installation steps work correctly on a fresh system
- Simulate what users will experience when running the bootstrap script
- **Use `./run-docker-tests.sh all`** when you want to:
- Ensure your test-setup.sh works across both Ubuntu and Debian
- Run comprehensive checks before committing changes
The test environment checks:
- Package availability and installation
- Core components (git, curl, wget, etc.)
- Additional packages from `setup/packages.list`
- Oh My Zsh and plugin installation
- Dotfile symlinks
Tests will continue even when some packages fail to install, reporting all issues in a comprehensive summary.
# plex.sh # plex.sh
This script is used to manage the Plex Media Server service on a systemd-based Linux distribution. It provides the following functionalities: This script is used to manage the Plex Media Server service on a systemd-based Linux distribution. It provides the following functionalities:

225
debian-patches.sh Executable file
View File

@@ -0,0 +1,225 @@
#!/bin/bash
# This script applies Debian-specific patches to the setup scripts
# It should be run before bootstrap.sh on Debian systems
set -e # Exit on error
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Check if running on Debian
if [ -f /etc/os-release ]; then
. /etc/os-release
if [[ "$ID" == "debian" ]]; then
echo -e "${BLUE}Running on Debian $VERSION_ID ($PRETTY_NAME)${NC}"
else
echo -e "${YELLOW}This script is intended for Debian systems but detected $PRETTY_NAME${NC}"
echo -e "${YELLOW}Continue anyway? [y/N]${NC}"
read -r response
if [[ ! "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
echo -e "${RED}Exiting...${NC}"
exit 1
fi
fi
fi
# Create a packages mapping file
PATCH_DIR="$HOME/.shell-debian-patches"
mkdir -p "$PATCH_DIR"
echo -e "${YELLOW}Creating Debian package name mappings...${NC}"
cat > "$PATCH_DIR/debian-packages.map" << 'EOF'
# Debian package name mappings
# format: ubuntu-name|debian-name
# bat is called batcat on Debian
bat|batcat
# Keep original names for packages that are the same
git|git
python3|python3
wget|wget
curl|curl
cowsay|cowsay
lolcat|lolcat
fzf|fzf
zsh|zsh
# Different package names for Nala source
software-properties-common|software-properties-common
EOF
# Create a patching script that will be called by setup.sh
echo -e "${YELLOW}Creating Debian patching script...${NC}"
cat > "$PATCH_DIR/apply-debian-patches.sh" << 'EOF'
#!/bin/bash
# Script to apply Debian-specific patches to the setup process
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
PATCH_DIR="$HOME/.shell-debian-patches"
# Check if running on Debian
if [ -f /etc/os-release ]; then
. /etc/os-release
if [[ "$ID" != "debian" ]]; then
echo -e "${YELLOW}Not running on Debian, skipping patches${NC}"
exit 0
fi
fi
echo -e "${BLUE}Applying Debian-specific patches...${NC}"
# Function to map package names from Ubuntu to Debian
map_package() {
local ubuntu_pkg="$1"
local debian_pkg
# Look for the package in the mapping file
if [ -f "$PATCH_DIR/debian-packages.map" ]; then
debian_pkg=$(grep -v "^#" "$PATCH_DIR/debian-packages.map" | grep "^$ubuntu_pkg|" | cut -d'|' -f2)
fi
# If not found or empty, use the original name
if [ -z "$debian_pkg" ]; then
debian_pkg="$ubuntu_pkg"
fi
echo "$debian_pkg"
}
# Patch the packages.list file if it exists
if [ -f "$HOME/shell/setup/packages.list" ]; then
echo -e "${YELLOW}Patching packages.list for Debian compatibility...${NC}"
# Create a temporary patched file
temp_file=$(mktemp)
# Process each line
while IFS= read -r line; do
# Skip comments and empty lines
if [[ "$line" =~ ^//.*$ ]] || [[ -z "$line" ]]; then
echo "$line" >> "$temp_file"
continue
fi
# Map the package name
debian_pkg=$(map_package "$line")
echo "$debian_pkg" >> "$temp_file"
done < "$HOME/shell/setup/packages.list"
# Backup original and replace with patched version
cp "$HOME/shell/setup/packages.list" "$HOME/shell/setup/packages.list.orig"
mv "$temp_file" "$HOME/shell/setup/packages.list"
echo -e "${GREEN}Patched packages.list for Debian compatibility${NC}"
fi
# Other Debian-specific patches can be added here...
# Add contrib and non-free repositories if they're not already enabled
echo -e "${YELLOW}Checking Debian repositories...${NC}"
if ! grep -q "contrib" /etc/apt/sources.list; then
echo -e "${YELLOW}Adding contrib and non-free repositories...${NC}"
# Create a backup of the original sources.list
sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup
# Add contrib and non-free to each deb line
sudo sed -i 's/main$/main contrib non-free non-free-firmware/g' /etc/apt/sources.list
echo -e "${GREEN}Added contrib and non-free repositories${NC}"
fi
echo -e "${GREEN}Debian patches applied successfully${NC}"
EOF
chmod +x "$PATCH_DIR/apply-debian-patches.sh"
# Create a wrapper script for bootstrap.sh
echo -e "${YELLOW}Creating Debian bootstrap wrapper...${NC}"
cat > "$HOME/debian-bootstrap.sh" << 'EOF'
#!/bin/bash
# Debian wrapper for bootstrap.sh
set -e # Exit on error
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
PATCH_DIR="$HOME/.shell-debian-patches"
# Apply Debian patches first
if [ -x "$PATCH_DIR/apply-debian-patches.sh" ]; then
echo -e "${BLUE}Applying Debian patches before bootstrap...${NC}"
"$PATCH_DIR/apply-debian-patches.sh"
fi
# Download and run the bootstrap script
echo -e "${BLUE}Running bootstrap script...${NC}"
curl -s https://raw.githubusercontent.com/acedanger/shell/main/bootstrap.sh | bash
# Apply patches again after bootstrap (in case packages.list was just downloaded)
if [ -x "$PATCH_DIR/apply-debian-patches.sh" ]; then
echo -e "${BLUE}Applying Debian patches after bootstrap...${NC}"
"$PATCH_DIR/apply-debian-patches.sh"
fi
echo -e "${GREEN}Debian bootstrap completed!${NC}"
EOF
chmod +x "$HOME/debian-bootstrap.sh"
# Add a hook to setup.sh to call the Debian patch script
echo -e "${YELLOW}Creating setup.sh hook for Debian...${NC}"
cat > "$PATCH_DIR/setup-hook.sh" << 'EOF'
#!/bin/bash
# Hook to modify setup.sh to call Debian patches
if [ -f /etc/os-release ]; then
. /etc/os-release
if [[ "$ID" == "debian" ]]; then
# Modify setup.sh to call Debian patches
if [ -f "$HOME/shell/setup/setup.sh" ]; then
# Check if the patch hasn't been applied yet
if ! grep -q "apply-debian-patches" "$HOME/shell/setup/setup.sh"; then
# Add call to Debian patch script right after the shebang
sed -i '2i\
# Apply Debian patches if available\
if [ -x "$HOME/.shell-debian-patches/apply-debian-patches.sh" ]; then\
echo -e "${YELLOW}Applying Debian-specific patches...${NC}"\
"$HOME/.shell-debian-patches/apply-debian-patches.sh"\
fi' "$HOME/shell/setup/setup.sh"
fi
fi
fi
fi
EOF
chmod +x "$PATCH_DIR/setup-hook.sh"
echo -e "${GREEN}Debian compatibility patch has been set up!${NC}"
echo -e "${YELLOW}To bootstrap your Debian system, run:${NC}"
echo -e " ${BLUE}bash ~/debian-bootstrap.sh${NC}"
echo ""
echo -e "${YELLOW}This has created:${NC}"
echo -e "1. Package name mappings for Debian"
echo -e "2. A patch script for Debian-specific adjustments"
echo -e "3. A Debian-specific bootstrap wrapper"

83
docs/testing-fixes.md Normal file
View File

@@ -0,0 +1,83 @@
# Docker-based Testing Framework Improvements
This document outlines the improvements made to the Docker-based testing framework for validating shell scripts and dotfiles across different environments.
## Issues Fixed
### 1. `local` Keyword Usage Outside Function
Fixed a syntax error where the `local` keyword was used outside of a function context:
```bash
# Before (incorrect):
for pkg in $packages; do
local actual_pkg=$(get_package_name "$pkg")
# ...
done
# After (correct):
for pkg in $packages; do
actual_pkg=$(get_package_name "$pkg")
# ...
done
```
### 2. Log Directory Handling
Enhanced log directory handling to ensure proper permissions and fallback mechanisms:
- Added better error handling for log directory creation and permissions
- Added validation to verify write permissions before proceeding
- Implemented fallback to /tmp if host volume mounting fails
- Added debugging information when log operations fail
### 3. Package Verification
Improved package detection, especially for packages like `cowsay` and `lolcat` that are typically installed in `/usr/games/`:
- Enhanced `test_package()` function to check in common alternate locations
- Added specific handling for packages that may be installed with different paths
- Added detailed debugging output for problematic packages
### 4. Docker Container Configuration
Improved the Docker container configuration for more reliable testing:
- Added proper volume mounting with explicit read/write permissions
- Added timestamp consistency between host and container
- Added container type labels to log files for better tracking
- Enhanced error detection for volume mounting issues
## Implementation Details
### 1. Enhanced Logging System
- Timestamps are now synchronized between host and container
- Log file names include container type (ubuntu/debian) for clarity
- Added validation to confirm logs are properly saved to host
### 2. Container Environment Setup
- Improved `startup.sh` with better diagnostics before running tests
- Added permissions verification for mounted volumes
- Added write tests to confirm permissions are correctly set
### 3. Test Framework Improvements
- Improved error handling for better diagnostics
- Enhanced reporting for package detection issues
- Better isolation between test iterations
## Running Tests
To run tests with the improved framework:
```bash
# Test in Ubuntu container
./run-docker-tests.sh ubuntu
# Test in Debian container
./run-docker-tests.sh debian
```
The logs will be saved in the `./logs` directory with filenames that include the timestamp and container type.

132
docs/testing.md Normal file
View File

@@ -0,0 +1,132 @@
# Shell Setup Testing Framework
This document describes the testing framework for validating the shell setup across different environments.
## Overview
The testing framework consists of three main components:
1. **test-setup.sh**: The main test script that validates the bootstrap and setup process
2. **run-docker-tests.sh**: A runner script that executes tests in Docker containers
3. **Dockerfile**: Definition of test environments (Ubuntu and Debian)
## Testing Features
- **Cross-platform testing**: Test on both Ubuntu and Debian environments
- **Isolated environments**: All tests run in fresh Docker containers
- **Comprehensive validation**: Tests both the bootstrap and setup processes
- **Continuous testing**: Tests all packages regardless of individual failures
- **Detailed reporting**: Summary of all successful and failed components
## How Testing Works
### The Docker Test Environment
The `Dockerfile` defines two testing environments:
- **ubuntu-test**: Based on Ubuntu 24.04
- **debian-test**: Based on Debian 12
Each environment:
1. Installs minimal dependencies (curl, git, sudo, wget)
2. Creates a test user with sudo permissions
3. Sets up the directory structure for testing
4. Copies the test script and packages list
5. Runs the test script when the container starts
### The Test Script (test-setup.sh)
The test script validates:
1. **Script Syntax**: Checks if bootstrap.sh and setup.sh have valid syntax
2. **Core Tools**: Verifies git, curl, wget are available
3. **Package Availability**: Checks if packages in packages.list are available in repositories
4. **Package Installation**: Tests if each package is installed
5. **Shell Setup**: Validates Oh My Zsh and plugin installation
6. **Dotfiles**: Checks if dotfiles are properly symlinked
The script tracks all missing or misconfigured components and provides a summary at the end, including suggestions for fixing issues.
### Test Runner (run-docker-tests.sh)
The runner script provides several test modes:
- **ubuntu**: Run test on Ubuntu container
- **debian**: Run test on Debian container
- **full-ubuntu**: Run full bootstrap test on Ubuntu
- **full-debian**: Run full bootstrap test on Debian
- **all**: Run tests on both Ubuntu and Debian
## Testing Without Stopping on Failures
A key feature is the ability to test all packages in `packages.list` without stopping at the first failure. This ensures:
1. Complete coverage of all requirements
2. Comprehensive reporting of all issues
3. Better debugging experience when multiple components need attention
## Running Tests
```bash
# Test on Ubuntu
./run-docker-tests.sh ubuntu
# Test on Debian
./run-docker-tests.sh debian
# Full bootstrap test on Ubuntu
./run-docker-tests.sh full-ubuntu
# Full bootstrap test on Debian
./run-docker-tests.sh full-debian
# Test on both Ubuntu and Debian
./run-docker-tests.sh all
```
### Choosing the Right Test Option
The testing framework offers different options for different testing needs:
| If you want to... | Use this command | Why |
|-------------------|------------------|-----|
| Quickly check if specific packages are available | `./run-docker-tests.sh ubuntu` or `debian` | Fast validation of packages without full installation |
| Test changes to the test-setup.sh script | `./run-docker-tests.sh ubuntu` or `debian` | Executes only the test script in a clean environment |
| Validate a fix for a package installation issue | `./run-docker-tests.sh ubuntu` or `debian` | Tests package availability and installation |
| Test the complete user experience | `./run-docker-tests.sh full-ubuntu` or `full-debian` | Executes the actual bootstrap script like a real user would |
| Ensure bootstrap.sh works correctly | `./run-docker-tests.sh full-ubuntu` or `full-debian` | Tests the entire installation process from scratch |
| Verify cross-platform compatibility | `./run-docker-tests.sh all` | Tests on both supported platforms |
| Before pushing changes to main | `./run-docker-tests.sh all` and both full tests | Complete validation across environments |
### Key Differences
**Standard Tests** (`ubuntu`, `debian`):
- Use the Docker targets defined in the main Dockerfile
- Run the `test-setup.sh` script to check components
- Faster execution, focused on component validation
- Don't perform the actual bootstrap installation
**Full Tests** (`full-ubuntu`, `full-debian`):
- Create a temporary Dockerfile for comprehensive testing
- Execute the bootstrap script directly from GitHub
- Complete end-to-end testing of the actual installation process
- Simulate the real user experience
## Test Output
The test provides:
1. A color-coded console output showing success/failure of each component
2. A list of missing packages at the end
3. A detailed log file with all test results (saved to /tmp)
4. Suggestions for fixing detected issues
## Adding New Tests
To add new package tests:
1. Add the package name to `setup/packages.list`
2. The test framework will automatically validate its availability and installation
For more complex components:
1. Add a new test function in `test-setup.sh`
2. Call the function in the main testing sequence
3. Increment the error counter if the test fails

View File

@@ -93,6 +93,41 @@ curl -fsSL https://raw.githubusercontent.com/acedanger/shell/main/bootstrap.sh |
- Configure zoxide for better navigation - Configure zoxide for better navigation
- Install and configure Git - Install and configure Git
## Testing
The repository includes a comprehensive testing framework to validate the shell setup process across different environments.
### Docker-Based Testing
Tests are run in isolated Docker containers to ensure consistent, repeatable validation:
- **Ubuntu 24.04 environment**: Tests compatibility with the latest Ubuntu LTS
- **Debian 12 environment**: Tests compatibility with Debian Stable
### Test Coverage
The tests validate:
- Package availability in repositories
- Successful installation of all packages in `packages.list`
- Oh My Zsh installation
- Zsh plugin installation
- Dotfile symlinking
- NVM and Node.js setup
### Running Tests
```bash
# Test your setup on Ubuntu
./run-docker-tests.sh ubuntu
# Test your setup on Debian
./run-docker-tests.sh debian
# Run a full bootstrap test (including installation)
./run-docker-tests.sh full-ubuntu
```
For more details on testing, see [Testing Documentation](../docs/testing.md).
## Manual Steps ## Manual Steps
If you need to manually set up aliases: If you need to manually set up aliases:

237
run-docker-tests.sh Executable file
View File

@@ -0,0 +1,237 @@
#!/bin/bash
# Script to run setup tests in Docker containers
# This allows testing the setup process in isolated environments
set -e # Exit on error
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Check if Docker is installed and working
if ! command -v docker &> /dev/null; then
echo -e "${RED}Error: Docker is not installed. Please install Docker to run tests.${NC}"
exit 1
fi
# Create logs directory at the top level to ensure it exists
LOGS_DIR="$(pwd)/logs"
if [ ! -d "$LOGS_DIR" ]; then
echo -e "${YELLOW}Creating logs directory at: $LOGS_DIR${NC}"
mkdir -p "$LOGS_DIR" || {
echo -e "${RED}Failed to create logs directory! Check permissions.${NC}"
exit 1
}
else
echo -e "${GREEN}Logs directory already exists at: $LOGS_DIR${NC}"
fi
# Ensure the logs directory is writable
if [ ! -w "$LOGS_DIR" ]; then
echo -e "${YELLOW}Setting permissions on logs directory...${NC}"
chmod -R 777 "$LOGS_DIR" || {
echo -e "${RED}Failed to set write permissions on logs directory!${NC}"
exit 1
}
fi
# Create a test file to verify we can write to it
if touch "$LOGS_DIR/test_file" && rm "$LOGS_DIR/test_file"; then
echo -e "${GREEN}Log directory is writable and ready for use${NC}"
else
echo -e "${RED}Cannot write to logs directory even after setting permissions!${NC}"
exit 1
fi
# Check if Docker is running
if ! docker info &>/dev/null; then
echo -e "${YELLOW}Warning: Docker appears to be installed but not running or not properly configured.${NC}"
echo -e "${YELLOW}If using WSL2, ensure Docker Desktop is running with WSL integration enabled.${NC}"
echo -e "${YELLOW}Would you like to run the local test instead? [Y/n]${NC}"
read -r response
if [[ "$response" =~ ^([nN][oO]|[nN])$ ]]; then
echo -e "${RED}Exiting...${NC}"
exit 1
else
echo -e "${BLUE}Running local test instead...${NC}"
./test-setup.sh
exit $?
fi
fi
# Build and run Ubuntu test container
run_ubuntu_test() {
echo -e "\n${BLUE}=== Running test in Ubuntu container ===${NC}"
# Create the logs directory if it doesn't exist
local log_dir="$(pwd)/logs"
mkdir -p "$log_dir" || true
# Use sudo for chmod only if necessary
if [ ! -w "$log_dir" ]; then
echo -e "${YELLOW}Attempting to fix permissions with sudo...${NC}"
sudo chmod -R 777 "$log_dir" 2>/dev/null || {
echo -e "${YELLOW}Could not change permissions with sudo, continuing anyway...${NC}"
}
fi
echo -e "${YELLOW}Logs will be saved to: $log_dir${NC}"
echo -e "${YELLOW}Building Ubuntu test container...${NC}"
docker build --target ubuntu-test -t shell-test:ubuntu .
echo -e "${GREEN}Running tests with package installation...${NC}"
# Create a timestamp for this test run
TEST_TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
echo -e "${YELLOW}Test run timestamp: $TEST_TIMESTAMP${NC}"
# Run container with proper volume mount and add environment variable for timestamp
docker run --rm -it \
-e TEST_TIMESTAMP="$TEST_TIMESTAMP" \
-e CONTAINER_TYPE="ubuntu" \
-v "$log_dir:/logs:z" \
shell-test:ubuntu
# Check if logs were created
if ls "$log_dir"/setup-test-*"$TEST_TIMESTAMP"* &>/dev/null 2>&1; then
echo -e "${GREEN}Test logs successfully created in host directory${NC}"
else
echo -e "${YELLOW}Warning: No log files found matching timestamp $TEST_TIMESTAMP${NC}"
echo -e "${YELLOW}This may indicate issues with volume mounting or permissions${NC}"
echo -e "${YELLOW}Contents of log directory:${NC}"
ls -la "$log_dir" || echo "Cannot list directory contents"
fi
echo -e "${BLUE}Test completed. Check logs in $log_dir directory${NC}"
}
# Build and run Debian test container
run_debian_test() {
echo -e "\n${BLUE}=== Running test in Debian container ===${NC}"
# Create the logs directory if it doesn't exist
local log_dir="$(pwd)/logs"
mkdir -p "$log_dir" || true
# Use sudo for chmod only if necessary
if [ ! -w "$log_dir" ]; then
echo -e "${YELLOW}Attempting to fix permissions with sudo...${NC}"
sudo chmod -R 777 "$log_dir" 2>/dev/null || {
echo -e "${YELLOW}Could not change permissions with sudo, continuing anyway...${NC}"
}
fi
echo -e "${YELLOW}Logs will be saved to: $log_dir${NC}"
echo -e "${YELLOW}Building Debian test container...${NC}"
docker build --target debian-test -t shell-test:debian .
echo -e "${GREEN}Running tests with package installation...${NC}"
# Create a timestamp for this test run
TEST_TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
echo -e "${YELLOW}Test run timestamp: $TEST_TIMESTAMP${NC}"
# Run container with proper volume mount and add environment variable for timestamp
docker run --rm -it \
-e TEST_TIMESTAMP="$TEST_TIMESTAMP" \
-e CONTAINER_TYPE="debian" \
-v "$log_dir:/logs:z" \
shell-test:debian
# Check if logs were created
if ls "$log_dir"/setup-test-*"$TEST_TIMESTAMP"* &>/dev/null 2>&1; then
echo -e "${GREEN}Test logs successfully created in host directory${NC}"
else
echo -e "${YELLOW}Warning: No log files found matching timestamp $TEST_TIMESTAMP${NC}"
echo -e "${YELLOW}This may indicate issues with volume mounting or permissions${NC}"
echo -e "${YELLOW}Contents of log directory:${NC}"
ls -la "$log_dir" || echo "Cannot list directory contents"
fi
echo -e "${BLUE}Test completed. Check logs in $log_dir directory${NC}"
}
# Full test with bootstrap script
run_full_test() {
local distro=$1
local tag_name=$(echo $distro | sed 's/:/-/g') # Replace colon with hyphen for tag
echo -e "\n${BLUE}=== Running full bootstrap test in $distro container ===${NC}"
# Create a Dockerfile for full test
cat > Dockerfile.fulltest <<EOF
FROM $distro
LABEL description="$distro full test environment for bootstrap.sh script"
# Install minimal dependencies needed to run the bootstrap
ENV TZ=America/New_York
ENV DEBIAN_FRONTEND=noninteractive
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \
&& apt-get update && apt-get install -y curl git sudo wget
# Create a test user with sudo permissions
RUN useradd -ms /bin/bash testuser && \\
echo "testuser ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/testuser
# Create directory structure for setup files
RUN mkdir -p /home/testuser/shell
# Copy test script for post-bootstrap validation
COPY --chown=testuser:testuser test-setup.sh /home/testuser/
# Copy entire repo structure to ensure we have all needed files
COPY --chown=testuser:testuser . /home/testuser/shell/
USER testuser
WORKDIR /home/testuser
# Make the script executable
RUN chmod +x /home/testuser/test-setup.sh
# Run tests before and after bootstrap to verify package installation
CMD ["/bin/bash", "-c", "echo -e '\\n\\nRunning pre-bootstrap tests...' && ./test-setup.sh && echo -e '\\n\\nRunning bootstrap...' && /home/testuser/shell/bootstrap.sh && echo -e '\\n\\nRunning post-bootstrap tests...' && ./test-setup.sh"]
EOF
# Build and run the container
# Create the logs directory if it doesn't exist
mkdir -p "$(pwd)/logs"
docker build -f Dockerfile.fulltest -t shell-full-test:$tag_name .
docker run --rm -it -v "$(pwd)/logs:/logs" shell-full-test:$tag_name
# Clean up
rm Dockerfile.fulltest
}
# Parse command line arguments
case "$1" in
ubuntu)
run_ubuntu_test
;;
debian)
run_debian_test
;;
full-ubuntu)
run_full_test "ubuntu:24.04"
;;
full-debian)
run_full_test "debian:12"
;;
all)
run_ubuntu_test
run_debian_test
;;
*)
echo -e "${BLUE}Shell Setup Test Runner${NC}"
echo -e "Usage: $0 [option]"
echo -e "\nOptions:"
echo " ubuntu Run test on Ubuntu container (tests packages and components)"
echo " debian Run test on Debian container (tests packages and components)"
echo " full-ubuntu Run full bootstrap test on Ubuntu container (performs complete installation)"
echo " full-debian Run full bootstrap test on Debian container (performs complete installation)"
echo " all Run tests on both Ubuntu and Debian containers (component tests only)"
echo -e "\nExamples:"
echo -e " $0 ubuntu # Quick test for package availability"
echo -e " $0 full-debian # Test complete bootstrap installation"
;;
esac

View File

@@ -25,11 +25,21 @@ echo -e "${YELLOW}Setting up Nala repository...${NC}"
if apt-cache show nala &>/dev/null; then if apt-cache show nala &>/dev/null; then
echo -e "${GREEN}Nala is available in standard repositories${NC}" echo -e "${GREEN}Nala is available in standard repositories${NC}"
else else
# Try Ubuntu PPA as an alternative echo -e "${YELLOW}Nala not found in standard repositories. Trying alternative installation methods...${NC}"
echo -e "${YELLOW}Trying Nala from Ubuntu PPA...${NC}"
# Check Ubuntu version
if grep -q "noble\|lunar\|mantic\|jammy" /etc/os-release; then
echo -e "${GREEN}Ubuntu $(grep VERSION_CODENAME /etc/os-release | cut -d= -f2) detected. Ensuring universe repository is enabled...${NC}"
# Make sure universe repository is enabled
sudo apt-get update sudo apt-get update
sudo apt-get install -y software-properties-common sudo apt-get install -y software-properties-common
sudo add-apt-repository -y ppa:volitank/ppa sudo add-apt-repository -y universe
else
# For older Ubuntu versions try to install directly
echo -e "${YELLOW}Older Ubuntu version detected. Trying to install Nala directly...${NC}"
sudo apt-get update
sudo apt-get install -y software-properties-common
fi
fi fi
# Setup VS Code repository # Setup VS Code repository
@@ -47,21 +57,49 @@ out=$(mktemp) && wget -nv -O$out https://cli.github.com/packages/githubcli-archi
&& rm "$out" \ && rm "$out" \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
# Update package lists # Initialize USING_NALA variable
sudo apt update USING_NALA=false
# Update package lists (ignoring previous errors)
echo -e "${YELLOW}Updating package lists...${NC}"
sudo apt update || echo -e "${YELLOW}Warning: apt update had some errors, but continuing...${NC}"
# Install Nala first # Install Nala first
echo -e "${YELLOW}Installing Nala package manager...${NC}" echo -e "${YELLOW}Installing Nala package manager...${NC}"
sudo apt-get install -y nala if sudo apt-get install -y nala; then
USING_NALA=true
echo -e "${GREEN}Nala installed successfully!${NC}"
else
echo -e "${YELLOW}Failed to install Nala. Continuing with standard apt...${NC}"
fi
# Configure Nala mirrors # Configure Nala mirrors and install packages
echo -e "${YELLOW}Configuring Nala mirrors...${NC}" if [ "$USING_NALA" = true ]; then
sudo nala fetch --auto --fetches 3 echo -e "${YELLOW}Configuring Nala mirrors...${NC}"
# Install remaining packages using Nala # First, remove any existing nala sources list to avoid issues with invalid mirrors
echo -e "${YELLOW}Installing packages from packages.list...${NC}" sudo rm -f /etc/apt/sources.list.d/nala-sources.list 2>/dev/null
mapfile -t pkgs < <(grep -v '^//' "$SCRIPT_DIR/packages.list" | grep -v -e '^$' -e '^nala$')
sudo nala install -y "${pkgs[@]}" # Try to fetch mirrors with less aggressive settings
if ! sudo nala fetch --auto --fetches 1 --country auto; then
echo -e "${YELLOW}Mirror selection failed, continuing with system default mirrors...${NC}"
# Remove any potentially corrupted Nala sources
sudo rm -f /etc/apt/sources.list.d/nala-sources.list 2>/dev/null
fi
# Install remaining packages using Nala
echo -e "${YELLOW}Installing packages from packages.list with Nala...${NC}"
mapfile -t pkgs < <(grep -v '^//' "$SCRIPT_DIR/packages.list" | grep -v -e '^$' -e '^nala$')
sudo nala install -y "${pkgs[@]}" || {
echo -e "${YELLOW}Nala install failed, falling back to apt...${NC}"
sudo apt-get install -y "${pkgs[@]}"
}
else
# Fall back to apt if Nala installation failed
echo -e "${YELLOW}Installing packages from packages.list with apt...${NC}"
mapfile -t pkgs < <(grep -v '^//' "$SCRIPT_DIR/packages.list" | grep -v -e '^$' -e '^nala$')
sudo apt-get install -y "${pkgs[@]}"
fi
# Install Zsh if not already installed # Install Zsh if not already installed
echo -e "${YELLOW}Installing Zsh...${NC}" echo -e "${YELLOW}Installing Zsh...${NC}"

75
startup.sh Executable file
View File

@@ -0,0 +1,75 @@
#!/bin/bash
# Startup script for Docker containers to ensure permissions and run tests
# Define colors for output
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}=== Container Startup Checks ===${NC}"
# Display system information
echo -e "${BLUE}System information:${NC}"
if [ -f /etc/os-release ]; then
. /etc/os-release
echo -e "- OS: ${GREEN}$PRETTY_NAME${NC}"
else
echo -e "- OS: ${YELLOW}Unknown${NC}"
fi
# Ensure packages.list is available
echo -e "${BLUE}Checking for packages.list:${NC}"
if [ -f "$HOME/shell/setup/packages.list" ]; then
echo -e "- packages.list: ${GREEN}Found${NC}"
# Count packages in list (excluding comments and empty lines)
pkg_count=$(grep -v '^//' "$HOME/shell/setup/packages.list" | grep -v -e '^$' | wc -l)
echo -e "- Package count: ${GREEN}$pkg_count packages${NC}"
else
echo -e "- packages.list: ${RED}Not found${NC}"
echo "Error: Could not find packages.list file. Tests will fail."
fi
# Ensure logs directory has correct permissions
echo -e "${BLUE}Setting up logs directory:${NC}"
if [ -d "/logs" ]; then
echo -e "- Logs directory: ${GREEN}Found${NC}"
# Check ownership and permissions
logs_owner=$(stat -c '%U:%G' /logs)
echo -e "- Current ownership: $logs_owner"
echo "- Setting permissions on /logs directory..."
sudo chown -R $(whoami):$(whoami) /logs 2>/dev/null || echo -e "${YELLOW}Failed to set ownership${NC}"
sudo chmod -R 777 /logs 2>/dev/null || echo -e "${YELLOW}Failed to set permissions${NC}"
# Verify permissions are correct
if [ -w "/logs" ]; then
echo -e "- Write permission: ${GREEN}OK${NC}"
# Create a test file to really verify we can write
if touch "/logs/test_file" 2>/dev/null; then
echo -e "- Test write: ${GREEN}Succeeded${NC}"
rm -f "/logs/test_file"
else
echo -e "- Test write: ${RED}Failed${NC}"
fi
else
echo -e "- Write permission: ${RED}Failed${NC}"
fi
else
echo -e "- Logs directory: ${YELLOW}Not found${NC}"
echo "- Creating /logs directory..."
if sudo mkdir -p /logs && sudo chown -R $(whoami):$(whoami) /logs && sudo chmod -R 777 /logs; then
echo -e "- Created logs directory with proper permissions: ${GREEN}Success${NC}"
else
echo -e "- Creating logs directory: ${RED}Failed${NC}"
echo "Warning: Logs will be saved inside container only"
fi
fi
echo -e "${BLUE}=== Starting Test Script ===${NC}"
# Run the test script
./test-setup.sh

764
test-setup.sh Executable file
View File

@@ -0,0 +1,764 @@
#!/bin/bash
# Script to test bootstrap.sh and setup.sh scripts in different environments
# This script can be run on different systems to validate the setup process
# NOTE: We don't use 'set -e' to allow testing all packages even if some fail
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Maximum number of installation attempts
MAX_INSTALL_ATTEMPTS=3
CURRENT_ATTEMPT=1
# Log file
# Create logs directory if it doesn't exist and is writable
# First, try creating the logs directory in case it doesn't exist
if [ -d "/logs" ] || mkdir -p /logs 2>/dev/null; then
if [ -w "/logs" ]; then
LOGS_DIR="/logs"
echo -e "${GREEN}Logs will be saved to host system at ./logs/${NC}"
else
echo -e "${YELLOW}Warning: /logs directory exists but is not writable${NC}"
sudo chmod -R 777 /logs 2>/dev/null || true
if [ -w "/logs" ]; then
LOGS_DIR="/logs"
echo -e "${GREEN}Logs will be saved to host system at ./logs/ (permissions fixed)${NC}"
else
LOGS_DIR="/tmp"
echo -e "${RED}Warning: Could not fix /logs permissions. Logs will be saved to $LOGS_DIR (container only)${NC}"
fi
fi
else
LOGS_DIR="/tmp"
echo -e "${YELLOW}Warning: /logs directory not available or could not be created. Logs will be saved to $LOGS_DIR (container only)${NC}"
fi
# Use the timestamp from environment variable if set, otherwise generate a new one
TIMESTAMP="${TEST_TIMESTAMP:-$(date +"%Y%m%d-%H%M%S")}"
CONTAINER_INFO="${CONTAINER_TYPE:+$CONTAINER_TYPE-}"
LOG_FILE="$LOGS_DIR/setup-test-${CONTAINER_INFO}${TIMESTAMP}.log"
echo "Starting setup test at $(date)" > "$LOG_FILE" || {
echo -e "${RED}Error: Failed to write to log file at $LOG_FILE. Check permissions.${NC}"
ls -la "$LOGS_DIR" 2>/dev/null || echo "Cannot list logs directory contents"
LOGS_DIR="/tmp"
LOG_FILE="$LOGS_DIR/setup-test-${CONTAINER_INFO}${TIMESTAMP}.log"
echo -e "${YELLOW}Attempting to use fallback log location: $LOG_FILE${NC}"
echo "Starting setup test at $(date)" > "$LOG_FILE"
}
# Identify the system
echo -e "${BLUE}=== System Information ===${NC}"
if [ -f /etc/os-release ]; then
. /etc/os-release
echo -e "Detected: ${GREEN}$PRETTY_NAME${NC}"
echo "Testing on: $PRETTY_NAME" >> "$LOG_FILE"
else
echo -e "${RED}Could not determine OS${NC}"
echo "Could not determine OS" >> "$LOG_FILE"
exit 1
fi
# Determine if this is a pre-bootstrap or post-bootstrap test
TEST_STAGE="Unknown"
if [ -d "$HOME/shell" ] && [ -f "$HOME/shell/bootstrap.sh" ] && [ -d "$HOME/shell/setup" ] && [ -f "$HOME/shell/setup/setup.sh" ]; then
# Check if there are any signs that bootstrap has been completed
if [ -d "$HOME/.oh-my-zsh" ] || [ -f "$HOME/.zshrc" ] || [ -d "$HOME/.nvm" ]; then
TEST_STAGE="Post-Bootstrap"
else
TEST_STAGE="Mid-Bootstrap"
fi
else
TEST_STAGE="Pre-Bootstrap"
fi
echo -e "Test Stage: ${GREEN}$TEST_STAGE${NC}"
echo "Test Stage: $TEST_STAGE" >> "$LOG_FILE"
# Check if this is running in a test environment (container or VM)
ENV_TYPE="Unknown"
if [ -f /.dockerenv ]; then
ENV_TYPE="Docker container"
elif grep -q "^flags.*hypervisor" /proc/cpuinfo 2>/dev/null; then
ENV_TYPE="Virtual machine"
else
ENV_TYPE="Physical machine"
fi
echo -e "Environment: ${GREEN}$ENV_TYPE${NC}"
echo "Environment: $ENV_TYPE" >> "$LOG_FILE"
# Initialize arrays for tracking
missing_packages=()
installed_this_round=()
failed_packages=()
# Helper functions
check_command() {
command -v "$1" &> /dev/null
}
test_package() {
local pkg=$1
local cmd=${2:-$1}
local alt_cmd=$3 # Optional alternative command name
echo -en "Testing if $pkg is installed... "
# Special case for cowsay and lolcat which might be in different paths
if [ "$pkg" = "cowsay" ]; then
if check_command "$cmd"; then
echo -e "${GREEN}${NC}"
echo "$pkg: Installed (found in PATH as $cmd)" >> "$LOG_FILE"
return 0
elif [ -x "/usr/games/cowsay" ]; then
echo -e "${GREEN}${NC} (in /usr/games)"
echo "$pkg: Installed (found in /usr/games/)" >> "$LOG_FILE"
# Create a symlink to make it available in PATH for other scripts
if [ ! -e "$HOME/.local/bin" ]; then
mkdir -p "$HOME/.local/bin"
fi
if [ ! -e "$HOME/.local/bin/cowsay" ] && [ -w "$HOME/.local/bin" ]; then
ln -sf /usr/games/cowsay "$HOME/.local/bin/cowsay"
echo "Created symlink for cowsay in $HOME/.local/bin" >> "$LOG_FILE"
fi
return 0
fi
elif [ "$pkg" = "lolcat" ]; then
if check_command "$cmd"; then
echo -e "${GREEN}${NC}"
echo "$pkg: Installed (found in PATH as $cmd)" >> "$LOG_FILE"
return 0
elif [ -x "/usr/games/lolcat" ]; then
echo -e "${GREEN}${NC} (in /usr/games)"
echo "$pkg: Installed (found in /usr/games/)" >> "$LOG_FILE"
# Create a symlink to make it available in PATH for other scripts
if [ ! -e "$HOME/.local/bin" ]; then
mkdir -p "$HOME/.local/bin"
fi
if [ ! -e "$HOME/.local/bin/lolcat" ] && [ -w "$HOME/.local/bin" ]; then
ln -sf /usr/games/lolcat "$HOME/.local/bin/lolcat"
echo "Created symlink for lolcat in $HOME/.local/bin" >> "$LOG_FILE"
fi
return 0
fi
elif check_command "$cmd"; then
echo -e "${GREEN}${NC}"
echo "$pkg: Installed (as $cmd)" >> "$LOG_FILE"
return 0
elif [ -n "$alt_cmd" ] && check_command "$alt_cmd"; then
echo -e "${GREEN}${NC} (as $alt_cmd)"
echo "$pkg: Installed (as $alt_cmd)" >> "$LOG_FILE"
return 0
else
echo -e "${RED}${NC}"
echo "$pkg: Missing" >> "$LOG_FILE"
return 1
fi
# Note: The calling code will handle the failure and continue testing
}
test_file_exists() {
local file=$1
local description=${2:-"File exists"}
echo -en "Testing if $file exists... "
if [ -e "$file" ]; then
echo -e "${GREEN}${NC}"
echo "$description: Yes" >> "$LOG_FILE"
return 0
else
echo -e "${RED}${NC}"
echo "$description: No" >> "$LOG_FILE"
return 1
fi
}
# Get actual package name based on distribution
get_package_name() {
local pkg=$1
# Handle Debian-specific package name differences
if [[ "$ID" == "debian" ]]; then
case "$pkg" in
"bat")
echo "batcat"
;;
*)
echo "$pkg"
;;
esac
else
# Default to the original package name for Ubuntu and others
echo "$pkg"
fi
}
# Function to install missing packages
install_missing_packages() {
local packages=("$@")
local install_cmd_name
local install_cmd=()
if [ ${#packages[@]} -eq 0 ]; then
echo -e "${GREEN}No packages to install${NC}"
echo "No packages to install" >> "$LOG_FILE"
return 0
fi
echo -e "\n${BLUE}=== Installing missing packages (Attempt $CURRENT_ATTEMPT of $MAX_INSTALL_ATTEMPTS) ===${NC}"
echo "=== Installing missing packages (Attempt $CURRENT_ATTEMPT of $MAX_INSTALL_ATTEMPTS) ===" >> "$LOG_FILE"
# Determine the best installation command
if check_command nala; then
install_cmd=(sudo DEBIAN_FRONTEND=noninteractive nala install -y)
install_cmd_name="nala"
echo -e "${GREEN}Using nala for package installation${NC}"
echo "Using nala for package installation" >> "$LOG_FILE"
else
install_cmd=(sudo DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confnew" install -y)
install_cmd_name="apt-get"
echo -e "${YELLOW}Using apt-get for package installation${NC}"
echo "Using apt-get for package installation" >> "$LOG_FILE"
fi
# Convert package list to distribution-specific names
local install_list=()
for pkg in "${packages[@]}"; do
local actual_pkg=$(get_package_name "$pkg")
install_list+=("$actual_pkg")
done
# Update package lists
echo -e "${YELLOW}Updating package lists...${NC}"
echo "Updating package lists" >> "$LOG_FILE"
if check_command nala; then
echo -e "${GREEN}Running: sudo DEBIAN_FRONTEND=noninteractive nala update${NC}"
sudo DEBIAN_FRONTEND=noninteractive nala update | tee -a "$LOG_FILE"
else
echo -e "${GREEN}Running: sudo DEBIAN_FRONTEND=noninteractive apt-get update${NC}"
sudo DEBIAN_FRONTEND=noninteractive apt-get update | tee -a "$LOG_FILE"
fi
# Install packages
echo -e "${YELLOW}Installing packages: ${install_list[*]}${NC}"
echo "Installing packages: ${install_list[*]}" >> "$LOG_FILE"
# Show the exact command being run for debugging
echo -e "${BLUE}Running: ${install_cmd[*]} ${install_list[*]}${NC}"
# Execute the install command with the package list
if ! "${install_cmd[@]}" "${install_list[@]}" 2>&1 | tee -a "$LOG_FILE"; then
echo -e "${RED}Failed to install some packages. Check the log for details.${NC}"
echo "Failed to install some packages" >> "$LOG_FILE"
# Try to install packages one by one to identify problematic ones
echo -e "${YELLOW}Trying to install packages individually...${NC}"
echo "Trying to install packages individually" >> "$LOG_FILE"
installed_this_round=()
local failed_this_round=()
for i in "${!packages[@]}"; do
local pkg="${packages[$i]}"
local actual_pkg="${install_list[$i]}"
echo -en "Installing $pkg as $actual_pkg... "
if "${install_cmd[@]}" "$actual_pkg" >> "$LOG_FILE" 2>&1; then
echo -e "${GREEN}${NC}"
echo "$pkg: Installed successfully" >> "$LOG_FILE"
installed_this_round+=("$pkg")
else
echo -e "${RED}${NC}"
echo "$pkg: Installation failed" >> "$LOG_FILE"
failed_this_round+=("$pkg")
fi
done
failed_packages=("${failed_this_round[@]}")
return 1
else
echo -e "${GREEN}Successfully installed all packages!${NC}"
echo "Successfully installed all packages" >> "$LOG_FILE"
installed_this_round=("${packages[@]}")
return 0
fi
}
# Create a temporary backup of .zshrc if it exists
if [ -f "$HOME/.zshrc" ]; then
cp "$HOME/.zshrc" "$HOME/.zshrc.test_backup"
echo "Backed up existing .zshrc" >> "$LOG_FILE"
fi
# Main testing sequence
echo -e "\n${BLUE}=== Testing bootstrap.sh ===${NC}"
echo "=== Testing bootstrap.sh ===" >> "$LOG_FILE"
# Get the bootstrap script if it doesn't exist locally
if [ ! -f "$HOME/shell/bootstrap.sh" ]; then
echo -e "${YELLOW}Downloading bootstrap.sh...${NC}"
echo "Downloading bootstrap.sh" >> "$LOG_FILE"
curl -s -o /tmp/bootstrap.sh https://raw.githubusercontent.com/acedanger/shell/main/bootstrap.sh || {
echo -e "${RED}Failed to download bootstrap.sh${NC}"
echo "Failed to download bootstrap.sh" >> "$LOG_FILE"
exit 1
}
chmod +x /tmp/bootstrap.sh
else
echo -e "${YELLOW}Using local bootstrap.sh${NC}"
echo "Using local bootstrap.sh" >> "$LOG_FILE"
cp "$HOME/shell/bootstrap.sh" /tmp/bootstrap.sh
fi
# Run bootstrap in test mode (no actual execution)
echo -e "${YELLOW}Analyzing bootstrap script...${NC}"
bash -n /tmp/bootstrap.sh
if [ $? -eq 0 ]; then
echo -e "${GREEN}Bootstrap script syntax is valid${NC}"
echo "Bootstrap script syntax: Valid" >> "$LOG_FILE"
else
echo -e "${RED}Bootstrap script has syntax errors${NC}"
echo "Bootstrap script syntax: Invalid" >> "$LOG_FILE"
exit 1
fi
echo -e "\n${BLUE}=== Testing setup.sh ===${NC}"
echo "=== Testing setup.sh ===" >> "$LOG_FILE"
# Check setup.sh script if available
if [ -f "$HOME/shell/setup/setup.sh" ]; then
echo -e "${YELLOW}Analyzing setup script...${NC}"
bash -n "$HOME/shell/setup/setup.sh"
if [ $? -eq 0 ]; then
echo -e "${GREEN}Setup script syntax is valid${NC}"
echo "Setup script syntax: Valid" >> "$LOG_FILE"
else
echo -e "${RED}Setup script has syntax errors${NC}"
echo "Setup script syntax: Invalid" >> "$LOG_FILE"
exit 1
fi
else
echo -e "${YELLOW}Setup script not available locally. Will be downloaded by bootstrap.${NC}"
echo "Setup script not available locally" >> "$LOG_FILE"
fi
echo -e "\n${BLUE}=== Testing Debian compatibility ===${NC}"
echo "=== Testing Debian compatibility ===" >> "$LOG_FILE"
# Check for Debian-specific commands used in scripts
echo -en "Checking if apt is available... "
if check_command apt; then
echo -e "${GREEN}${NC}"
echo "apt: Available" >> "$LOG_FILE"
else
echo -e "${RED}${NC} (Scripts may not work here)"
echo "apt: Not available" >> "$LOG_FILE"
fi
# Check if the package list is valid for this system
if [ -f "$HOME/shell/setup/packages.list" ]; then
echo -e "${YELLOW}Testing package availability in repositories:${NC}"
echo "Testing package availability:" >> "$LOG_FILE"
# Exclude commented lines and empty lines
packages=$(grep -v '^//' "$HOME/shell/setup/packages.list" | grep -v -e '^$')
for pkg in $packages; do
echo -en "Checking if $pkg is available in repos... "
actual_pkg=$(get_package_name "$pkg")
if apt-cache show "$actual_pkg" &>/dev/null; then
echo -e "${GREEN}${NC}"
echo "$pkg: Available in repos as $actual_pkg" >> "$LOG_FILE"
else
echo -e "${RED}${NC}"
echo "$pkg: Not available in repos" >> "$LOG_FILE"
fi
done
fi
# Main testing and installation loop
while [ $CURRENT_ATTEMPT -le $MAX_INSTALL_ATTEMPTS ]; do
echo -e "\n${BLUE}=== Testing installed components (Attempt $CURRENT_ATTEMPT of $MAX_INSTALL_ATTEMPTS) ===${NC}"
echo "=== Testing installed components (Attempt $CURRENT_ATTEMPT of $MAX_INSTALL_ATTEMPTS) ===" >> "$LOG_FILE"
errors=0
missing_packages=()
# Test core required tools
core_tools=("git" "curl" "wget")
for tool in "${core_tools[@]}"; do
if ! test_package "$tool"; then
((errors++))
missing_packages+=("$tool")
fi
done
# Test if setup has already been run
if [ -d "$HOME/.oh-my-zsh" ]; then
echo -e "Oh My Zsh: ${GREEN}Installed${NC}"
echo "Oh My Zsh: Installed" >> "$LOG_FILE"
else
echo -e "Oh My Zsh: ${YELLOW}Not installed${NC}"
echo "Oh My Zsh: Not installed" >> "$LOG_FILE"
fi
# Check custom packages from packages.list
echo -e "${YELLOW}Testing packages listed in packages.list:${NC}"
echo "Testing packages listed in packages.list:" >> "$LOG_FILE"
if [ -f "$HOME/shell/setup/packages.list" ]; then
# Exclude commented lines and empty lines
packages=$(grep -v '^//' "$HOME/shell/setup/packages.list" | grep -v -e '^$')
for pkg in $packages; do
case "$pkg" in
"bat")
if ! test_package "bat" "bat" "batcat"; then
((errors++))
missing_packages+=("$pkg")
fi
;;
"cowsay")
# Extra debugging for cowsay
echo -e "\n${BLUE}Debugging cowsay package:${NC}" | tee -a "$LOG_FILE"
if [ -f "/usr/games/cowsay" ]; then
echo -e "- Cowsay found at /usr/games/cowsay" | tee -a "$LOG_FILE"
ls -la /usr/games/cowsay | tee -a "$LOG_FILE"
else
echo -e "- Cowsay not found at /usr/games/cowsay" | tee -a "$LOG_FILE"
fi
if check_command cowsay; then
echo -e "- Cowsay found in PATH" | tee -a "$LOG_FILE"
command -v cowsay | tee -a "$LOG_FILE"
else
echo -e "- Cowsay not found in PATH" | tee -a "$LOG_FILE"
fi
if ! test_package "cowsay" "cowsay"; then
((errors++))
missing_packages+=("$pkg")
fi
;;
"lolcat")
# Extra debugging for lolcat
echo -e "\n${BLUE}Debugging lolcat package:${NC}" | tee -a "$LOG_FILE"
if [ -f "/usr/games/lolcat" ]; then
echo -e "- Lolcat found at /usr/games/lolcat" | tee -a "$LOG_FILE"
ls -la /usr/games/lolcat | tee -a "$LOG_FILE"
else
echo -e "- Lolcat not found at /usr/games/lolcat" | tee -a "$LOG_FILE"
fi
if check_command lolcat; then
echo -e "- Lolcat found in PATH" | tee -a "$LOG_FILE"
command -v lolcat | tee -a "$LOG_FILE"
else
echo -e "- Lolcat not found in PATH" | tee -a "$LOG_FILE"
fi
if ! test_package "lolcat" "lolcat"; then
((errors++))
missing_packages+=("$pkg")
fi
;;
*)
if ! test_package "$pkg" "$pkg"; then
((errors++))
missing_packages+=("$pkg")
fi
;;
esac
done
# Report missing packages
if [ ${#missing_packages[@]} -gt 0 ]; then
echo -e "\n${YELLOW}Missing packages:${NC}"
for pkg in "${missing_packages[@]}"; do
echo -e "- ${RED}$pkg${NC}"
done
# Count installed vs. total packages
total_pkgs=$(grep -v '^//' "$HOME/shell/setup/packages.list" | grep -v -e '^$' | wc -l)
installed_pkgs=$((total_pkgs - ${#missing_packages[@]}))
echo -e "${GREEN}$installed_pkgs of $total_pkgs packages installed${NC} (${YELLOW}${#missing_packages[@]} missing${NC})"
echo "$installed_pkgs of $total_pkgs packages installed (${#missing_packages[@]} missing)" >> "$LOG_FILE"
# Install missing packages if we haven't reached the maximum attempts
if [ $CURRENT_ATTEMPT -lt $MAX_INSTALL_ATTEMPTS ]; then
install_missing_packages "${missing_packages[@]}"
echo -e "\n${BLUE}=== Installation Results ===${NC}"
if [ ${#installed_this_round[@]} -gt 0 ]; then
echo -e "${GREEN}Successfully installed:${NC}"
for pkg in "${installed_this_round[@]}"; do
echo -e "- ${GREEN}$pkg${NC}"
done
echo "Successfully installed: ${installed_this_round[*]}" >> "$LOG_FILE"
fi
if [ ${#failed_packages[@]} -gt 0 ]; then
echo -e "${RED}Failed to install:${NC}"
for pkg in "${failed_packages[@]}"; do
echo -e "- ${RED}$pkg${NC}"
done
echo "Failed to install: ${failed_packages[*]}" >> "$LOG_FILE"
fi
CURRENT_ATTEMPT=$((CURRENT_ATTEMPT + 1))
echo -e "\n${YELLOW}Continuing to next test iteration...${NC}"
echo "Continuing to next test iteration" >> "$LOG_FILE"
continue
fi
else
total_pkgs=$(grep -v '^//' "$HOME/shell/setup/packages.list" | grep -v -e '^$' | wc -l)
echo -e "\n${GREEN}All $total_pkgs packages are installed!${NC}"
echo "All $total_pkgs packages are installed" >> "$LOG_FILE"
break
fi
else
echo -e "${RED}packages.list file not found at $HOME/shell/setup/packages.list${NC}"
echo "packages.list file not found" >> "$LOG_FILE"
fi
# If no missing packages or we've reached max attempts, break out of the loop
if [ ${#missing_packages[@]} -eq 0 ] || [ $CURRENT_ATTEMPT -ge $MAX_INSTALL_ATTEMPTS ]; then
break
fi
CURRENT_ATTEMPT=$((CURRENT_ATTEMPT + 1))
done
# Test nvm installation
if [ -d "$HOME/.nvm" ]; then
echo -e "NVM: ${GREEN}Installed${NC}"
echo "NVM: Installed" >> "$LOG_FILE"
# Source NVM
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
# Test Node.js installed by NVM
if check_command node; then
node_version=$(node -v)
echo -e "Node.js: ${GREEN}$node_version${NC}"
echo "Node.js: $node_version" >> "$LOG_FILE"
else
echo -e "Node.js: ${RED}Not installed${NC}"
echo "Node.js: Not installed" >> "$LOG_FILE"
((errors++))
fi
else
echo -e "NVM: ${YELLOW}Not installed${NC}"
echo "NVM: Not installed" >> "$LOG_FILE"
fi
# Test zoxide
if test_package "zoxide"; then
echo -e "Zoxide integration: ${GREEN}Available${NC}"
echo "Zoxide integration: Available" >> "$LOG_FILE"
fi
# Test ZSH plugins
zsh_plugins=(
"$HOME/.oh-my-zsh/custom/plugins/zsh-autosuggestions"
"$HOME/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting"
"$HOME/.oh-my-zsh/custom/plugins/zsh-you-should-use"
)
for plugin_dir in "${zsh_plugins[@]}"; do
plugin_name=$(basename "$plugin_dir")
if [ -d "$plugin_dir" ]; then
echo -e "ZSH plugin $plugin_name: ${GREEN}Installed${NC}"
echo "ZSH plugin $plugin_name: Installed" >> "$LOG_FILE"
else
echo -e "ZSH plugin $plugin_name: ${YELLOW}Not installed${NC}"
echo "ZSH plugin $plugin_name: Not installed" >> "$LOG_FILE"
fi
done
# Test dotfile linking
dotfiles=(
"$HOME/.zshrc"
"$HOME/.nanorc"
"$HOME/.profile"
"$HOME/.gitconfig"
)
for dotfile in "${dotfiles[@]}"; do
if [ -L "$dotfile" ]; then
echo -e "Dotfile $dotfile: ${GREEN}Symlinked${NC}"
echo "Dotfile $dotfile: Symlinked" >> "$LOG_FILE"
# Check if symlink is valid
if [ -e "$dotfile" ]; then
target=$(readlink -f "$dotfile")
echo -e " → Links to: ${GREEN}$target${NC}"
echo " → Links to: $target" >> "$LOG_FILE"
else
echo -e "${RED}Broken symlink${NC}"
echo " → Broken symlink" >> "$LOG_FILE"
((errors++))
fi
elif [ -f "$dotfile" ]; then
echo -e "Dotfile $dotfile: ${YELLOW}Exists but not symlinked${NC}"
echo "Dotfile $dotfile: Exists but not symlinked" >> "$LOG_FILE"
else
echo -e "Dotfile $dotfile: ${YELLOW}Not present${NC}"
echo "Dotfile $dotfile: Not present" >> "$LOG_FILE"
fi
done
echo -e "\n${BLUE}=== Summary ===${NC}"
echo "=== Summary ===" >> "$LOG_FILE"
# Test summary
if [ $errors -eq 0 ]; then
echo -e "${GREEN}All critical components and packages passed! Your setup appears to be working correctly.${NC}"
echo "Result: All critical components and packages passed" >> "$LOG_FILE"
else
echo -e "${RED}Found $errors potential issues with your setup.${NC}"
echo "Result: Found $errors potential issues" >> "$LOG_FILE"
# Display missing packages if any
if [ ${#missing_packages[@]} -gt 0 ]; then
echo -e "\n${YELLOW}The following packages were not found:${NC}"
echo "Missing packages:" >> "$LOG_FILE"
for pkg in "${missing_packages[@]}"; do
echo -e " - ${RED}$pkg${NC}"
echo " - $pkg" >> "$LOG_FILE"
done
if [ $CURRENT_ATTEMPT -gt $MAX_INSTALL_ATTEMPTS ]; then
echo -e "\n${RED}Reached maximum installation attempts ($MAX_INSTALL_ATTEMPTS).${NC}"
echo -e "${YELLOW}Some packages could not be installed automatically.${NC}"
echo "Reached maximum installation attempts" >> "$LOG_FILE"
fi
echo -e "\n${BLUE}You can manually install these packages with:${NC}"
echo -e " sudo apt-get install ${missing_packages[*]}"
fi
fi
# Provide more detailed information about log files
if [[ "$LOG_FILE" == "/logs/"* ]]; then
HOST_LOG_FILE="./logs/$(basename "$LOG_FILE")"
echo -e "\n${YELLOW}Complete test log saved to:${NC} $LOG_FILE"
echo -e "${GREEN}This log file is accessible on the host system at:${NC} $HOST_LOG_FILE"
else
echo -e "\n${YELLOW}Complete test log saved to:${NC} $LOG_FILE (in container only)"
echo -e "${YELLOW}Note: This log file will be lost when the container exits."
echo -e "To preserve logs, run with the logs volume mounted using run-docker-tests.sh${NC}"
fi
# Check for Debian-specific issues
if [[ "$ID" == "debian" ]]; then
echo -e "\n${BLUE}=== Debian-Specific Recommendations ===${NC}"
echo "=== Debian-Specific Recommendations ===" >> "$LOG_FILE"
echo "1. Ensure Debian's 'universe' equivalent repositories are enabled (contrib, non-free)"
echo "2. Some packages like 'bat' may have different names in Debian (batcat)"
echo "3. Consider adding Debian-specific adjustments to setup.sh"
# Add specific Debian package name mappings
echo -e "\nOn Debian, you may need these package name adjustments:"
echo " - bat → batcat"
echo " - (add more as needed)"
echo "Debian package name mappings may be required" >> "$LOG_FILE"
fi
# Enhanced testing for bootstrapped environment
check_bootstrapped_environment() {
echo -e "\n${BLUE}=== Checking for bootstrapped environment ===${NC}"
echo "=== Checking for bootstrapped environment ===" >> "$LOG_FILE"
if [ -d "$HOME/shell" ] && [ -f "$HOME/shell/bootstrap.sh" ]; then
echo -e "${GREEN}Environment appears to be bootstrapped:${NC}"
echo "Environment is bootstrapped" >> "$LOG_FILE"
# Check the shell repository structure
if [ -d "$HOME/shell/setup" ] && [ -f "$HOME/shell/setup/setup.sh" ]; then
echo -e " - ${GREEN}Setup directory and script present${NC}"
echo "Setup directory and script: Present" >> "$LOG_FILE"
# Check if setup.sh is executable
if [ -x "$HOME/shell/setup/setup.sh" ]; then
echo -e " - ${GREEN}Setup script is executable${NC}"
echo "Setup script is executable: Yes" >> "$LOG_FILE"
else
echo -e " - ${RED}Setup script is not executable${NC}"
echo "Setup script is executable: No" >> "$LOG_FILE"
fi
else
echo -e " - ${RED}Setup directory or setup.sh missing${NC}"
echo "Setup directory or setup.sh: Missing" >> "$LOG_FILE"
fi
# Check packages.list
if [ -f "$HOME/shell/setup/packages.list" ]; then
echo -e " - ${GREEN}Packages list present${NC}"
echo "Packages list: Present" >> "$LOG_FILE"
# Count packages in list
pkg_count=$(grep -v '^//' "$HOME/shell/setup/packages.list" | grep -v -e '^$' | wc -l)
echo -e " - ${GREEN}Package list contains $pkg_count packages${NC}"
echo "Package list count: $pkg_count" >> "$LOG_FILE"
else
echo -e " - ${RED}Packages list missing${NC}"
echo "Packages list: Missing" >> "$LOG_FILE"
fi
# Check dotfiles directory
if [ -d "$HOME/shell/dotfiles" ]; then
echo -e " - ${GREEN}Dotfiles directory present${NC}"
echo "Dotfiles directory: Present" >> "$LOG_FILE"
# Check if dotfiles are properly symlinked
dotfiles_linked=true
for dotfile in "$HOME/.zshrc" "$HOME/.nanorc" "$HOME/.profile" "$HOME/.gitconfig"; do
if [ -L "$dotfile" ]; then
target=$(readlink -f "$dotfile" 2>/dev/null)
if [[ "$target" == *"shell/dotfiles"* ]]; then
continue
else
dotfiles_linked=false
break
fi
else
dotfiles_linked=false
break
fi
done
if $dotfiles_linked; then
echo -e " - ${GREEN}Dotfiles are properly symlinked${NC}"
echo "Dotfiles symlinked: Yes" >> "$LOG_FILE"
else
echo -e " - ${YELLOW}Some dotfiles are not properly symlinked${NC}"
echo "Dotfiles symlinked: No" >> "$LOG_FILE"
fi
else
echo -e " - ${RED}Dotfiles directory missing${NC}"
echo "Dotfiles directory: Missing" >> "$LOG_FILE"
fi
else
echo -e "${YELLOW}No bootstrapped environment detected${NC}"
echo "No bootstrapped environment detected" >> "$LOG_FILE"
fi
}
# Call the check if we're not in a simple test environment
if [ -d "$HOME/shell" ] && [ -f "$HOME/shell/bootstrap.sh" ]; then
check_bootstrapped_environment
fi
# Restore .zshrc if we backed it up
if [ -f "$HOME/.zshrc.test_backup" ]; then
echo -e "\n${YELLOW}Restoring original .zshrc${NC}"
mv "$HOME/.zshrc.test_backup" "$HOME/.zshrc"
echo "Restored original .zshrc" >> "$LOG_FILE"
fi
echo -e "\n${GREEN}Test completed!${NC}"
echo "Test completed at $(date)" >> "$LOG_FILE"