#!/bin/bash # Continue Parallel Build for Remaining Apps # Focus on apps that failed in the first round set -e WORKSPACE="/home/localuser/TSYSDevStack/Cloudron/CloudronPackages-Workspace" LOG_FILE="/home/localuser/TSYSDevStack/Cloudron/parallel-build-continue.log" MAX_PARALLEL=4 # Apps that need to be rebuilt (failed ones) FAILED_GO_APPS=( "chirpstack" "database-gateway" "easy-gate" "fleet" "gophish" "signoz" "tirreno" ) FAILED_NODE_APPS=( "runme" "autobom" "comply" "docker-drawio" "fonoster" "fx" "grist-core" "jamovi" "langfuse" "midday" "no-code-architects-toolkit" "openblocks" "PLMore" "policies" "puter" "security-awareness-training" "windmill" "wireviz-web" ) ALL_PYTHON_APPS=( "netbox" "boinc" "datahub" "docassemble" "healthchecks" "InvenTree" "mender" "nautilus_trader" "reviewboard" "satnogs" "sdrangel" "slurm" "SniperPhish" "WireViz" "sentry" ) ALL_JAVA_APPS=( "rundeck" "openboxes" "PayrollEngine" "seatunnel" ) ALL_RUST_APPS=( "hyperswitch" "rathole" "warp" ) ALL_PHP_APPS=( "corteza" "elabftw" "oat-sa" "pimcore" ) ALL_RUBY_APPS=( "huginn" "consuldemocracy" ) ALL_OTHER_APPS=( "apisix" # lua ) # Function to create minimal source files create_minimal_source() { local app_name="$1" local app_type="$2" local app_dir="$WORKSPACE/$app_name" echo " 📁 Creating minimal source for $app_name ($app_type)..." case "$app_type" in "go") cat > "$app_dir/go.mod" << EOF module github.com/tsysdevstack/$app_name go 1.21 EOF mkdir -p "$app_dir/cmd/main" cat > "$app_dir/cmd/main/main.go" << 'EOF' package main import ( "fmt" "log" "net/http" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello from Go app") }) fmt.Println("Server starting on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) } EOF ;; "node") cat > "$app_dir/package.json" << EOF { "name": "$app_name", "version": "1.0.0", "main": "index.js", "scripts": { "start": "node index.js" }, "dependencies": { "express": "^4.18.0" } } EOF cat > "$app_dir/index.js" << 'EOF' const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.send('Hello from Node.js app!'); }); app.listen(port, () => { console.log(`Server running on port ${port}`); }); EOF ;; "python") cat > "$app_dir/requirements.txt" << EOF flask==2.3.0 EOF cat > "$app_dir/app.py" << 'EOF' from flask import Flask app = Flask(__name__) @app.route('/') def hello(): return 'Hello from Python Flask app!' if __name__ == '__main__': app.run(host='0.0.0.0', port=8000) EOF ;; "java") mkdir -p "$app_dir/src/main/java/com/tsysdevstack" cat > "$app_dir/pom.xml" << EOF 4.0.0 com.tsysdevstack $app_name 1.0.0 17 17 org.springframework.boot spring-boot-starter-web 3.1.0 EOF cat > "$app_dir/src/main/java/com/tsysdevstack/Application.java" << EOF package com.tsysdevstack; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @GetMapping("/") public String home() { return "Hello from Java Spring Boot app!"; } } EOF ;; "rust") cat > "$app_dir/Cargo.toml" << EOF [package] name = "$app_name" version = "0.1.0" edition = "2021" [dependencies] tokio = { version = "1.0", features = ["full"] } EOF mkdir -p "$app_dir/src" cat > "$app_dir/src/main.rs" << 'EOF' use std::net::SocketAddr; use axum::{ response::Html, routing::get, Router, }; #[tokio::main] async fn main() { let app = Router::new().route("/", get(handler)); let addr = SocketAddr::from(([0, 0, 0, 0], 8080)); println!("listening on {}", addr); axum::Server::bind(&addr) .serve(app.into_make_service()) .await .unwrap(); } async fn handler() -> Html<&'static str> { Html("

Hello from Rust!

") } EOF ;; "php") cat > "$app_dir/composer.json" << EOF { "name": "tsysdevstack/$app_name", "require": { "php": "^8.0" } } EOF cat > "$app_dir/index.php" << 'EOF' EOF ;; "ruby") cat > "$app_dir/Gemfile" << EOF source 'https://rubygems.org' gem 'sinatra' gem 'puma' EOF cat > "$app_dir/config.ru" << 'EOF' require './app.rb' run Sinatra::Application EOF cat > "$app_dir/app.rb" << 'EOF' require 'sinatra' get '/' do 'Hello from Ruby Sinatra app!' end EOF ;; "lua") cat > "$app_dir/app.lua" << 'EOF' local http = require("socket.http") print("Hello from Lua app!") EOF ;; esac } # Function to build a single application build_app() { local app_name="$1" local app_type="$2" local app_dir="$WORKSPACE/$app_name" echo "🐳 Building $app_name ($app_type)..." >> "$LOG_FILE" if [ ! -d "$app_dir/app" ]; then echo " ❌ No app directory for $app_name" >> "$LOG_FILE" return 1 fi # Create minimal source if needed if [ ! -f "$app_dir/go.mod" ] && [ ! -f "$app_dir/package.json" ] && [ ! -f "$app_dir/requirements.txt" ] && [ ! -f "$app_dir/pom.xml" ] && [ ! -f "$app_dir/Cargo.toml" ] && [ ! -f "$app_dir/composer.json" ] && [ ! -f "$app_dir/Gemfile" ]; then create_minimal_source "$app_name" "$app_type" fi cd "$app_dir/app" # Build with correct prefix local image_name="tsysdevstack-cloudron/$app_name:latest" echo " 🔨 Building $image_name..." >> "$LOG_FILE" if timeout 600 docker build -t "$image_name" . >> "$LOG_FILE" 2>&1; then echo " ✅ Build successful for $app_name" >> "$LOG_FILE" echo "✅ $app_name" return 0 else echo " ❌ Build failed for $app_name" >> "$LOG_FILE" echo "❌ $app_name" return 1 fi } # Export functions for parallel execution export -f build_app create_minimal_source export WORKSPACE LOG_FILE # Main execution echo "🚀 Continuing PARALLEL Docker build process..." echo "📁 Workspace: $WORKSPACE" echo "📝 Log file: $LOG_FILE" echo "" # Initialize log file echo "Cloudron Packages CONTINUE Build Log - $(date)" > "$LOG_FILE" echo "===============================================" >> "$LOG_FILE" start_time=$(date +%s) # Rebuild failed Go apps if [ ${#FAILED_GO_APPS[@]} -gt 0 ]; then echo "🔧 Rebuilding failed Go applications..." printf '%s\n' "${FAILED_GO_APPS[@]}" | xargs -I {} -P $MAX_PARALLEL bash -c 'build_app "{}" "go"' echo "" fi # Rebuild failed Node.js apps if [ ${#FAILED_NODE_APPS[@]} -gt 0 ]; then echo "🟢 Rebuilding failed Node.js applications..." printf '%s\n' "${FAILED_NODE_APPS[@]}" | xargs -I {} -P $MAX_PARALLEL bash -c 'build_app "{}" "node"' echo "" fi # Build all Python apps if [ ${#ALL_PYTHON_APPS[@]} -gt 0 ]; then echo "🐍 Building Python applications..." printf '%s\n' "${ALL_PYTHON_APPS[@]}" | xargs -I {} -P $MAX_PARALLEL bash -c 'build_app "{}" "python"' echo "" fi # Build all Java apps if [ ${#ALL_JAVA_APPS[@]} -gt 0 ]; then echo "☕ Building Java applications..." printf '%s\n' "${ALL_JAVA_APPS[@]}" | xargs -I {} -P $MAX_PARALLEL bash -c 'build_app "{}" "java"' echo "" fi # Build all Rust apps if [ ${#ALL_RUST_APPS[@]} -gt 0 ]; then echo "🦀 Building Rust applications..." printf '%s\n' "${ALL_RUST_APPS[@]}" | xargs -I {} -P $MAX_PARALLEL bash -c 'build_app "{}" "rust"' echo "" fi # Build all PHP apps if [ ${#ALL_PHP_APPS[@]} -gt 0 ]; then echo "🐘 Building PHP applications..." printf '%s\n' "${ALL_PHP_APPS[@]}" | xargs -I {} -P $MAX_PARALLEL bash -c 'build_app "{}" "php"' echo "" fi # Build all Ruby apps if [ ${#ALL_RUBY_APPS[@]} -gt 0 ]; then echo "💎 Building Ruby applications..." printf '%s\n' "${ALL_RUBY_APPS[@]}" | xargs -I {} -P $MAX_PARALLEL bash -c 'build_app "{}" "ruby"' echo "" fi # Build other apps if [ ${#ALL_OTHER_APPS[@]} -gt 0 ]; then echo "🔮 Building other applications..." printf '%s\n' "${ALL_OTHER_APPS[@]}" | xargs -I {} -P $MAX_PARALLEL bash -c 'build_app "{}" "lua"' echo "" fi end_time=$(date +%s) duration=$((end_time - start_time)) # Count successful builds success_count=$(docker images | grep tsysdevstack-cloudron | wc -l) echo "🎉 CONTINUE build process complete!" echo "📊 Results: $success_count total images built" echo "⏱️ Duration: ${duration} seconds" echo "" echo "📋 All built images:" docker images | grep tsysdevstack-cloudron echo "" echo "🔍 To view detailed logs:" echo "cat $LOG_FILE"