From 103289a12a3922fccb5f7e64f4300bce9a3e1660 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Fri, 25 Mar 2022 15:28:14 +0100 Subject: [PATCH] Add macOS and Windows builds to GHA CI build matrix Signed-off-by: Wouter Born --- .github/java/MavenBuild.java | 187 +++++++++++++++++++++++++++++++++ .github/scripts/maven-build | 51 --------- .github/workflows/ci-build.yml | 13 ++- .gitignore | 2 + 4 files changed, 200 insertions(+), 53 deletions(-) create mode 100644 .github/java/MavenBuild.java delete mode 100755 .github/scripts/maven-build diff --git a/.github/java/MavenBuild.java b/.github/java/MavenBuild.java new file mode 100644 index 0000000000..ad45317cd0 --- /dev/null +++ b/.github/java/MavenBuild.java @@ -0,0 +1,187 @@ +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class MavenBuild { + + static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor(); + static final String BUILD_LOG = "build.log"; + + static class Command { + final String command; + + Command(String command) { + this.command = command; + } + + String getCommandForCurrentOS() { + if (System.getProperty("os.name").toLowerCase().startsWith("windows")) { + return "cmd.exe /c " + command; + } else { + return command; + } + } + + @Override + public String toString() { + return command; + } + } + + static class MaxCapacityList extends ArrayList { + + final int maxCapacity; + + public MaxCapacityList(int maxCapacity) { + super(maxCapacity); + this.maxCapacity = maxCapacity; + } + + @Override + public boolean add(E e) { + if (size() > maxCapacity) { + remove(0); + } + return super.add(e); + } + } + + static class CommandProcess { + + final ProcessBuilder builder = new ProcessBuilder(); + final Command command; + + CommandProcess(Command command) { + this.command = command; + builder.command(command.getCommandForCurrentOS().split(" ")); + builder.directory(new File(System.getProperty("user.dir"))); + builder.environment().putAll(System.getenv()); + builder.redirectErrorStream(true); + } + + void execute() throws Exception { + Process process = builder.start(); + handleInputStream(process.getInputStream()).get(); + int exitCode = process.waitFor(); + + if (exitCode != 0) { + handleError(); + System.exit(exitCode); + } + + handleSuccess(); + } + + Future handleInputStream(InputStream inputStream) { + return CompletableFuture.completedFuture(null); + } + + void handleError() { + } + + void handleSuccess() { + } + } + + static class MavenVersionCommandProcess extends CommandProcess { + MavenVersionCommandProcess() { + super(new Command("mvn -v")); + builder.inheritIO(); + } + } + + static class MavenBuildCommandProcess extends CommandProcess { + + final MaxCapacityList lastLines = new MaxCapacityList<>(2000); + final Pattern pattern = Pattern.compile("^\\[INFO\\] Building (?.+) \\[(?\\d+)/(?\\d+)\\]$"); + + MavenBuildCommandProcess() { + super(new Command("mvn clean verify -B -T 1.5C -U")); + } + + @Override + void execute() throws Exception { + List.of("Building all projects", "", "+ " + command, "").stream().forEach(System.out::println); + super.execute(); + } + + void printProgress(String line) { + Matcher matcher = pattern.matcher(line); + if (matcher.matches()) { + String index = matcher.group("index"); + String size = matcher.group("size"); + String name = matcher.group("name"); + String padding = " ".repeat(size.length() - index.length()); + System.out.println(String.format("%s%s/%s| %s", padding, index, size, name)); + } + } + + @Override + Future handleInputStream(InputStream inputStream) { + return EXECUTOR.submit(() -> { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + BufferedWriter writer = Files.newBufferedWriter(Path.of(BUILD_LOG), StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING)) { + String line; + while ((line = reader.readLine()) != null) { + printProgress(line); + writer.append(line + System.lineSeparator()); + lastLines.add(line); + } + } catch (IOException e) { + } + }); + } + + @Override + void handleError() { + System.out.println(); + lastLines.forEach(System.out::println); + } + + @Override + void handleSuccess() { + String separatorPrefix = "[INFO] " + "-".repeat(70); + String summaryPrefix = "[INFO] Reactor Summary"; + + int start = 0; + int end = lastLines.size(); + + for (int i = 0; i < lastLines.size(); i++) { + String line = lastLines.get(i); + if (line.startsWith(summaryPrefix)) { + start = i - 1; + } else if (line.startsWith(separatorPrefix)) { + end = i + 1; + } + } + + System.out.println(); + lastLines.subList(start, end).stream() // + .map(s -> s.replaceFirst("\\[INFO\\] ", "")) // + .forEach(System.out::println); + } + + } + + public static void main(String[] args) throws Exception { + new MavenVersionCommandProcess().execute(); + System.out.println(); + new MavenBuildCommandProcess().execute(); + System.exit(0); + } +} diff --git a/.github/scripts/maven-build b/.github/scripts/maven-build deleted file mode 100755 index 29cb4f5008..0000000000 --- a/.github/scripts/maven-build +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash - -BUILD_LOG=build.log - -ARGUMENTS="clean verify -B -T 1.5C -U" -if [ $# -ge 1 ]; then - ARGUMENTS=$@ -fi - -function print_reactor_summary() { - local start_end=$(grep -anE "\[INFO\] \\-{70,}" "$BUILD_LOG" | tail -n4 | cut -f1 -d: | sed -e 1b -e '$!d' | xargs) - local start=$(awk '{print $1}' <<< $start_end) - local end=$(awk '{print $2}' <<< $start_end) - cat "$BUILD_LOG" | sed -n "${start},${end}p" | sed 's/\[INFO\] //' -} - -function mvnp() { - set -o pipefail # exit build with error when pipes fail - local reactor_size=$(find -name "pom.xml" | grep -vE '/src/|/target/' | wc -l) - local padding=$(bc -l <<< "scale=0;2*(l($reactor_size)/l(10)+1)") - local command=(mvn $@) - exec "${command[@]}" 2>&1 | # execute, redirect stderr to stdout - tee "$BUILD_LOG" | # write output to log - stdbuf -oL grep -aE '^\[INFO\] Building .+ \[.+\]$' | # filter progress - stdbuf -o0 sed -uE 's/^\[INFO\] Building (.*[^ ])[ ]+\[([0-9]+\/[0-9]+)\]$/\2| \1/' | # prefix project name with progress - stdbuf -o0 sed -e :a -e "s/^.\{1,${padding}\}|/ &/;ta" # right align progress with padding -} - -function build_all() { - echo - echo "Building all projects" - echo - echo "+ mvn $ARGUMENTS" - echo - - mvnp $ARGUMENTS - - status=$? - echo - - if [ $status -eq 0 ]; then - print_reactor_summary - else - tail -n 2000 "$BUILD_LOG" - fi - - exit $status -} - -mvn -v -build_all diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index cac7f55ebd..a23e701eec 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -4,6 +4,7 @@ on: push: branches: - 'main' + - 'multi-os' paths-ignore: - '.github/**/*.md' pull_request: @@ -20,10 +21,16 @@ jobs: matrix: java: [ '17' ] maven: [ '3.9.4' ] - os: [ 'ubuntu-22.04' ] + os: [ 'macos-12', 'ubuntu-22.04', 'windows-2022' ] name: Build (Java ${{ matrix.java }}, ${{ matrix.os }}) runs-on: ${{ matrix.os }} steps: + - name: Set up line endings + if: ${{ matrix.os == 'windows-2022' }} + run: | + git config --global core.autocrlf false + git config --global core.eol crlf + - name: Checkout if: github.head_ref == '' uses: actions/checkout@v3 @@ -57,7 +64,9 @@ jobs: - name: Build id: build - run: './.github/scripts/maven-build' + run: | + javac .github/java/MavenBuild.java + java -cp .github/java MavenBuild env: MAVEN_OPTS: >- -Xmx2g diff --git a/.gitignore b/.gitignore index 13897fb9f7..d1b0e4f477 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,9 @@ .idea .vscode .DS_Store +*.class *.iml +*.log .gradle maven-metadata-local.xml Californium.properties