From 34e1ff8730e116694886509a8633f08e84852193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Blin?= <sebastien.blin@savoirfairelinux.com> Date: Fri, 12 Feb 2021 14:54:33 -0500 Subject: [PATCH] swarm: add "linearizedParent" into commit infos Previously clients needed to store a graph to linearize and do complex non-ui work with graph reconstruction and ordering. So, this commit introduces linearizedParent that gives for each commit what is the parent message. So clients just needs to store a list<interactions> and insert new messages after the announced parent. This parent is calculated with the equivalent of `git log --topo-order --date-order` Change-Id: I10d0809496a9de5b9110fe8164d3d23be1c023d3 --- src/jamidht/conversation.cpp | 2 + src/jamidht/conversationrepository.cpp | 60 +++++++++++++++++++++++--- src/jamidht/conversationrepository.h | 6 +++ 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/jamidht/conversation.cpp b/src/jamidht/conversation.cpp index 8a2120b044..83a98283df 100644 --- a/src/jamidht/conversation.cpp +++ b/src/jamidht/conversation.cpp @@ -244,8 +244,10 @@ Conversation::Impl::convCommitToMap(const std::vector<ConversationCommit>& commi JAMI_WARN("%s", err.c_str()); } } + auto linearizedParent = repository_->linearizedParent(commit.id); message["id"] = commit.id; message["parents"] = parents; + message["linearizedParent"] = linearizedParent ? *linearizedParent : ""; message["author"] = authorId; message["type"] = type; message["timestamp"] = std::to_string(commit.timestamp); diff --git a/src/jamidht/conversationrepository.cpp b/src/jamidht/conversationrepository.cpp index e86e549d45..5607c9a047 100644 --- a/src/jamidht/conversationrepository.cpp +++ b/src/jamidht/conversationrepository.cpp @@ -108,6 +108,7 @@ public: std::vector<ConversationCommit> log(const std::string& from, const std::string& to, unsigned n) const; + std::optional<std::string> linearizedParent(const std::string& commitId) const; GitObject fileAtTree(const std::string& path, const GitTree& tree) const; // NOTE! GitDiff needs to be deteleted before repo @@ -715,7 +716,8 @@ ConversationRepository::Impl::checkVote(const std::string& userDevice, return false; } auto* blob = reinterpret_cast<git_blob*>(vote.get()); - auto voteContent = std::string_view(static_cast<const char*>(git_blob_rawcontent(blob)), git_blob_rawsize(blob)); + auto voteContent = std::string_view(static_cast<const char*>(git_blob_rawcontent(blob)), + git_blob_rawsize(blob)); if (!voteContent.empty()) { JAMI_ERR("Vote file not empty: %s", votedFile.c_str()); return false; @@ -823,7 +825,8 @@ ConversationRepository::Impl::checkValidAdd(const std::string& userDevice, } auto* blob = reinterpret_cast<git_blob*>(blob_invite.get()); - auto invitation = std::string_view(static_cast<const char*>(git_blob_rawcontent(blob)), git_blob_rawsize(blob)); + auto invitation = std::string_view(static_cast<const char*>(git_blob_rawcontent(blob)), + git_blob_rawsize(blob)); if (!invitation.empty()) { JAMI_ERR("Invitation not empty for commit %s", commitId.c_str()); return false; @@ -1100,9 +1103,11 @@ ConversationRepository::Impl::isValidUserAtCommit(const std::string& userDevice, // Check that certificate matches auto* blob = reinterpret_cast<git_blob*>(blob_device.get()); - auto deviceCert = std::string_view(static_cast<const char*>(git_blob_rawcontent(blob)), git_blob_rawsize(blob)); + auto deviceCert = std::string_view(static_cast<const char*>(git_blob_rawcontent(blob)), + git_blob_rawsize(blob)); blob = reinterpret_cast<git_blob*>(blob_parent.get()); - auto parentCert = std::string_view(static_cast<const char*>(git_blob_rawcontent(blob)), git_blob_rawsize(blob)); + auto parentCert = std::string_view(static_cast<const char*>(git_blob_rawcontent(blob)), + git_blob_rawsize(blob)); auto deviceCertStr = cert->toString(false); auto parentCertStr = cert->issuer->toString(true); @@ -1454,7 +1459,7 @@ ConversationRepository::Impl::log(const std::string& from, const std::string& to return commits; } GitRevWalker walker {walker_ptr, git_revwalk_free}; - git_revwalk_sorting(walker.get(), GIT_SORT_TOPOLOGICAL); + git_revwalk_sorting(walker.get(), GIT_SORT_TOPOLOGICAL | GIT_SORT_TIME); for (auto idx = 0u; !git_revwalk_next(&oid, walker.get()); ++idx) { if (n != 0 && idx == n) { @@ -1507,6 +1512,45 @@ ConversationRepository::Impl::log(const std::string& from, const std::string& to return commits; } +std::optional<std::string> +ConversationRepository::Impl::linearizedParent(const std::string& commitId) const +{ + git_oid oid; + auto repo = repository(); + if (!repo or git_reference_name_to_id(&oid, repo.get(), "HEAD") < 0) { + JAMI_ERR("Cannot get reference for HEAD"); + return std::nullopt; + } + + git_revwalk* walker_ptr = nullptr; + if (git_revwalk_new(&walker_ptr, repo.get()) < 0 || git_revwalk_push(walker_ptr, &oid) < 0) { + if (walker_ptr) + git_revwalk_free(walker_ptr); + // This fail can be ok in the case we check if a commit exists before pulling (so can fail + // there). only log if the fail is unwanted. + return std::nullopt; + } + GitRevWalker walker {walker_ptr, git_revwalk_free}; + git_revwalk_sorting(walker.get(), GIT_SORT_TOPOLOGICAL | GIT_SORT_TIME); + + auto ret = false; + for (auto idx = 0u; !git_revwalk_next(&oid, walker.get()); ++idx) { + git_commit* commit_ptr = nullptr; + std::string id = git_oid_tostr_s(&oid); + if (git_commit_lookup(&commit_ptr, repo.get(), &oid) < 0) { + JAMI_WARN("Failed to look up commit %s", id.c_str()); + break; + } + + if (ret) + return id; + if (id == commitId) + ret = true; + } + + return std::nullopt; +} + GitObject ConversationRepository::Impl::fileAtTree(const std::string& path, const GitTree& tree) const { @@ -2734,6 +2778,12 @@ ConversationRepository::validClone() const return pimpl_->validCommits(logN("", 0)); } +std::optional<std::string> +ConversationRepository::linearizedParent(const std::string& commitId) const +{ + return pimpl_->linearizedParent(commitId); +} + void ConversationRepository::removeBranchWith(const std::string& remoteDevice) { diff --git a/src/jamidht/conversationrepository.h b/src/jamidht/conversationrepository.h index 71457148a6..2d368db6f1 100644 --- a/src/jamidht/conversationrepository.h +++ b/src/jamidht/conversationrepository.h @@ -191,6 +191,12 @@ public: const std::string& to = "") const; std::optional<ConversationCommit> getCommit(const std::string& commitId) const; + /** + * Get parent via topological + date sort in branch main of a commit + * @param commitId id to choice + */ + std::optional<std::string> linearizedParent(const std::string& commitId) const; + /** * Merge another branch into the main branch * @param merge_id The reference to merge -- GitLab