Add 'cli' library (#249)
author박종현/동작제어Lab(SR)/Senior Engineer/삼성전자 <jh1302.park@samsung.com>
Tue, 29 May 2018 08:05:45 +0000 (17:05 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Tue, 29 May 2018 08:05:45 +0000 (17:05 +0900)
This commit introduces 'cli' library (under contrib/) and rewrites
caffegen, caffekit, tflitekit tools using newly introduced 'cli'
library.

Signed-off-by: Jonghyun Park <jh1302.park@samsung.com>
18 files changed:
contrib/caffegen/CMakeLists.txt
contrib/caffegen/include/Command.h [deleted file]
contrib/caffegen/src/DecodeCommand.cpp
contrib/caffegen/src/DecodeCommand.h
contrib/caffegen/src/Driver.cpp
contrib/caffegen/src/EncodeCommand.cpp
contrib/caffegen/src/EncodeCommand.h
contrib/caffegen/src/FillCommand.cpp
contrib/caffegen/src/FillCommand.h
contrib/caffekit/CMakeLists.txt
contrib/caffekit/src/caffekit.cpp
contrib/cli/CMakeLists.txt [new file with mode: 0644]
contrib/cli/include/cli/App.h [new file with mode: 0644]
contrib/cli/include/cli/Command.h [new file with mode: 0644]
contrib/cli/src/App.cpp [new file with mode: 0644]
contrib/cli/src/App.test.cpp [new file with mode: 0644]
contrib/tflitekit/CMakeLists.txt
contrib/tflitekit/src/tflitekit.cpp

index 9527a66..36256b0 100644 (file)
@@ -4,4 +4,5 @@ if(TARGET nncc_frontend_caffe_core)
   add_executable(caffegen ${SOURCES})
   target_include_directories(caffegen PRIVATE include)
   target_link_libraries(caffegen nncc_foundation nncc_frontend_caffe_core)
+  target_link_libraries(caffegen cli)
 endif(TARGET nncc_frontend_caffe_core)
diff --git a/contrib/caffegen/include/Command.h b/contrib/caffegen/include/Command.h
deleted file mode 100644 (file)
index 1ca806a..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef __COMMAND_H__
-#define __COMMAND_H__
-
-struct Command
-{
-  virtual ~Command() = default;
-
-  virtual int run(int argc, char **argv) const = 0;
-};
-
-#endif // __COMMAND_H__
index abd62c3..62fc04f 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <iostream>
 
-int DecodeCommand::run(int, char **) const
+int DecodeCommand::run(int, const char * const *) const
 {
   caffe::NetParameter param;
 
index 1fea0c4..284059e 100644 (file)
@@ -1,11 +1,11 @@
 #ifndef __DECODE_COMMAND_H__
 #define __DECODE_COMMAND_H__
 
-#include "Command.h"
+#include <cli/Command.h>
 
-struct DecodeCommand final : public Command
+struct DecodeCommand final : public cli::Command
 {
-  int run(int argc, char **argv) const override;
+  int run(int argc, const char * const *argv) const override;
 };
 
 #endif // __DECODE_COMMAND_H__
index 5581f1a..9e3239f 100644 (file)
@@ -2,6 +2,7 @@
 #include "EncodeCommand.h"
 #include "DecodeCommand.h"
 
+#include <cli/App.h>
 #include <nncc/foundation/Memory.h>
 
 #include <map>
 
 int main(int argc, char **argv)
 {
-  std::map<std::string, std::unique_ptr<Command>> commands;
+  cli::App app{argv[0]};
 
-  commands["fill"] = nncc::foundation::make_unique<FillCommand>();
-  commands["encode"] = nncc::foundation::make_unique<EncodeCommand>();
-  commands["decode"] = nncc::foundation::make_unique<DecodeCommand>();
+  app.insert("fill", nncc::foundation::make_unique<FillCommand>());
+  app.insert("encode", nncc::foundation::make_unique<EncodeCommand>());
+  app.insert("decode", nncc::foundation::make_unique<DecodeCommand>());
 
-  return commands.at(argv[1])->run(argc - 2, argv + 2);
+  return app.run(argc - 1, argv + 1);
 }
index 3f7428d..ab4a3b0 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <iostream>
 
-int EncodeCommand::run(int, char **) const
+int EncodeCommand::run(int, const char * const *) const
 {
   caffe::NetParameter param;
 
index 2188297..d1daa8a 100644 (file)
@@ -1,11 +1,11 @@
 #ifndef __ENCODE_COMMAND_H__
 #define __ENCODE_COMMAND_H__
 
-#include "Command.h"
+#include <cli/Command.h>
 
-struct EncodeCommand final : public Command
+struct EncodeCommand final : public cli::Command
 {
-  int run(int argc, char **argv) const override;
+  int run(int argc, const char * const *argv) const override;
 };
 
 #endif // __ENCODE_COMMAND_H__
index 8fd83b3..09b0499 100644 (file)
@@ -15,7 +15,7 @@
 #include <random>
 #include <iostream>
 
-int FillCommand::run(int, char **) const
+int FillCommand::run(int, const char * const *) const
 {
   auto param = nncc::foundation::make_unique<::caffe::NetParameter>();
 
index 1300cef..38f127b 100644 (file)
@@ -1,11 +1,11 @@
 #ifndef __FILL_COMMAND_H__
 #define __FILL_COMMAND_H__
 
-#include "Command.h"
+#include <cli/Command.h>
 
-struct FillCommand final : public Command
+struct FillCommand final : public cli::Command
 {
-  int run(int argc, char **argv) const override;
+  int run(int argc, const char * const *argv) const override;
 };
 
 #endif // __FILL_COMMAND_H__
index bf7a887..fa219a1 100644 (file)
@@ -8,4 +8,5 @@ file(GLOB_RECURSE SOURCES "src/*.cpp")
 
 add_executable(caffekit ${SOURCES})
 target_link_libraries(caffekit nncc_foundation)
+target_link_libraries(caffekit cli)
 target_link_libraries(caffekit caffe)
index 23331c3..80467d6 100644 (file)
@@ -1,21 +1,15 @@
-struct Command
-{
-  virtual ~Command() = default;
-
-  virtual int run(int argc, char **argv) const = 0;
-};
-
+#include <cli/Command.h>
 #include <caffe/caffe.hpp>
 
 #include <iostream>
 
-class RunCommand final : public Command
+class RunCommand final : public cli::Command
 {
 public:
-  int run(int argc, char **argv) const override;
+  int run(int argc, const char * const *argv) const override;
 };
 
-int RunCommand::run(int argc, char **argv) const
+int RunCommand::run(int argc, const char * const *argv) const
 {
   // USAGE: HEADER run [.prototxt] ([.caffemodel])
   caffe::Net<float> net(argv[0], caffe::TEST);
@@ -33,6 +27,7 @@ int RunCommand::run(int argc, char **argv) const
 }
 
 #include <nncc/foundation/Memory.h>
+#include <cli/App.h>
 
 #include <map>
 #include <memory>
@@ -40,32 +35,9 @@ int RunCommand::run(int argc, char **argv) const
 
 int main(int argc, char **argv)
 {
-  std::map<std::string, std::unique_ptr<Command>> commands;
-
-  commands["run"] = nncc::foundation::make_unique<RunCommand>();
+  cli::App app{argv[0]};
 
-  if (argc < 2)
-  {
-    std::cerr << "ERROR: COMMAND is not provided" << std::endl;
-    std::cerr << std::endl;
-    std::cerr << "USAGE: " << argv[0] << " [COMMAND] ..." << std::endl;
-    return 255;
-  }
-
-  // USAGE: HEADER [command] ...
-  if (commands.find(argv[1]) == commands.end())
-  {
-    std::cerr << "ERROR: '" << argv[1] << "' is not a valid command" << std::endl;
-    std::cerr << std::endl;
-    std::cerr << "USAGE: " << argv[0] << " [COMMAND] ..." << std::endl;
-    std::cerr << std::endl;
-    std::cerr << "SUPPORTED COMMANDS:" << std::endl;
-    for (auto it = commands.begin(); it != commands.end(); ++it)
-    {
-      std::cerr << "  " << it->first << std::endl;
-    }
-    return 255;
-  }
+  app.insert("run", nncc::foundation::make_unique<RunCommand>());
 
-  return commands.at(argv[1])->run(argc - 2, argv + 2);
+  return app.run(argc - 1, argv + 1);
 }
diff --git a/contrib/cli/CMakeLists.txt b/contrib/cli/CMakeLists.txt
new file mode 100644 (file)
index 0000000..41dd1f1
--- /dev/null
@@ -0,0 +1,17 @@
+list(APPEND SOURCES "src/App.cpp")
+list(APPEND TESTS "src/App.test.cpp")
+
+add_library(cli ${SOURCES})
+target_include_directories(cli PUBLIC include)
+
+nncc_find_package(GTest QUIET)
+
+if(NOT GTest_FOUND)
+  return()
+endif(NOT GTest_FOUND)
+
+add_executable(cli_test ${TESTS})
+target_link_libraries(cli_test cli)
+target_link_libraries(cli_test nncc_foundation)
+target_link_libraries(cli_test gtest_main)
+add_test(cli_test cli_test)
diff --git a/contrib/cli/include/cli/App.h b/contrib/cli/include/cli/App.h
new file mode 100644 (file)
index 0000000..39ee86d
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __CLI_APP_H__
+#define __CLI_APP_H__
+
+#include "Command.h"
+
+#include <map>
+#include <memory>
+#include <string>
+
+namespace cli
+{
+
+class App
+{
+public:
+  explicit App(const std::string &name);
+
+public:
+  App &insert(const std::string &tag, std::unique_ptr<Command> &&command);
+
+public:
+  int run(int argc, const char * const *argv) const;
+
+private:
+  const std::string _name;
+  std::map<std::string, std::unique_ptr<Command>> _commands;
+};
+
+} // namespace cli
+
+#endif // __APP_H__
diff --git a/contrib/cli/include/cli/Command.h b/contrib/cli/include/cli/Command.h
new file mode 100644 (file)
index 0000000..0107188
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __CLI_COMMAND_H__
+#define __CLI_COMMAND_H__
+
+namespace cli
+{
+
+struct Command
+{
+  virtual ~Command() = default;
+
+  virtual int run(int argc, const char * const *argv) const = 0;
+};
+
+} // namespace cli
+
+#endif // __CLI_COMMAND_H__
diff --git a/contrib/cli/src/App.cpp b/contrib/cli/src/App.cpp
new file mode 100644 (file)
index 0000000..56119f8
--- /dev/null
@@ -0,0 +1,54 @@
+#include "cli/App.h"
+
+#include <iostream>
+#include <cassert>
+
+namespace cli
+{
+
+App::App(const std::string &name) : _name{name}
+{
+  // DO NOTHING
+}
+
+App &App::insert(const std::string &tag, std::unique_ptr<Command> &&command)
+{
+  assert(_commands.find(tag) == _commands.end());
+
+  _commands[tag] = std::move(command);
+
+  return (*this);
+}
+
+int App::run(int argc, const char * const *argv) const
+{
+  if (argc < 1)
+  {
+    std::cerr << "ERROR: COMMAND is not provided" << std::endl;
+    std::cerr << std::endl;
+    std::cerr << "USAGE: " << _name << " [COMMAND] ..." << std::endl;
+    return 255;
+  }
+
+  const std::string command{argv[0]};
+
+  auto it = _commands.find(command);
+
+  if (it == _commands.end())
+  {
+    std::cerr << "ERROR: '" << command << "' is not a valid command" << std::endl;
+    std::cerr << std::endl;
+    std::cerr << "USAGE: " << _name << " [COMMAND] ..." << std::endl;
+    std::cerr << std::endl;
+    std::cerr << "SUPPORTED COMMANDS:" << std::endl;
+    for (auto it = _commands.begin(); it != _commands.end(); ++it)
+    {
+      std::cerr << "  " << it->first << std::endl;
+    }
+    return 255;
+  }
+
+  return it->second->run(argc - 1, argv + 1);
+}
+
+} // namespace cli
diff --git a/contrib/cli/src/App.test.cpp b/contrib/cli/src/App.test.cpp
new file mode 100644 (file)
index 0000000..450dd21
--- /dev/null
@@ -0,0 +1,51 @@
+#include "cli/App.h"
+
+#include <nncc/foundation/Memory.h>
+
+#include <gtest/gtest.h>
+
+class RecordCommand final : public cli::Command
+{
+public:
+  RecordCommand(int ret, std::string &out) : _ret{ret}, _out(out)
+  {
+    // DO NOTHING
+  }
+
+public:
+  int run(int argc, const char * const *argv) const override
+  {
+    _out += std::to_string(argc);
+
+    for (int n = 0; n < argc; ++n)
+    {
+      _out += ";";
+      _out += argv[n];
+    }
+
+    return _ret;
+  }
+
+private:
+  int const _ret;
+  std::string &_out;
+};
+
+TEST(APP, run)
+{
+  cli::App app("test");
+
+  std::string args;
+  app.insert("record", nncc::foundation::make_unique<RecordCommand>(3, args));
+
+  const char *argv[] = {
+    "record",
+    "hello",
+    "world"
+  };
+
+  int ret = app.run(3, argv);
+
+  ASSERT_EQ(ret, 3);
+  ASSERT_EQ(args, "2;hello;world");
+}
index 5f95cdf..e990643 100644 (file)
@@ -8,4 +8,5 @@ file(GLOB_RECURSE SOURCES "src/*.cpp")
 
 add_executable(tflitekit ${SOURCES})
 target_link_libraries(tflitekit nncc_foundation)
+target_link_libraries(tflitekit cli)
 target_link_libraries(tflitekit tensorflowlite)
index 1612153..f29cf48 100644 (file)
@@ -1,25 +1,19 @@
-struct Command
-{
-  virtual ~Command() = default;
-
-  virtual int run(int argc, char **argv) const = 0;
-};
-
 #include "tensorflow/contrib/lite/kernels/register.h"
 #include "tensorflow/contrib/lite/model.h"
 
+#include <cli/Command.h>
 #include <iostream>
 
 using namespace tflite;
 using namespace tflite::ops::builtin;
 
-class RunCommand final : public Command
+class RunCommand final : public cli::Command
 {
 public:
-  int run(int argc, char **argv) const override;
+  int run(int argc, const char * const *argv) const override;
 };
 
-int RunCommand::run(int argc, char **argv) const
+int RunCommand::run(int argc, const char * const *argv) const
 {
   // USAGE: HEADER run [.tflite]
   const auto filename = argv[0];
@@ -52,6 +46,7 @@ int RunCommand::run(int argc, char **argv) const
 }
 
 #include <nncc/foundation/Memory.h>
+#include <cli/App.h>
 
 #include <map>
 #include <memory>
@@ -59,32 +54,9 @@ int RunCommand::run(int argc, char **argv) const
 
 int main(int argc, char **argv)
 {
-  std::map<std::string, std::unique_ptr<Command>> commands;
-
-  commands["run"] = nncc::foundation::make_unique<RunCommand>();
-
-  if (argc < 2)
-  {
-    std::cerr << "ERROR: COMMAND is not provided" << std::endl;
-    std::cerr << std::endl;
-    std::cerr << "USAGE: " << argv[0] << " [COMMAND] ..." << std::endl;
-    return 255;
-  }
-
-  // USAGE: HEADER [command] ...
-  if (commands.find(argv[1]) == commands.end())
-  {
-    std::cerr << "ERROR: '" << argv[1] << "' is not a valid command" << std::endl;
-    std::cerr << std::endl;
-    std::cerr << "USAGE: " << argv[0] << " [COMMAND] ..." << std::endl;
-    std::cerr << std::endl;
-    std::cerr << "SUPPORTED COMMANDS:" << std::endl;
-    for (auto it = commands.begin(); it != commands.end(); ++it)
-    {
-      std::cerr << "  " << it->first << std::endl;
-    }
-    return 255;
-  }
-
-  return commands.at(argv[1])->run(argc - 2, argv + 2);
+  cli::App app{argv[0]};
+
+  app.insert("run", nncc::foundation::make_unique<RunCommand>());
+
+  return app.run(argc - 1, argv + 1);
 }