Skip to content

Add airstack CLI tool for developer convenience #272

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions .airstack/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# AirStack CLI Tool

The `airstack` command-line tool provides a unified interface for common development tasks in the AirStack project, including setup, installation, and container management.

## Installation

The `airstack` tool is included in the AirStack repository. To set it up:

1. Clone the AirStack repository:
```bash
git clone https://github.com/castacks/AirStack.git
cd AirStack
```

2. Run the setup command:
```bash
./airstack setup
```

This will add the `airstack` command to your PATH by modifying your shell profile (`.bashrc` or `.zshrc`).

## Basic Usage

```bash
airstack <command> [options]
```

To see all available commands:
```bash
airstack commands
```

To get help for a specific command:
```bash
airstack help <command>
```

## Core Commands

- `install`: Install dependencies (Docker Engine, Docker Compose, etc.)
- `setup`: Configure AirStack settings and add to shell profile
- `launch [service]`: Start services using Docker Compose
- `stop [service]`: Stop services
- `connect [container]`: Connect to a running container (supports partial name matching)
- `status`: Show status of all containers
- `logs [container]`: View logs for a container (supports partial name matching)

### Container Name Matching

The `connect` and `logs` commands support partial name matching for container names. This means you can:

1. Use just a portion of the container name (e.g., `airstack connect web` will match `airstack_web_1`)
2. If multiple containers match, you'll be shown a list and prompted to select one
3. The matching is case-insensitive and supports fuzzy matching

Example:
```bash
$ airstack connect web
[WARN] Multiple containers match 'web'. Please be more specific or select from the list below:
NUM CONTAINER NAME IMAGE STATUS
1 airstack_web_1 nginx:latest Up 2 hours
2 airstack_webapi_1 node:14 Up 2 hours

Options:
1. Enter a number to select a container
2. Type 'q' to quit
3. Press Ctrl+C to cancel and try again with a more specific name

Your selection: 1
[INFO] Connecting to container: airstack_web_1
[INFO] Tip: Next time, you can directly use 'airstack connect airstack_web_1' for this container
```

## Development Commands

- `test`: Run tests
- `docs`: Build documentation
- `lint`: Lint code
- `format`: Format code

## Extending the Tool

The `airstack` tool is designed to be easily extensible. You can add new commands by creating module files in the `.airstack/modules/` directory.

### Creating a New Module

1. Create a new `.sh` file in the `.airstack/modules/` directory:
```bash
touch .airstack/modules/mymodule.sh
```

2. Add your command functions and register them:
```bash
#!/usr/bin/env bash

# Function to implement your command
function cmd_mymodule_mycommand {
log_info "Running my command..."
# Your command implementation here
}

# Register commands from this module
function register_mymodule_commands {
COMMANDS["mycommand"]="cmd_mymodule_mycommand"
COMMAND_HELP["mycommand"]="Description of my command"
}
```

3. Make the module executable:
```bash
chmod +x .airstack/modules/mymodule.sh
```

Your new command will be automatically loaded and available as `airstack mycommand`.

### Available Helper Functions

When creating modules, you can use these helper functions:

- `log_info "message"`: Print an info message
- `log_warn "message"`: Print a warning message
- `log_error "message"`: Print an error message
- `check_docker`: Check if Docker is installed and running

## Configuration

The `airstack` tool stores its configuration in `~/.airstack.conf`. This file is created when you run `airstack setup`.

## License

This tool is part of the AirStack project and is subject to the same license terms.
110 changes: 110 additions & 0 deletions .airstack/modules/config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env bash

# config.sh - Configuration-related commands for AirStack
# This module provides commands for configuring the AirStack environment

# Helper function for confirmation prompts
function confirm_no {
read -r -p "${1:-Are you sure? [y/N]} " response
case "$response" in
[yY][eE][sS]|[yY])
true
;;
*)
false
;;
esac
}

# Function to configure Isaac Sim settings
function cmd_config_isaac_sim {
log_info "Configuring Isaac Sim settings..."

# Generate user.config.json for IsaacSim settings
local USER_CONFIG_JSON_SOURCE="${PROJECT_ROOT}/simulation/isaac-sim/docker/user_TEMPLATE.config.json"
local USER_CONFIG_JSON_DESTINATION="${PROJECT_ROOT}/simulation/isaac-sim/docker/user.config.json"

log_info "Generating Default IsaacSim Config ($USER_CONFIG_JSON_DESTINATION)"

if [ -d "$USER_CONFIG_JSON_DESTINATION" ] && [ $(ls -A "$USER_CONFIG_JSON_DESTINATION" | wc -l) == 0 ]; then
# delete an empty directory with the same name as $USER_CONFIG_JSON_DESTINATION which gets created when
# docker compose up is run before this script. Doing this will create a directory name user.config.json because
# it is being mounted as a volume but it doesn't exist yet.
rm -rf "$USER_CONFIG_JSON_DESTINATION"
fi

if [ -f "$USER_CONFIG_JSON_DESTINATION" ]; then
log_warn "The file $USER_CONFIG_JSON_DESTINATION already exists."
confirm_no "Do you want to reset it to the default? [y/N]" && cp "$USER_CONFIG_JSON_SOURCE" "$USER_CONFIG_JSON_DESTINATION"
else
cp "$USER_CONFIG_JSON_SOURCE" "$USER_CONFIG_JSON_DESTINATION"
fi

log_info "Isaac Sim configuration complete"
}

# Function to configure AirLab Omniverse Nucleus Server Login
function cmd_config_nucleus {
log_info "Configuring AirLab Nucleus Login..."

# AirLab Omniverse Nucleus Server Login Config
local OMNI_PASS_SOURCE="${PROJECT_ROOT}/simulation/isaac-sim/docker/omni_pass_TEMPLATE.env"
local OMNI_PASS_DESTINATION="${PROJECT_ROOT}/simulation/isaac-sim/docker/omni_pass.env"

log_info "Configure AirLab Nucleus Login ($OMNI_PASS_DESTINATION)"

log_info "Go to https://airlab-storage.andrew.cmu.edu:8443/omni/web3/, log in, then right click on the cloud and click the \"API Tokens\" window to generate an API token and paste it here. Leave this blank if you want to skip this step: "
if [ -f "$OMNI_PASS_DESTINATION" ]; then
log_warn "The file $OMNI_PASS_DESTINATION already exists, leave it blank to skip."
fi
read -r -p "API Token: " API_TOKEN

if [ ! -z "${API_TOKEN}" ]; then
sed "s/PASTE-YOUR-API-TOKEN/$API_TOKEN/g" "$OMNI_PASS_SOURCE" > "$OMNI_PASS_DESTINATION"
log_info "Nucleus login configuration complete"
else
log_info "Skipping Nucleus login configuration"
fi
}

# Function to set up Git Hooks
function cmd_config_git_hooks {
log_info "Setting up Git Hooks..."

# Git Hooks
local HOOKS_SOURCE="${PROJECT_ROOT}/git-hooks/docker-versioning/update-docker-image-tag.pre-commit"
local HOOKS_DESTINATION="${PROJECT_ROOT}/.git/hooks/pre-commit"

if [ -f "$HOOKS_SOURCE" ]; then
cp "$HOOKS_SOURCE" "$HOOKS_DESTINATION"
chmod +x "$HOOKS_DESTINATION"
log_info "Git hooks setup complete"
else
log_error "Git hooks source file not found: $HOOKS_SOURCE"
fi
}

# Function to run all configuration tasks
function cmd_config_all {
log_info "Running all configuration tasks..."

cmd_config_isaac_sim
cmd_config_nucleus
cmd_config_git_hooks

log_info "All configuration tasks complete"
}

# Register commands from this module
function register_config_commands {
COMMANDS["config"]="cmd_config_all"
COMMANDS["config:isaac-sim"]="cmd_config_isaac_sim"
COMMANDS["config:nucleus"]="cmd_config_nucleus"
COMMANDS["config:git-hooks"]="cmd_config_git_hooks"

# Add command help
COMMAND_HELP["config"]="Run all configuration tasks"
COMMAND_HELP["config:isaac-sim"]="Configure Isaac Sim settings"
COMMAND_HELP["config:nucleus"]="Configure AirLab Nucleus login"
COMMAND_HELP["config:git-hooks"]="Set up Git hooks"
}
88 changes: 88 additions & 0 deletions .airstack/modules/dev.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env bash

# dev.sh - Development-related commands for AirStack
# This module provides commands for development tasks

# Function to run tests
function cmd_dev_test {
log_info "Running tests..."

local test_path="$PROJECT_ROOT/tests"
local test_filter=""

# Parse arguments
for arg in "$@"; do
if [[ "$arg" == --path=* ]]; then
test_path="${arg#--path=}"
elif [[ "$arg" == --filter=* ]]; then
test_filter="${arg#--filter=}"
fi
done

if [ -n "$test_filter" ]; then
log_info "Running tests matching '$test_filter' in $test_path"
# Add your test command here, e.g.:
# pytest "$test_path" -k "$test_filter"
echo "Test command would run here with filter: $test_filter"
else
log_info "Running all tests in $test_path"
# Add your test command here, e.g.:
# pytest "$test_path"
echo "Test command would run here"
fi
}

# Function to build documentation
function cmd_dev_docs {
log_info "Building documentation..."

# Check if mkdocs is installed
if ! command -v mkdocs &> /dev/null; then
log_warn "mkdocs not found. Installing..."
pip install mkdocs mkdocs-material
fi

# Build documentation
cd "$PROJECT_ROOT"
mkdocs build

# Serve documentation if requested
if [[ "$1" == "serve" ]]; then
log_info "Serving documentation at http://localhost:8000"
mkdocs serve
fi
}

# Function to lint code
function cmd_dev_lint {
log_info "Linting code..."

# Add your linting commands here
# For example:
# flake8 "$PROJECT_ROOT"
echo "Linting command would run here"
}

# Function to format code
function cmd_dev_format {
log_info "Formatting code..."

# Add your formatting commands here
# For example:
# black "$PROJECT_ROOT"
echo "Formatting command would run here"
}

# Register commands from this module
function register_dev_commands {
COMMANDS["test"]="cmd_dev_test"
COMMANDS["docs"]="cmd_dev_docs"
COMMANDS["lint"]="cmd_dev_lint"
COMMANDS["format"]="cmd_dev_format"

# Add command help
COMMAND_HELP["test"]="Run tests (options: --path=PATH, --filter=PATTERN)"
COMMAND_HELP["docs"]="Build documentation (options: serve)"
COMMAND_HELP["lint"]="Lint code"
COMMAND_HELP["format"]="Format code"
}
Loading