Skip to content

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:

bash
# 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
fi

Step 2: Version Verification

If a binary is found, verify it responds to version commands to ensure it's functional.

Implementation:

bash
if "$BIN_NAME" "$VERSION_FLAG" >/dev/null 2>&1; then
  # Binary is functional
  return 0
fi

Step 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:

bash
mise install "$PROVIDER"

Step 6: Post-Install Verification

After installation, verify the binary is accessible and functional.

Implementation:

bash
# 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
fi

Platform-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:

  1. Mise Which (Primary): mise which <tool> - handles platform-specific binaries automatically
  2. Command -v (Fallback 1): command -v <tool> - for tools in PATH
  3. Mise Where + Find (Fallback 2): Search mise installation directory with pattern matching

Example:

bash
# For editorconfig-checker on Linux x86_64
# Mise automatically resolves to: ec-linux-amd64

# For hadolint on Windows
# Mise automatically resolves to: hadolint.exe

Performance 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:

bash
DEBUG=1 ./scripts/setup.sh

Debug 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:

bash
VERBOSE=2 ./scripts/setup.sh

Atomic Verification Steps

Each verification step is atomic and reports its status:

bash
 Binary found: shfmt
 Version check passed: shfmt --version
 Installation successful: shfmt

Common Failure Scenarios

Scenario 1: Binary Not Found After Installation

❌ Binary not found after installation: tool-name

Possible causes:

  • Mise installation directory not in PATH
  • Platform-specific binary name not recognized
  • Installation failed silently

Solution:

  1. Check mise installation: mise list
  2. Verify PATH includes mise shims: echo $PATH
  3. Try manual installation: mise install tool-name

Scenario 2: Binary Not Functional

❌ Binary not functional after installation: tool-name

Possible causes:

  • Binary is corrupted
  • Missing dependencies
  • Incompatible platform

Solution:

  1. Remove and reinstall: mise uninstall tool-name && mise install tool-name
  2. Check tool documentation for dependencies
  3. 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:

  1. Check tool's GitHub releases for your platform
  2. Update mise provider configuration
  3. Use alternative installation method

Code Examples

Basic Tool Installation

bash
# Install shfmt with default settings
install_tool_safe "shfmt" "${VER_SHFMT_PROVIDER:-}" "Shfmt" "--version" 0 "*.sh *.bash" ""

Parameters:

  • BIN_NAME: "shfmt" - binary name to verify
  • PROVIDER: mise provider string (e.g., "github:mvdan/sh")
  • DISPLAY_NAME: "Shfmt" - human-readable name for logging
  • VERSION_FLAG: "--version" - flag to check version
  • SKIP_FILE_CHECK: 0 - check for relevant files before installing
  • FILE_PATTERNS: ".sh.bash" - file patterns to check
  • FILE_DIR: "" - directory to search (empty = current directory)

Platform-Specific Tool Installation

bash
# 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

bash
# Install tool with custom version flag
install_tool_safe "tool-name" "${VER_TOOL_PROVIDER:-}" "Tool Name" "-v" 0 "" ""

Skip File Check

bash
# 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:

  • 0 or unset: Normal logging
  • 1: Debug logging enabled

Example:

bash
DEBUG=1 ./scripts/setup.sh

VERBOSE

Control verbosity level.

Values:

  • 0: Minimal output
  • 1: Normal output (default)
  • 2: Verbose output

Example:

bash
VERBOSE=2 ./scripts/setup.sh

CI

Indicates CI environment.

Values:

  • true: CI environment (install all tools)
  • false or unset: Local development (skip optional tools)

Example:

bash
CI=true ./scripts/setup.sh

MISE_OFFLINE

Use mise in offline mode (no network access).

Values:

  • 1: Offline mode enabled
  • 0 or unset: Online mode

Example:

bash
MISE_OFFLINE=1 ./scripts/setup.sh

Performance 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.

References

Released under the MIT License.