Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1) - OpenOCPP extracted (firmware OCPP 1.6J/2.0.1) - ShapeShifter library installed (pip install -e) - ShapeShifter specification extracted - EVerest extracted TODO updated with progress
This commit is contained in:
690
tools/EVerest-main/applications/devrd/devrd
Executable file
690
tools/EVerest-main/applications/devrd/devrd
Executable file
@@ -0,0 +1,690 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
# Default values
|
||||
EVEREST_TOOL_BRANCH="main"
|
||||
# Script directory - where devrd is located
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# .devcontainer directory is always relative to the script location
|
||||
DEVCONTAINER_DIR="${SCRIPT_DIR}/../../.devcontainer"
|
||||
# .env file is always in the .devcontainer directory (relative to script)
|
||||
ENV_FILE="${DEVCONTAINER_DIR}/.env"
|
||||
|
||||
# Function to load HOST_WORKSPACE_FOLDER from .env file
|
||||
# Usage: load_workspace_from_env [fallback]
|
||||
# If fallback is provided and workspace not found in .env, returns fallback
|
||||
# If no fallback provided, returns empty string (for use with ${var:-default} syntax)
|
||||
load_workspace_from_env() {
|
||||
local fallback="$1"
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
local workspace=$(grep "^HOST_WORKSPACE_FOLDER=" "$ENV_FILE" 2>/dev/null | cut -d'=' -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||||
if [ -n "$workspace" ]; then
|
||||
echo "$workspace"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
# If fallback provided and workspace not found, return fallback
|
||||
if [ -n "$fallback" ]; then
|
||||
echo "$fallback"
|
||||
fi
|
||||
}
|
||||
|
||||
# HOST_WORKSPACE_FOLDER is the folder that is mapped to /workspace in the container
|
||||
# Priority: 1) Command line/env var, 2) .env file, 3) Current directory
|
||||
HOST_WORKSPACE_FOLDER="${HOST_WORKSPACE_FOLDER:-$(load_workspace_from_env)}"
|
||||
HOST_WORKSPACE_FOLDER="${HOST_WORKSPACE_FOLDER:-$(pwd)}"
|
||||
|
||||
# Docker Compose project name (defaults to workspace folder name with _devcontainer suffix, can be overridden)
|
||||
# This matches VSC's naming convention: {workspace-folder-name}_devcontainer-{service-name}-1
|
||||
# If needed (and not running in VSCode), can be changed by setting the DOCKER_COMPOSE_PROJECT_NAME environment variable.
|
||||
DOCKER_COMPOSE_PROJECT_NAME="${DOCKER_COMPOSE_PROJECT_NAME:-$(basename "$HOST_WORKSPACE_FOLDER" | tr \"A-Z\" \"a-z\")_devcontainer}"
|
||||
|
||||
|
||||
# Function to detect if running inside container
|
||||
is_inside_container() {
|
||||
# Check for /.dockerenv (standard Docker indicator)
|
||||
[ -f /.dockerenv ] && return 0
|
||||
# Check if /workspace exists and is mounted (devcontainer specific)
|
||||
[ -d /workspace ] && [ -f /workspace/.devcontainer/devrd ] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to show error when command is run from inside container
|
||||
show_inside_container_error() {
|
||||
local cmd_name="${1:-this command}"
|
||||
echo "✖ Error: This command cannot be run from inside the container"
|
||||
echo ""
|
||||
echo "You are currently inside the development container."
|
||||
echo "Please run this command from the host system instead:"
|
||||
echo ""
|
||||
echo " 1. Exit the container (type 'exit' or press Ctrl+D)"
|
||||
echo " 2. Run the command from your host terminal:"
|
||||
echo " ./devrd $cmd_name"
|
||||
echo ""
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Function to run docker compose with static project name
|
||||
# Compose files are always relative to the script's .devcontainer directory
|
||||
docker_compose() {
|
||||
docker compose -p "$DOCKER_COMPOSE_PROJECT_NAME" \
|
||||
-f "${DEVCONTAINER_DIR}/docker-compose.yml" \
|
||||
-f "${DEVCONTAINER_DIR}/general-devcontainer/docker-compose.devcontainer.yml" "$@"
|
||||
}
|
||||
|
||||
# Function to validate folder path
|
||||
validate_folder() {
|
||||
local folder="$1"
|
||||
|
||||
# Convert relative path to absolute
|
||||
case "$folder" in
|
||||
/*) ;; # Already absolute
|
||||
*) folder="$(cd "$folder" && pwd)" ;; # Convert relative to absolute
|
||||
esac
|
||||
|
||||
# Check if folder exists
|
||||
if [ ! -d "$folder" ]; then
|
||||
echo "Error: Folder '$folder' does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if folder is readable
|
||||
if [ ! -r "$folder" ]; then
|
||||
echo "Error: Folder '$folder' is not accessible (permission denied)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$folder"
|
||||
}
|
||||
|
||||
|
||||
# Function to generate .env file
|
||||
generate_env() {
|
||||
if is_inside_container; then
|
||||
show_inside_container_error "env"
|
||||
fi
|
||||
# Process command line options
|
||||
if [ -n "$ENV_OPTIONS" ]; then
|
||||
set -- $ENV_OPTIONS
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
-v|--version)
|
||||
EVEREST_TOOL_BRANCH="$2"
|
||||
shift 2
|
||||
;;
|
||||
-w|--workspace)
|
||||
HOST_WORKSPACE_FOLDER="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
# Set workspace folder
|
||||
if [ -n "$HOST_WORKSPACE_FOLDER" ]; then
|
||||
HOST_WORKSPACE_FOLDER=$(validate_folder "$HOST_WORKSPACE_FOLDER")
|
||||
else
|
||||
HOST_WORKSPACE_FOLDER="$(pwd)"
|
||||
fi
|
||||
|
||||
# Get commit hash
|
||||
COMMIT_HASH=$(git ls-remote https://github.com/EVerest/everest-dev-environment.git ${EVEREST_TOOL_BRANCH} | cut -f1 2>/dev/null || echo "")
|
||||
|
||||
# Check if we need to update existing file
|
||||
local needs_update=false
|
||||
if [ -f "$ENV_FILE" ] && [ -s "$ENV_FILE" ]; then
|
||||
# File exists, check if we have options that require updates
|
||||
if [ -n "$ENV_OPTIONS" ]; then
|
||||
needs_update=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -f "$ENV_FILE" ] || [ ! -s "$ENV_FILE" ] || [ "$needs_update" = true ]; then
|
||||
cat > "$ENV_FILE" << EOF
|
||||
# Auto-generated by devrd script
|
||||
ORGANIZATION_ARG=EVerest
|
||||
REPOSITORY_HOST=github.com
|
||||
REPOSITORY_USER=git
|
||||
COMMIT_HASH=$COMMIT_HASH
|
||||
EVEREST_TOOL_BRANCH=$EVEREST_TOOL_BRANCH
|
||||
UID=$(id -u)
|
||||
GID=$(id -g)
|
||||
HOST_WORKSPACE_FOLDER=$HOST_WORKSPACE_FOLDER
|
||||
EOF
|
||||
if [ "$needs_update" = true ]; then
|
||||
echo "Updated .env file"
|
||||
else
|
||||
echo "Generated .env file"
|
||||
fi
|
||||
else
|
||||
echo "Found existing .env file"
|
||||
cat "$ENV_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to build the container
|
||||
build_container() {
|
||||
if is_inside_container; then
|
||||
show_inside_container_error "build"
|
||||
fi
|
||||
echo "Building development container..."
|
||||
docker_compose --profile all build
|
||||
}
|
||||
|
||||
# Function to get actual port mapping from docker compose
|
||||
get_port_mapping() {
|
||||
local service_name=$1
|
||||
local internal_port=$2
|
||||
|
||||
# Get the actual port mapping from docker compose
|
||||
local port_mapping=$(docker_compose port $service_name $internal_port 2>/dev/null)
|
||||
|
||||
if [ -n "$port_mapping" ]; then
|
||||
# Extract just the host port (remove the host part)
|
||||
echo "$port_mapping" | sed 's/.*://'
|
||||
else
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Function to display container links and tips
|
||||
display_container_status() {
|
||||
echo ""
|
||||
echo "Container Services Summary:"
|
||||
echo "=============================="
|
||||
|
||||
# Get actual port mappings from docker compose
|
||||
local mqtt_explorer_port=$(get_port_mapping mqtt-explorer 4000)
|
||||
local steve_http_port=$(get_port_mapping steve 8180)
|
||||
|
||||
# Display links with actual ports
|
||||
if [ -n "$mqtt_explorer_port" ]; then
|
||||
echo "MQTT Explorer: http://localhost:$mqtt_explorer_port"
|
||||
else
|
||||
echo "MQTT Explorer: currently not running"
|
||||
fi
|
||||
|
||||
if [ -n "$steve_http_port" ]; then
|
||||
echo "Steve (HTTP): http://localhost:$steve_http_port"
|
||||
else
|
||||
echo "Steve (HTTP): currently not running"
|
||||
fi
|
||||
|
||||
# Check if Node-RED is running
|
||||
if docker_compose ps | grep -q "nodered"; then
|
||||
echo "Node-RED UI: http://localhost:1880/ui"
|
||||
else
|
||||
echo "Node-RED UI: currently not running"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Tips:"
|
||||
echo " • MQTT Explorer: Browse and debug MQTT topics"
|
||||
echo " • Steve: OCPP backend management interface"
|
||||
echo " • Node-RED: Web-based UI for SIL simulations"
|
||||
echo " • Use './devrd prompt' to access the container shell"
|
||||
echo " • Use './devrd nodered-flows' to see available flows"
|
||||
echo ""
|
||||
}
|
||||
|
||||
|
||||
# Function to start containers using profiles
|
||||
start_compose_profile() {
|
||||
if is_inside_container; then
|
||||
show_inside_container_error "start"
|
||||
fi
|
||||
local profile_or_service="$1"
|
||||
|
||||
if [ -n "$profile_or_service" ]; then
|
||||
echo "Starting containers for profile/service: $profile_or_service..."
|
||||
docker_compose --profile "$profile_or_service" up -d
|
||||
else
|
||||
echo "Starting the development container and all services..."
|
||||
docker_compose --profile all up -d
|
||||
fi
|
||||
|
||||
# Display workspace mapping
|
||||
echo "Workspace mapping: $HOST_WORKSPACE_FOLDER → /workspace"
|
||||
echo ""
|
||||
|
||||
# Display container links
|
||||
display_container_status
|
||||
}
|
||||
|
||||
# Function to stop containers using profiles or container name pattern
|
||||
stop_compose_profile() {
|
||||
if is_inside_container; then
|
||||
show_inside_container_error "stop"
|
||||
fi
|
||||
local profile_or_pattern="$1"
|
||||
|
||||
if [ -n "$profile_or_pattern" ]; then
|
||||
# Check if it's a valid profile name
|
||||
case "$profile_or_pattern" in
|
||||
mqtt|ocpp|sil|all)
|
||||
echo "Stopping containers for profile: $profile_or_pattern..."
|
||||
docker_compose --profile "$profile_or_pattern" stop
|
||||
;;
|
||||
*)
|
||||
# Treat as container name pattern
|
||||
echo "Stopping containers matching pattern: $profile_or_pattern..."
|
||||
local containers=$(docker ps --format "{{.Names}}" | grep -E "($profile_or_pattern)" || true)
|
||||
if [ -z "$containers" ]; then
|
||||
echo "No running containers found matching pattern: $profile_or_pattern"
|
||||
return 1
|
||||
fi
|
||||
echo "$containers" | while read container; do
|
||||
echo "Stopping container: $container"
|
||||
docker stop "$container" 2>/dev/null || echo "Failed to stop container: $container"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "Stopping the development container and all services..."
|
||||
docker_compose --profile all stop
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to purge everything
|
||||
purge_everything() {
|
||||
if is_inside_container; then
|
||||
show_inside_container_error "purge"
|
||||
fi
|
||||
local purge_pattern="${1:-$(basename "$HOST_WORKSPACE_FOLDER")}"
|
||||
local current_project="$(basename "$HOST_WORKSPACE_FOLDER")"
|
||||
echo "Purging all devcontainer resources for pattern: $purge_pattern..."
|
||||
|
||||
# Only use docker_compose down if purging the current project
|
||||
if [ "$purge_pattern" = "$current_project" ]; then
|
||||
echo "Stopping and removing containers for current project..."
|
||||
docker_compose down -v --remove-orphans
|
||||
else
|
||||
echo "Purging resources for different project pattern: $purge_pattern"
|
||||
echo "Skipping docker-compose cleanup (not current project)"
|
||||
fi
|
||||
|
||||
# Remove all images related to the project
|
||||
echo "Removing devcontainer images..."
|
||||
docker images --format "table {{.Repository}}:{{.Tag}}" | grep -E "($purge_pattern)" | awk '{print $1}' | xargs -r docker rmi -f
|
||||
|
||||
# Remove all volumes related to the project (with force if needed)
|
||||
echo "Removing devcontainer volumes..."
|
||||
docker volume ls --format "{{.Name}}" | grep -E "($purge_pattern)" | while read volume; do
|
||||
echo "Removing volume: $volume"
|
||||
docker volume rm -f "$volume" 2>/dev/null || echo "Volume $volume could not be removed (may be in use)"
|
||||
done
|
||||
|
||||
# Ask user if they want to purge CPM cache volume
|
||||
echo ""
|
||||
echo "CPM source cache volume (everest-cpm-source-cache) is shared across all workspaces."
|
||||
read -p "Do you want to purge the CPM cache volume as well? [y/N]: " purge_cache
|
||||
purge_cache="${purge_cache:-N}"
|
||||
if [[ "$purge_cache" =~ ^[Yy]$ ]]; then
|
||||
echo "Removing CPM cache volume..."
|
||||
if docker volume rm everest-cpm-source-cache 2>/dev/null; then
|
||||
echo "✔ CPM cache volume removed"
|
||||
else
|
||||
echo "⚠ CPM cache volume could not be removed (may be in use or not exist)"
|
||||
fi
|
||||
else
|
||||
echo "Keeping CPM cache volume (will be reused for faster builds)"
|
||||
fi
|
||||
|
||||
# Remove any dangling images and containers
|
||||
echo ""
|
||||
echo "Cleaning up dangling resources..."
|
||||
docker system prune -f
|
||||
|
||||
echo ""
|
||||
echo "✔ Purge complete! All devcontainer resources have been removed."
|
||||
}
|
||||
|
||||
# Function to check if SSH agent is running
|
||||
check_ssh_agent() {
|
||||
if [ -z "$SSH_AUTH_SOCK" ] || ! ssh-add -l >/dev/null 2>&1; then
|
||||
echo "Error: SSH agent is not running or no keys are loaded."
|
||||
echo "Please start the SSH agent and add your keys:"
|
||||
echo " eval \$(ssh-agent)"
|
||||
echo " ssh-add ~/.ssh/id_rsa # or your private key"
|
||||
echo "Or if you're using a different key:"
|
||||
echo " ssh-add ~/.ssh/your_private_key"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to execute a command in the container
|
||||
exec_devcontainer() {
|
||||
if is_inside_container; then
|
||||
echo "✖ You're already inside the container."
|
||||
echo ""
|
||||
echo "To run a command, just execute it directly:"
|
||||
if [ $# -gt 0 ]; then
|
||||
echo " $@"
|
||||
else
|
||||
echo " <your-command>"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
echo "Checking if development container is running..."
|
||||
|
||||
# Check if the devcontainer service is running
|
||||
if ! docker_compose ps devcontainer | grep -q "Up"; then
|
||||
echo "Error: Development container is not running."
|
||||
echo "Please start the container first with: ./devrd start"
|
||||
echo "Or build and start with: ./devrd build && ./devrd start"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Executing command in development container..."
|
||||
run_in_devcontainer "$@"
|
||||
}
|
||||
|
||||
# Function to get a shell prompt in the container
|
||||
prompt_devcontainer() {
|
||||
if is_inside_container; then
|
||||
echo "✖ You're already inside the container shell."
|
||||
exit 1
|
||||
fi
|
||||
echo "Starting shell in development container..."
|
||||
exec_devcontainer /bin/bash
|
||||
}
|
||||
|
||||
# Helper function to check if Node-RED is running and get the URL
|
||||
# Sets nodered_url variable and returns 0 if running, 1 if not
|
||||
check_nodered_running() {
|
||||
if is_inside_container; then
|
||||
nodered_url="http://nodered:1880"
|
||||
curl -s "$nodered_url/flows" >/dev/null 2>&1 && return 0
|
||||
else
|
||||
nodered_url="http://localhost:1880"
|
||||
docker_compose ps | grep -q "nodered" && return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Helper function to execute a command in the container
|
||||
# Usage: run_in_devcontainer [--no-tty] <command> [args...]
|
||||
# Executes directly if inside container, via docker_compose exec if on host
|
||||
# No error checking - assumes container is running when called from host
|
||||
# Use --no-tty for non-interactive commands that need output capture
|
||||
run_in_devcontainer() {
|
||||
local no_tty=false
|
||||
if [ "$1" = "--no-tty" ]; then
|
||||
no_tty=true
|
||||
shift
|
||||
fi
|
||||
|
||||
if is_inside_container; then
|
||||
"$@"
|
||||
else
|
||||
if [ "$no_tty" = true ]; then
|
||||
docker_compose exec -T devcontainer "$@"
|
||||
else
|
||||
docker_compose exec devcontainer "$@"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to list available flows
|
||||
list_nodered_flows() {
|
||||
echo ""
|
||||
echo "Available Node-RED Flows:"
|
||||
echo "============================="
|
||||
|
||||
# Check if Node-RED is running
|
||||
if ! check_nodered_running; then
|
||||
echo "✖ Node-RED container is not running"
|
||||
echo "Please start with './devrd start' first"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Find all flow files in the workspace
|
||||
local flows
|
||||
if is_inside_container; then
|
||||
flows=$(find /workspace -name "*-flow.json" -type f 2>/dev/null | sort)
|
||||
else
|
||||
flows=$(docker_compose exec -T devcontainer find /workspace -name "*-flow.json" -type f 2>/dev/null | sort)
|
||||
fi
|
||||
|
||||
if [ -z "$flows" ]; then
|
||||
echo "No flow files found in workspace"
|
||||
echo ""
|
||||
echo "Expected pattern: *-flow.json"
|
||||
echo "Search location: /workspace"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "Found $(echo "$flows" | wc -l) flow file(s):"
|
||||
echo ""
|
||||
for flow in $flows; do
|
||||
# Remove /workspace/ prefix to get relative path from workspace root
|
||||
local relative_path=$(echo "$flow" | sed 's|^/workspace/||')
|
||||
echo " Path: $relative_path"
|
||||
done
|
||||
echo ""
|
||||
echo "Usage: ./devrd flow <flow-file-path>"
|
||||
echo "Example: ./devrd flow EVerest/config/nodered/config-sil-dc-flow.json"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Function to switch flow using REST API
|
||||
switch_nodered_flow() {
|
||||
local flow_path="$1"
|
||||
|
||||
if [ -z "$flow_path" ]; then
|
||||
echo "Error: Please specify a flow file path"
|
||||
echo ""
|
||||
echo "Available flows:"
|
||||
list_nodered_flows
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if Node-RED is running
|
||||
if ! check_nodered_running; then
|
||||
echo "✖ Node-RED container is not running"
|
||||
echo "Please start with './devrd start' first"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Construct full path in container
|
||||
local full_path="/workspace/$flow_path"
|
||||
|
||||
# Check if file exists and is readable, then copy to temp file
|
||||
if ! run_in_devcontainer --no-tty test -r "$full_path"; then
|
||||
echo "✖ Flow file not found or not readable: $flow_path"
|
||||
echo ""
|
||||
echo "Available flows:"
|
||||
list_nodered_flows
|
||||
return 1
|
||||
fi
|
||||
# Copy flow to temporary file
|
||||
run_in_devcontainer --no-tty cat "$full_path" > /tmp/flows.json
|
||||
|
||||
echo "Switching Node-RED to flow: $(basename "$flow_path")"
|
||||
echo "Source: $flow_path"
|
||||
|
||||
# Process environment variables in the flow JSON
|
||||
# Replace "broker": "localhost" with "broker": "mqtt-server"
|
||||
sed -i 's/"broker": "localhost"/"broker": "mqtt-server"/g' /tmp/flows.json
|
||||
|
||||
# Deploy flow via Node-RED REST API
|
||||
echo "Deploying flow via Node-RED API..."
|
||||
local response=$(curl -s -w "%{http_code}" -X POST "$nodered_url/flows" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @/tmp/flows.json)
|
||||
|
||||
local http_code="${response: -3}"
|
||||
|
||||
if [ "$http_code" = "200" ] || [ "$http_code" = "204" ]; then
|
||||
echo "✔ Node-RED flow deployed successfully via API!"
|
||||
if is_inside_container; then
|
||||
echo "Access at: http://nodered:1880/ui (from container) or http://localhost:1880/ui (from host)"
|
||||
else
|
||||
echo "Access at: http://localhost:1880/ui"
|
||||
fi
|
||||
else
|
||||
echo "✖ Failed to deploy flow via API (HTTP $http_code)"
|
||||
echo "Response: ${response%???}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Clean up temporary file
|
||||
rm -f /tmp/flows.json
|
||||
}
|
||||
|
||||
|
||||
# Function to display help
|
||||
show_help() {
|
||||
echo "Usage: $0 [COMMAND] [OPTIONS]"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " env Generate .env file with repository information (default)"
|
||||
echo " build Build the development container"
|
||||
echo " start [profile] Start containers (profiles: mqtt, ocpp, sil, all)"
|
||||
echo " stop [profile|pattern] Stop containers by profile (mqtt, ocpp, sil, all) or container name pattern"
|
||||
echo " purge [pattern] Remove all devcontainer resources (containers, images, volumes)"
|
||||
echo " Optional pattern to match (default: current folder name)"
|
||||
echo " exec <command> Execute a command in the development container (requires the container to be running)"
|
||||
echo " prompt Get a shell prompt in the development container (requires the container to be running)"
|
||||
echo " flows List available flows"
|
||||
echo " flow <path> Switch to specific flow file"
|
||||
echo ""
|
||||
echo "Options (for env command only):"
|
||||
echo " -v, --version VERSION Everest tool branch (default: $EVEREST_TOOL_BRANCH, preserves existing if not specified)"
|
||||
echo " -w, --workspace DIR Workspace directory to map to /workspace in container (default: current directory)"
|
||||
echo " --help Display this help message"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 env # Generate .env file with repository information"
|
||||
echo " $0 build # Build container"
|
||||
echo " $0 start # Start all containers"
|
||||
echo " $0 start sil # Start SIL simulation tools (Node-RED, MQTT Explorer)"
|
||||
echo " $0 start ocpp # Start OCPP services (Steve, OCPP DB, MQTT)"
|
||||
echo " $0 start mqtt # Start only MQTT server"
|
||||
echo " $0 stop sil # Stop SIL simulation tools"
|
||||
echo " $0 stop ev-ws # Stop all containers matching pattern 'ev-ws'"
|
||||
echo " $0 purge # Remove all devcontainer resources for current folder"
|
||||
echo " $0 purge my-project # Remove all devcontainer resources matching 'my-project'"
|
||||
echo " $0 exec ls -la # Execute command in container"
|
||||
echo " $0 prompt # Get shell prompt in container"
|
||||
echo " $0 flows # List available flows"
|
||||
echo " $0 flow <path> # Switch to specific Node-RED flow file"
|
||||
|
||||
echo " $0 -w ~/Documents # Map Documents folder to /workspace"
|
||||
echo " $0 --workspace /opt/tools # Map tools folder to /workspace"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
COMMAND="env"
|
||||
ENV_OPTIONS=""
|
||||
|
||||
# First pass: collect all options
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
-v|--version|-w|--workspace)
|
||||
# Store env-specific options for later use
|
||||
ENV_OPTIONS="$ENV_OPTIONS $1 $2"
|
||||
shift 2
|
||||
;;
|
||||
--help)
|
||||
show_help
|
||||
;;
|
||||
exec)
|
||||
COMMAND="$1"
|
||||
shift
|
||||
# For exec, pass all remaining arguments to the exec function
|
||||
break
|
||||
;;
|
||||
env|build|prompt|flows)
|
||||
COMMAND="$1"
|
||||
shift
|
||||
# Don't break here, continue to collect more options
|
||||
;;
|
||||
flow)
|
||||
COMMAND="$1"
|
||||
shift
|
||||
# For flow, pass any remaining arguments as flow path
|
||||
break
|
||||
;;
|
||||
purge)
|
||||
COMMAND="$1"
|
||||
shift
|
||||
# For purge, pass any remaining arguments as pattern
|
||||
break
|
||||
;;
|
||||
start|stop)
|
||||
COMMAND="$1"
|
||||
shift
|
||||
# For start/stop, pass any remaining arguments as container name
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
show_help
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Execute the command
|
||||
case $COMMAND in
|
||||
env)
|
||||
# Check SSH agent for Git operations
|
||||
check_ssh_agent
|
||||
generate_env
|
||||
;;
|
||||
build)
|
||||
# Only generate env if .env file doesn't exist or is empty
|
||||
if [ ! -f "$ENV_FILE" ] || [ ! -s "$ENV_FILE" ]; then
|
||||
# Check SSH agent for Git operations
|
||||
check_ssh_agent
|
||||
generate_env
|
||||
fi
|
||||
build_container
|
||||
;;
|
||||
start)
|
||||
# Only generate env if .env file doesn't exist or is empty
|
||||
if [ ! -f "$ENV_FILE" ] || [ ! -s "$ENV_FILE" ]; then
|
||||
# Check SSH agent for Git operations
|
||||
check_ssh_agent
|
||||
generate_env
|
||||
fi
|
||||
start_compose_profile "$@"
|
||||
;;
|
||||
stop)
|
||||
stop_compose_profile "$@"
|
||||
;;
|
||||
purge)
|
||||
purge_everything "$@"
|
||||
;;
|
||||
exec)
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Error: exec command requires arguments"
|
||||
show_help
|
||||
fi
|
||||
exec_devcontainer "$@"
|
||||
;;
|
||||
prompt)
|
||||
prompt_devcontainer
|
||||
;;
|
||||
flows)
|
||||
list_nodered_flows
|
||||
;;
|
||||
flow)
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Error: flow command requires a flow file path"
|
||||
show_help
|
||||
fi
|
||||
switch_nodered_flow "$1"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown command: $COMMAND"
|
||||
show_help
|
||||
;;
|
||||
esac
|
||||
97
tools/EVerest-main/applications/devrd/devrd-completion.bash
Executable file
97
tools/EVerest-main/applications/devrd/devrd-completion.bash
Executable file
@@ -0,0 +1,97 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Bash completion for devrd script
|
||||
# Source this file or add to your .bashrc to enable completion
|
||||
|
||||
_devrd_completion() {
|
||||
local cur prev opts cmds
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
|
||||
# Available commands
|
||||
cmds="install env build start stop prompt purge exec flows flow"
|
||||
|
||||
# Available options
|
||||
opts="-v --version -w --workspace --help"
|
||||
|
||||
# Function to get available Node-RED flows dynamically
|
||||
_get_nodered_flows() {
|
||||
# Get the current project name (same logic as devrd script)
|
||||
local project_name="${DOCKER_COMPOSE_PROJECT_NAME:-$(basename "$(pwd)")_devcontainer}"
|
||||
|
||||
# Check if we're in the right directory and container is running
|
||||
if [ -f "devrd" ] && docker compose -p "$project_name" -f .devcontainer/docker-compose.yml -f .devcontainer/general-devcontainer/docker-compose.devcontainer.yml ps devcontainer | grep -q "Up"; then
|
||||
# Get flows from the container and return full paths (relative to workspace)
|
||||
docker compose -p "$project_name" -f .devcontainer/docker-compose.yml -f .devcontainer/general-devcontainer/docker-compose.devcontainer.yml exec -T devcontainer find /workspace -name "*-flow.json" -type f 2>/dev/null | sed 's|/workspace/||' | sort
|
||||
else
|
||||
# Fallback to common flow file paths
|
||||
echo "EVerest/config/nodered/config-sil-dc-flow.json"
|
||||
echo "EVerest/config/nodered/config-sil-dc-bpt-flow.json"
|
||||
echo "EVerest/config/nodered/config-sil-energy-management-flow.json"
|
||||
echo "EVerest/config/nodered/config-sil-two-evse-flow.json"
|
||||
echo "EVerest/config/nodered/config-sil-flow.json"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to get available container names
|
||||
_get_container_names() {
|
||||
echo "mqtt ocpp sil"
|
||||
}
|
||||
|
||||
# If the previous word is an option that takes an argument, complete based on the option
|
||||
case "$prev" in
|
||||
|
||||
-v|--version)
|
||||
# Complete with common version patterns
|
||||
COMPREPLY=( $(compgen -W "main master develop release/1.0 release/1.1" -- "$cur") )
|
||||
return 0
|
||||
;;
|
||||
-w|--workspace)
|
||||
# Complete directories
|
||||
COMPREPLY=( $(compgen -d -- "$cur") )
|
||||
return 0
|
||||
;;
|
||||
flow)
|
||||
# Complete with available flow file paths dynamically
|
||||
local flows
|
||||
flows=$(_get_nodered_flows)
|
||||
COMPREPLY=( $(compgen -W "$flows" -- "$cur") )
|
||||
return 0
|
||||
;;
|
||||
start|stop)
|
||||
# Complete with available container names
|
||||
local containers
|
||||
containers=$(_get_container_names)
|
||||
COMPREPLY=( $(compgen -W "$containers" -- "$cur") )
|
||||
return 0
|
||||
;;
|
||||
exec)
|
||||
# For exec command, complete with common commands
|
||||
COMPREPLY=( $(compgen -W "ls pwd cd cmake ninja make" -- "$cur") )
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# If we're completing the first word (command), show commands
|
||||
if [ $COMP_CWORD -eq 1 ]; then
|
||||
COMPREPLY=( $(compgen -W "$cmds" -- "$cur") )
|
||||
return 0
|
||||
fi
|
||||
|
||||
# If we're completing an option, show options
|
||||
if [[ "$cur" == -* ]]; then
|
||||
COMPREPLY=( $(compgen -W "$opts" -- "$cur") )
|
||||
return 0
|
||||
fi
|
||||
|
||||
# For other cases, complete with files/directories
|
||||
COMPREPLY=( $(compgen -f -- "$cur") )
|
||||
return 0
|
||||
}
|
||||
|
||||
# Register the completion function
|
||||
complete -F _devrd_completion devrd
|
||||
complete -F _devrd_completion ./devrd
|
||||
complete -F _devrd_completion ../devrd
|
||||
complete -F _devrd_completion ./applications/devrd/devrd
|
||||
90
tools/EVerest-main/applications/devrd/devrd-completion.zsh
Executable file
90
tools/EVerest-main/applications/devrd/devrd-completion.zsh
Executable file
@@ -0,0 +1,90 @@
|
||||
#!/bin/zsh
|
||||
|
||||
# Zsh completion for devrd script
|
||||
# Source this file or add to your .zshrc to enable completion
|
||||
|
||||
_devrd_completion() {
|
||||
local context state line
|
||||
typeset -A opt_args
|
||||
|
||||
# Available commands
|
||||
local commands=(
|
||||
'env:Generate .env file with repository information'
|
||||
'build:Build the development container'
|
||||
'start:Start containers (profiles: mqtt, ocpp, sil)'
|
||||
'stop:Stop containers (profiles: mqtt, ocpp, sil)'
|
||||
'purge:Remove all devcontainer resources (containers, images, volumes)'
|
||||
'exec:Execute a command in the container'
|
||||
'prompt:Get a shell prompt in the container'
|
||||
'flows:List available flows'
|
||||
'flow:Switch to specific flow file'
|
||||
)
|
||||
|
||||
# Available options
|
||||
local options=(
|
||||
'-v[Everest tool branch]:version:'
|
||||
'--version[Everest tool branch]:version:'
|
||||
'-w[Workspace directory]:directory:_files -/'
|
||||
'--workspace[Workspace directory]:directory:_files -/'
|
||||
'--help[Display help message]'
|
||||
)
|
||||
|
||||
# Function to get available Node-RED flows dynamically
|
||||
_get_nodered_flows() {
|
||||
# Get the current project name (same logic as devrd script)
|
||||
local project_name="${DOCKER_COMPOSE_PROJECT_NAME:-$(basename "$(pwd)")_devcontainer}"
|
||||
|
||||
# Check if we're in the right directory and container is running
|
||||
if [ -f "devrd" ] && docker compose -p "$project_name" -f .devcontainer/docker-compose.yml -f .devcontainer/general-devcontainer/docker-compose.devcontainer.yml ps devcontainer | grep -q "Up"; then
|
||||
# Get flows from the container and return full paths (relative to workspace)
|
||||
docker compose -p "$project_name" -f .devcontainer/docker-compose.yml -f .devcontainer/general-devcontainer/docker-compose.devcontainer.yml exec -T devcontainer find /workspace -name "*-flow.json" -type f 2>/dev/null | sed 's|/workspace/||' | sort
|
||||
else
|
||||
# Fallback to common flow file paths
|
||||
echo "EVerest/config/nodered/config-sil-dc-flow.json"
|
||||
echo "EVerest/config/nodered/config-sil-dc-bpt-flow.json"
|
||||
echo "EVerest/config/nodered/config-sil-energy-management-flow.json"
|
||||
echo "EVerest/config/nodered/config-sil-two-evse-flow.json"
|
||||
echo "EVerest/config/nodered/config-sil-flow.json"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to get available container names
|
||||
_get_container_names() {
|
||||
echo "mqtt ocpp sil"
|
||||
}
|
||||
|
||||
# Main completion logic
|
||||
_arguments -C \
|
||||
"$options[@]" \
|
||||
"1: :{_describe 'commands' commands}" \
|
||||
"*::arg:->args"
|
||||
|
||||
case $state in
|
||||
args)
|
||||
case $line[1] in
|
||||
flow)
|
||||
_values 'flow files' $(_get_nodered_flows)
|
||||
;;
|
||||
start|stop)
|
||||
_values 'profiles' $(_get_container_names)
|
||||
;;
|
||||
exec)
|
||||
_values 'commands' 'ls' 'pwd' 'cd' 'cmake' 'ninja' 'make'
|
||||
;;
|
||||
purge)
|
||||
_files
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Register the completion function
|
||||
if command -v compdef >/dev/null 2>&1; then
|
||||
compdef _devrd_completion devrd
|
||||
compdef _devrd_completion ./devrd
|
||||
compdef _devrd_completion ../devrd
|
||||
compdef _devrd_completion ./applications/devrd/devrd
|
||||
else
|
||||
echo "Warning: zsh completion system not loaded. Add 'autoload -U compinit && compinit' to your .zshrc"
|
||||
fi
|
||||
Reference in New Issue
Block a user