gomcc - Go Multi-Component Command launcher
This repo is reachable at https://github.com/mmirko/gomcc.git
A flexible CLI launcher for managing application dependencies and conditional execution based on check results. The project is the AI re-implementation of an old python tool called “mcc” that I wrote several years ago.
Features
-
Two Types of Apps:
- Executable Apps: Standard programs that spawn processes and continue running
- Check Apps: Validation scripts that exit with status codes (0 for success, non-zero for failure)
-
Dependency-Based Execution: Apps can have dependencies on check apps, with different commands executed based on check results
-
Tag-Based Filtering: Organize and filter apps using tags
-
Multiple Execution Modes:
- List all executable apps
- Launch all apps
- Launch apps by tag(s)
- Launch a specific app
- Test a check app
-
Logging Levels: Normal, verbose, and debug modes for different levels of detail
-
Dry-Run Mode: Preview what would be executed without actually running anything
-
Process Independence: Launched processes continue running after gomcc exits
Installation
Build from Source
# Clone the repository
git clone https://github.com/mmirko/gomcc.git
cd gomcc
# Build the binary
go build -o gomcc
# Optional: Install to your PATH
sudo mv gomcc /usr/local/bin/
Configuration File
The configuration file is a JSON file that defines all apps and their dependencies.
Configuration Structure
{
"apps": [
{
"name": "app_name",
"type": "executable|check",
"command": "command_to_execute",
"args": ["arg1", "arg2"],
"tags": ["tag1", "tag2"],
"dependencies": {
"check_app_name": {
"on_success": "command to run if check succeeds",
"on_failure": "command to run if check fails"
}
}
}
]
}
Field Descriptions
- name (required): Unique identifier for the app
- type (required): Either
"check"or"executable" - command (required): The command to execute
- args (optional): Array of command arguments
- tags (optional): Array of tags for filtering and grouping
- dependencies (optional): Map of check app names to dependency actions
- on_success: Command to execute if the check succeeds
- on_failure: Command to execute if the check fails
Usage
Command-Line Options
-f <path> Path to the JSON configuration file (default: ~/.gomcc.json)
-l List executable app names (one per line)
-L List all executable apps with detailed information
-t <tags> Comma-separated list of tags to filter apps
-v Enable verbose mode
-d Enable debug mode (implies verbose)
-r Enable dry-run mode (don't actually execute)
-c <appname> Launch a specific app by name
-g <tagname> Launch all apps with a specific tag
-e <checkapp> Execute and print result of a check app
Examples
1. List Executable Apps
# List app names only (one per line)
gomcc -l
# List with detailed information
gomcc -L
# List from specific config
gomcc -f config.json -l
# List with details from specific config
gomcc -f config.json -L
# List apps filtered by tags
gomcc -l -t web,backend
2. Launch All Apps
# Using default config (~/.gomcc.json)
gomcc
# Using specific config
gomcc -f config.json
3. Launch Apps with Specific Tags
# Launch apps tagged with 'web' or 'backend'
gomcc -f config.json -t web,backend
4. Launch a Specific App
gomcc -f config.json -c myapp
5. Launch All Apps with a Specific Tag
gomcc -f config.json -g production
6. Test a Check App
gomcc -f config.json -e checkapp
7. Dry-Run Mode
# See what would be executed without running anything
gomcc -f config.json -r
8. Verbose Mode
gomcc -f config.json -v
9. Debug Mode
gomcc -f config.json -d
Complete Example
This example demonstrates a program that can run on different hosts based on check results.
Configuration File (config.json)
{
"apps": [
{
"name": "checkonhostA",
"type": "check",
"command": "ping",
"args": ["-c", "1", "hostA"],
"tags": ["hostA"]
},
{
"name": "checkonhostB",
"type": "check",
"command": "ping",
"args": ["-c", "1", "hostB"],
"tags": ["hostB"]
},
{
"name": "startprogramtest",
"type": "executable",
"command": "startprogramtest",
"dependencies": {
"checkonhostA": {
"on_success": "startprogramtest"
},
"checkonhostB": {
"on_success": "ssh hostB startprogramtest"
}
},
"tags": ["program", "test"]
}
]
}
How It Works
- checkonhostA: Pings hostA to check if it’s reachable
- checkonhostB: Pings hostB to check if it’s reachable
- startprogramtest:
- If
checkonhostAsucceeds, runsstartprogramtestlocally - If
checkonhostBsucceeds, runsssh hostB startprogramtestremotely - Can be launched both ways if both checks succeed
- If
Running the Example
# Launch the program
gomcc -f config.json -c startprogramtest
# Dry-run to see what would happen
gomcc -f config.json -c startprogramtest -r -v
# Test individual checks
gomcc -f config.json -e checkonhostA
gomcc -f config.json -e checkonhostB
Advanced Example: Web Application Stack
{
"apps": [
{
"name": "check_docker",
"type": "check",
"command": "docker",
"args": ["info"],
"tags": ["infrastructure"]
},
{
"name": "check_port_80",
"type": "check",
"command": "sh",
"args": ["-c", "! netstat -tuln | grep ':80 '"],
"tags": ["infrastructure"]
},
{
"name": "database",
"type": "executable",
"command": "docker",
"args": ["run", "-d", "--name", "mydb", "postgres:latest"],
"dependencies": {
"check_docker": {
"on_success": "docker run -d --name mydb postgres:latest"
}
},
"tags": ["backend", "database"]
},
{
"name": "webserver",
"type": "executable",
"command": "nginx",
"dependencies": {
"check_port_80": {
"on_success": "nginx"
}
},
"tags": ["web", "frontend"]
},
{
"name": "api_server",
"type": "executable",
"command": "/opt/myapp/api-server",
"args": ["--port", "3000"],
"tags": ["backend", "api"]
}
]
}
Running Different Scenarios
# Launch only backend components
gomcc -f webapp.json -t backend
# Launch only frontend
gomcc -f webapp.json -t frontend
# Launch everything
gomcc -f webapp.json
# Check if Docker is available
gomcc -f webapp.json -e check_docker
# Dry-run the entire stack
gomcc -f webapp.json -r -v
Exit Codes
- 0: All apps launched successfully
- 1: One or more apps failed to launch or configuration error
Tips and Best Practices
-
Use Specific Checks: Create check apps that validate exact prerequisites for your executables
-
Tag Wisely: Use tags to create logical groups (e.g., “production”, “development”, “backend”, “frontend”)
-
Test Checks First: Use the
-eflag to test individual check apps before running the full configuration -
Dry-Run Before Production: Always use
-r -vto preview execution in complex scenarios -
Cache Check Results: gomcc automatically caches check results within a single execution to avoid redundant checks
-
Process Independence: Launched processes are detached and will continue running after gomcc exits
-
Dependency Actions: You can specify both
on_successandon_failureactions for the same dependency to handle both scenarios
Troubleshooting
App Not Launching
# Use debug mode to see detailed execution flow
gomcc -f config.json -c myapp -d
Check Dependencies
# Test individual checks
gomcc -f config.json -e mycheck
Validate Configuration
# Dry-run with debug mode
gomcc -f config.json -r -d
License
See LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit issues or pull requests.