package com.github.sormuras.bach;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;

/** Bach's main program. */
public class Main {

  /**
   * An annotated method indicates that it is intended to be run from Bach's main program's CLI.
   *
   * @see #performAction(String)
   */
  @Target(ElementType.METHOD)
  @Retention(RetentionPolicy.SOURCE)
  @Documented
  @Inherited
  public @interface Action {
    String[] value() default {};
  }

  public static void main(String... args) {
    System.exit(run("build", args));
  }

  public static int run(String module, String... args) {
    var bach = Bach.of(module);
    if (args.length == 0) {
      bach.print("No argument, no action.");
      return 0;
    }
    return new Main(bach).performActions(args);
  }

  private final Bach bach;

  public Main(Bach bach) {
    this.bach = bach;
  }

  public int performActions(String... actions) {
    var list = List.of(actions);
    bach.debug("Perform %d action%s: %s", list.size(), list.size() == 1 ? "" : "s", list);
    for (var action : list) {
      var status = performAction(action);
      if (status != 0) return status;
    }
    return 0;
  }

  public int performAction(String action) {
    bach.debug("Perform main action: `%s`", action);
    try {
      switch (action) {
        case "build" -> bach.build();
        case "clean" -> bach.clean();
        case "help", "usage" -> bach.printHelp();
        case "info" -> bach.printInfo();
        case "version" -> bach.printVersion();
        default -> {
          bach.print("Unsupported action: %s", action);
          return 4;
        }
      }
      return 0;
    } catch (Exception exception) {
      bach.print("Action %s failed: %s", action, exception);
      exception.printStackTrace(System.err);
      return 1;
    }
  }
}

@@ -268,16 +268,45 @@
 Target;%0A
+import java.util.ArrayDeque;%0A
 import j
@@ -940,32 +940,744 @@
 return 0;%0A    %7D%0A
+    if (args%5B0%5D.equals(%22tool%22)) %7B%0A      var deque = new ArrayDeque%3C%3E(List.of(args));%0A      deque.removeFirst(); // %22tool%22%0A      if (deque.isEmpty()) %7B%0A        bach.print(%22Main action 'tool' requires at a name: bach tool NAME %3CARGS...%3E%22);%0A        return 1;%0A      %7D%0A      var command = Command.of(deque.removeFirst());%0A      var recording = bach.run(deque.isEmpty() ? command : command.add(%22%22, deque.toArray()));%0A      if (!recording.errors().isEmpty()) bach.print(recording.errors());%0A      if (!recording.output().isEmpty()) bach.print(recording.output());%0A      if (recording.isError())%0A        bach.print(%22Tool %25s returned exit code %25d%22, command.name(), recording.code());%0A      return recording.code();%0A    %7D%0A
     return new M

Add support for launching tools from the command line