5.4 KiB
5.4 KiB
| name | title | description |
|---|---|---|
| build-script-modularization | Build Script Modularization and Database Separation | Guidelines for separating database setup from application build scripts and implementing modular processing loops |
Build Script Modularization and Database Separation
Problem Statement
Build scripts often fail in production environments because they attempt to create databases using root privileges, which is both a security risk and often fails due to permission restrictions. Additionally, repetitive code for processing multiple modules reduces maintainability.
Solution Approach
1. Separate Database Setup
- Create an external
setup_database.shscript that handles:- Database creation
- User creation
- Permission grants
- This script requires root privileges and should be run separately
2. External Password Encryption
- Create a dedicated encryption script (
encrypt_password.py) that:- Uses the application's encryption library (e.g., apppublic)
- Reads existing config files to get encryption keys
- Updates configuration with encrypted passwords
- Provides fallback mechanisms for encryption failures
3. Modular Processing Loop
- Define modules as an array:
MODULES=("module1" "module2" "module3") - Use a for loop to process each module uniformly:
- Clone/install modules
- Generate database DDL from models
- Generate CRUD UI from JSON definitions
- Handle module-specific logic with conditional checks
4. Three-Step Deployment Process
- Database Setup: Run external database script with root privileges
- Configuration Encryption: Encrypt sensitive data and update configs
- Application Build: Run main build script without elevated privileges
Implementation Template
setup_database.sh
#!/usr/bin/env bash
set -e
DB_NAME="your_db"
DB_USER="your_user"
DB_PASS="secure_password"
mysql -u root -e "CREATE DATABASE IF NOT EXISTS ${DB_NAME} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
mysql -u root -e "CREATE USER IF NOT EXISTS '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';"
mysql -u root -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'localhost';"
mysql -u root -e "FLUSH PRIVILEGES;"
encrypt_password.py
#!/usr/bin/env python3
import json
import sys
def encrypt_password(password, key):
# Use application-specific encryption library
# Provide fallback if library unavailable
pass
# Read config, encrypt password, update config file
build.sh (modular version)
#!/usr/bin/env bash
set -e
MODULES=("appbase" "rbac" "contract_management")
for modulename in "${MODULES[@]}"; do
echo "Processing ${modulename}..."
# Uniform processing logic for all modules
done
Benefits
- Security: No root privileges needed during application build
- Maintainability: Single code path for all modules
- Reliability: Clear separation of concerns reduces failure points
- Reusability: Pattern applies to any multi-module application
Common Pitfalls
- Forgetting to update config files after password encryption
- Not handling module-specific installation differences (git vs local copy)
- Assuming MySQL connection details are always available during build
- Missing error handling for missing model or JSON files
- Case sensitivity issues: On Linux systems, Python import statements are case-sensitive.
from appPublic.jsonconfigwill fail if the actual file isjsonConfig.py. Always verify exact module names by inspecting the source repository structure.
Sage Module Build Pattern
For Sage platform modules, follow this standard build.sh structure:
Standard Sage build.sh Template
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Find Sage root (try multiple candidates)
SAGE_ROOT=""
for candidate in "$SCRIPT_DIR/../.." "$HOME/repos/sage" "$HOME/sage"; do
if [ -d "$candidate/wwwroot" ] && [ -d "$candidate/py3/bin" ]; then
SAGE_ROOT="$(cd "$candidate" && pwd)"
break
fi
done
if [ -z "$SAGE_ROOT" ]; then
echo "ERROR: Sage root not found"
exit 1
fi
echo "Sage root: $SAGE_ROOT"
# Generate DDL from model JSON files
if [ -d "$SCRIPT_DIR/models" ]; then
echo "Generating DDL from models..."
cd "$SCRIPT_DIR/models"
if ls *.json 1>/dev/null 2>&1; then
"$SAGE_ROOT/py3/bin/json2ddl" mysql . > mysql.ddl.sql
echo "DDL generated: models/mysql.ddl.sql"
fi
fi
# Link wwwroot to Sage via symlink (not copy)
echo "Linking wwwroot to Sage..."
rm -f "$SAGE_ROOT/wwwroot/<module_name>"
ln -sf "$SCRIPT_DIR/wwwroot" "$SAGE_ROOT/wwwroot/<module_name>"
echo "<Module Name> build complete."
Key Sage Build Patterns
- Sage Root Detection: Check for both
wwwroot/andpy3/bin/directories to confirm valid Sage installation - DDL Generation: Use
$SAGE_ROOT/py3/bin/json2ddl mysql .in the models/ directory to generate SQL from JSON model definitions - wwwroot Linking: Always use symlinks (
ln -sf), never copy files - this keeps modules in sync during development - Model Directory: JSON model files live in
models/*.json, DDL output goes tomodels/mysql.ddl.sql - Module Naming: Replace
<module_name>with your actual module name (e.g.,sage_datamart,dashboard_for_sage)
Examples from Sage Codebase
supplychain/build.sh- includes CRUD UI generation from json/ definitionsdashboard_for_sage/build.sh- includes pip install and API file linking