aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2023-01-13 07:08:02 -0800
committerGitHub <[email protected]>2023-01-13 07:08:02 -0800
commit61f18d2de7f37aa03aa09d55562d05c6da033eb2 (patch)
tree217828004ee4417b6f2be80a7bf778b808798e4d
parentAdd info (GET) endpoints for structured cache (#211) (diff)
downloadzen-61f18d2de7f37aa03aa09d55562d05c6da033eb2.tar.xz
zen-61f18d2de7f37aa03aa09d55562d05c6da033eb2.zip
zen command line tool improvements (#212)
- Feature: zen command line tool `cache-info` to show cache, namespace or bucket info - Feature: zen command line tool `project-info` to show store, project or oplog info - Feature: zen command line tool `project-drop` to drop project or oplog - Feature: zen command line tool `gc` to trigger a GC run - Feature: zen command line tool `gc-info` to check status of GC - Improvement: zen command line tool now fails on any unrecognized arguments - Improvement: zen command line tool now displays extra help for all sub-commands - Improvement: host address can now be configured for zen command line tool `drop` command changelog
-rw-r--r--CHANGELOG.md10
-rw-r--r--zen/chunk/chunk.cpp5
-rw-r--r--zen/chunk/chunk.h2
-rw-r--r--zen/cmds/cache.cpp70
-rw-r--r--zen/cmds/cache.h21
-rw-r--r--zen/cmds/copy.cpp9
-rw-r--r--zen/cmds/copy.h2
-rw-r--r--zen/cmds/dedup.cpp9
-rw-r--r--zen/cmds/dedup.h2
-rw-r--r--zen/cmds/exportproject.cpp7
-rw-r--r--zen/cmds/exportproject.h2
-rw-r--r--zen/cmds/hash.cpp5
-rw-r--r--zen/cmds/hash.h2
-rw-r--r--zen/cmds/importproject.cpp7
-rw-r--r--zen/cmds/importproject.h2
-rw-r--r--zen/cmds/print.cpp22
-rw-r--r--zen/cmds/print.h4
-rw-r--r--zen/cmds/projectstore.cpp132
-rw-r--r--zen/cmds/projectstore.h36
-rw-r--r--zen/cmds/run.cpp4
-rw-r--r--zen/cmds/run.h2
-rw-r--r--zen/cmds/scrub.cpp116
-rw-r--r--zen/cmds/scrub.h23
-rw-r--r--zen/cmds/status.h2
-rw-r--r--zen/cmds/top.h4
-rw-r--r--zen/cmds/up.h4
-rw-r--r--zen/cmds/version.cpp7
-rw-r--r--zen/cmds/version.h2
-rw-r--r--zen/zen.cpp100
-rw-r--r--zen/zen.h4
-rw-r--r--zenserver/projectstore.cpp1
31 files changed, 519 insertions, 99 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d9cf77196..bfce09d7b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,15 @@
- `/z$/{namespace}/{bucket}` - get bucket info
- Feature: Added project store oplog info: `markerpath`, `totalsize`, `opcount`, `expired` on GET requests for oplog
- Feature: Added project store project info: `expired` on GET requests for project
-- Feature :Added project store root route `/prj` which is identical to `/prj/list`
+- Feature: Added project store root route `/prj` which is identical to `/prj/list`
+- Feature: zen command line tool `cache-info` to show cache, namespace or bucket info
+- Feature: zen command line tool `project-info` to show store, project or oplog info
+- Feature: zen command line tool `project-drop` to drop project or oplog
+- Feature: zen command line tool `gc` to trigger a GC run
+- Feature: zen command line tool `gc-info` to check status of GC
+- Improvement: zen command line tool now fails on any unrecognized arguments
+- Improvement: zen command line tool now displays extra help for all sub-commands
+- Improvement: host address can now be configured for zen command line tool `drop` command
## 0.2.1
- Feature: Oplog level GC in project store. If gc marker file path is given by UE, oplogs will be GC:d when marker file is deleted (and GC is triggered)
diff --git a/zen/chunk/chunk.cpp b/zen/chunk/chunk.cpp
index 3fd7c4c1f..d3591f8ca 100644
--- a/zen/chunk/chunk.cpp
+++ b/zen/chunk/chunk.cpp
@@ -978,7 +978,10 @@ ChunkCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{
ZEN_UNUSED(GlobalOptions);
- auto result = m_Options.parse(argc, argv);
+ if (!ParseOptions(argc, argv))
+ {
+ return 0;
+ }
bool IsValid = m_ScanDirectory.length();
diff --git a/zen/chunk/chunk.h b/zen/chunk/chunk.h
index 32d87b1b7..e796f4147 100644
--- a/zen/chunk/chunk.h
+++ b/zen/chunk/chunk.h
@@ -12,7 +12,7 @@ public:
~ChunkCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"chunk", "Do a chunking pass"};
diff --git a/zen/cmds/cache.cpp b/zen/cmds/cache.cpp
index a4fe4da34..2407f5f55 100644
--- a/zen/cmds/cache.cpp
+++ b/zen/cmds/cache.cpp
@@ -16,8 +16,10 @@ ZEN_THIRD_PARTY_INCLUDES_END
DropCommand::DropCommand()
{
m_Options.add_options()("h,help", "Print help");
+ m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value("http://localhost:1337"), "<hosturl>");
m_Options.add_option("", "n", "namespace", "Namnspace name", cxxopts::value(m_NamespaceName), "<namespacename>");
m_Options.add_option("", "b", "bucket", "Bucket name", cxxopts::value(m_BucketName), "<bucketname>");
+ m_Options.parse_positional({"namespace", "bucket"});
}
DropCommand::~DropCommand() = default;
@@ -25,10 +27,12 @@ DropCommand::~DropCommand() = default;
int
DropCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{
- ZEN_UNUSED(GlobalOptions, argc, argv);
+ ZEN_UNUSED(GlobalOptions);
- m_Options.parse_positional({"namespace", "bucket"});
- m_Options.parse(argc, argv);
+ if (!ParseOptions(argc, argv))
+ {
+ return 0;
+ }
if (m_NamespaceName.empty())
{
@@ -67,3 +71,63 @@ DropCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
return 1;
}
+
+CacheInfoCommand::CacheInfoCommand()
+{
+ m_Options.add_options()("h,help", "Print help");
+ m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value("http://localhost:1337"), "<hosturl>");
+ m_Options.add_option("", "n", "namespace", "Namnspace name", cxxopts::value(m_NamespaceName), "<namespacename>");
+ m_Options.add_option("", "b", "bucket", "Bucket name", cxxopts::value(m_BucketName), "<bucketname>");
+ m_Options.parse_positional({"namespace", "bucket"});
+}
+
+CacheInfoCommand::~CacheInfoCommand() = default;
+
+int
+CacheInfoCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
+{
+ ZEN_UNUSED(GlobalOptions);
+
+ if (!ParseOptions(argc, argv))
+ {
+ return 0;
+ }
+
+ cpr::Session Session;
+ Session.SetHeader(cpr::Header{{"Accept", "application/json"}});
+ if (m_HostName.empty())
+ {
+ ZEN_CONSOLE("Info on cache from '{}'", m_HostName);
+ Session.SetUrl({fmt::format("{}/z$", m_HostName)});
+ }
+ else if (m_BucketName.empty())
+ {
+ ZEN_CONSOLE("Info on cache namespace '{}' from '{}'", m_NamespaceName, m_HostName);
+ Session.SetUrl({fmt::format("{}/z$/{}", m_HostName, m_NamespaceName)});
+ }
+ else
+ {
+ ZEN_CONSOLE("Info on cache bucket '{}/{}' from '{}'", m_NamespaceName, m_BucketName, m_HostName);
+ Session.SetUrl({fmt::format("{}/z$/{}/{}", m_HostName, m_NamespaceName, m_BucketName)});
+ }
+
+ cpr::Response Result = Session.Get();
+
+ if (zen::IsHttpSuccessCode(Result.status_code))
+ {
+ ZEN_CONSOLE("{}", Result.text);
+
+ return 0;
+ }
+
+ if (Result.status_code)
+ {
+ ZEN_ERROR("Info failed: {}: {} ({})", Result.status_code, Result.reason, Result.text);
+ }
+ else
+ {
+ ZEN_ERROR("Info failed: {}", Result.error.message);
+ }
+
+ return 1;
+}
diff --git a/zen/cmds/cache.h b/zen/cmds/cache.h
index 1eb32eb99..915c3d7d3 100644
--- a/zen/cmds/cache.h
+++ b/zen/cmds/cache.h
@@ -11,11 +11,26 @@ public:
~DropCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
- cxxopts::Options m_Options{"drop", "Drop one or more cache buckets"};
+ cxxopts::Options m_Options{"drop", "Drop cache namespace or bucket"};
+ std::string m_HostName;
+ std::string m_NamespaceName;
+ std::string m_BucketName;
+};
+
+class CacheInfoCommand : public ZenCmdBase
+{
+public:
+ CacheInfoCommand();
+ ~CacheInfoCommand();
+ virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
+ virtual cxxopts::Options& Options() override { return m_Options; }
+
+private:
+ cxxopts::Options m_Options{"cache-info", "Info on cache, namespace or bucket"};
+ std::string m_HostName;
std::string m_NamespaceName;
std::string m_BucketName;
- std::string m_HostName{"http://localhost:1337"};
};
diff --git a/zen/cmds/copy.cpp b/zen/cmds/copy.cpp
index f3ca242e3..6f6c078d4 100644
--- a/zen/cmds/copy.cpp
+++ b/zen/cmds/copy.cpp
@@ -16,6 +16,7 @@ CopyCommand::CopyCommand()
m_Options.add_option("", "s", "source", "Copy source", cxxopts::value(m_CopySource), "<file/directory>");
m_Options.add_option("", "t", "target", "Copy target", cxxopts::value(m_CopyTarget), "<file/directory>");
m_Options.add_option("", "", "positional", "Positional arguments", cxxopts::value(m_Positional), "");
+ m_Options.parse_positional({"source", "target", "positional"});
}
CopyCommand::~CopyCommand() = default;
@@ -25,14 +26,8 @@ CopyCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{
ZEN_UNUSED(GlobalOptions);
- m_Options.parse_positional({"source", "target", "positional"});
-
- auto result = m_Options.parse(argc, argv);
-
- if (result.count("help"))
+ if (!ZenCmdBase::ParseOptions(argc, argv))
{
- std::cout << m_Options.help({"", "Group"}) << std::endl;
-
return 0;
}
diff --git a/zen/cmds/copy.h b/zen/cmds/copy.h
index 322cf3f2f..5527ae9b8 100644
--- a/zen/cmds/copy.h
+++ b/zen/cmds/copy.h
@@ -14,7 +14,7 @@ public:
CopyCommand();
~CopyCommand();
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
private:
diff --git a/zen/cmds/dedup.cpp b/zen/cmds/dedup.cpp
index 2b599c307..b48fb8c2d 100644
--- a/zen/cmds/dedup.cpp
+++ b/zen/cmds/dedup.cpp
@@ -44,6 +44,7 @@ DedupCommand::DedupCommand()
m_Options.add_option("", "s", "source", "Copy source", cxxopts::value(m_DedupSource), "<file/directory>");
m_Options.add_option("", "t", "target", "Copy target", cxxopts::value(m_DedupTarget), "<file/directory>");
m_Options.add_option("", "", "positional", "Positional arguments", cxxopts::value(m_Positional), "");
+ m_Options.parse_positional({"source", "target", "positional"});
}
DedupCommand::~DedupCommand() = default;
@@ -53,14 +54,8 @@ DedupCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{
ZEN_UNUSED(GlobalOptions);
- m_Options.parse_positional({"source", "target", "positional"});
-
- auto result = m_Options.parse(argc, argv);
-
- if (result.count("help"))
+ if (!ParseOptions(argc, argv))
{
- std::cout << m_Options.help({"", "Group"}) << std::endl;
-
return 0;
}
diff --git a/zen/cmds/dedup.h b/zen/cmds/dedup.h
index dbda236f6..6318704f5 100644
--- a/zen/cmds/dedup.h
+++ b/zen/cmds/dedup.h
@@ -14,7 +14,7 @@ public:
DedupCommand();
~DedupCommand();
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
private:
diff --git a/zen/cmds/exportproject.cpp b/zen/cmds/exportproject.cpp
index 8c7c6821b..6925c9f03 100644
--- a/zen/cmds/exportproject.cpp
+++ b/zen/cmds/exportproject.cpp
@@ -29,6 +29,7 @@ ExportProjectCommand::ExportProjectCommand()
m_Options.add_option("", "t", "target", "Target path", cxxopts::value(m_TargetPath), "<targetpath>");
m_Options.add_option("", "p", "project", "Project name", cxxopts::value(m_ProjectName), "<projectname>");
m_Options.add_option("", "o", "oplog", "Oplog name", cxxopts::value(m_OplogNames), "<oplog>");
+ m_Options.parse_positional({"target", "project", "oplog"});
}
ExportProjectCommand::~ExportProjectCommand() = default;
@@ -59,8 +60,10 @@ ExportProjectCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** a
ZEN_UNUSED(GlobalOptions);
- m_Options.parse_positional({"target", "project", "oplog"});
- m_Options.parse(argc, argv);
+ if (!ParseOptions(argc, argv))
+ {
+ return 0;
+ }
if (m_ProjectName.empty())
{
diff --git a/zen/cmds/exportproject.h b/zen/cmds/exportproject.h
index bf41e2d7b..3fe7a2263 100644
--- a/zen/cmds/exportproject.h
+++ b/zen/cmds/exportproject.h
@@ -23,7 +23,7 @@ public:
~ExportProjectCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
struct OplogHeader
{
diff --git a/zen/cmds/hash.cpp b/zen/cmds/hash.cpp
index 95f960e29..7987d7738 100644
--- a/zen/cmds/hash.cpp
+++ b/zen/cmds/hash.cpp
@@ -65,7 +65,10 @@ HashCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{
ZEN_UNUSED(GlobalOptions);
- auto result = m_Options.parse(argc, argv);
+ if (!ParseOptions(argc, argv))
+ {
+ return 0;
+ }
bool valid = m_ScanDirectory.length();
diff --git a/zen/cmds/hash.h b/zen/cmds/hash.h
index 3cc2d1440..e5ee071e9 100644
--- a/zen/cmds/hash.h
+++ b/zen/cmds/hash.h
@@ -16,7 +16,7 @@ public:
~HashCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"hash", "Hash files"};
diff --git a/zen/cmds/importproject.cpp b/zen/cmds/importproject.cpp
index f92e8fcc0..3a2605ebb 100644
--- a/zen/cmds/importproject.cpp
+++ b/zen/cmds/importproject.cpp
@@ -28,6 +28,7 @@ ImportProjectCommand::ImportProjectCommand()
m_Options.add_option("", "s", "source", "Source path", cxxopts::value(m_SourcePath), "<sourcepath>");
m_Options.add_option("", "p", "project", "Project name", cxxopts::value(m_ProjectName), "<projectname>");
m_Options.add_option("", "o", "oplog", "Oplog name", cxxopts::value(m_OplogNames), "<oplog>");
+ m_Options.parse_positional({"source", "project", "oplog"});
}
ImportProjectCommand::~ImportProjectCommand() = default;
@@ -39,8 +40,10 @@ ImportProjectCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** a
ZEN_UNUSED(GlobalOptions);
- m_Options.parse_positional({"source", "project", "oplog"});
- m_Options.parse(argc, argv);
+ if (!ParseOptions(argc, argv))
+ {
+ return 0;
+ }
if (m_ProjectName.empty())
{
diff --git a/zen/cmds/importproject.h b/zen/cmds/importproject.h
index 326ccfe92..8d79f06fd 100644
--- a/zen/cmds/importproject.h
+++ b/zen/cmds/importproject.h
@@ -11,7 +11,7 @@ public:
~ImportProjectCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"import-project", "Import project oplogs from disk"};
diff --git a/zen/cmds/print.cpp b/zen/cmds/print.cpp
index 067dc844a..67191605c 100644
--- a/zen/cmds/print.cpp
+++ b/zen/cmds/print.cpp
@@ -34,6 +34,7 @@ PrintCommand::PrintCommand()
{
m_Options.add_options()("h,help", "Print help");
m_Options.add_option("", "s", "source", "Object payload file", cxxopts::value(m_Filename), "<file name>");
+ m_Options.parse_positional({"source"});
}
PrintCommand::~PrintCommand() = default;
@@ -41,16 +42,10 @@ PrintCommand::~PrintCommand() = default;
int
PrintCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{
- ZEN_UNUSED(GlobalOptions, argc, argv);
-
- m_Options.parse_positional({"source"});
+ ZEN_UNUSED(GlobalOptions);
- auto result = m_Options.parse(argc, argv);
-
- if (result.count("help"))
+ if (!ParseOptions(argc, argv))
{
- std::cout << m_Options.help({"", "Group"}) << std::endl;
-
return 0;
}
@@ -153,6 +148,7 @@ PrintPackageCommand::PrintPackageCommand()
{
m_Options.add_options()("h,help", "Print help");
m_Options.add_option("", "s", "source", "Package payload file", cxxopts::value(m_Filename), "<file name>");
+ m_Options.parse_positional({"source"});
}
PrintPackageCommand::~PrintPackageCommand()
@@ -162,16 +158,10 @@ PrintPackageCommand::~PrintPackageCommand()
int
PrintPackageCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{
- ZEN_UNUSED(GlobalOptions, argc, argv);
-
- m_Options.parse_positional({"source"});
+ ZEN_UNUSED(GlobalOptions);
- auto result = m_Options.parse(argc, argv);
-
- if (result.count("help"))
+ if (!ParseOptions(argc, argv))
{
- std::cout << m_Options.help({"", "Group"}) << std::endl;
-
return 0;
}
diff --git a/zen/cmds/print.h b/zen/cmds/print.h
index eed0aa14e..09d91830a 100644
--- a/zen/cmds/print.h
+++ b/zen/cmds/print.h
@@ -15,7 +15,7 @@ public:
~PrintCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"print", "Print compact binary object"};
@@ -31,7 +31,7 @@ public:
~PrintPackageCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"printpkg", "Print compact binary package"};
diff --git a/zen/cmds/projectstore.cpp b/zen/cmds/projectstore.cpp
new file mode 100644
index 000000000..d83bff53c
--- /dev/null
+++ b/zen/cmds/projectstore.cpp
@@ -0,0 +1,132 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "projectstore.h"
+
+#include <zencore/filesystem.h>
+#include <zencore/logging.h>
+#include <zenhttp/httpcommon.h>
+#include <zenutil/zenserverprocess.h>
+
+#include <memory>
+
+ZEN_THIRD_PARTY_INCLUDES_START
+#include <cpr/cpr.h>
+ZEN_THIRD_PARTY_INCLUDES_END
+
+DropProjectCommand::DropProjectCommand()
+{
+ m_Options.add_options()("h,help", "Print help");
+ m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value("http://localhost:1337"), "<hosturl>");
+ m_Options.add_option("", "p", "project", "Namnspace name", cxxopts::value(m_ProjectName), "<projectname>");
+ m_Options.add_option("", "o", "oplog", "Oplog name", cxxopts::value(m_OplogName), "<oplogname>");
+ m_Options.parse_positional({"{project}", "{oplog}"});
+}
+
+DropProjectCommand::~DropProjectCommand() = default;
+
+int
+DropProjectCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
+{
+ ZEN_UNUSED(GlobalOptions);
+
+ if (!ParseOptions(argc, argv))
+ {
+ return 0;
+ }
+
+ if (m_ProjectName.empty())
+ {
+ throw cxxopts::OptionParseException("Drop command requires a project");
+ }
+
+ cpr::Session Session;
+ if (m_OplogName.empty())
+ {
+ ZEN_CONSOLE("Dropping project '{}' from '{}'", m_ProjectName, m_HostName);
+ Session.SetUrl({fmt::format("{}/prj/{}", m_HostName, m_ProjectName)});
+ }
+ else
+ {
+ ZEN_CONSOLE("Dropping oplog '{}/{}' from '{}'", m_ProjectName, m_OplogName, m_HostName);
+ Session.SetUrl({fmt::format("{}/prj/{}/oplog/{}", m_HostName, m_ProjectName, m_OplogName)});
+ }
+
+ cpr::Response Result = Session.Delete();
+
+ if (zen::IsHttpSuccessCode(Result.status_code))
+ {
+ ZEN_CONSOLE("OK: drop succeeded");
+ return 0;
+ }
+
+ if (Result.status_code)
+ {
+ ZEN_ERROR("Drop failed: {}: {} ({})", Result.status_code, Result.reason, Result.text);
+ }
+ else
+ {
+ ZEN_ERROR("Drop failed: {}", Result.error.message);
+ }
+
+ return 1;
+}
+
+ProjectInfoCommand::ProjectInfoCommand()
+{
+ m_Options.add_options()("h,help", "Print help");
+ m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value("http://localhost:1337"), "<hosturl>");
+ m_Options.add_option("", "p", "project", "Namnspace name", cxxopts::value(m_ProjectName), "<projectname>");
+ m_Options.add_option("", "o", "oplog", "Oplog name", cxxopts::value(m_OplogName), "<oplogname>");
+ m_Options.parse_positional({"{project}", "{oplog}"});
+}
+
+ProjectInfoCommand::~ProjectInfoCommand() = default;
+
+int
+ProjectInfoCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
+{
+ ZEN_UNUSED(GlobalOptions);
+
+ if (!ParseOptions(argc, argv))
+ {
+ return 0;
+ }
+
+ cpr::Session Session;
+ Session.SetHeader(cpr::Header{{"Accept", "application/json"}});
+ if (m_ProjectName.empty())
+ {
+ ZEN_CONSOLE("Info from '{}'", m_HostName);
+ Session.SetUrl({fmt::format("{}/prj", m_HostName)});
+ }
+ else if (m_OplogName.empty())
+ {
+ ZEN_CONSOLE("Info on project '{}' from '{}'", m_ProjectName, m_HostName);
+ Session.SetUrl({fmt::format("{}/prj/{}", m_HostName, m_ProjectName)});
+ }
+ else
+ {
+ ZEN_CONSOLE("Info on oplog '{}/{}' from '{}'", m_ProjectName, m_OplogName, m_HostName);
+ Session.SetUrl({fmt::format("{}/prj/{}/oplog/{}", m_HostName, m_ProjectName, m_OplogName)});
+ }
+
+ cpr::Response Result = Session.Get();
+
+ if (zen::IsHttpSuccessCode(Result.status_code))
+ {
+ ZEN_CONSOLE("{}", Result.text);
+
+ return 0;
+ }
+
+ if (Result.status_code)
+ {
+ ZEN_ERROR("Info failed: {}: {} ({})", Result.status_code, Result.reason, Result.text);
+ }
+ else
+ {
+ ZEN_ERROR("Info failed: {}", Result.error.message);
+ }
+
+ return 1;
+}
diff --git a/zen/cmds/projectstore.h b/zen/cmds/projectstore.h
new file mode 100644
index 000000000..98e60cb17
--- /dev/null
+++ b/zen/cmds/projectstore.h
@@ -0,0 +1,36 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "../zen.h"
+
+class DropProjectCommand : public ZenCmdBase
+{
+public:
+ DropProjectCommand();
+ ~DropProjectCommand();
+
+ virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
+ virtual cxxopts::Options& Options() override { return m_Options; }
+
+private:
+ cxxopts::Options m_Options{"project-drop", "Drop project or project oplog"};
+ std::string m_HostName;
+ std::string m_ProjectName;
+ std::string m_OplogName;
+};
+
+class ProjectInfoCommand : public ZenCmdBase
+{
+public:
+ ProjectInfoCommand();
+ ~ProjectInfoCommand();
+ virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
+ virtual cxxopts::Options& Options() override { return m_Options; }
+
+private:
+ cxxopts::Options m_Options{"project-info", "Info on project or project oplog"};
+ std::string m_HostName;
+ std::string m_ProjectName;
+ std::string m_OplogName;
+};
diff --git a/zen/cmds/run.cpp b/zen/cmds/run.cpp
index 6e04d7ebf..6ba74e2fd 100644
--- a/zen/cmds/run.cpp
+++ b/zen/cmds/run.cpp
@@ -69,6 +69,10 @@ RunCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
Zen1.SetTestDir(TestDir);
Zen1.SpawnServer(13337);
+ if (!ParseOptions(argc, argv))
+ {
+ return 0;
+ }
auto result = m_Options.parse(argc, argv);
std::filesystem::path TreePath{m_ExeTree};
diff --git a/zen/cmds/run.h b/zen/cmds/run.h
index c5595f235..440ea4ea4 100644
--- a/zen/cmds/run.h
+++ b/zen/cmds/run.h
@@ -17,7 +17,7 @@ public:
~RunCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"run", "Run command"};
diff --git a/zen/cmds/scrub.cpp b/zen/cmds/scrub.cpp
index c0fe8ca61..27ff5e0ac 100644
--- a/zen/cmds/scrub.cpp
+++ b/zen/cmds/scrub.cpp
@@ -1,7 +1,12 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "scrub.h"
-#include <zenutil/zenserverprocess.h>
+#include <zencore/logging.h>
+#include <zenhttp/httpcommon.h>
+
+ZEN_THIRD_PARTY_INCLUDES_START
+#include <cpr/cpr.h>
+ZEN_THIRD_PARTY_INCLUDES_END
using namespace std::literals;
@@ -9,6 +14,8 @@ namespace zen {
ScrubCommand::ScrubCommand()
{
+ m_Options.add_options()("h,help", "Print help");
+ m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value("http://localhost:1337"), "<hosturl>");
}
ScrubCommand::~ScrubCommand() = default;
@@ -25,6 +32,26 @@ ScrubCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
GcCommand::GcCommand()
{
+ m_Options.add_options()("h,help", "Print help");
+ m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value("http://localhost:1337"), "<hosturl>");
+ m_Options.add_option("",
+ "s",
+ "smallobjects",
+ "Collect small objects",
+ cxxopts::value(m_SmallObjects)->default_value("false"),
+ "<smallobjects>");
+ m_Options.add_option("",
+ "m",
+ "maxcacheduration",
+ "Max cache lifetime (in seconds)",
+ cxxopts::value(m_MaxCacheDuration)->default_value("0"),
+ "<maxcacheduration>");
+ m_Options.add_option("",
+ "d",
+ "disksizesoftlimit",
+ "Max disk usage size (in bytes)",
+ cxxopts::value(m_DiskSizeSoftLimit)->default_value("0"),
+ "<disksizesoftlimit>");
}
GcCommand::~GcCommand()
@@ -36,7 +63,92 @@ GcCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{
ZEN_UNUSED(GlobalOptions, argc, argv);
- return 0;
+ if (!ParseOptions(argc, argv))
+ {
+ return 0;
+ }
+
+ cpr::Parameters Params;
+ if (m_SmallObjects)
+ {
+ Params.Add({"smallobjects", "true"});
+ }
+ if (m_MaxCacheDuration != 0)
+ {
+ Params.Add({"maxcacheduration", fmt::format("{}", m_MaxCacheDuration)});
+ }
+ if (m_DiskSizeSoftLimit != 0)
+ {
+ Params.Add({"disksizesoftlimit", fmt::format("{}", m_DiskSizeSoftLimit)});
+ }
+
+ cpr::Session Session;
+ Session.SetHeader(cpr::Header{{"Accept", "application/json"}});
+ Session.SetUrl({fmt::format("{}/admin/gc", m_HostName)});
+ Session.SetParameters(Params);
+
+ cpr::Response Result = Session.Post();
+
+ if (zen::IsHttpSuccessCode(Result.status_code))
+ {
+ ZEN_CONSOLE("OK: {}", Result.text);
+ return 0;
+ }
+
+ if (Result.status_code)
+ {
+ ZEN_ERROR("GC start failed: {}: {} ({})", Result.status_code, Result.reason, Result.text);
+ }
+ else
+ {
+ ZEN_ERROR("GC start failed: {}", Result.error.message);
+ }
+
+ return 1;
+}
+
+GcStatusCommand::GcStatusCommand()
+{
+ m_Options.add_options()("h,help", "Print help");
+ m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value("http://localhost:1337"), "<hosturl>");
+}
+
+GcStatusCommand::~GcStatusCommand()
+{
+}
+
+int
+GcStatusCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
+{
+ ZEN_UNUSED(GlobalOptions, argc, argv);
+
+ if (!ParseOptions(argc, argv))
+ {
+ return 0;
+ }
+
+ cpr::Session Session;
+ Session.SetHeader(cpr::Header{{"Accept", "application/json"}});
+ Session.SetUrl({fmt::format("{}/admin/gc", m_HostName)});
+
+ cpr::Response Result = Session.Get();
+
+ if (zen::IsHttpSuccessCode(Result.status_code))
+ {
+ ZEN_CONSOLE("OK: {}", Result.text);
+ return 0;
+ }
+
+ if (Result.status_code)
+ {
+ ZEN_ERROR("GC status failed: {}: {} ({})", Result.status_code, Result.reason, Result.text);
+ }
+ else
+ {
+ ZEN_ERROR("GC status failed: {}", Result.error.message);
+ }
+
+ return 1;
}
} // namespace zen
diff --git a/zen/cmds/scrub.h b/zen/cmds/scrub.h
index 561ae578d..ee8b4fdbb 100644
--- a/zen/cmds/scrub.h
+++ b/zen/cmds/scrub.h
@@ -15,10 +15,11 @@ public:
~ScrubCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"scrub", "Scrub zen storage"};
+ std::string m_HostName;
};
/** Garbage collect storage
@@ -30,10 +31,28 @@ public:
~GcCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"gc", "Garbage collect zen storage"};
+ std::string m_HostName;
+ bool m_SmallObjects{false};
+ uint64_t m_MaxCacheDuration{0};
+ uint64_t m_DiskSizeSoftLimit{0};
+};
+
+class GcStatusCommand : public ZenCmdBase
+{
+public:
+ GcStatusCommand();
+ ~GcStatusCommand();
+
+ virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
+ virtual cxxopts::Options& Options() override { return m_Options; }
+
+private:
+ cxxopts::Options m_Options{"gc-status", "Garbage collect zen storage status check"};
+ std::string m_HostName;
};
} // namespace zen
diff --git a/zen/cmds/status.h b/zen/cmds/status.h
index acde280c5..98f72e651 100644
--- a/zen/cmds/status.h
+++ b/zen/cmds/status.h
@@ -13,7 +13,7 @@ public:
~StatusCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"status", "Show zen status"};
diff --git a/zen/cmds/top.h b/zen/cmds/top.h
index d8bf91a1c..83410587b 100644
--- a/zen/cmds/top.h
+++ b/zen/cmds/top.h
@@ -13,7 +13,7 @@ public:
~TopCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"top", "Show dev UI"};
@@ -26,7 +26,7 @@ public:
~PsCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"ps", "Enumerate running Zen server instances"};
diff --git a/zen/cmds/up.h b/zen/cmds/up.h
index fe1ed7a0c..c0f1beaba 100644
--- a/zen/cmds/up.h
+++ b/zen/cmds/up.h
@@ -13,7 +13,7 @@ public:
~UpCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"up", "Bring up zen service"};
@@ -26,7 +26,7 @@ public:
~DownCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"down", "Bring down zen service"};
diff --git a/zen/cmds/version.cpp b/zen/cmds/version.cpp
index b92ef670a..ba83b527d 100644
--- a/zen/cmds/version.cpp
+++ b/zen/cmds/version.cpp
@@ -22,6 +22,7 @@ VersionCommand::VersionCommand()
m_Options.add_options()("h,help", "Print help");
m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName), "[hosturl]");
m_Options.add_option("", "d", "detailed", "Detailed Version", cxxopts::value(m_DetailedVersion), "[detailedversion]");
+ m_Options.parse_positional({"hosturl"});
}
VersionCommand::~VersionCommand() = default;
@@ -30,8 +31,10 @@ int
VersionCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{
ZEN_UNUSED(GlobalOptions);
- m_Options.parse_positional({"hosturl"});
- m_Options.parse(argc, argv);
+ if (!ParseOptions(argc, argv))
+ {
+ return 0;
+ }
std::string Version;
diff --git a/zen/cmds/version.h b/zen/cmds/version.h
index 17aec73e3..0e37e91a0 100644
--- a/zen/cmds/version.h
+++ b/zen/cmds/version.h
@@ -13,7 +13,7 @@ public:
~VersionCommand();
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"version", "Get zen service version"};
diff --git a/zen/zen.cpp b/zen/zen.cpp
index 447c4f825..b4159df3a 100644
--- a/zen/zen.cpp
+++ b/zen/zen.cpp
@@ -13,7 +13,9 @@
#include "cmds/hash.h"
#include "cmds/importproject.h"
#include "cmds/print.h"
+#include "cmds/projectstore.h"
#include "cmds/run.h"
+#include "cmds/scrub.h"
#include "cmds/status.h"
#include "cmds/top.h"
#include "cmds/up.h"
@@ -48,7 +50,7 @@ public:
return 0;
}
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"template", "EDIT THIS COMMAND DESCRIPTION"};
@@ -57,6 +59,36 @@ private:
//////////////////////////////////////////////////////////////////////////
+bool
+ZenCmdBase::ParseOptions(int argc, char** argv)
+{
+ cxxopts::Options& CmdOptions = Options();
+ cxxopts::ParseResult Result = CmdOptions.parse(argc, argv);
+ if (Result.count("help"))
+ {
+ printf("%s\n", CmdOptions.help({}).c_str());
+ return false;
+ }
+ if (!Result.unmatched().empty())
+ {
+ zen::ExtendableStringBuilder<64> StringBuilder;
+ for (bool First = true; const auto& Param : Result.unmatched())
+ {
+ if (!First)
+ {
+ StringBuilder.Append(", ");
+ }
+ StringBuilder.Append('"');
+ StringBuilder.Append(Param);
+ StringBuilder.Append('"');
+ First = false;
+ }
+ throw cxxopts::OptionParseException(fmt::format("Invalid arguments: {}", StringBuilder.ToView()));
+ }
+
+ return true;
+}
+
#if ZEN_WITH_TESTS
class RunTestsCommand : public ZenCmdBase
@@ -84,7 +116,7 @@ public:
return ZEN_RUN_TESTS(argc, argv);
}
- virtual cxxopts::Options* Options() override { return &m_Options; }
+ virtual cxxopts::Options& Options() override { return m_Options; }
private:
cxxopts::Options m_Options{"runtests", "Run tests"};
@@ -129,6 +161,11 @@ main(int argc, char** argv)
ExportProjectCommand ExportProjectCmd;
ImportProjectCommand ImportProjectCmd;
VersionCommand VersionCmd;
+ CacheInfoCommand CacheInfoCmd;
+ DropProjectCommand ProjectDropCmd;
+ ProjectInfoCommand ProjectInfoCmd;
+ GcCommand GcCmd;
+ GcStatusCommand GcStatusCmd;
#if ZEN_WITH_TESTS
RunTestsCommand RunTestsCmd;
@@ -141,28 +178,33 @@ main(int argc, char** argv)
const char* CmdSummary;
} Commands[] = {
// clang-format off
-// {"chunk", &ChunkCmd, "Perform chunking"},
- {"copy", &CopyCmd, "Copy file(s)"},
- {"dedup", &DedupCmd, "Dedup files"},
- {"drop", &DropCmd, "Drop cache namespace or bucket"},
- {"export-project", &ExportProjectCmd, "Export project store oplog"},
- {"hash", &HashCmd, "Compute file hashes"},
- {"import-project", &ImportProjectCmd, "Import project store oplog"},
- {"print", &PrintCmd, "Print compact binary object"},
- {"printpackage", &PrintPkgCmd, "Print compact binary package"},
+// {"chunk", &ChunkCmd, "Perform chunking"},
+ {"copy", &CopyCmd, "Copy file(s)"},
+ {"dedup", &DedupCmd, "Dedup files"},
+ {"drop", &DropCmd, "Drop cache namespace or bucket"},
+ {"export-project", &ExportProjectCmd, "Export project store oplog"},
+ {"hash", &HashCmd, "Compute file hashes"},
+ {"import-project", &ImportProjectCmd, "Import project store oplog"},
+ {"print", &PrintCmd, "Print compact binary object"},
+ {"printpackage", &PrintPkgCmd, "Print compact binary package"},
#if ZEN_WITH_EXEC_SERVICES
- {"run", &RunCmd, "Remote execution"},
+ {"run", &RunCmd, "Remote execution"},
#endif // ZEN_WITH_EXEC_SERVICES
- {"status", &StatusCmd, "Show zen status"},
- {"ps", &PsCmd, "Enumerate running zen server instances"},
- {"top", &TopCmd, "Monitor zen server activity"},
- {"up", &UpCmd, "Bring zen server up"},
- {"down", &DownCmd, "Bring zen server down"},
- {"version", &VersionCmd, "Get zen server version"},
- // clang-format on
+ {"status", &StatusCmd, "Show zen status"},
+ {"ps", &PsCmd, "Enumerate running zen server instances"},
+ {"top", &TopCmd, "Monitor zen server activity"},
+ {"up", &UpCmd, "Bring zen server up"},
+ {"down", &DownCmd, "Bring zen server down"},
+ {"version", &VersionCmd, "Get zen server version"},
+ {"cache-info", &CacheInfoCmd, "Info on cache, namespace or bucket"},
+ {"project-drop", &ProjectDropCmd, "Drop project or project oplog"},
+ {"project-info", &ProjectInfoCmd, "Info on project or project oplog"},
+ {"gc", &GcCmd, "Garbage collect zen storage"},
+ {"gc-status", &GcStatusCmd, "Garbage collect zen storage status check"},
#if ZEN_WITH_TESTS
- {"runtests", &RunTestsCmd, "Run zen tests"},
+ {"runtests", &RunTestsCmd, "Run zen tests"},
#endif
+ // clang-format on
};
// Build set containing available commands
@@ -286,28 +328,18 @@ main(int argc, char** argv)
{
if (StrCaseCompare(SubCommand.c_str(), CmdInfo.CmdName) == 0)
{
- cxxopts::Options* VerbOptions = CmdInfo.Cmd->Options();
-
+ cxxopts::Options& VerbOptions = CmdInfo.Cmd->Options();
try
{
return CmdInfo.Cmd->Run(GlobalOptions, (int)CommandArgVec.size(), CommandArgVec.data());
}
catch (cxxopts::OptionParseException& Ex)
{
- if (VerbOptions)
- {
- std::string help = VerbOptions->help();
-
- printf("Error parsing arguments for command '%s': %s\n\n%s", SubCommand.c_str(), Ex.what(), help.c_str());
+ std::string help = VerbOptions.help();
- exit(11);
- }
- else
- {
- printf("Error parsing arguments for command '%s': %s\n\n", SubCommand.c_str(), Ex.what());
+ printf("Error parsing arguments for command '%s': %s\n\n%s", SubCommand.c_str(), Ex.what(), help.c_str());
- exit(11);
- }
+ exit(11);
}
}
}
diff --git a/zen/zen.h b/zen/zen.h
index b4d41a094..40fb65257 100644
--- a/zen/zen.h
+++ b/zen/zen.h
@@ -29,5 +29,7 @@ class ZenCmdBase
{
public:
virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) = 0;
- virtual cxxopts::Options* Options() = 0;
+ virtual cxxopts::Options& Options() = 0;
+
+ bool ParseOptions(int argc, char** argv);
};
diff --git a/zenserver/projectstore.cpp b/zenserver/projectstore.cpp
index d1033dea1..1779bfb3c 100644
--- a/zenserver/projectstore.cpp
+++ b/zenserver/projectstore.cpp
@@ -2676,6 +2676,7 @@ HttpProjectService::HttpProjectService(CidStore& Store, ProjectStore* Projects)
fmt::format("project {} not found", ProjectId));
}
+ ZEN_INFO("deleting project '{}'", ProjectId);
if (!m_ProjectStore->DeleteProject(ProjectId))
{
return Req.ServerRequest().WriteResponse(HttpResponseCode::Locked,