AAPT2: Refactor flags into commands

Refactors the flag based command invocation into classes that make using
subcommands easier.

Test: manual tests of printing
Change-Id: Ic8df6af0be30db552e32150afebecbfeec7e1075
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 808b29c..23903c9e 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -29,6 +29,13 @@
 #include "androidfw/StringPiece.h"
 
 #include "Diagnostics.h"
+#include "cmd/Command.h"
+#include "cmd/Compile.h"
+#include "cmd/Convert.h"
+#include "cmd/Diff.h"
+#include "cmd/Dump.h"
+#include "cmd/Link.h"
+#include "cmd/Optimize.h"
 #include "util/Files.h"
 #include "util/Util.h"
 
@@ -43,114 +50,121 @@
 // Update minor version whenever a feature or flag is added.
 static const char* sMinorVersion = "19";
 
-static void PrintVersion() {
-  std::cerr << StringPrintf("Android Asset Packaging Tool (aapt) %s:%s", sMajorVersion,
-                            sMinorVersion)
-            << std::endl;
-}
+/** Prints the version information of AAPT2. */
+class VersionCommand : public Command {
+ public:
+  explicit VersionCommand() : Command("version") {
+    SetDescription("Prints the version of aapt.");
+  }
 
-static void PrintUsage() {
-  std::cerr << "\nusage: aapt2 [compile|link|dump|diff|optimize|convert|version] ..." << std::endl;
-}
-
-extern int Compile(const std::vector<StringPiece>& args, IDiagnostics* diagnostics);
-extern int Link(const std::vector<StringPiece>& args, IDiagnostics* diagnostics);
-extern int Dump(const std::vector<StringPiece>& args);
-extern int Diff(const std::vector<StringPiece>& args);
-extern int Optimize(const std::vector<StringPiece>& args);
-extern int Convert(const std::vector<StringPiece>& args);
-
-static int ExecuteCommand(const StringPiece& command, const std::vector<StringPiece>& args,
-                          IDiagnostics* diagnostics) {
-  if (command == "compile" || command == "c") {
-    return Compile(args, diagnostics);
-  } else if (command == "link" || command == "l") {
-    return Link(args, diagnostics);
-  } else if (command == "dump" || command == "d") {
-    return Dump(args);
-  } else if (command == "diff") {
-    return Diff(args);
-  } else if (command == "optimize") {
-    return Optimize(args);
-  } else if (command == "convert") {
-    return Convert(args);
-  } else if (command == "version") {
-    PrintVersion();
+  int Action(const std::vector<std::string>& /* args */) override {
+    std::cerr << StringPrintf("Android Asset Packaging Tool (aapt) %s:%s", sMajorVersion,
+                              sMinorVersion)
+              << std::endl;
     return 0;
   }
-  diagnostics->Error(DiagMessage() << "unknown command '" << command << "'");
-  return -1;
-}
+};
 
-static void RunDaemon(IDiagnostics* diagnostics) {
-  std::cout << "Ready" << std::endl;
-
-  // Run in daemon mode. The first line of input is the command. This can be 'quit' which ends
-  // the daemon mode. Each subsequent line is a single parameter to the command. The end of a
-  // invocation is signaled by providing an empty line. At any point, an EOF signal or the
-  // command 'quit' will end the daemon mode.
-  while (true) {
-    std::vector<std::string> raw_args;
-    for (std::string line; std::getline(std::cin, line) && !line.empty();) {
-      raw_args.push_back(line);
-    }
-
-    if (!std::cin) {
-      break;
-    }
-
-    // An empty command does nothing.
-    if (raw_args.empty()) {
-      continue;
-    }
-
-    if (raw_args[0] == "quit") {
-      break;
-    }
-
-    std::vector<StringPiece> args;
-    args.insert(args.end(), ++raw_args.begin(), raw_args.end());
-    int ret = ExecuteCommand(raw_args[0], args, diagnostics);
-    if (ret != 0) {
-      std::cerr << "Error" << std::endl;
-    }
-    std::cerr << "Done" << std::endl;
+/** The main entry point of AAPT. */
+class MainCommand : public Command {
+ public:
+  explicit MainCommand(IDiagnostics* diagnostics) : Command("aapt2"), diagnostics_(diagnostics) {
+    AddOptionalSubcommand(util::make_unique<CompileCommand>(diagnostics));
+    AddOptionalSubcommand(util::make_unique<LinkCommand>(diagnostics));
+    AddOptionalSubcommand(util::make_unique<DumpCommand>());
+    AddOptionalSubcommand(util::make_unique<DiffCommand>());
+    AddOptionalSubcommand(util::make_unique<OptimizeCommand>());
+    AddOptionalSubcommand(util::make_unique<ConvertCommand>());
+    AddOptionalSubcommand(util::make_unique<VersionCommand>());
   }
-  std::cout << "Exiting daemon" << std::endl;
-}
+
+  int Action(const std::vector<std::string>& args) override {
+    if (args.size() == 0) {
+      diagnostics_->Error(DiagMessage() << "no subcommand specified");
+    } else {
+      diagnostics_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'");
+    }
+
+    Usage(&std::cerr);
+    return -1;
+  }
+
+ private:
+  IDiagnostics* diagnostics_;
+};
+
+/*
+ * Run in daemon mode. The first line of input is the command. This can be 'quit' which ends
+ * the daemon mode. Each subsequent line is a single parameter to the command. The end of a
+ * invocation is signaled by providing an empty line. At any point, an EOF signal or the
+ * command 'quit' will end the daemon mode.
+ */
+class DaemonCommand : public Command {
+ public:
+  explicit DaemonCommand(IDiagnostics* diagnostics) : Command("daemon", "m"),
+                                                      diagnostics_(diagnostics) {
+    SetDescription("Runs aapt in daemon mode. Each subsequent line is a single parameter to the\n"
+        "command. The end of an invocation is signaled by providing an empty line.");
+  }
+
+  int Action(const std::vector<std::string>& /* args */) override {
+    std::cout << "Ready" << std::endl;
+
+    while (true) {
+      std::vector<std::string> raw_args;
+      for (std::string line; std::getline(std::cin, line) && !line.empty();) {
+        raw_args.push_back(line);
+      }
+
+      if (!std::cin) {
+        break;
+      }
+
+      // An empty command does nothing.
+      if (raw_args.empty()) {
+        continue;
+      }
+
+      // End the dameon
+      if (raw_args[0] == "quit") {
+        break;
+      }
+
+      std::vector<StringPiece> args;
+      args.insert(args.end(), raw_args.begin(), raw_args.end());
+      if (MainCommand(diagnostics_).Execute(args, &std::cerr) != 0) {
+        std::cerr << "Error" << std::endl;
+      }
+      std::cerr << "Done" << std::endl;
+    }
+    std::cout << "Exiting daemon" << std::endl;
+
+    return 0;
+  }
+
+ private:
+  IDiagnostics* diagnostics_;
+};
 
 }  // namespace aapt
 
 int MainImpl(int argc, char** argv) {
-  if (argc < 2) {
-    std::cerr << "no command specified\n";
-    aapt::PrintUsage();
+  if (argc < 1) {
     return -1;
   }
 
-  argv += 1;
-  argc -= 1;
-
-  aapt::StdErrDiagnostics diagnostics;
-
   // Collect the arguments starting after the program name and command name.
   std::vector<StringPiece> args;
   for (int i = 1; i < argc; i++) {
     args.push_back(argv[i]);
   }
 
-  const StringPiece command(argv[0]);
-  if (command != "daemon" && command != "m") {
-    // Single execution.
-    const int result = aapt::ExecuteCommand(command, args, &diagnostics);
-    if (result < 0) {
-      aapt::PrintUsage();
-    }
-    return result;
-  }
+  // Add the daemon subcommand here so it cannot be called while executing the daemon
+  aapt::StdErrDiagnostics diagnostics;
+  auto main_command = new aapt::MainCommand(&diagnostics);
+  main_command->AddOptionalSubcommand(aapt::util::make_unique<aapt::DaemonCommand>(&diagnostics));
 
-  aapt::RunDaemon(&diagnostics);
-  return 0;
+  return main_command->Execute(args, &std::cerr);
 }
 
 int main(int argc, char** argv) {