repo: visualize contents of the repo
Change-Id: Ifc960d0aaedf816488616aec9ef457b66be9414c
refs #1789
diff --git a/tools/repo-ng-ls.cpp b/tools/repo-ng-ls.cpp
new file mode 100644
index 0000000..be51b34
--- /dev/null
+++ b/tools/repo-ng-ls.cpp
@@ -0,0 +1,204 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California.
+ *
+ * This file is part of NDN repo-ng (Next generation of NDN repository).
+ * See AUTHORS.md for complete list of repo-ng authors and contributors.
+ *
+ * repo-ng is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * repo-ng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * repo-ng, e.g., in COPYING.md file. if (not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "../src/common.hpp"
+#include "config.hpp"
+#include <string>
+#include <sqlite3.h>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/info_parser.hpp>
+
+namespace repo {
+
+using namespace ndn::time;
+
+void
+printUsage(const char* programName)
+{
+
+ std::cout
+ << "Usage:\n"
+ << " " << programName << " [-c <path/to/repo-ng.conf>] [-n] [-h]\n"
+ << "\n"
+ << "List names of Data packets in NDN repository. "
+ << "By default, all names will include the implicit digest of Data packets\n"
+ << "\n"
+ << "Options:\n"
+ << " -h: show help message\n"
+ << " -c: set config file path\n"
+ << " -n: do not show implicit digest\n"
+ << std::endl;
+ ;
+}
+
+class RepoEnumerator
+{
+public:
+ class Error : public std::runtime_error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : std::runtime_error(what)
+ {
+ }
+ };
+
+public:
+ RepoEnumerator(const std::string& configFile);
+
+ uint64_t
+ enumerate(bool showImplicitDigest);
+
+private:
+ void
+ readConfig(const std::string& configFile);
+
+private:
+ sqlite3* m_db;
+ std::string m_dbPath;
+};
+
+RepoEnumerator::RepoEnumerator(const std::string& configFile)
+{
+ readConfig(configFile);
+ char* errMsg = 0;
+ int rc = sqlite3_open_v2(m_dbPath.c_str(), &m_db,
+ SQLITE_OPEN_READONLY,
+ #ifdef DISABLE_SQLITE3_FS_LOCKING
+ "unix-dotfile"
+ #else
+ 0
+ #endif
+ );
+ if (rc != SQLITE_OK) {
+ throw Error("Database file open failure");
+ }
+ sqlite3_exec(m_db, "PRAGMA synchronous = OFF", 0, 0, &errMsg);
+ sqlite3_exec(m_db, "PRAGMA journal_mode = WAL", 0, 0, &errMsg);
+}
+
+void
+RepoEnumerator::readConfig(const std::string& configFile)
+{
+ if (configFile.empty()) {
+ throw Error("Invalid configuration file name");
+ }
+
+ std::ifstream fin(configFile.c_str());
+ if (!fin.is_open())
+ throw Error("failed to open configuration file '" + configFile + "'");
+
+ using namespace boost::property_tree;
+ ptree propertyTree;
+ try {
+ read_info(fin, propertyTree);
+ }
+ catch (ptree_error& e) {
+ throw Error("failed to read configuration file '" + configFile + "'");
+ }
+ ptree repoConf = propertyTree.get_child("repo");
+ m_dbPath = repoConf.get<std::string>("storage.path");
+ m_dbPath += "/ndn_repo.db";
+}
+
+uint64_t
+RepoEnumerator::enumerate(bool showImplicitDigest)
+{
+ sqlite3_stmt* m_stmt = 0;
+ int rc = SQLITE_DONE;
+ string sql = string("SELECT id, name, keylocatorHash FROM NDN_REPO;");
+ rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &m_stmt, 0);
+ if (rc != SQLITE_OK)
+ throw Error("Initiation Read Entries from Database Prepare error");
+ uint64_t entryNumber = 0;
+ while (true) {
+ rc = sqlite3_step(m_stmt);
+ if (rc == SQLITE_ROW) {
+ Name name;
+ name.wireDecode(Block(sqlite3_column_blob(m_stmt, 1),
+ sqlite3_column_bytes(m_stmt, 1)));
+ try {
+ if (showImplicitDigest) {
+ std::cout << name << std::endl;
+ }
+ else {
+ std::cout << name.getPrefix(-1) << std::endl;
+ }
+ }
+ catch (...){
+ sqlite3_finalize(m_stmt);
+ throw;
+ }
+ entryNumber++;
+ }
+ else if (rc == SQLITE_DONE) {
+ sqlite3_finalize(m_stmt);
+ break;
+ }
+ else {
+ sqlite3_finalize(m_stmt);
+ throw Error("Initiation Read Entries error");
+ }
+ }
+ return entryNumber;
+}
+
+int
+main(int argc, char** argv)
+{
+ string configPath = DEFAULT_CONFIG_FILE;
+ bool showImplicitDigest = true;
+ int opt;
+ while ((opt = getopt(argc, argv, "hc:n")) != -1) {
+ switch (opt) {
+ case 'h':
+ printUsage(argv[0]);
+ return 0;
+ case 'c':
+ configPath = string(optarg);
+ break;
+ case 'n':
+ showImplicitDigest = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ RepoEnumerator instance(configPath);
+ uint64_t count = instance.enumerate(showImplicitDigest);
+ std::cerr << "Total number of data = " << count << std::endl;
+ return 0;
+}
+
+} // namespace repo
+
+
+int
+main(int argc, char** argv)
+{
+ try {
+ return repo::main(argc, argv);
+ }
+ catch (std::exception& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ return 2;
+ }
+}