diff options
| author | Dan Engelbrecht <[email protected]> | 2024-09-11 13:53:12 +0200 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2024-09-11 13:53:12 +0200 |
| commit | 5b9d20635600a285cbf35b824e417a0e4c35b735 (patch) | |
| tree | eac5484def492d178a6e1558ae2d8200d7b9eeef /src | |
| parent | validate oplog before opening - if invalid, warn and wipe oplog (#153) (diff) | |
| download | zen-5b9d20635600a285cbf35b824e417a0e4c35b735.tar.xz zen-5b9d20635600a285cbf35b824e417a0e4c35b735.zip | |
oplog cmd improvements (#152)
- Improvement: Removed redundant commands `project-delete` and `oplog-delete`. Use already existing `project-drop` instead.
- Improvement: zen oplog commands `project-drop`, `project-info`, `oplog-create`, `oplog-import`, `oplog-mirror` can now help resolve partial project and oplog identifiers
- Improvement: zen `oplog-mirror` command now has new filter options to control which files are realized to disk: `--key` for op key, `--file` for file path matching and `--chunk` for chunk id matching
- Improvement: `project-drop` command defaults to `--dry-run=true` and will only delete the target if `--dry-run=false` is added to the command line to avoid accidental delete
Diffstat (limited to 'src')
| -rw-r--r-- | src/zen/cmds/projectstore_cmd.cpp | 509 | ||||
| -rw-r--r-- | src/zen/cmds/projectstore_cmd.h | 35 | ||||
| -rw-r--r-- | src/zen/zen.cpp | 4 |
3 files changed, 343 insertions, 205 deletions
diff --git a/src/zen/cmds/projectstore_cmd.cpp b/src/zen/cmds/projectstore_cmd.cpp index 6591c05cd..55e5299e3 100644 --- a/src/zen/cmds/projectstore_cmd.cpp +++ b/src/zen/cmds/projectstore_cmd.cpp @@ -200,6 +200,191 @@ namespace { } } + std::vector<std::string> GetProjectIds(HttpClient& Http) + { + std::vector<std::string> AvailableProjects; + if (HttpClient::Response Result = Http.Get("/prj")) + { + CbObject CompactBinary = Result.AsObject(); + for (CbFieldView Field : CompactBinary.AsFieldView().AsArrayView()) + { + if (auto Id = Field.AsObjectView()["Id"].AsString(); !Id.empty()) + { + AvailableProjects.push_back(std::string(Id)); + } + } + } + else + { + Result.ThrowError(fmt::format("failed to fetch available projects from '{}'", Http.GetBaseUri())); + } + return AvailableProjects; + } + + std::vector<std::string> GetOlogIds(HttpClient& Http, std::string_view ProjectId) + { + std::vector<std::string> AvailableOplogs; + if (HttpClient::Response Result = Http.Get(fmt::format("/prj/{}", ProjectId))) + { + CbObject CompactBinary = Result.AsObject(); + for (CbFieldView Field : CompactBinary["oplogs"].AsArrayView()) + { + if (auto Id = Field.AsObjectView()["id"].AsString(); !Id.empty()) + { + AvailableOplogs.push_back(std::string(Id)); + } + } + } + else + { + Result.ThrowError(fmt::format("failed to fetch available oplogs from '{}' for project '{}'", Http.GetBaseUri(), ProjectId)); + } + return AvailableOplogs; + } + + std::vector<std::string> MatchId(const std::vector<std::string>& Ids, std::string_view FindId) + { + bool FindHasDotDelimiter = FindId.find('.') != std::string_view::npos; + std::vector<std::string> PossibleIds; + for (const std::string& Id : Ids) + { + if (Id == FindId) + { + return std::vector<std::string>{Id}; + } + else if (Id.starts_with(FindId)) + { + if (FindHasDotDelimiter || Id[FindId.length()] == '.') + { + PossibleIds.push_back(Id); + } + } + } + return PossibleIds; + } + + std::string FmtArray(const std::vector<std::string>& Values, std::string_view Separator = ", "sv, std::string_view Quotes = "'"sv) + { + ExtendableStringBuilder<512> SB; + for (const std::string& Value : Values) + { + if (SB.Size() > 0 && !Separator.empty()) + { + SB.Append(Separator); + } + if (!Quotes.empty()) + { + SB.Append(Quotes); + } + SB.Append(Value); + if (!Quotes.empty()) + { + SB.Append(Quotes); + } + } + return SB.ToString(); + } + + std::string ResolveProject(HttpClient& Http, std::string_view OptionalProjectName) + { + std::vector<std::string> AvailableProjects = GetProjectIds(Http); + if (AvailableProjects.empty()) + { + if (OptionalProjectName.empty()) + { + ZEN_CONSOLE("No projects found at {}", Http.GetBaseUri()); + } + else + { + ZEN_CONSOLE("Unable to resolve project name '{}', no projects found at {}", OptionalProjectName, Http.GetBaseUri()); + } + return {}; + } + + if (OptionalProjectName.empty()) + { + ZEN_CONSOLE("Available projects at {}: {}", Http.GetBaseUri(), FmtArray(AvailableProjects)); + return {}; + } + + std::vector<std::string> MatchingProjectIds = MatchId(AvailableProjects, OptionalProjectName); + if (MatchingProjectIds.empty()) + { + ZEN_CONSOLE("Unable to match project name '{}' at {}, available projects: {}", + OptionalProjectName, + Http.GetBaseUri(), + FmtArray(AvailableProjects)); + return {}; + } + + if (MatchingProjectIds.size() == 1) + { + return MatchingProjectIds.front(); + } + + ZEN_CONSOLE("Project name is ambigous '{}' at {}: possible matches: {}", + OptionalProjectName, + Http.GetBaseUri(), + FmtArray(MatchingProjectIds)); + return {}; + } + + std::string ResolveOplog(HttpClient& Http, std::string_view ProjectName, std::string_view OptionalOplogName) + { + std::vector<std::string> AvailableOplogs = GetOlogIds(Http, ProjectName); + if (AvailableOplogs.empty()) + { + if (OptionalOplogName.empty()) + { + ZEN_CONSOLE("No oplogs for project '{}' found at {}", ProjectName, Http.GetBaseUri()); + } + else + { + ZEN_CONSOLE("Unable to resolve oplog name '{}' for project '{}', no oplogs found at {}", + OptionalOplogName, + ProjectName, + Http.GetBaseUri()); + } + return {}; + } + + if (OptionalOplogName.empty()) + { + if (AvailableOplogs.size() == 1) + { + return AvailableOplogs.front(); + } + else + { + ZEN_CONSOLE("Available oplogs for project '{}' at {}: {}", ProjectName, Http.GetBaseUri(), FmtArray(AvailableOplogs)); + return {}; + } + } + + std::vector<std::string> MatchingOplogIds = MatchId(AvailableOplogs, OptionalOplogName); + if (MatchingOplogIds.empty()) + { + ZEN_CONSOLE("Unable to match oplog name '{}' for project '{}', available oplogs at {}: {}", + OptionalOplogName, + ProjectName, + Http.GetBaseUri(), + FmtArray(AvailableOplogs)); + return {}; + } + + if (MatchingOplogIds.size() == 1) + { + return MatchingOplogIds.front(); + } + + ZEN_CONSOLE("Oplog name '{}' for project '{}' at {}, is ambigous, possible matches: {}", + OptionalOplogName, + ProjectName, + Http.GetBaseUri(), + FmtArray(MatchingOplogIds)); + return {}; + } + } // namespace /////////////////////////////////////// @@ -210,6 +395,7 @@ DropProjectCommand::DropProjectCommand() m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value(""), "<hosturl>"); m_Options.add_option("", "p", "project", "Project name", cxxopts::value(m_ProjectName), "<projectid>"); m_Options.add_option("", "o", "oplog", "Oplog name", cxxopts::value(m_OplogName), "<oplogid>"); + m_Options.add_option("", "", "dryrun", "Dry run - resolve arguments but do not drop", cxxopts::value(m_DryRun), "<dryrun>"); m_Options.parse_positional({"project", "oplog"}); m_Options.positional_help("[<projectid> [<oplogid>]]"); } @@ -235,36 +421,49 @@ DropProjectCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg throw OptionParseException("unable to resolve server specification"); } + HttpClient Http(m_HostName); + + m_ProjectName = ResolveProject(Http, m_ProjectName); if (m_ProjectName.empty()) { - throw OptionParseException("Drop command requires a project"); + return 1; } - HttpClient Http(m_HostName); if (m_OplogName.empty()) { - ZEN_CONSOLE("Dropping project '{}' from '{}'", m_ProjectName, m_HostName); - if (HttpClient::Response Result = Http.Delete(fmt::format("/prj/{}", m_ProjectName))) - { - ZEN_CONSOLE("{}", Result); - } - else + ZEN_CONSOLE("{} project '{}' from '{}'", m_DryRun ? "Would drop" : "Dropping", m_ProjectName, m_HostName); + if (!m_DryRun) { - Result.ThrowError("delete project failed"sv); - return 1; + if (HttpClient::Response Result = Http.Delete(fmt::format("/prj/{}", m_ProjectName))) + { + ZEN_CONSOLE("{}", Result); + } + else + { + Result.ThrowError("delete project failed"sv); + return 1; + } } } else { - ZEN_CONSOLE("Dropping oplog '{}/{}' from '{}'", m_ProjectName, m_OplogName, m_HostName); - if (HttpClient::Response Result = Http.Delete(fmt::format("/prj/{}/oplog/{}", m_ProjectName, m_OplogName))) + m_OplogName = ResolveOplog(Http, m_ProjectName, m_OplogName); + if (m_OplogName.empty()) { - ZEN_CONSOLE("{}", Result); + return 1; } - else + ZEN_CONSOLE("{} oplog '{}/{}' from '{}'", m_DryRun ? "Would drop" : "Dropping", m_ProjectName, m_OplogName, m_HostName); + if (!m_DryRun) { - Result.ThrowError("delete oplog failed"sv); - return 1; + if (HttpClient::Response Result = Http.Delete(fmt::format("/prj/{}/oplog/{}", m_ProjectName, m_OplogName))) + { + ZEN_CONSOLE("{}", Result); + } + else + { + Result.ThrowError("delete oplog failed"sv); + return 1; + } } } @@ -319,11 +518,29 @@ ProjectInfoCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg } else if (m_OplogName.empty()) { + m_ProjectName = ResolveProject(Http, m_ProjectName); + if (m_ProjectName.empty()) + { + return 1; + } + Url = fmt::format("/prj/{}", m_ProjectName); ZEN_CONSOLE("Info on project '{}' from '{}{}'", m_ProjectName, m_HostName, Url); } else { + m_ProjectName = ResolveProject(Http, m_ProjectName); + if (m_ProjectName.empty()) + { + return 1; + } + + m_OplogName = ResolveOplog(Http, m_ProjectName, m_OplogName); + if (m_OplogName.empty()) + { + return 1; + } + Url = fmt::format("/prj/{}/oplog/{}", m_ProjectName, m_OplogName); ZEN_CONSOLE("Info on oplog '{}/{}' from '{}{}'", m_ProjectName, m_OplogName, m_HostName, Url); } @@ -331,13 +548,13 @@ ProjectInfoCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg if (HttpClient::Response Result = Http.Get(Url, HttpClient::Accept(ZenContentType::kJSON))) { ZEN_CONSOLE("{}", Result.ToText()); + return 0; } else { Result.ThrowError("failed to fetch info"sv); return 1; } - return 1; } /////////////////////////////////////// @@ -417,64 +634,6 @@ CreateProjectCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** a /////////////////////////////////////// -DeleteProjectCommand::DeleteProjectCommand() -{ - m_Options.add_options()("h,help", "Print help"); - m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value(""), "<hosturl>"); - m_Options.add_option("", "p", "project", "Project name", cxxopts::value(m_ProjectId), "<projectid>"); -} - -DeleteProjectCommand::~DeleteProjectCommand() = default; - -int -DeleteProjectCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) -{ - ZEN_UNUSED(GlobalOptions); - - using namespace std::literals; - - if (!ParseOptions(argc, argv)) - { - return 0; - } - - m_HostName = ResolveTargetHostSpec(m_HostName); - - if (m_HostName.empty()) - { - throw OptionParseException("unable to resolve server specification"); - } - - if (m_ProjectId.empty()) - { - ZEN_ERROR("Project name must be given"); - return 1; - } - - HttpClient Http(m_HostName); - - std::string Url = fmt::format("/prj/{}", m_ProjectId); - - if (HttpClient::Response Result = Http.Get(Url, HttpClient::Accept(ZenContentType::kJSON)); !Result) - { - Result.ThrowError("failed deleting project"sv); - return 1; - } - - if (HttpClient::Response Result = Http.Delete(Url, HttpClient::Accept(ZenContentType::kText))) - { - ZEN_CONSOLE("{}", Result); - return 0; - } - else - { - Result.ThrowError("failed deleting project"sv); - return 1; - } -} - -/////////////////////////////////////// - CreateOplogCommand::CreateOplogCommand() { m_Options.add_options()("h,help", "Print help"); @@ -512,13 +671,18 @@ CreateOplogCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg throw OptionParseException("project name must be specified"); } + HttpClient Http(m_HostName); + m_ProjectId = ResolveProject(Http, m_ProjectId); + if (m_ProjectId.empty()) + { + return 1; + } + if (m_OplogId.empty()) { throw OptionParseException("oplog name must be specified"); } - HttpClient Http(m_HostName); - std::string Url = fmt::format("/prj/{}/oplog/{}", m_ProjectId, m_OplogId); if (!m_ForceUpdate) { @@ -550,69 +714,6 @@ CreateOplogCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg /////////////////////////////////////// -DeleteOplogCommand::DeleteOplogCommand() -{ - m_Options.add_options()("h,help", "Print help"); - m_Options.add_option("", "u", "hosturl", "Host URL", cxxopts::value(m_HostName)->default_value(""), "<hosturl>"); - m_Options.add_option("", "p", "project", "Project name", cxxopts::value(m_ProjectId), "<projectid>"); - m_Options.add_option("", "o", "oplog", "Oplog name", cxxopts::value(m_OplogId), "<oplogid>"); - m_Options.parse_positional({"project", "oplog", "gcpath"}); -} - -DeleteOplogCommand::~DeleteOplogCommand() = default; - -int -DeleteOplogCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) -{ - ZEN_UNUSED(GlobalOptions); - - using namespace std::literals; - - if (!ParseOptions(argc, argv)) - { - return 0; - } - - m_HostName = ResolveTargetHostSpec(m_HostName); - - if (m_HostName.empty()) - { - throw OptionParseException("unable to resolve server specification"); - } - - if (m_ProjectId.empty()) - { - throw OptionParseException("project name must be specified"); - } - - if (m_OplogId.empty()) - { - throw OptionParseException("oplog name must be specified"); - } - - HttpClient Http(m_HostName); - std::string Url = fmt::format("/prj/{}/oplog/{}", m_ProjectId, m_OplogId); - - if (HttpClient::Response Result = Http.Get(Url, HttpClient::Accept(ZenContentType::kJSON)); !Result) - { - Result.ThrowError("failed deleting oplog"sv); - return 1; - } - - if (HttpClient::Response Result = Http.Delete(Url, HttpClient::Accept(ZenContentType::kText))) - { - ZEN_CONSOLE("{}", Result); - return 0; - } - else - { - Result.ThrowError("failed deleting oplog"sv); - return 1; - } -} - -/////////////////////////////////////// - ExportOplogCommand::ExportOplogCommand() { m_Options.add_options()("h,help", "Print help"); @@ -736,9 +837,17 @@ ExportOplogCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg throw OptionParseException("project name must be specified"); } + HttpClient Http(m_HostName); + m_ProjectName = ResolveProject(Http, m_ProjectName); + if (m_ProjectName.empty()) + { + return 1; + } + + m_OplogName = ResolveOplog(Http, m_ProjectName, m_OplogName); if (m_OplogName.empty()) { - throw OptionParseException("oplog identifier must be specified"); + return 1; } size_t TargetCount = 0; @@ -794,7 +903,6 @@ ExportOplogCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg TargetUrlBase = fmt::format("http://{}", TargetUrlBase); } - HttpClient Http(TargetUrlBase); std::string Url = fmt::format("/prj/{}/oplog/{}", m_ZenProjectName, m_ZenOplogName); bool CreateOplog = false; @@ -976,7 +1084,6 @@ ExportOplogCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg ZEN_CONSOLE("Saving oplog '{}/{}' from '{}' to {}", m_ProjectName, m_OplogName, m_HostName, TargetDescription); - HttpClient Http(m_HostName); if (m_Async) { if (HttpClient::Response Result = Http.Post(fmt::format("/prj/{}/oplog/{}/rpc", m_ProjectName, m_OplogName), @@ -1102,6 +1209,19 @@ ImportOplogCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg return 1; } + HttpClient Http(m_HostName); + m_ProjectName = ResolveProject(Http, m_ProjectName); + if (m_ProjectName.empty()) + { + return 1; + } + + m_OplogName = ResolveOplog(Http, m_ProjectName, m_OplogName); + if (m_OplogName.empty()) + { + return 1; + } + size_t TargetCount = 0; TargetCount += m_CloudUrl.empty() ? 0 : 1; TargetCount += m_ZenUrl.empty() ? 0 : 1; @@ -1153,8 +1273,6 @@ ImportOplogCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg } } - HttpClient Http(m_HostName); - std::string Url = fmt::format("/prj/{}/oplog/{}", m_ProjectName, m_OplogName); bool CreateOplog = false; @@ -1331,22 +1449,28 @@ SnapshotOplogCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** a throw OptionParseException("unable to resolve server specification"); } + HttpClient Http(m_HostName); + if (m_ProjectName.empty()) { ZEN_ERROR("Project name must be given"); return 1; } + m_ProjectName = ResolveProject(Http, m_ProjectName); + if (m_ProjectName.empty()) + { + return 1; + } + + m_OplogName = ResolveOplog(Http, m_ProjectName, m_OplogName); if (m_OplogName.empty()) { - ZEN_ERROR("Oplog name must be given"); return 1; } IoBuffer Payload = MakeCbObjectPayload([&](CbObjectWriter& Writer) { Writer.AddString("method"sv, "snapshot"sv); }); - HttpClient Http(m_HostName); - ZEN_CONSOLE("Snapshotting oplog '{}/{}' to {}", m_ProjectName, m_OplogName, m_HostName); if (HttpClient::Response Result = Http.Post(fmt::format("/prj/{}/oplog/{}/rpc", m_ProjectName, m_OplogName), Payload, HttpClient::Accept(ZenContentType::kJSON))) @@ -1444,16 +1568,18 @@ ProjectDetailsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** throw OptionParseException("unable to resolve server specification"); } - if (!m_OpId.empty()) + HttpClient Http(m_HostName); + + if (!m_ProjectName.empty()) { - if (m_ProjectName.empty() || m_OplogName.empty()) + m_ProjectName = ResolveProject(Http, m_ProjectName); + if (m_ProjectName.empty()) { - ZEN_ERROR("Provide project and oplog name"); - ZEN_CONSOLE("{}", m_Options.help({""}).c_str()); return 1; } } - else if (!m_OplogName.empty()) + + if (!m_OplogName.empty() || !m_OpId.empty()) { if (m_ProjectName.empty()) { @@ -1461,9 +1587,19 @@ ProjectDetailsCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** ZEN_CONSOLE("{}", m_Options.help({""}).c_str()); return 1; } + m_OplogName = ResolveOplog(Http, m_ProjectName, m_OplogName); + if (m_OplogName.empty()) + { + return 1; + } } - HttpClient Http(m_HostName); + if (!m_OpId.empty() && m_OplogName.empty()) + { + ZEN_ERROR("Provide project and oplog name"); + ZEN_CONSOLE("{}", m_Options.help({""}).c_str()); + return 1; + } ExtendableStringBuilder<128> Url; Url.Append("/prj/details$"); @@ -1510,6 +1646,24 @@ OplogMirrorCommand::OplogMirrorCommand() m_Options.add_option("", "p", "project", "Project name to get info from", cxxopts::value(m_ProjectName), "<projectid>"); m_Options.add_option("", "l", "oplog", "Oplog name to get info from", cxxopts::value(m_OplogName), "<oplogid>"); m_Options.add_option("", "t", "target", "Target directory for mirror", cxxopts::value(m_MirrorRootPath), "<path>"); + m_Options.add_option("", + "k", + "key", + "Oplog key string to limit output (substring match), defaults to no filtering", + cxxopts::value(m_KeyFilter), + "<key>"); + m_Options.add_option("", + "f", + "file", + "Oplog file entry path string to limit output (substring match), defaults to no filtering", + cxxopts::value(m_FilenameFilter), + "<filename>"); + m_Options.add_option("", + "c", + "chunk", + "Oplog file entry chunk id to limit output, defaults to no filtering", + cxxopts::value(m_ChunkIdFilter), + "<chunkid>"); m_Options.parse_positional({"project", "oplog", "target"}); m_Options.positional_help("[<projectid> <oplogid> <target>]"); @@ -1536,14 +1690,18 @@ OplogMirrorCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg throw OptionParseException("unable to resolve server specification"); } + HttpClient Http(m_HostName); + + m_ProjectName = ResolveProject(Http, m_ProjectName); if (m_ProjectName.empty()) { - throw OptionParseException("a project must be specified"); + return 1; } + m_OplogName = ResolveOplog(Http, m_ProjectName, m_OplogName); if (m_OplogName.empty()) { - throw OptionParseException("an oplog must be specified"); + return 1; } if (m_MirrorRootPath.empty()) @@ -1551,21 +1709,17 @@ OplogMirrorCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg throw OptionParseException("a target path must be specified"); } - ZEN_CONSOLE("Emitting file data from oplog '{}/{}' to '{}'", m_ProjectName, m_OplogName, m_MirrorRootPath); - - HttpClient Http(m_HostName); - - if (HttpClient::Response Result = Http.Get(fmt::format("/prj/{}/oplog/{}", m_ProjectName, m_OplogName))) + Oid ChunkIdFilter = Oid::Zero; + if (!m_ChunkIdFilter.empty()) { - // The info requested is not really used at this moment, we just use the probe to be able to provide - // better diagnostics up front + ChunkIdFilter = Oid::TryFromHexString(m_ChunkIdFilter); + if (ChunkIdFilter == Oid::Zero) + { + throw OptionParseException("chunkid must be an Oid hex string"); + } } - else - { - Result.ThrowError("oplog info fetch failed"sv); - return 1; - } + ZEN_CONSOLE("Emitting file data from oplog '{}/{}' to '{}'", m_ProjectName, m_OplogName, m_MirrorRootPath); // Emit file data to target directory @@ -1590,7 +1744,15 @@ OplogMirrorCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg if (CbObjectView Data = DataIter.AsObjectView()) { std::string FileName = std::string(Data["filename"sv].AsString()); - Oid ChunkId = Data["id"sv].AsObjectId(); + if (!m_FilenameFilter.empty() && FileName.find(m_FilenameFilter) == std::string::npos) + { + continue; + } + Oid ChunkId = Data["id"sv].AsObjectId(); + if (ChunkIdFilter != Oid::Zero && ChunkIdFilter != ChunkId) + { + continue; + } if (!FileNames.insert(FileName).second) { continue; @@ -1625,7 +1787,14 @@ OplogMirrorCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg for (auto EntryIter : ResponseObject["entries"sv]) { CbObjectView Entry = EntryIter.AsObjectView(); - + if (!m_KeyFilter.empty()) + { + // ZEN_CONSOLE("{}", Entry["key"].AsString()); + if (Entry["key"].AsString().find(m_KeyFilter) == std::string_view::npos) + { + continue; + } + } EmitFilesForDataArray(Entry["packagedata"sv].AsArrayView()); EmitFilesForDataArray(Entry["bulkdata"sv].AsArrayView()); diff --git a/src/zen/cmds/projectstore_cmd.h b/src/zen/cmds/projectstore_cmd.h index 215614b01..8eee570c8 100644 --- a/src/zen/cmds/projectstore_cmd.h +++ b/src/zen/cmds/projectstore_cmd.h @@ -25,6 +25,7 @@ private: std::string m_HostName; std::string m_ProjectName; std::string m_OplogName; + bool m_DryRun = true; }; class ProjectInfoCommand : public ProjectStoreCommand @@ -62,21 +63,6 @@ private: bool m_ForceUpdate = false; }; -class DeleteProjectCommand : public ProjectStoreCommand -{ -public: - DeleteProjectCommand(); - ~DeleteProjectCommand(); - - 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-delete", "Delete project and all its oplogs"}; - std::string m_HostName; - std::string m_ProjectId; -}; - class CreateOplogCommand : public ProjectStoreCommand { public: @@ -95,22 +81,6 @@ private: bool m_ForceUpdate = false; }; -class DeleteOplogCommand : public ProjectStoreCommand -{ -public: - DeleteOplogCommand(); - ~DeleteOplogCommand(); - - virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override; - virtual cxxopts::Options& Options() override { return m_Options; } - -private: - cxxopts::Options m_Options{"oplog-delete", "Delete oplog and all its data"}; - std::string m_HostName; - std::string m_ProjectId; - std::string m_OplogId; -}; - class ExportOplogCommand : public ProjectStoreCommand { public: @@ -261,6 +231,9 @@ private: std::string m_ProjectName; std::string m_OplogName; std::string m_MirrorRootPath; + std::string m_KeyFilter; + std::string m_FilenameFilter; + std::string m_ChunkIdFilter; }; } // namespace zen diff --git a/src/zen/zen.cpp b/src/zen/zen.cpp index 05af79b31..0f21de130 100644 --- a/src/zen/zen.cpp +++ b/src/zen/zen.cpp @@ -295,9 +295,7 @@ main(int argc, char** argv) CopyCommand CopyCmd; CopyStateCommand CopyStateCmd; CreateOplogCommand CreateOplogCmd; - DeleteOplogCommand DeleteOplogCmd; CreateProjectCommand CreateProjectCmd; - DeleteProjectCommand DeleteProjectCmd; DedupCommand DedupCmd; DownCommand DownCmd; DropCommand DropCmd; @@ -358,7 +356,6 @@ main(int argc, char** argv) {"jobs", &JobCmd, "Show/cancel zen background jobs"}, {"logs", &LoggingCmd, "Show/control zen logging"}, {"oplog-create", &CreateOplogCmd, "Create a project oplog"}, - {"oplog-delete", &DeleteOplogCmd, "Delete a project oplog"}, {"oplog-export", &ExportOplogCmd, "Export project store oplog"}, {"oplog-import", &ImportOplogCmd, "Import project store oplog"}, {"oplog-mirror", &OplogMirrorCmd, "Mirror project store oplog to file system"}, @@ -366,7 +363,6 @@ main(int argc, char** argv) {"print", &PrintCmd, "Print compact binary object"}, {"printpackage", &PrintPkgCmd, "Print compact binary package"}, {"project-create", &CreateProjectCmd, "Create a project"}, - {"project-delete", &DeleteProjectCmd, "Delete a project"}, {"project-details", &ProjectDetailsCmd, "Details on project store"}, {"project-drop", &ProjectDropCmd, "Drop project or project oplog"}, {"project-info", &ProjectInfoCmd, "Info on project or project oplog"}, |