diff --git a/scripts/backup-appfactory.sh b/scripts/backup-appfactory.sh index d1f68a0..258159d 100755 --- a/scripts/backup-appfactory.sh +++ b/scripts/backup-appfactory.sh @@ -1,22 +1,28 @@ #!/usr/bin/env bash set -euo pipefail -BASE_DIR="/opt/appfactory" -BACKUP_DIR="$BASE_DIR/backups" +CONFIG_FILE="/opt/appfactory/config/appfactory.env" +source "$CONFIG_FILE" + TIMESTAMP="$(date +%Y%m%d-%H%M%S)" BACKUP_FILE="$BACKUP_DIR/appfactory-backup-$TIMESTAMP.tar.gz" mkdir -p "$BACKUP_DIR" -tar -czf "$BACKUP_FILE" \ - /opt/appfactory/apps \ - /opt/appfactory/config \ - /opt/appfactory/data/gitea \ - /opt/appfactory/data/registry \ - /opt/appfactory/deploy \ - /opt/appfactory/gateway \ - /opt/appfactory/templates \ - /opt/appfactory/services \ - /home/jiri/workspace - +echo "Creating backup:" +echo "$BACKUP_FILE" + +tar -czf "$BACKUP_FILE" \ + "$APPFACTORY_DIR/apps" \ + "$APPFACTORY_DIR/config" \ + "$APPFACTORY_DIR/data/gitea" \ + "$APPFACTORY_DIR/data/registry" \ + "$APPFACTORY_DIR/deploy" \ + "$APPFACTORY_DIR/gateway" \ + "$APPFACTORY_DIR/templates" \ + "$APPFACTORY_DIR/services" \ + "$WORKSPACE_DIR" + +echo "" +echo "DONE" echo "$BACKUP_FILE" diff --git a/scripts/bootstrap-new-server.sh b/scripts/bootstrap-new-server.sh index f77d9f4..85bff22 100755 --- a/scripts/bootstrap-new-server.sh +++ b/scripts/bootstrap-new-server.sh @@ -10,7 +10,6 @@ WORKSPACE_DIR="/home/$APP_USER/workspace" echo "======================================================" echo "AppFactory Bootstrap" echo "======================================================" -echo "" echo "User: $APP_USER" echo "Workspace: $WORKSPACE_DIR" echo "AppFactory: $APPFACTORY_DIR" @@ -23,74 +22,30 @@ if [ "$CONFIRM" != "yes" ]; then exit 1 fi -echo "" -echo "Updating system..." - apt update -apt install -y \ - docker.io \ - docker-compose-plugin \ - git \ - curl \ - jq \ - python3 \ - python3-pip - -echo "" -echo "Enabling Docker..." +apt install -y docker.io docker-compose-plugin git curl jq python3 python3-pip systemctl enable docker systemctl start docker -echo "" -echo "Adding user to docker group..." - usermod -aG docker "$APP_USER" -echo "" -echo "Creating directories..." - -mkdir -p "$APPFACTORY_DIR" -mkdir -p "$APPFACTORY_DIR/apps" -mkdir -p "$APPFACTORY_DIR/backups" -mkdir -p "$APPFACTORY_DIR/config" -mkdir -p "$APPFACTORY_DIR/data" -mkdir -p "$APPFACTORY_DIR/data/gitea" -mkdir -p "$APPFACTORY_DIR/data/registry" -mkdir -p "$APPFACTORY_DIR/deploy" -mkdir -p "$APPFACTORY_DIR/gateway" -mkdir -p "$APPFACTORY_DIR/gateway/static" -mkdir -p "$APPFACTORY_DIR/services" -mkdir -p "$APPFACTORY_DIR/templates" - +mkdir -p "$APPFACTORY_DIR"/{apps,backups,config,data/gitea,data/registry,deploy,gateway/static,services,templates} mkdir -p "$WORKSPACE_DIR" -echo "" -echo "Creating config..." - -cat > "$APPFACTORY_DIR/config/appfactory.env" < "$APPFACTORY_DIR/config/appfactory.env" <" + echo "Usage: ./delete-app.sh " exit 1 fi CONFIG_FILE="/opt/appfactory/config/appfactory.env" - -if [ -f "$CONFIG_FILE" ]; then - source "$CONFIG_FILE" -fi - -APPFACTORY_DIR="${APPFACTORY_DIR:-/opt/appfactory}" -WORKSPACE_DIR="${WORKSPACE_DIR:-/home/jiri/workspace}" +source "$CONFIG_FILE" COMPOSE_FILE="$APPFACTORY_DIR/deploy/apps-compose.yml" CATALOG_FILE="$APPFACTORY_DIR/apps/catalog.yml" CADDY_FILE="$APPFACTORY_DIR/gateway/Caddyfile" - TOOLS_DIR="$WORKSPACE_DIR/appfactory-tools" echo "Deleting app: $APP_ID" -if [ -n "${GITEA_URL:-}" ] && [ -n "${GITEA_TOKEN:-}" ] && [ -n "${GITEA_ORG:-}" ]; then - echo "Deleting Gitea repository..." - - curl -sS -X DELETE \ - "$GITEA_URL/api/v1/repos/$GITEA_ORG/$APP_ID" \ - -H "Authorization: token $GITEA_TOKEN" || true -fi +echo "Deleting Gitea repository..." +curl -sS -X DELETE \ + "$GITEA_URL/api/v1/repos/$GITEA_ORG/$APP_ID" \ + -H "Authorization: token $GITEA_TOKEN" || true echo "Stopping container..." docker rm -f "$APP_ID" || true @@ -55,61 +44,37 @@ caddy_file = Path(sys.argv[4]) def remove_block(lines, predicate): out = [] i = 0 - while i < len(lines): line = lines[i] - if predicate(line): indent = len(line) - len(line.lstrip()) i += 1 - while i < len(lines): next_line = lines[i] - if next_line.strip(): next_indent = len(next_line) - len(next_line.lstrip()) - if next_indent <= indent: break - i += 1 - continue - out.append(line) i += 1 - return out if compose_file.exists(): - compose_lines = compose_file.read_text().splitlines() - - compose_lines = remove_block( - compose_lines, - lambda l: l.startswith(f" {app_id}:") - ) - - compose_file.write_text("\n".join(compose_lines) + "\n") + lines = compose_file.read_text().splitlines() + lines = remove_block(lines, lambda l: l.startswith(f" {app_id}:")) + compose_file.write_text("\n".join(lines).rstrip() + "\n") if catalog_file.exists(): - catalog_lines = catalog_file.read_text().splitlines() - - catalog_lines = remove_block( - catalog_lines, - lambda l: l.strip() == f"- id: {app_id}" - ) - - catalog_file.write_text("\n".join(catalog_lines) + "\n") + lines = catalog_file.read_text().splitlines() + lines = remove_block(lines, lambda l: l.strip() == f"- id: {app_id}") + catalog_file.write_text("\n".join(lines).rstrip() + "\n") if caddy_file.exists(): - caddy_lines = caddy_file.read_text().splitlines() - - caddy_lines = remove_block( - caddy_lines, - lambda l: f"/apps/{app_id}/*" in l - ) - - caddy_file.write_text("\n".join(caddy_lines) + "\n") + lines = caddy_file.read_text().splitlines() + lines = remove_block(lines, lambda l: f"/apps/{app_id}/*" in l) + caddy_file.write_text("\n".join(lines).rstrip() + "\n") PY echo "Regenerating generated files..." diff --git a/scripts/deploy-app.sh b/scripts/deploy-app.sh index d3e3c1c..5447773 100755 --- a/scripts/deploy-app.sh +++ b/scripts/deploy-app.sh @@ -4,19 +4,12 @@ set -euo pipefail APP_ID="${1:-}" if [ -z "$APP_ID" ]; then - echo "Usage:" - echo " ./deploy-app.sh " + echo "Usage: ./deploy-app.sh " exit 1 fi CONFIG_FILE="/opt/appfactory/config/appfactory.env" - -if [ -f "$CONFIG_FILE" ]; then - source "$CONFIG_FILE" -fi - -APPFACTORY_DIR="${APPFACTORY_DIR:-/opt/appfactory}" -WORKSPACE_DIR="${WORKSPACE_DIR:-/home/jiri/workspace}" +source "$CONFIG_FILE" APP_SOURCE_DIR="$WORKSPACE_DIR/$APP_ID" CATALOG_FILE="$APPFACTORY_DIR/apps/catalog.yml" @@ -32,14 +25,15 @@ if [ ! -f "$APP_SOURCE_DIR/Dockerfile" ]; then exit 1 fi +chown -R "$APP_USER:$APP_GROUP" "$APP_SOURCE_DIR" || true + echo "Updating source code..." cd "$APP_SOURCE_DIR" if [ -d ".git" ]; then + git config --global --add safe.directory "$APP_SOURCE_DIR" || true git fetch origin main git reset --hard origin/main -else - echo "WARNING: $APP_SOURCE_DIR is not a git repository" fi echo "Building Docker image..." @@ -63,7 +57,7 @@ cat >> "$CATALOG_FILE" < "$COMPOSE_FILE" <<'EOF_COMPOSE' services: @@ -11,7 +13,6 @@ EOF_COMPOSE awk ' /- id:/ { app=$3 } - /language:/ { lang=$2 } /status:/ { if (app != "") { print " " app ":" diff --git a/scripts/generate-apps-page.sh b/scripts/generate-apps-page.sh index 6666242..f7b4462 100755 --- a/scripts/generate-apps-page.sh +++ b/scripts/generate-apps-page.sh @@ -1,14 +1,16 @@ #!/usr/bin/env bash set -euo pipefail -BASE_DIR="/opt/appfactory" -CATALOG_FILE="$BASE_DIR/apps/catalog.yml" -OUTPUT_DIR="$BASE_DIR/gateway/static" +CONFIG_FILE="/opt/appfactory/config/appfactory.env" +source "$CONFIG_FILE" + +CATALOG_FILE="$APPFACTORY_DIR/apps/catalog.yml" +OUTPUT_DIR="$APPFACTORY_DIR/gateway/static" OUTPUT_FILE="$OUTPUT_DIR/apps.html" mkdir -p "$OUTPUT_DIR" -cat > "$OUTPUT_FILE" <<'EOF' +cat > "$OUTPUT_FILE" <<'EOF_HTML' @@ -31,7 +33,7 @@ cat > "$OUTPUT_FILE" <<'EOF' Docs Health -EOF +EOF_HTML awk ' function print_row() { @@ -57,10 +59,10 @@ awk ' } ' "$CATALOG_FILE" >> "$OUTPUT_FILE" -cat >> "$OUTPUT_FILE" <<'EOF' +cat >> "$OUTPUT_FILE" <<'EOF_HTML' -EOF +EOF_HTML echo "Generated: $OUTPUT_FILE" diff --git a/scripts/generate-caddyfile.sh b/scripts/generate-caddyfile.sh index e534345..1382f0d 100755 --- a/scripts/generate-caddyfile.sh +++ b/scripts/generate-caddyfile.sh @@ -1,9 +1,11 @@ #!/usr/bin/env bash set -euo pipefail -BASE_DIR="/opt/appfactory" -CATALOG_FILE="$BASE_DIR/apps/catalog.yml" -CADDY_FILE="$BASE_DIR/gateway/Caddyfile" +CONFIG_FILE="/opt/appfactory/config/appfactory.env" +source "$CONFIG_FILE" + +CATALOG_FILE="$APPFACTORY_DIR/apps/catalog.yml" +CADDY_FILE="$APPFACTORY_DIR/gateway/Caddyfile" cat > "$CADDY_FILE" <<'EOF_CADDY' :80 { @@ -48,4 +50,4 @@ cat >> "$CADDY_FILE" <<'EOF_CADDY' } EOF_CADDY -docker exec appfactory-caddy caddy reload --config /etc/caddy/Caddyfile +docker exec appfactory-caddy caddy reload --config /etc/caddy/Caddyfile || docker restart appfactory-caddy diff --git a/scripts/new-python-app.sh b/scripts/new-python-app.sh index 85d5595..4fbea82 100755 --- a/scripts/new-python-app.sh +++ b/scripts/new-python-app.sh @@ -1,24 +1,14 @@ #!/usr/bin/env bash set -euo pipefail -CONFIG_FILE="$HOME/.appfactory/env" - -if [ ! -f "$CONFIG_FILE" ]; then - echo "Missing config file: $CONFIG_FILE" - exit 1 -fi - +CONFIG_FILE="/opt/appfactory/config/appfactory.env" source "$CONFIG_FILE" APP_ID="${1:-}" APP_NAME="${2:-$APP_ID}" if [ -z "$APP_ID" ]; then - echo "Usage:" - echo " ./new-python-app.sh [app-name]" - echo "" - echo "Example:" - echo " ./new-python-app.sh gmail-app \"Gmail App\"" + echo "Usage: ./new-python-app.sh [app-name]" exit 1 fi @@ -48,7 +38,7 @@ id: $APP_ID name: $APP_NAME language: python version: 1.0.0 -base_path: /$APP_ID +base_path: /apps/$APP_ID port: 8000 status: development EOF_APP @@ -57,19 +47,6 @@ cat > README.md </tmp/appfactory-emergency-backup-errors.log || { - echo "Emergency backup failed." - echo "Errors:" - cat /tmp/appfactory-emergency-backup-errors.log - exit 1 - } + "$WORKSPACE_DIR" -echo "" -echo "Emergency backup created." - -echo "" echo "Stopping AppFactory containers..." if [ -d "$APPFACTORY_DIR/deploy" ]; then @@ -102,85 +76,41 @@ if [ -d "$APPFACTORY_DIR/deploy" ]; then docker compose -f docker-compose.yml -f apps-compose.yml down || true fi -echo "" -echo "Restoring files from backup..." - +echo "Restoring backup..." tar -xzf "$BACKUP_FILE" -C / -echo "" echo "Fixing ownership..." - chown -R "$APP_USER:$APP_GROUP" "$APPFACTORY_DIR" chown -R "$APP_USER:$APP_GROUP" "$WORKSPACE_DIR" +chmod 600 "$APPFACTORY_DIR/config/appfactory.env" || true -if [ -f "$APPFACTORY_DIR/config/appfactory.env" ]; then - chmod 600 "$APPFACTORY_DIR/config/appfactory.env" -fi - -echo "" echo "Starting core services..." - cd "$APPFACTORY_DIR/deploy" - docker compose -f docker-compose.yml up -d -echo "" -echo "Regenerating generated files..." - TOOLS_DIR="$WORKSPACE_DIR/appfactory-tools" -if [ ! -d "$TOOLS_DIR" ]; then - echo "Missing tools directory:" - echo "$TOOLS_DIR" - echo "" - echo "Core services started, but app rebuild skipped." - exit 0 -fi +if [ -d "$TOOLS_DIR" ]; then + cd "$TOOLS_DIR" -cd "$TOOLS_DIR" + ./scripts/generate-apps-compose.sh || true + ./scripts/generate-caddyfile.sh || true + ./scripts/generate-apps-page.sh || true -if [ -x "./scripts/generate-apps-compose.sh" ]; then - ./scripts/generate-apps-compose.sh -fi - -if [ -x "./scripts/generate-caddyfile.sh" ]; then - ./scripts/generate-caddyfile.sh -fi - -if [ -x "./scripts/generate-apps-page.sh" ]; then - ./scripts/generate-apps-page.sh -fi - -echo "" -echo "Rebuilding apps from workspace..." - -for app_dir in "$WORKSPACE_DIR"/*; do - if [ -f "$app_dir/app.yml" ]; then - app_id="$(basename "$app_dir")" - - echo "" - echo "Rebuilding app: $app_id" - - if [ -x "$TOOLS_DIR/scripts/deploy-app.sh" ]; then - "$TOOLS_DIR/scripts/deploy-app.sh" "$app_id" || { - echo "WARNING: failed to rebuild app: $app_id" - } + for app_dir in "$WORKSPACE_DIR"/*; do + if [ -f "$app_dir/app.yml" ]; then + app_id="$(basename "$app_dir")" + echo "Rebuilding app: $app_id" + ./scripts/deploy-app.sh "$app_id" || true fi - fi -done + done +fi -echo "" echo "Final compose up..." - cd "$APPFACTORY_DIR/deploy" docker compose -f docker-compose.yml -f apps-compose.yml up -d echo "" echo "DONE" -echo "" echo "Emergency backup:" echo "$EMERGENCY_BACKUP_FILE" -echo "" -echo "Check:" -echo " docker ps" -echo " curl http://localhost/health"