import java.io.File;
import java.lang.module.FindException;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.lang.module.ResolutionException;
import java.nio.file.Path;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.spi.ToolProvider;

class Bootstrap {
  public static void main(String[] args) {
    System.out.println("Bootstrap Bach");

    var bootstrap = Path.of(".bach/workspace/classes/bootstrap");
    var pattern = DateTimeFormatter.ofPattern("yyyy.MM.dd.HHmm").withZone(ZoneId.of("UTC"));
    var version = ModuleDescriptor.Version.parse(pattern.format(Instant.now()));

    run(
        ToolProvider.findFirst("javac").orElseThrow(),
        "--module=build,com.github.sormuras.bach",
        "--module-source-path=.bach" + File.pathSeparator + "./*/main/java",
        "--module-version=" + version + "-BOOTSTRAP",
        "-Werror",
        "-Xlint",
        "-encoding",
        "UTF-8",
        "-d",
        bootstrap.toString());

    run(tool(ModuleFinder.of(bootstrap), "build"));
  }

  static ToolProvider tool(ModuleFinder finder, String name) {
    var parent = Bootstrap.class.getClassLoader();
    try {
      var boot = ModuleLayer.boot();
      var configuration = boot.configuration().resolveAndBind(finder, ModuleFinder.of(), Set.of());
      var controller = ModuleLayer.defineModulesWithOneLoader(configuration, List.of(boot), parent);
      var layer = controller.layer();
      var serviceLoader = ServiceLoader.load(layer, ToolProvider.class);
      return serviceLoader.stream()
          .map(ServiceLoader.Provider::get)
          .filter(tool -> tool.name().equals(name))
          .findFirst()
          .orElseThrow();
    } catch (FindException | ResolutionException exception) {
      throw new Error("Build program failed!", exception);
    }
  }

  static void run(ToolProvider tool, String... args) {
    System.out.println(">> " + tool.name() + " " + String.join(" ", args));
    var code = tool.run(System.out, System.err, args);
    if (code != 0) throw new Error("Non-zero exit code: " + code);
  }
}

@@ -170,32 +170,109 @@
 utionException;%0A
+import java.nio.file.DirectoryNotEmptyException;%0Aimport java.nio.file.Files;%0A
 import java.nio.
@@ -601,49 +601,154 @@
     
-var bootstrap = Path.of(%22.bach/workspace/
+System.out.println(%22Delete workspace%22);%0A    var workspace = deleteDirectories(Path.of(%22.bach/workspace%22));%0A    var bootstrap = workspace.resolve(%22
 clas
@@ -1357,16 +1357,307 @@
 uild%22));
+%0A%0A    System.out.println(%22END.%22);%0A  %7D%0A%0A  static void run(ToolProvider tool, String... args) %7B%0A    System.out.println(%22%3E%3E %22 + tool.name() + %22 %22 + String.join(%22 %22, args));%0A    var code = tool.run(System.out, System.err, args);%0A    if (code != 0) throw new Error(%22Non-zero exit code: %22 + code);
 %0A  %7D%0A%0A  
@@ -2397,30 +2397,36 @@
 or(%22
-Build program failed!%22
+No such tool found: %22 + name
 , ex
@@ -2459,250 +2459,742 @@
 tic 
-void run(ToolProvider tool, String... args) %7B%0A    System.out.println(%22%3E%3E %22 + tool.name() + %22 %22 + String.join(%22 %22, args));%0A    var code = tool.run(System.out, System.err, args);%0A    if (code != 0) throw new Error(%22Non-zero exit code: %22 + code)
+Path deleteDirectories(Path directory) %7B%0A    try %7B // trivial case: delete existing empty directory or single file%0A      Files.deleteIfExists(directory);%0A      return directory;%0A    %7D catch (DirectoryNotEmptyException ignored) %7B%0A      // fall-through%0A    %7D catch (Exception exception) %7B%0A      throw new Error(%22Delete directories failed: %22 + directory, exception);%0A    %7D%0A    try (var stream = Files.walk(directory)) %7B // default case: walk the tree...%0A      var selected = stream.sorted((p, q) -%3E -p.compareTo(q));%0A      for (var path : selected.toArray(Path%5B%5D::new)) Files.deleteIfExists(path);%0A    %7D catch (Exception exception) %7B%0A      throw new Error(%22Delete directories failed: %22 + directory, exception);%0A    %7D%0A    return directory
 ;%0A  

Delete workspace on bootstrap