code: // Licensed to the Software Freedom Conservancy (SFC) under one
  // or more contributor license agreements.  See the NOTICE file
  // distributed with this work for additional information
  // regarding copyright ownership.  The SFC licenses this file
  // to you under the Apache License, Version 2.0 (the
  // "License"); you may not use this file except in compliance
  // with the License.  You may obtain a copy of the License at
  //
  //   http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing,
  // software distributed under the License is distributed on an
  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied.  See the License for the
  // specific language governing permissions and limitations
  // under the License.
  package org.openqa.selenium.build;
  
  import static org.junit.jupiter.api.Assertions.fail;
  import static org.openqa.selenium.Platform.WINDOWS;
  import static org.openqa.selenium.build.DevMode.isInDevMode;
  
  import java.io.BufferedReader;
  import java.io.InputStreamReader;
  import java.nio.charset.Charset;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  import java.util.logging.Logger;
  import org.openqa.selenium.Platform;
  
  public class Build {
    private static final Logger LOG = Logger.getLogger(Build.class.getName());
  
    private final List<String> targets = new ArrayList<>();
  
    public Build of(String... targets) {
      this.targets.addAll(Arrays.asList(targets));
      return this;
    }
  
    public void go() {
      if (!isInDevMode()) {
        // we should only need to do this when we're in dev mode
        // when running in a test suite, our dependencies should already
        // be listed.
        LOG.info("Not in dev mode. Ignoring attempt to build: " + targets);
        return;
      }
  
      if (targets.isEmpty()) {
        throw new IllegalStateException("No targets specified");
      }
      System.out.println("\nBuilding " + targets + " ...");
      ProcessBuilder builder = prepareBuild();
      try {
        executeBuild(builder);
      } catch (Exception e) {
        e.printStackTrace(System.err);
        fail("Cannot build");
      }
    }
  
    private ProcessBuilder prepareBuild() {
      List<String> command = new ArrayList<>();
      if (Platform.getCurrent().is(WINDOWS)) {
        command.add("cmd.exe");
        command.add("/c");
        command.add("go.bat");
      } else {
        command.add("./go");
      }
      command.addAll(targets);
      ProcessBuilder builder = new ProcessBuilder(command);
      builder.directory(InProject.locate("Rakefile").getParent().toFile());
      builder.redirectErrorStream(true);
      return builder;
    }
  
    private void executeBuild(ProcessBuilder builder) throws Exception {
      Process process = builder.start();
      BuildWatcher buildWatcher = new BuildWatcher(process);
      buildWatcher.start();
      int exitValue = process.waitFor();
      if (exitValue != 0) {
        fail("Unable to build artifacts");
      }
    }
  
    private static class BuildWatcher extends Thread {
      private final Process buildProcess;
  
      private BuildWatcher(Process buildProcess) {
        super("BuildWatcher");
        this.buildProcess = buildProcess;
      }
  
      @Override
      public void run() {
        try (BufferedReader buildOutput =
            new BufferedReader(
                new InputStreamReader(buildProcess.getInputStream(), Charset.defaultCharset()),
                8192)) {
          for (String s = buildOutput.readLine();
              s != null && !interrupted();
              s = buildOutput.readLine()) {
            try {
              System.out.println(">>> " + s);
            } catch (Throwable ignored) {
            }
          }
        } catch (Throwable e) {
          System.err.print("ERROR: Could not read from stdout of " + buildProcess + ":");
          e.printStackTrace(System.err);
        }
      }
    }
  }
  