All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.appland.appmap.cli.Status Maven / Gradle / Ivy

package com.appland.appmap.cli;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.lang3.SystemUtils;
import org.yaml.snakeyaml.Yaml;
import picocli.CommandLine;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

@CommandLine.Command(name = "status", description = "Prints AppMap status of the Java project in a specified directory.")
public class Status implements Callable {
  @CommandLine.ParentCommand
  private CLI parent;

  static class Command {
    public String program;
    public List args = new ArrayList<>();
    public Map environment = new HashMap<>();
  }

  static class TestCommand {
    public String framework;
    public Command command;

    TestCommand(String framework) {
      this.framework = framework;
    }
  }

  static class ConfigStatus {
    public String app;
    public boolean present;
    public boolean valid;
  }

  static class AgentStatus {
    public String version = Status.class.getPackage().getImplementationVersion();
  }

  static class ProjectStatus {
    public String language = "java";
  }

  static class FrameworkStatus {
    public String name;
    public boolean present;
    public boolean valid;
  }

  static class Properties {
    public ConfigStatus config = new ConfigStatus();
    public AgentStatus agent = new AgentStatus();
    public ProjectStatus project = new ProjectStatus();
    public List frameworks = new ArrayList<>();

    static boolean isConfigValid(Path path) {
      // Start with simple YAML validation
      Yaml yaml = new Yaml();
      InputStream inputStream = null;
      try {
        inputStream = Files.newInputStream(path);
      } catch (IOException e) {
        // System.err.println(e);
        return false;
      }
      try {
        yaml.load(inputStream);
      } catch (RuntimeException e) {
        // TODO: Good validation messages are available here. An example:
        /*
        while scanning a simple key
         in 'reader', line 7, column 1:
            xx
            ^
        could not find expected ':'
         in 'reader', line 7, column 3:
            xx
              ^
        */
        // System.err.println(e);
        return false;
      }

      return true;
    }

    static boolean isGradlePresent(Path projectPath) {
      return Arrays.stream(new String[]{"build.gradle", "build.gradle.kts"})
          .map(new Function() {
            public Path apply(String pathName) {
              return projectPath.resolve(pathName);
            }
          })
          .filter((Path path) -> Files.exists(path))
          .anyMatch((path) -> {
            try {
              return Files.readAllLines(path).stream().anyMatch((line) -> line.contains("com.appland.appmap"));
            } catch (IOException e) {
              return false;
            }
          });
    }

    static boolean isGradleValid(Path projectPath) {
      String gradleWrapper = SystemUtils.IS_OS_WINDOWS ? "gradlew.bat" : "./gradlew";
      if (!projectPath.resolve(gradleWrapper).toFile().exists()) {
        gradleWrapper = "gradle";
      }

      // Our doc says that the user can run: gradle appmap test
      // Try and run gradle --help appmap
      String command = gradleWrapper + " --help appmap";
      // System.err.printf("Attempting: %s\n", command);
      try {
        Process process = Runtime.getRuntime().exec(command);
        process.waitFor(60, TimeUnit.SECONDS);
        return process.exitValue() == 0;
      } catch (IOException | InterruptedException e) {
        return false;
      }
    }

    static boolean isMavenPresent(Path projectPath) {
      Path pom = projectPath.resolve("pom.xml");
      if (!Files.exists(pom)) {
        return false;
      }

      try {
        // This is hokey compared to parsing the pom, but ...
        return Files.readAllLines(pom).stream().anyMatch((line) -> line.contains("appmap-maven-plugin"));
      } catch (IOException e) {
        return false;
      }
    }

    static boolean isMavenValid(Path projectPath) {
      String mavenWrapper = SystemUtils.IS_OS_WINDOWS ? "mvnw.cmd" : "./mvnw";
      if (!projectPath.resolve(mavenWrapper).toFile().exists()) {
        mavenWrapper = "mvn";
      }

      String command = mavenWrapper + " -Dplugin=com.appland:appmap-maven-plugin help:describe";
      // System.err.printf("Attempting: %s\n", command);
      try {
        Process process = Runtime.getRuntime().exec(command);
        process.waitFor(60, TimeUnit.SECONDS);
        return process.exitValue() == 0;
      } catch (IOException | InterruptedException e) {
        return false;
      }
    }
  }

  static class Result {
    public List testCommands = new ArrayList<>();
    public Status.Properties properties = new Status.Properties();
  }

  public Integer call() {
    System.err.printf("Reporting AppMap project status in directory: %s\n", parent.directory);

    Path dirPath = Paths.get(parent.directory);
    Path configPath = dirPath.resolve("appmap.yml");

    Result result = new Result();
    result.properties.config.app = CLI.projectName(dirPath.toFile());
    result.properties.config.present = Files.exists(configPath);
    if (result.properties.config.present) {
      result.properties.config.valid = Properties.isConfigValid(configPath);
    }
    FrameworkStatus gradleStatus = new FrameworkStatus();
    gradleStatus.name = "gradle";
    gradleStatus.present = Properties.isGradlePresent(dirPath);
    if (gradleStatus.present) {
      gradleStatus.valid = Properties.isGradleValid(dirPath);
    }
    result.properties.frameworks.add(gradleStatus);

    FrameworkStatus mavenStatus = new FrameworkStatus();
    mavenStatus.name = "maven";
    mavenStatus.present = Properties.isMavenPresent(dirPath);
    if (mavenStatus.present) {
      mavenStatus.valid = Properties.isMavenValid(dirPath);
    }
    result.properties.frameworks.add(mavenStatus);

    if (gradleStatus.valid) {
      String gradleWrapper = SystemUtils.IS_OS_WINDOWS ? "gradlew.bat" : "./gradlew";

      Command command = new Command();
      command.program = gradleWrapper;
      command.args.add("appmap");
      command.args.add("test");

      TestCommand tc = new TestCommand("gradle");
      tc.command = command;

      result.testCommands.add(tc);
    }
    if (mavenStatus.valid) {
      String mavenWrapper = SystemUtils.IS_OS_WINDOWS ? "mvnw.cmd" : "./mvnw";
      if (!dirPath.resolve(mavenWrapper).toFile().exists()) {
        mavenWrapper = "mvn";
      }

      Command command = new Command();
      command.program = mavenWrapper;
      command.args.add("test");

      TestCommand tc = new TestCommand("maven");
      tc.command = command;

      result.testCommands.add(tc);
    }

    parent.getOutputStream().println(JSON.toJSONString(result, SerializerFeature.PrettyFormat));

    return 0;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy