Files
robot-plugins/validate.sh

398 lines
9.7 KiB
Bash
Executable File

#!/bin/bash
# HRIStudio Plugin Repository Validation Script
# This script provides convenient commands for plugin development and validation
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
log() {
echo -e "${BLUE}[INFO]${NC} $1"
}
success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Check if Node.js is available
check_node() {
if ! command -v node &> /dev/null; then
error "Node.js is required but not installed."
error "Please install Node.js from https://nodejs.org/"
exit 1
fi
}
# Validate JSON syntax
validate_json() {
local file="$1"
if ! node -e "JSON.parse(require('fs').readFileSync('$file', 'utf8'))" 2>/dev/null; then
error "Invalid JSON syntax in $file"
return 1
fi
return 0
}
# Validate all JSON files
validate_json_files() {
log "Validating JSON syntax..."
local valid=true
for file in repository.json plugins/*.json; do
if [ -f "$file" ]; then
if validate_json "$file"; then
success "$file"
else
error "$file"
valid=false
fi
fi
done
if [ "$valid" = true ]; then
success "All JSON files have valid syntax"
else
error "Some JSON files have syntax errors"
return 1
fi
}
# Validate plugins using the Node.js script
validate_plugins() {
log "Validating plugins..."
check_node
if [ ! -f "scripts/validate-plugin.js" ]; then
error "Plugin validator script not found: scripts/validate-plugin.js"
return 1
fi
node scripts/validate-plugin.js validate-all
}
# Update plugin index
update_index() {
log "Updating plugin index..."
check_node
if [ ! -f "scripts/validate-plugin.js" ]; then
error "Plugin validator script not found: scripts/validate-plugin.js"
return 1
fi
node scripts/validate-plugin.js update-index
}
# Start local development server
serve() {
local port="${1:-8080}"
log "Starting development server on port $port..."
if command -v python3 &> /dev/null; then
log "Using Python 3 HTTP server"
python3 -m http.server "$port"
elif command -v python &> /dev/null; then
log "Using Python HTTP server"
python -m SimpleHTTPServer "$port"
elif command -v node &> /dev/null; then
log "Using Node.js http-server (install with: npm install -g http-server)"
if command -v http-server &> /dev/null; then
http-server -p "$port" -c-1
else
error "http-server not found. Install with: npm install -g http-server"
exit 1
fi
else
error "No suitable HTTP server found. Please install Python or Node.js with http-server"
exit 1
fi
}
# Test the repository
test_repo() {
log "Running repository tests..."
# Validate JSON syntax
validate_json_files || return 1
# Validate plugins
validate_plugins || return 1
# Check assets exist
log "Checking asset files..."
local missing_assets=false
for plugin_file in plugins/*.json; do
if [ "$plugin_file" = "plugins/index.json" ] || [ "$plugin_file" = "plugins/*.json" ]; then
continue
fi
local plugin_name=$(basename "$plugin_file" .json)
log "Checking assets for $plugin_name..."
# Extract asset paths and check they exist
if [ -f "$plugin_file" ]; then
local thumbnail=$(node -e "
const plugin = JSON.parse(require('fs').readFileSync('$plugin_file', 'utf8'));
console.log(plugin.assets?.thumbnailUrl || '');
")
if [ -n "$thumbnail" ] && [ ! -f "$thumbnail" ]; then
warn "Missing thumbnail: $thumbnail"
missing_assets=true
fi
fi
done
if [ "$missing_assets" = true ]; then
warn "Some assets are missing - this may cause display issues"
fi
# Test web interface
log "Testing web interface..."
if command -v curl &> /dev/null; then
# Start server in background
python3 -m http.server 8000 &>/dev/null &
local server_pid=$!
# Wait for server to start
sleep 2
# Test endpoints
if curl -sf http://localhost:8000/index.html >/dev/null 2>&1; then
success "✓ Web interface accessible"
else
error "✗ Web interface not accessible"
fi
if curl -sf http://localhost:8000/repository.json >/dev/null 2>&1; then
success "✓ Repository metadata accessible"
else
error "✗ Repository metadata not accessible"
fi
# Cleanup
kill $server_pid 2>/dev/null || true
else
warn "curl not available - skipping web interface test"
fi
success "Repository validation completed"
}
# Build for production
build() {
log "Building repository for production..."
# Validate everything first
test_repo || return 1
# Update index
update_index
# Optimize JSON files (remove extra whitespace)
log "Optimizing JSON files..."
for file in repository.json plugins/*.json; do
if [ -f "$file" ]; then
node -e "
const fs = require('fs');
const data = JSON.parse(fs.readFileSync('$file', 'utf8'));
fs.writeFileSync('$file', JSON.stringify(data));
"
success "✓ Optimized $file"
fi
done
success "Build completed - repository is ready for production"
}
# Create a new plugin template
create_plugin() {
local robot_id="$1"
if [ -z "$robot_id" ]; then
error "Usage: $0 create <robot-id>"
error "Example: $0 create my-robot"
exit 1
fi
local plugin_file="plugins/${robot_id}.json"
local asset_dir="assets/${robot_id}"
if [ -f "$plugin_file" ]; then
error "Plugin already exists: $plugin_file"
exit 1
fi
log "Creating plugin template for $robot_id..."
# Create asset directory
mkdir -p "$asset_dir"
# Create plugin template
cat > "$plugin_file" << EOF
{
"robotId": "$robot_id",
"name": "Robot Name",
"description": "Description of the robot platform",
"platform": "ROS2",
"version": "1.0.0",
"pluginApiVersion": "1.0",
"hriStudioVersion": ">=0.1.0",
"trustLevel": "community",
"category": "mobile-robot",
"manufacturer": {
"name": "Manufacturer Name",
"website": "https://example.com",
"support": "https://example.com/support"
},
"documentation": {
"mainUrl": "https://example.com/docs"
},
"assets": {
"thumbnailUrl": "$asset_dir/thumb.png",
"images": {
"main": "$asset_dir/main.jpg"
}
},
"specs": {
"dimensions": {
"length": 0.5,
"width": 0.3,
"height": 0.2,
"weight": 5.0
},
"capabilities": ["example_capability"]
},
"actions": [
{
"id": "example_action",
"name": "Example Action",
"description": "An example action for demonstration",
"category": "movement",
"icon": "move",
"timeout": 30000,
"retryable": true,
"parameterSchema": {
"type": "object",
"properties": {
"parameter": {
"type": "string",
"default": "value",
"description": "Example parameter"
}
},
"required": ["parameter"]
},
"ros2": {
"messageType": "std_msgs/msg/String",
"topic": "/example_topic",
"payloadMapping": {
"type": "transform",
"transformFn": "exampleTransform"
}
}
}
]
}
EOF
success "✓ Created plugin template: $plugin_file"
success "✓ Created asset directory: $asset_dir"
warn "Don't forget to:"
warn " 1. Edit the plugin details in $plugin_file"
warn " 2. Add robot images to $asset_dir/"
warn " 3. Run './validate.sh update-index' to include the plugin"
warn " 4. Run './validate.sh validate' to check your plugin"
}
# Show help
show_help() {
cat << EOF
HRIStudio Plugin Repository Development Tools
Usage: $0 <command> [arguments]
Commands:
validate Validate all plugins and repository metadata
update-index Update plugins/index.json with all plugin files
serve [port] Start local development server (default port: 8080)
test Run full test suite
build Build and optimize for production
create <robot-id> Create a new plugin template
help Show this help message
Examples:
$0 validate # Validate all plugins
$0 serve 3000 # Start server on port 3000
$0 create my-robot # Create new plugin template
$0 test # Run all tests
$0 build # Build for production
Requirements:
- Node.js (for plugin validation)
- Python 3 or Python 2 (for development server)
- curl (for testing, optional)
EOF
}
# Main command dispatcher
main() {
case "${1:-help}" in
validate)
validate_plugins
;;
update-index)
update_index
;;
serve)
serve "${2:-8080}"
;;
test)
test_repo
;;
build)
build
;;
create)
create_plugin "$2"
;;
help|--help|-h)
show_help
;;
*)
error "Unknown command: $1"
echo
show_help
exit 1
;;
esac
}
# Run main function with all arguments
main "$@"