diff --git a/scripts/build/.env b/scripts/build/.env new file mode 100644 index 000000000..8637b2d39 --- /dev/null +++ b/scripts/build/.env @@ -0,0 +1,10 @@ +EVOMASTER_VERSION=5.0.3-SNAPSHOT +DIST_FOLDER=../../dist +JACOCO_FOLDER=../../jacoco +JDK_8_MVN_FOLDER=../../jdk_8_maven +JDK_8_GRADLE_FOLDER=../../jdk_8_gradle +JDK_11_MVN_FOLDER=../../jdk_11_maven +JDK_11_GRADLE_FOLDER=../../jdk_11_gradle +JDK_17_MVN_FOLDER=../../jdk_17_maven +JDK_17_GRADLE_FOLDER=../../jdk_17_gradle +JDK_21_MVN_FOLDER=../../jdk_21_maven diff --git a/scripts/build/Dockerfile.jdk11 b/scripts/build/Dockerfile.jdk11 new file mode 100644 index 000000000..998873b22 --- /dev/null +++ b/scripts/build/Dockerfile.jdk11 @@ -0,0 +1,13 @@ +FROM maven:3.9-eclipse-temurin-11 + +RUN apt-get update && \ + apt-get install -y wget unzip && \ + wget https://services.gradle.org/distributions/gradle-6.9.4-bin.zip && \ + unzip gradle-6.9.4-bin.zip -d /opt && \ + rm gradle-6.9.4-bin.zip && \ + ln -s /opt/gradle-6.9.4/bin/gradle /usr/bin/gradle && \ + apt-get clean + +WORKDIR /build + +CMD ["/bin/bash"] diff --git a/scripts/build/Dockerfile.jdk17 b/scripts/build/Dockerfile.jdk17 new file mode 100644 index 000000000..777c4239e --- /dev/null +++ b/scripts/build/Dockerfile.jdk17 @@ -0,0 +1,13 @@ +FROM maven:3.9-eclipse-temurin-17 + +RUN apt-get update && \ + apt-get install -y wget unzip && \ + wget https://services.gradle.org/distributions/gradle-8.5-bin.zip && \ + unzip gradle-8.5-bin.zip -d /opt && \ + rm gradle-8.5-bin.zip && \ + ln -s /opt/gradle-8.5/bin/gradle /usr/bin/gradle && \ + apt-get clean + +WORKDIR /build + +CMD ["/bin/bash"] diff --git a/scripts/build/Dockerfile.jdk21 b/scripts/build/Dockerfile.jdk21 new file mode 100644 index 000000000..79d3c2664 --- /dev/null +++ b/scripts/build/Dockerfile.jdk21 @@ -0,0 +1,5 @@ +FROM maven:3.9-eclipse-temurin-21 + +WORKDIR /build + +CMD ["/bin/bash"] diff --git a/scripts/build/Dockerfile.jdk8 b/scripts/build/Dockerfile.jdk8 new file mode 100644 index 000000000..dd85c7089 --- /dev/null +++ b/scripts/build/Dockerfile.jdk8 @@ -0,0 +1,13 @@ +FROM maven:3.9-eclipse-temurin-8 + +RUN apt-get update && \ + apt-get install -y wget unzip && \ + wget https://services.gradle.org/distributions/gradle-6.9.4-bin.zip && \ + unzip gradle-6.9.4-bin.zip -d /opt && \ + rm gradle-6.9.4-bin.zip && \ + ln -s /opt/gradle-6.9.4/bin/gradle /usr/bin/gradle && \ + apt-get clean + +WORKDIR /build + +CMD ["/bin/bash"] diff --git a/scripts/build/docker-compose.build.yml b/scripts/build/docker-compose.build.yml new file mode 100644 index 000000000..9fa550f5e --- /dev/null +++ b/scripts/build/docker-compose.build.yml @@ -0,0 +1,289 @@ +services: + build-jdk8-maven: + build: + context: . + dockerfile: Dockerfile.jdk8 + image: emb-build-jdk8 + volumes: + - ${HOME}/.m2:/root/.m2 + - ${DIST_FOLDER}:/dist + - ${JDK_8_MVN_FOLDER}:/build/jdk_8_maven + working_dir: /build/jdk_8_maven + command: + - bash + - -c + - | + set -e + if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then + mvn clean install -DskipTests + else + (cd cs && mvn clean install -DskipTests) + fi + cp cs/rest/original/blogapi/target/blogapi-sut.jar /dist/ + cp cs/rest/original/user-management/target/user-management-sut.jar /dist/ + cp cs/rest/original/features-service/target/features-service-sut.jar /dist/ + cp cs/rest/original/scout-api/api/target/scout-api-sut.jar /dist/ + cp cs/rest/original/proxyprint/target/proxyprint-sut.jar /dist/ + cp cs/rest/original/catwatch/catwatch-backend/target/catwatch-sut.jar /dist/ + cp cs/rest/artificial/ncs/target/rest-ncs-sut.jar /dist/ + cp cs/rest/original/youtube-mock/target/youtube-mock-sut.jar /dist/ + cp cs/rest/artificial/scs/target/rest-scs-sut.jar /dist/ + cp cs/rest/artificial/news/target/rest-news-sut.jar /dist/ + cp cs/rest-gui/ocvn/web/target/ocvn-sut.jar /dist/ + cp cs/rest/original/languagetool/languagetool-server/target/languagetool-sut.jar /dist/ + cp cs/rest/original/restcountries/target/restcountries-sut.jar /dist/ + cp cs/rest/original/session-service/target/session-service-sut.jar /dist/ + cp cs/rest-gui/gestaohospital/target/gestaohospital-sut.jar /dist/ + cp cs/rest-gui/genome-nexus/web/target/genome-nexus-sut.jar /dist/ + cp cs/rest/original/spring-batch-rest/example/api/target/spring-batch-rest-sut.jar /dist/ + cp cs/rest/original/spring-actuator-demo/target/spring-actuator-demo-sut.jar /dist/ + cp cs/rest/original/swagger-petstore/target/swagger-petstore-sut.jar /dist/ + cp cs/rest/original/spring-ecommerce/target/spring-ecommerce-sut.jar /dist/ + cp cs/graphql/petclinic-graphql/target/petclinic-graphql-sut.jar /dist/ + cp cs/graphql/graphql-ncs/target/graphql-ncs-sut.jar /dist/ + cp cs/graphql/graphql-scs/target/graphql-scs-sut.jar /dist/ + cp cs/rpc/thrift/artificial/thrift-ncs/target/rpc-thrift-ncs-sut.jar /dist/ + cp cs/rpc/thrift/artificial/thrift-scs/target/rpc-thrift-scs-sut.jar /dist/ + cp cs/rpc/grpc/artificial/grpc-ncs/target/rpc-grpc-ncs-sut.jar /dist/ + cp cs/rpc/grpc/artificial/grpc-scs/target/rpc-grpc-scs-sut.jar /dist/ + if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then + cp em/external/rest/blogapi/target/blogapi-evomaster-runner.jar /dist/ + cp em/external/rest/user-management/target/user-management-evomaster-runner.jar /dist/ + cp em/external/rest/features-service/target/features-service-evomaster-runner.jar /dist/ + cp em/external/rest/scout-api/target/scout-api-evomaster-runner.jar /dist/ + cp em/external/rest/proxyprint/target/proxyprint-evomaster-runner.jar /dist/ + cp em/external/rest/catwatch/target/catwatch-evomaster-runner.jar /dist/ + cp em/external/rest/ncs/target/rest-ncs-evomaster-runner.jar /dist/ + cp em/external/rest/youtube-mock/target/youtube-mock-evomaster-runner.jar /dist/ + cp em/external/rest/scs/target/rest-scs-evomaster-runner.jar /dist/ + cp em/external/rest/news/target/rest-news-evomaster-runner.jar /dist/ + cp em/external/rest/ocvn/target/ocvn-evomaster-runner.jar /dist/ + cp em/external/rest/languagetool/target/languagetool-evomaster-runner.jar /dist/ + cp em/external/rest/restcountries/target/restcountries-evomaster-runner.jar /dist/ + cp em/external/rest/session-service/target/session-service-evomaster-runner.jar /dist/ + cp em/external/rest/gestaohospital/target/gestaohospital-evomaster-runner.jar /dist/ + cp em/external/rest/genome-nexus/target/genome-nexus-evomaster-runner.jar /dist/ + cp em/external/rest/spring-batch-rest/target/spring-batch-rest-evomaster-runner.jar /dist/ + cp em/external/rest/spring-actuator-demo/target/spring-actuator-demo-evomaster-runner.jar /dist/ + cp em/external/rest/swagger-petstore/target/swagger-petstore-evomaster-runner.jar /dist/ + cp em/external/rest/spring-ecommerce/target/spring-ecommerce-evomaster-runner.jar /dist/ + cp em/external/graphql/petclinic-graphql/target/petclinic-graphql-evomaster-runner.jar /dist/ + cp em/external/graphql/graphql-ncs/target/graphql-ncs-evomaster-runner.jar /dist/ + cp em/external/graphql/graphql-scs/target/graphql-scs-evomaster-runner.jar /dist/ + cp em/external/thrift/ncs/target/rpc-thrift-ncs-evomaster-runner.jar /dist/ + cp em/external/thrift/scs/target/rpc-thrift-scs-evomaster-runner.jar /dist/ + cp em/external/grpc/ncs/target/rpc-grpc-ncs-evomaster-runner.jar /dist/ + cp em/external/grpc/scs/target/rpc-grpc-scs-evomaster-runner.jar /dist/ + fi + echo 'JDK 8 Maven build completed' + + build-jdk8-gradle: + build: + context: . + dockerfile: Dockerfile.jdk8 + image: emb-build-jdk8 + volumes: + - ${HOME}/.m2:/root/.m2 + - gradle-cache-jdk8:/root/.gradle + - ${DIST_FOLDER}:/dist + - ${JDK_8_GRADLE_FOLDER}:/build/jdk_8_gradle + working_dir: /build/jdk_8_gradle + command: + - bash + - -c + - | + set -e + if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then + gradle build -x test + else + (cd cs && gradle build -x test) + fi + cp cs/rest/erc20-rest-service/build/libs/erc20-rest-service-sut.jar /dist/ + if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then + cp em/external/rest/erc20-rest-service/build/libs/erc20-rest-service-evomaster-runner.jar /dist/ + fi + echo 'JDK 8 Gradle build completed' + + build-jdk11-maven: + build: + context: . + dockerfile: Dockerfile.jdk11 + image: emb-build-jdk11 + volumes: + - ${HOME}/.m2:/root/.m2 + - ${DIST_FOLDER}:/dist + - ${JDK_11_MVN_FOLDER}:/build/jdk_11_maven + working_dir: /build/jdk_11_maven + command: + - bash + - -c + - | + set -e + if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then + mvn clean install -DskipTests + else + (cd cs && mvn clean install -DskipTests) + fi + cp cs/rest/tracking-system/target/tracking-system-sut.jar /dist/ + cp cs/rest/cwa-verification-server/target/cwa-verification-sut.jar /dist/ + cp cs/graphql/timbuctoo/timbuctoo-instancev4/target/timbuctoo-sut.jar /dist/ + cp cs/rest-gui/market/market-rest/target/market-sut.jar /dist/ + cp cs/rest/pay-publicapi/target/pay-publicapi-sut.jar /dist/ + cp cs/rest/http-patch-spring/target/http-patch-spring-sut.jar /dist/ + cp cs/rest-gui/quartz-manager/quartz-manager-parent/quartz-manager-web-showcase/target/quartz-manager-sut.jar /dist/ + if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then + cp em/external/rest/tracking-system/target/tracking-system-evomaster-runner.jar /dist/ + cp em/external/rest/cwa-verification/target/cwa-verification-evomaster-runner.jar /dist/ + cp em/external/graphql/timbuctoo/target/timbuctoo-evomaster-runner.jar /dist/ + cp em/external/rest/market/target/market-evomaster-runner.jar /dist/ + cp em/external/rest/pay-publicapi/target/pay-publicapi-evomaster-runner.jar /dist/ + cp em/external/rest/http-patch-spring/target/http-patch-spring-evomaster-runner.jar /dist/ + cp em/external/rest/quartz-manager/target/quartz-manager-evomaster-runner.jar /dist/ + fi + echo 'JDK 11 Maven build completed' + + build-jdk11-gradle: + build: + context: . + dockerfile: Dockerfile.jdk11 + image: emb-build-jdk11 + volumes: + - ${HOME}/.m2:/root/.m2 + - gradle-cache-jdk11:/root/.gradle + - ${DIST_FOLDER}:/dist + - ${JDK_11_GRADLE_FOLDER}:/build/jdk_11_gradle + working_dir: /build/jdk_11_gradle + command: + - bash + - -c + - | + set -e + if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then + gradle build -x test + else + (cd cs && gradle build -x test) + fi + cp cs/graphql/patio-api/build/libs/patio-api-sut.jar /dist/ + cp cs/rest/reservations-api/build/libs/reservations-api-sut.jar /dist/ + if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then + cp em/external/graphql/patio-api/build/libs/patio-api-evomaster-runner.jar /dist/ + cp em/external/rest/reservations-api/build/libs/reservations-api-evomaster-runner.jar /dist/ + fi + echo 'JDK 11 Gradle build completed' + + build-jdk17-maven: + build: + context: . + dockerfile: Dockerfile.jdk17 + image: emb-build-jdk17 + volumes: + - ${HOME}/.m2:/root/.m2 + - ${DIST_FOLDER}:/dist + - ${JDK_17_MVN_FOLDER}:/build/jdk_17_maven + working_dir: /build/jdk_17_maven + command: + - bash + - -c + - | + set -e + if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then + mvn clean install -DskipTests + else + (cd cs && mvn clean install -DskipTests) + fi + cp cs/web/spring-petclinic/target/spring-petclinic-sut.jar /dist/ + cp cs/grpc/signal-registration/target/signal-registration-sut.jar /dist/ + cp cs/rest/familie-ba-sak/target/familie-ba-sak-sut.jar /dist/ + cp cs/rest/tiltaksgjennomforing/target/tiltaksgjennomforing-sut.jar /dist/ + cp cs/rest/ohsome-api/target/ohsome-api-sut.jar /dist/ + cp cs/rest/spring-rest-example/target/spring-rest-example-sut.jar /dist/ + if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then + cp em/external/web/spring-petclinic/target/spring-petclinic-evomaster-runner.jar /dist/ + cp em/external/grpc/signal-registration/target/signal-registration-evomaster-runner.jar /dist/ + cp em/external/rest/familie-ba-sak/target/familie-ba-sak-evomaster-runner.jar /dist/ + cp em/external/rest/tiltaksgjennomforing/target/tiltaksgjennomforing-evomaster-runner.jar /dist/ + cp em/external/rest/ohsome-api/target/ohsome-api-evomaster-runner.jar /dist/ + cp em/external/rest/spring-rest-example/target/spring-rest-example-evomaster-runner.jar /dist/ + fi + echo 'JDK 17 Maven build completed' + + build-jdk17-gradle: + build: + context: . + dockerfile: Dockerfile.jdk17 + image: emb-build-jdk17 + volumes: + - ${HOME}/.m2:/root/.m2 + - gradle-cache-jdk17:/root/.gradle + - ${DIST_FOLDER}:/dist + - ${JDK_17_GRADLE_FOLDER}:/build/jdk_17_gradle + working_dir: /build/jdk_17_gradle + command: + - bash + - -c + - | + set -e + if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then + gradle build -x test -x spotlessCheck -x spotlessJavaCheck + else + (cd cs && gradle build -x test -x spotlessCheck -x spotlessJavaCheck) + fi + cp cs/rest/bibliothek/build/libs/bibliothek-sut.jar /dist/ + if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then + cp em/external/rest/bibliothek/build/libs/bibliothek-evomaster-runner.jar /dist/ + fi + echo 'JDK 17 Gradle build completed' + + build-jdk21-maven: + build: + context: . + dockerfile: Dockerfile.jdk21 + image: emb-build-jdk21 + volumes: + - ${HOME}/.m2:/root/.m2 + - ${DIST_FOLDER}:/dist + - ${JDK_21_MVN_FOLDER}:/build/jdk_21_maven + working_dir: /build/jdk_21_maven + command: + - bash + - -c + - | + set -e + if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then + mvn clean install -DskipTests + else + (cd cs && mvn clean install -DskipTests) + fi + cp cs/rest/person-controller/target/person-controller-sut.jar /dist/ + cp cs/rest-gui/webgoat/target/webgoat-sut.jar /dist/ + cp cs/rest-gui/microcks/webapp/target/microcks-sut.jar /dist/ + if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then + cp em/external/rest/person-controller/target/person-controller-evomaster-runner.jar /dist/ + cp em/external/rest-gui/webgoat/target/webgoat-evomaster-runner.jar /dist/ + cp em/external/rest-gui/microcks/target/microcks-evomaster-runner.jar /dist/ + fi + echo 'JDK 21 Maven build completed' + + copy-jacoco: + image: alpine:latest + volumes: + - ${DIST_FOLDER}:/dist + - ${JACOCO_FOLDER}:/jacoco + command: > + sh -c "cp /jacoco/jacocoagent.jar /dist/ && + cp /jacoco/jacococli.jar /dist/ && + echo 'Jacoco files copied'" + + copy-evomaster-agent: + image: alpine:latest + volumes: + - ${HOME}/.m2:/root/.m2 + - ${DIST_FOLDER}:/dist + command: > + sh -c "cp /root/.m2/repository/org/evomaster/evomaster-client-java-instrumentation/${EVOMASTER_VERSION}/evomaster-client-java-instrumentation-${EVOMASTER_VERSION}.jar /dist/evomaster-agent.jar && + echo 'evomaster-agent.jar copied'" + +volumes: + gradle-cache-jdk8: + gradle-cache-jdk11: + gradle-cache-jdk17: diff --git a/scripts/dist-docker.py b/scripts/dist-docker.py new file mode 100644 index 000000000..f08f40a9f --- /dev/null +++ b/scripts/dist-docker.py @@ -0,0 +1,372 @@ +#!/usr/bin/env python3 +"""Docker-based build script for WFD project. + +Builds all jdk_* projects using Docker containers +and copies the results to the dist folder. +""" + +import argparse +import os +import shutil +import subprocess +import sys +import time +from pathlib import Path + + +SCRIPT_DIR = Path(__file__).resolve().parent +PROJ_DIR = SCRIPT_DIR.parent + +COMPOSE_FILE = "./scripts/build/docker-compose.build.yml" + +JDK_VERSIONS = ["8", "11", "17", "21"] +BUILD_TOOLS = ["maven", "gradle"] + +ALL_SERVICES = [ + ("8", "maven"), + ("8", "gradle"), + ("11", "maven"), + ("11", "gradle"), + ("17", "maven"), + ("17", "gradle"), + ("21", "maven"), +] + + +def detect_compose_cmd(): + try: + subprocess.run( + ["docker", "compose", "version"], + check=True, capture_output=True, + ) + return ["docker", "compose"] + except (subprocess.CalledProcessError, FileNotFoundError): + pass + if shutil.which("docker-compose"): + return ["docker-compose"] + print("ERROR: Docker Compose is not installed") + sys.exit(1) + + +def format_elapsed_time(seconds): + m, s = divmod(int(seconds), 60) + return f"{m}m {s}s" if m else f"{s}s" + + +def run(cmd, check=True): + return subprocess.run(cmd, check=check) + + +def run_build(compose, service, *, background=False, evomaster=False): + env_args = ["-e", "BUILD_EVOMASTER=true"] if evomaster else [] + cmd = compose + ["-f", COMPOSE_FILE, "run", "--rm", "-T"] + env_args + [service] + if background: + return subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + return subprocess.run(cmd, check=False) + + +def copy_jacoco(compose): + print(">>> Copying jacoco files to dist...") + run(compose + ["-f", COMPOSE_FILE, "run", "--rm", "-T", "copy-jacoco"]) + print("Jacoco files copied!\n") + + +def copy_evomaster_agent(compose): + print(">>> Copying evomaster-agent to dist...") + run(compose + ["-f", COMPOSE_FILE, "run", "--rm", "-T", "copy-evomaster-agent"]) + print("evomaster-agent.jar copied!\n") + + +def show_jar(path): + p = PROJ_DIR / "dist" / path + if p.exists(): + print(f"{p.name} ({p.stat().st_size // 1024} KB)") + + +def count_jars(): + return len(list((PROJ_DIR / "dist").glob("**/*.jar"))) + + +def service_dir_exists(jdk, tool): + return (PROJ_DIR / f"jdk_{jdk}_{tool}").is_dir() + + +def should_build(jdk, tool, jdk_filter, tool_filter): + if jdk_filter != "all" and jdk_filter != jdk: + return False + if tool_filter != "all" and tool_filter != tool: + return False + return True + + +def parse_args(): + parser = argparse.ArgumentParser( + description="WFD Docker Build Script", + formatter_class=argparse.RawTextHelpFormatter, + epilog=( + "Examples:\n" + " dist-docker.py # Build all projects sequentially\n" + " dist-docker.py --parallel # Build all projects in parallel\n" + " dist-docker.py 8 gradle # Build only JDK 8 Gradle projects\n" + " dist-docker.py 11 maven -p # Build JDK 11 Maven in parallel mode\n" + " dist-docker.py --copy-files # Only copy jacoco files\n" + " dist-docker.py --copy-files -E # Only copy jacoco + evomaster-agent files\n" + " dist-docker.py --interactive # Prompt before deleting dist/ on full build\n" + " dist-docker.py --evomaster # Also build evomaster runners + copy evomaster-agent\n" + " dist-docker.py -E --parallel # Full build in parallel" + ), + ) + parser.add_argument( + "jdk_version", + nargs="?", + default="all", + metavar="JDK_VERSION", + help="8, 11, 17, 21, or 'all' (default: all)", + ) + parser.add_argument( + "build_tool", + nargs="?", + default="all", + metavar="BUILD_TOOL", + help="maven, gradle, or 'all' (default: all)", + ) + parser.add_argument( + "--parallel", "-p", + action="store_true", + help="Run builds in parallel (faster but uses more resources)", + ) + parser.add_argument( + "--copy-files", "-c", + action="store_true", + dest="copy_only", + help="Only copy additional files (evomaster-agent, jacoco)", + ) + parser.add_argument( + "--interactive", "-i", + action="store_true", + help="Prompt for confirmation before destructive operations (e.g. deleting dist/)", + ) + parser.add_argument( + "--evomaster", "-E", + action="store_true", + help="Also build evomaster runner jars (em/) and copy additional files. " + "Default: SUT-only mode (only cs/ is built, no evomaster runners)", + ) + args = parser.parse_args() + + valid_jdks = set(JDK_VERSIONS) | {"all"} + if args.jdk_version not in valid_jdks: + parser.error(f"Invalid JDK version '{args.jdk_version}'. Valid options: {', '.join(sorted(valid_jdks))}") + + valid_tools = set(BUILD_TOOLS) | {"all"} + if args.build_tool not in valid_tools: + parser.error(f"Invalid build tool '{args.build_tool}'. Valid options: {', '.join(sorted(valid_tools))}") + + return args + + +def main(): + args = parse_args() + compose = detect_compose_cmd() + + print("WFD Docker Build Script") + print(f"Project directory: {PROJ_DIR}") + print(f"JDK Version: {args.jdk_version}") + print(f"Build Tool: {args.build_tool}") + print(f"Mode: {'PARALLEL' if args.parallel else 'Sequential'}") + print(f"Build scope: {'Full (SUT + Evomaster runners)' if args.evomaster else 'SUT-only (cs/ only)'}") + print(f"Using: {' '.join(compose)}\n") + + # Check Docker + if not shutil.which("docker"): + print("ERROR: Docker is not installed or not in PATH") + sys.exit(1) + + dist_dir = PROJ_DIR / "dist" + + os.environ.setdefault("HOME", str(Path.home())) + + # --- Copy-only mode --- + if args.copy_only: + print("Copy Additional Files Only Mode") + dist_dir.mkdir(parents=True, exist_ok=True) + os.chdir(PROJ_DIR) + copy_jacoco(compose) + if args.evomaster: + copy_evomaster_agent(compose) + print("Files copied successfully!") + for f in ["evomaster-agent.jar", "jacocoagent.jar", "jacococli.jar"]: + show_jar(f) + return + + # --- Collect services --- + services = [ + f"build-jdk{jdk}-{tool}" + for jdk, tool in ALL_SERVICES + if should_build(jdk, tool, args.jdk_version, args.build_tool) + and service_dir_exists(jdk, tool) + ] + + # --- Full-build warning & dist cleanup --- + if args.jdk_version == "all" and args.build_tool == "all": + print("WARNING: Full build mode detected!") + print("This will DELETE the entire dist/ folder and rebuild all projects.\n") + if dist_dir.exists(): + jar_count = len(list(dist_dir.glob("**/*.jar"))) + print(f"Current dist folder contents:\n - {jar_count} JAR files found\n - Location: {dist_dir}") + else: + print("Dist folder does not exist yet.") + + if args.interactive: + print() + try: + reply = input("Do you want to continue and DELETE dist folder? (y/N): ").strip().lower() + except EOFError: + reply = "" + + if reply not in ("y", "yes"): + print("\nBuild cancelled by user.") + print("Tip: Use 'dist-docker.py ' for incremental builds") + print(" Example: dist-docker.py 8 gradle") + return + + print("\nCleaning dist folder (building all projects)...") + if dist_dir.exists(): + shutil.rmtree(dist_dir) + dist_dir.mkdir(parents=True) + print("Dist folder cleaned") + else: + print("Incremental build mode - preserving existing dist folder...") + dist_dir.mkdir(parents=True, exist_ok=True) + print("Building into existing dist folder (will overwrite duplicates)") + print() + + # --- Ensure Maven / Gradle cache dirs exist --- + home = Path.home() + for cache_name, cache_dir in [(".m2", home / ".m2"), (".gradle", home / ".gradle")]: + if not cache_dir.exists(): + print(f"WARNING: {cache_name} cache not found at {cache_dir}, creating...") + cache_dir.mkdir(parents=True) + + os.chdir(PROJ_DIR) + + if not services: + print("No matching builds found!") + print(f"JDK Version: {args.jdk_version}\nBuild Tool: {args.build_tool}\n") + print("Available combinations:") + for d in sorted(PROJ_DIR.glob("jdk_*")): + if d.is_dir(): + print(f" - {d.name}") + return + + print("Building Docker images and running builds...") + print(f"Services to build: {services}\n") + + total = len(services) + build_start = time.time() + + # Step 1: Build Docker images in parallel (output suppressed to avoid interleaving) + print(f"Step 1: Building {total} Docker image(s)...") + img_start = time.time() + img_pending = {} + for svc in services: + proc = subprocess.Popen( + compose + ["-f", COMPOSE_FILE, "build", svc], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, + ) + img_pending[svc] = (proc, time.time()) + done = 0 + while img_pending: + for svc, (proc, svc_start) in list(img_pending.items()): + if proc.poll() is not None: + done += 1 + print(f" [{done}/{total}] Image ready: {svc} ({format_elapsed_time(time.time() - svc_start)})") + del img_pending[svc] + if img_pending: + time.sleep(2) + print(f"All Docker images built! (took {format_elapsed_time(time.time() - img_start)})\n") + + # Step 2: Run builds + step2_start = time.time() + print("Step 2: Running builds...") + if args.parallel: + print(">>> Running builds in PARALLEL mode...") + print(f">>> WARNING: This will use significant CPU and RAM!") + print(f">>> Launching {total} build(s)...\n") + + pending = {} + for svc in services: + proc = run_build(compose, svc, background=True, evomaster=args.evomaster) + pending[svc] = (proc, time.time()) + print(f" [launched] {svc}") + print(f"\nWaiting for all {total} builds to complete...\n") + + failed = 0 + done = 0 + while pending: + for svc, (proc, svc_start) in list(pending.items()): + code = proc.poll() + if code is not None: + done += 1 + svc_elapsed = format_elapsed_time(time.time() - svc_start) + if code != 0: + print(f" [{done}/{total}] FAILED: {svc} (exit code {code}, {svc_elapsed})") + failed += 1 + else: + print(f" [{done}/{total}] OK: {svc} ({svc_elapsed})") + del pending[svc] + if pending: + time.sleep(2) + + if failed: + print(f"\nERROR: {failed} build(s) failed!") + sys.exit(1) + + print(f"\nAll parallel builds completed successfully! (took {format_elapsed_time(time.time() - step2_start)})\n") + else: + print(">>> Running builds in SEQUENTIAL mode...\n") + for i, svc in enumerate(services, 1): + print(f">>> [{i}/{total}] Building: {svc}") + svc_start = time.time() + result = run_build(compose, svc, evomaster=args.evomaster) + svc_elapsed = format_elapsed_time(time.time() - svc_start) + if result.returncode != 0: + print(f"\nERROR: {svc} build failed! (after {svc_elapsed})") + sys.exit(1) + print(f" Completed in {svc_elapsed}\n") + + copy_jacoco(compose) + if args.evomaster: + copy_evomaster_agent(compose) + + # Cleanup + print("Cleaning up Docker containers...") + run(compose + ["-f", COMPOSE_FILE, "down"]) + + # Summary + total_elapsed = format_elapsed_time(time.time() - build_start) + print() + print("Build Summary") + print(f"Builds executed: {len(services)}") + print(f"Total time: {total_elapsed}") + print("Checking dist folder contents...\n") + + jar_count = count_jars() + print(f"Total JAR files created: {jar_count}\n") + + if jar_count > 0: + print("Files in dist:") + for f in sorted(dist_dir.iterdir()): + print(f" {f.name} ({f.stat().st_size // 1024} KB)") + print() + print("SUCCESS - Builds completed!") + print(f"Output location: {dist_dir}") + print(f"JDK Version: {args.jdk_version}") + print(f"Build Tool: {args.build_tool}") + else: + print("WARNING - No JAR files found in dist!") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/scripts/version.py b/scripts/version.py index 5792132fc..234526f09 100755 --- a/scripts/version.py +++ b/scripts/version.py @@ -73,6 +73,11 @@ def replaceInDist(): replacement = 'EVOMASTER_VERSION = "'+version+'"\n' replace("scripts/dist.py", regex, replacement) +def replaceInDockerEnv(): + regex = re.compile(r'^EVOMASTER_VERSION\s*=\s*.*$') + replacement = 'EVOMASTER_VERSION='+version+'\n' + replace("scripts/build/.env", regex, replacement) + def replaceInProperty(file): regex = re.compile(r'.*EVOMASTER_VERSION.*=.*') replacement = 'EVOMASTER_VERSION='+version+'\n' @@ -139,8 +144,8 @@ def versionSetMaven(folder, jdk_home): replaceInGradle("jdk_8_gradle/build.gradle") replaceInGradle("jdk_11_gradle/build.gradle") replaceInGradle("jdk_17_gradle/build.gradle") - replaceInDist() + replaceInDockerEnv() if target == "wfd": versionSetMaven("/jdk_8_maven",JAVA_HOME_8)