Compi
A build system written in Rust.
Features
- Clean TOML structure: Compi uses a clean TOML structure to define tasks.
- Safety: Compi uses dependencies, inputs and outputs defined for the tasks to warn you of potential issues.
- Dependencies: By using dependencies, Compi allows for a clean representation of very complex command chains.
- Parallel execution: Compi runs independent tasks concurrently for faster execution.
Installation
From crates.io
From GitHub
From Source
From GitHub Releases
Download the latest binary for your platform from the GitHub Releases page.
Linux
macOS
Windows
Download the executable from the releases page and add it to your PATH.
CLI Usage
# Run default task
# Run specific task
# Use a different config file
# Verbose output
# Remove outputs after successful execution
# Run with specific number of workers
# Set task timeout and dry run
# Continue on failure with verbose output
# Combine flags
# Show help
Command Options
-f, --file <FILE>
: Configuration file (default:compi.toml
)-v, --verbose
: Enable verbose output--rm
: Remove outputs after successful task execution-j, --workers <N>
: Number of parallel workers (default: CPU cores)-t, --timeout <DURATION>
: Default timeout for tasks (e.g., "30s", "5m")--dry-run
: Show what would be executed without running tasks--continue-on-failure
: Continue running independent tasks when others failTASK
: Task to run
Configuration Format
Create a compi.toml
file in your project root:
Basic Structure
[]
= "build" # Default task to run
= "cache" # Cache directory
= 4 # Number of parallel workers (default: CPU cores)
= "5m" # Default timeout for tasks
[]
= "shell command" # Command to execute
= ["dep1"] # Tasks that must run before this one
= ["src/*.rs"] # Input files
= ["target/app"] # Output files
= false # Automatically remove outputs after successful execution
= "10m" # Task-specific timeout (overrides default)
Example Configuration
[]
= "build"
= ".build-cache"
[]
= "target"
= "myapp"
= "src/**/*.rs"
= "tests/**/*.rs"
[]
= "prep"
= "mkdir -p ${TARGET_DIR}"
= ["${TARGET_DIR}/"]
[]
= "cargo build"
= ["prep"]
= [
"${SOURCE_PATTERN}",
"Cargo.toml"
]
= ["${TARGET_DIR}/debug/${APP_NAME}"]
[]
= "cargo test"
= ["build"]
= ["${SOURCE_PATTERN}", "${TEST_PATTERN}"]
[]
= "rm -rf ${TARGET_DIR}/"
Variables
Compi supports variables for reducing duplication and making configurations more maintainable.
Variable Definition
Define variables in the [variables]
section:
[]
= "target"
= "debug"
= "myapp"
= "src/**/*.rs"
= "--release --target x86_64-unknown-linux-gnu"
Variable Usage
Use variables anywhere in your configuration with ${VAR_NAME}
or $VAR_NAME
syntax:
[]
= "cargo build ${COMPILE_FLAGS}"
= ["${SOURCE_PATTERN}", "Cargo.toml"]
= ["${TARGET_DIR}/${BUILD_TYPE}/${BINARY_NAME}"]
Built-in Variables
Compi provides several built-in variables:
$PWD
: Current working directory$ENV_*
: All environment variables prefixed withENV_
(e.g.,$ENV_HOME
,$ENV_USER
)
Environment Variables
Access environment variables using the ENV_
prefix:
[]
= "${ENV_HOME}"
= "${ENV_USER}"
[]
= "scp app ${ENV_USER}@server:/home/${ENV_USER}/bin/"
Task Fields
Required Fields
command
: Shell command to execute
Optional Fields
id
: Override the task name (defaults to[task.name]
)dependencies
: Array of task names that must run firstinputs
: Array of input files/patterns (supports globs)outputs
: Array of output files this task producesauto_remove
: Automatically remove outputs after successful execution (default:false
)timeout
: Task timeout duration (e.g., "30s", "5m", "1h") - overrides default
Build Logic
Compi uses a 4-tier system to determine if a task should run:
- No inputs: Always run (e.g., cleanup tasks)
- Missing outputs: Must run if any output file doesn't exist
- Outdated outputs: Run if any input is newer than any output
- Content changed: Run if file content hash changed since last run
Glob Patterns
Input files support standard glob patterns:
*.rs
: All Rust files in current directorysrc/**/*.rs
: All Rust files in src and subdirectoriestest/*.{rs,toml}
: Rust and TOML files in test directory
Dependency Management
- Tasks run in topological order based on dependencies
- Independent tasks can execute in parallel using configurable worker pools
- Circular dependencies are detected and reported as errors
- Missing dependencies cause build failure
Output Cleanup
Compi provides two ways to automatically clean up outputs after successful task execution:
CLI Flag
Use the --rm
flag to remove outputs after running a task:
# Remove outputs after building
# Remove outputs with verbose logging
Auto-Remove Field
Set auto_remove = true
in task configuration for automatic cleanup:
[]
= "gcc -o temp_app *.c"
= ["temp_app", "*.o"]
= true # Always clean up after successful execution
[]
= "doxygen"
= ["docs/"]
# Only removed if --rm flag is used
Behavior
- Only on success: Outputs are only removed if the task exits with code 0
- Glob expansion: Patterns like
*.o
are expanded to actual files before removal - Safe deletion: Only the files/directories explicitly listed in outputs are deleted
Cache System
- Stores file content hashes to detect changes
- Configurable location via
cache_dir
in config - Cache location is relative to the config file
Error Handling
- Errors: Stop execution (missing tasks, circular deps, command failures)
- Warnings: Continue execution (missing files, glob errors)
- Info: Verbose mode only (dependency relationships)
Examples
Simple Build Pipeline
[]
= "deploy"
[]
= "gcc *.c -o app"
= ["*.c", "*.h"]
= ["app"]
[]
= "./app --test"
= ["compile"]
= ["app"]
[]
= "scp app server:/"
= ["test"]
= ["app"]
Multi-Language Project
[]
= "all"
[]
= "npm run build"
= ["src/**/*.js", "package.json"]
= ["dist/app.js"]
[]
= "sass src/style.scss dist/style.css"
= ["src/**/*.scss"]
= ["dist/style.css"]
[]
= ["js", "css"]
= "echo 'Build complete'"
Build with Cleanup
[]
= "package"
[]
= "gcc *.c -o app"
= ["*.c", "*.h"]
= ["app", "*.o"]
[]
= "./app --test > test.log"
= ["compile"]
= ["app"]
= ["test.log"]
= true # Always clean up test logs
[]
= "tar -czf app.tar.gz app"
= ["test"]
= ["app"]
= ["app.tar.gz"]
# Usage:
# compi --rm compile # Removes app and *.o files after compilation
# compi test # Automatically removes test.log (auto_remove = true)
# compi package # Keeps app.tar.gz (no cleanup)