Tool Installation Architecture
This document describes the tool installation architecture used in this project, focusing on the install_tool_safe() pattern that provides binary-first detection, platform-specific binary name handling, and comprehensive debugging capabilities.
Overview
The project uses a unified tool installation pattern that:
- Detects existing tool binaries before attempting installation
- Handles platform-specific binary names (e.g.,
ec-linux-amd64,ec-darwin-arm64,hadolint.exe) - Provides atomic verification steps for debugging
- Supports both CI and local development environments
- Integrates with mise for version management
The Six-Step Installation Process
The install_tool_safe() function implements a six-step process for reliable tool installation:
Step 1: Binary-First Detection
Before attempting installation, the function checks if the tool binary already exists in the system PATH or mise installation directory.
Benefits:
- Avoids unnecessary installations
- Faster setup in environments where tools are pre-installed
- Reduces network usage and installation time
Implementation:
# Check if binary exists using multiple strategies
if command -v "$BIN_NAME" >/dev/null 2>&1; then
# Binary found in PATH
return 0
fi
# Check mise installation directory
if mise which "$BIN_NAME" >/dev/null 2>&1; then
# Binary found in mise
return 0
fiStep 2: Version Verification
If a binary is found, verify it responds to version commands to ensure it's functional.
Implementation:
if "$BIN_NAME" "$VERSION_FLAG" >/dev/null 2>&1; then
# Binary is functional
return 0
fiStep 3: Installation Decision
Based on the environment (CI vs local development), decide whether to proceed with installation.
Behavior:
- CI Environment: Always install missing tools (fail if installation fails)
- Local Development: Skip installation (developer can install manually)
Step 4: Cleanup (if needed)
If a non-functional binary is found, remove it before reinstalling.
Step 5: Mise Installation
Use mise to install the tool with the specified version.
Implementation:
mise install "$PROVIDER"Step 6: Post-Install Verification
After installation, verify the binary is accessible and functional.
Implementation:
# Refresh PATH to include newly installed tools
eval "$(mise activate bash)"
# Verify binary exists
if ! command -v "$BIN_NAME" >/dev/null 2>&1; then
log_error "Binary not found after installation: $BIN_NAME"
return 1
fi
# Verify binary is functional
if ! "$BIN_NAME" "$VERSION_FLAG" >/dev/null 2>&1; then
log_error "Binary not functional after installation: $BIN_NAME"
return 1
fiPlatform-Specific Binary Handling
Many tools provide platform-specific binaries with different names. The installation system handles these automatically.
Naming Patterns
Linux:
ec-linux-amd64(x86_64)ec-linux-arm64(ARM64)
macOS:
ec-darwin-amd64(Intel)ec-darwin-arm64(Apple Silicon)
Windows:
ec-windows-amd64.exe(x86_64)hadolint.exe(any tool with .exe extension)
Resolution Strategy
The system uses a layered resolution strategy:
- Mise Which (Primary):
mise which <tool>- handles platform-specific binaries automatically - Command -v (Fallback 1):
command -v <tool>- for tools in PATH - Mise Where + Find (Fallback 2): Search mise installation directory with pattern matching
Example:
# For editorconfig-checker on Linux x86_64
# Mise automatically resolves to: ec-linux-amd64
# For hadolint on Windows
# Mise automatically resolves to: hadolint.exePerformance Considerations
- Binary resolution completes within 5 seconds (Requirement 3.1)
- Platform-specific resolution completes within 3 seconds (Requirement 3.3)
- Results are cached during script execution to avoid repeated lookups
Debugging and Error Handling
The installation system provides comprehensive debugging capabilities.
Debug Mode
Enable detailed logging with the DEBUG environment variable:
DEBUG=1 ./scripts/setup.shDebug output includes:
- Each step of the installation process
- Binary resolution attempts and results
- Timing information for each phase
- Error messages with context
Verbose Mode
Enable verbose output with the VERBOSE environment variable:
VERBOSE=2 ./scripts/setup.shAtomic Verification Steps
Each verification step is atomic and reports its status:
✓ Binary found: shfmt
✓ Version check passed: shfmt --version
✓ Installation successful: shfmtCommon Failure Scenarios
Scenario 1: Binary Not Found After Installation
❌ Binary not found after installation: tool-namePossible causes:
- Mise installation directory not in PATH
- Platform-specific binary name not recognized
- Installation failed silently
Solution:
- Check mise installation:
mise list - Verify PATH includes mise shims:
echo $PATH - Try manual installation:
mise install tool-name
Scenario 2: Binary Not Functional
❌ Binary not functional after installation: tool-namePossible causes:
- Binary is corrupted
- Missing dependencies
- Incompatible platform
Solution:
- Remove and reinstall:
mise uninstall tool-name && mise install tool-name - Check tool documentation for dependencies
- Verify platform compatibility
Scenario 3: Platform-Specific Binary Not Found
❌ Could not resolve platform-specific binary: ec-*Possible causes:
- Tool doesn't provide binaries for your platform
- Mise provider doesn't support platform-specific names
Solution:
- Check tool's GitHub releases for your platform
- Update mise provider configuration
- Use alternative installation method
Code Examples
Basic Tool Installation
# Install shfmt with default settings
install_tool_safe "shfmt" "${VER_SHFMT_PROVIDER:-}" "Shfmt" "--version" 0 "*.sh *.bash" ""Parameters:
BIN_NAME: "shfmt" - binary name to verifyPROVIDER: mise provider string (e.g., "github:mvdan/sh")DISPLAY_NAME: "Shfmt" - human-readable name for loggingVERSION_FLAG: "--version" - flag to check versionSKIP_FILE_CHECK: 0 - check for relevant files before installingFILE_PATTERNS: ".sh.bash" - file patterns to checkFILE_DIR: "" - directory to search (empty = current directory)
Platform-Specific Tool Installation
# Install editorconfig-checker (handles ec-linux-amd64, ec-darwin-arm64, etc.)
install_tool_safe "editorconfig-checker" "${VER_EDITORCONFIG_CHECKER_PROVIDER:-}" \
"EditorConfig Checker" "--version" 0 "" ""Tool with Custom Version Flag
# Install tool with custom version flag
install_tool_safe "tool-name" "${VER_TOOL_PROVIDER:-}" "Tool Name" "-v" 0 "" ""Skip File Check
# Install tool without checking for relevant files
install_tool_safe "tool-name" "${VER_TOOL_PROVIDER:-}" "Tool Name" "--version" 1 "" ""Environment Variables
DEBUG
Enable detailed debug logging.
Values:
0or unset: Normal logging1: Debug logging enabled
Example:
DEBUG=1 ./scripts/setup.shVERBOSE
Control verbosity level.
Values:
0: Minimal output1: Normal output (default)2: Verbose output
Example:
VERBOSE=2 ./scripts/setup.shCI
Indicates CI environment.
Values:
true: CI environment (install all tools)falseor unset: Local development (skip optional tools)
Example:
CI=true ./scripts/setup.shMISE_OFFLINE
Use mise in offline mode (no network access).
Values:
1: Offline mode enabled0or unset: Online mode
Example:
MISE_OFFLINE=1 ./scripts/setup.shPerformance Characteristics
Based on performance testing (see Performance Testing):
- Total setup time: ~5 minutes (300 seconds) for all tools
- Binary verification: < 5 seconds per tool
- Platform-specific resolution: < 3 seconds per tool
- Cache effectiveness: 50% speedup with warm cache
Performance Budgets
Per-category budgets:
- Security tools: 60 seconds
- Linters: 90 seconds
- Formatters: 70 seconds
- Runtimes: 80 seconds
See benchmarks/budgets.json for detailed budgets.
Migrated Tools
The following 45 tools have been migrated to the install_tool_safe() pattern:
Security Tools:
- gitleaks
- osv-scanner
- zizmor
Linters:
- shellcheck
- hadolint
- tflint
- actionlint
- yamllint
- markdownlint-cli2
- editorconfig-checker
Formatters:
- shfmt
- prettier
And 33 more tools...
For a complete list, see the implementation in scripts/lib/langs/*.sh.
