Skip to main content

Creating Tools

Learn how to create custom tool scripts for EnvForge.

Tool Script Template

Start with this template:

#!/bin/bash

# Source utilities
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
source "$PROJECT_ROOT/lib/utils.sh"

# Define packages or resources
apt_packages=("package1" "package2")

# Pre-installation phase
pre_install() {
log_info "Preparing to install <tool-name>..."

# Check if already installed
if command -v <command> &> /dev/null; then
log_info "<tool-name> already installed: $(<command> --version)"
fi
}

# Installation phase
install() {
log_info "Installing <tool-name>..."
install_apt_packages "${apt_packages[@]}"
}

# Post-installation phase
post_install() {
if command -v <command> &> /dev/null; then
log_success "<tool-name> installed: $(<command> --version)"
else
log_error "<tool-name> installation failed"
exit 1
fi
}

# Enable standalone execution
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
pre_install
install
post_install
fi

Step-by-Step Guide

1. Create the Script File

cd ~/.envforge/tools
touch mytool.sh
chmod +x mytool.sh

2. Add Shebang and Imports

#!/bin/bash

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
source "$PROJECT_ROOT/lib/utils.sh"

3. Define What to Install

# For APT packages
apt_packages=("curl" "wget")

# For downloads
DOWNLOAD_URL="https://example.com/tool.tar.gz"
INSTALL_DIR="$HOME/.local/bin"

4. Implement pre_install

pre_install() {
log_info "Checking for MyTool..."

# Check existing installation
if command -v mytool &> /dev/null; then
log_info "MyTool already installed: $(mytool --version)"
return 0
fi

# Validate prerequisites
if ! command -v curl &> /dev/null; then
log_error "curl is required but not installed"
exit 1
fi
}

5. Implement install

install() {
log_info "Installing MyTool..."

# Option 1: APT packages
install_apt_packages "${apt_packages[@]}"

# Option 2: Download and install
# curl -fsSL "$DOWNLOAD_URL" -o /tmp/mytool.tar.gz
# tar -xzf /tmp/mytool.tar.gz -C "$INSTALL_DIR"

# Option 3: Custom installation
# ./configure && make && sudo make install
}

6. Implement post_install

post_install() {
# Verify installation
if command -v mytool &> /dev/null; then
log_success "MyTool installed successfully"
log_info "Version: $(mytool --version)"
else
log_error "MyTool installation failed"
exit 1
fi

# Optional: Additional configuration
# echo "export MYTOOL_HOME=$HOME/.mytool" >> ~/.bashrc
}

7. Add Standalone Support

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
pre_install
install
post_install
fi

Real-World Examples

Example 1: Simple APT Package

#!/bin/bash

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
source "$PROJECT_ROOT/lib/utils.sh"

apt_packages=("git")

pre_install() {
log_info "Installing Git..."
}

install() {
install_apt_packages "${apt_packages[@]}"
}

post_install() {
if command -v git &> /dev/null; then
log_success "Git installed: $(git --version)"
else
log_error "Git installation failed"
exit 1
fi
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
pre_install
install
post_install
fi

Example 2: Download and Install

#!/bin/bash

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
source "$PROJECT_ROOT/lib/utils.sh"

TOOL_VERSION="1.2.3"
DOWNLOAD_URL="https://github.com/user/tool/releases/download/v${TOOL_VERSION}/tool-linux-amd64.tar.gz"
INSTALL_DIR="$HOME/.local/bin"

pre_install() {
log_info "Preparing to install Tool v${TOOL_VERSION}..."

if command -v tool &> /dev/null; then
log_info "Tool already installed: $(tool --version)"
fi

mkdir -p "$INSTALL_DIR"
}

install() {
log_info "Downloading Tool..."
curl -fsSL "$DOWNLOAD_URL" -o /tmp/tool.tar.gz

log_info "Extracting Tool..."
tar -xzf /tmp/tool.tar.gz -C "$INSTALL_DIR"
chmod +x "$INSTALL_DIR/tool"

# Add to PATH
add_to_path "$INSTALL_DIR"
}

post_install() {
# Cleanup
rm -f /tmp/tool.tar.gz

# Verify
if command -v tool &> /dev/null; then
log_success "Tool installed: $(tool --version)"
else
log_error "Tool installation failed"
exit 1
fi
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
pre_install
install
post_install
fi

Example 3: PPA Installation

#!/bin/bash

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
source "$PROJECT_ROOT/lib/utils.sh"

PPA="ppa:git-core/ppa"
apt_packages=("git")

pre_install() {
log_info "Installing Git from PPA..."
}

install() {
log_info "Adding PPA: $PPA"
add_ppa "$PPA"

log_info "Installing Git..."
install_apt_packages "${apt_packages[@]}"
}

post_install() {
if command -v git &> /dev/null; then
log_success "Git installed: $(git --version)"
else
log_error "Git installation failed"
exit 1
fi
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
pre_install
install
post_install
fi

Best Practices

1. Always Verify Installation

post_install() {
if ! command -v mytool &> /dev/null; then
log_error "Installation failed"
exit 1
fi
}

2. Use Logging Functions

log_info "Starting installation..."
log_success "Installation complete"
log_error "Installation failed"

3. Handle Errors Gracefully

install() {
if ! install_apt_packages "${apt_packages[@]}"; then
log_error "Failed to install packages"
exit 1
fi
}

4. Make Scripts Idempotent

pre_install() {
if command -v mytool &> /dev/null; then
log_info "Already installed, skipping..."
exit 0
fi
}

5. Clean Up Temporary Files

post_install() {
rm -f /tmp/mytool.tar.gz
rm -rf /tmp/mytool-build
}

Testing Your Tool

Test Standalone

./tools/mytool.sh

Test in Bundle

Create a test bundle:

name: "Test Bundle"
tools:
- mytool:

Run it:

envforge up --env test.yaml --dry-run
envforge up --env test.yaml

Test with Dependencies

name: "Test with Dependencies"
tools:
- build-essential:
- mytool:
depends_on:
- build-essential

Next Steps