diff options
Diffstat (limited to 'src/git.cc')
-rw-r--r-- | src/git.cc | 242 |
1 files changed, 0 insertions, 242 deletions
diff --git a/src/git.cc b/src/git.cc deleted file mode 100644 index 029b02bf..00000000 --- a/src/git.cc +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright 2019 Roman Perepelitsa. -// -// This file is part of GitStatus. -// -// GitStatus 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. -// -// GitStatus 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 GitStatus. If not, see <https://www.gnu.org/licenses/>. - -#include "git.h" - -#include <cstdlib> -#include <cstring> -#include <fstream> -#include <sstream> -#include <utility> - -#include <fcntl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "arena.h" -#include "check.h" -#include "print.h" -#include "scope_guard.h" - -namespace gitstatus { - -const char* GitError() { - const git_error* err = git_error_last(); - return err && err->message ? err->message : "unknown error"; -} - -std::string RepoState(git_repository* repo) { - Arena arena; - StringView gitdir(git_repository_path(repo)); - - // These names mostly match gitaction in vcs_info: - // https://github.com/zsh-users/zsh/blob/master/Functions/VCS_Info/Backends/VCS_INFO_get_data_git. - auto State = [&]() { - switch (git_repository_state(repo)) { - case GIT_REPOSITORY_STATE_NONE: - return ""; - case GIT_REPOSITORY_STATE_MERGE: - return "merge"; - case GIT_REPOSITORY_STATE_REVERT: - return "revert"; - case GIT_REPOSITORY_STATE_REVERT_SEQUENCE: - return "revert-seq"; - case GIT_REPOSITORY_STATE_CHERRYPICK: - return "cherry"; - case GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE: - return "cherry-seq"; - case GIT_REPOSITORY_STATE_BISECT: - return "bisect"; - case GIT_REPOSITORY_STATE_REBASE: - return "rebase"; - case GIT_REPOSITORY_STATE_REBASE_INTERACTIVE: - return "rebase-i"; - case GIT_REPOSITORY_STATE_REBASE_MERGE: - return "rebase-m"; - case GIT_REPOSITORY_STATE_APPLY_MAILBOX: - return "am"; - case GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE: - return "am/rebase"; - } - return "action"; - }; - - auto DirExists = [&](StringView name) { - int fd = open(arena.StrCat(gitdir, "/", name), O_DIRECTORY | O_CLOEXEC); - if (fd < 0) return false; - CHECK(!close(fd)) << Errno(); - return true; - }; - - auto ReadFile = [&](StringView name) { - std::ifstream strm(arena.StrCat(gitdir, "/", name)); - std::string res; - strm >> res; - return res; - }; - - std::string next; - std::string last; - - if (DirExists("rebase-merge")) { - next = ReadFile("rebase-merge/msgnum"); - last = ReadFile("rebase-merge/end"); - } else if (DirExists("rebase-apply")) { - next = ReadFile("rebase-apply/next"); - last = ReadFile("rebase-apply/last"); - } - - std::ostringstream res; - res << State(); - if (!next.empty() && !last.empty()) res << ' ' << next << '/' << last; - return res.str(); -} - -size_t CountRange(git_repository* repo, const std::string& range) { - git_revwalk* walk = nullptr; - VERIFY(!git_revwalk_new(&walk, repo)) << GitError(); - ON_SCOPE_EXIT(=) { git_revwalk_free(walk); }; - VERIFY(!git_revwalk_push_range(walk, range.c_str())) << GitError(); - size_t res = 0; - while (true) { - git_oid oid; - switch (git_revwalk_next(&oid, walk)) { - case 0: - ++res; - break; - case GIT_ITEROVER: - return res; - default: - LOG(ERROR) << "git_revwalk_next: " << range << ": " << GitError(); - throw Exception(); - } - } -} - -size_t NumStashes(git_repository* repo) { - size_t res = 0; - auto* cb = +[](size_t index, const char* message, const git_oid* stash_id, void* payload) { - ++*static_cast<size_t*>(payload); - return 0; - }; - if (!git_stash_foreach(repo, cb, &res)) return res; - // Example error: failed to parse signature - malformed e-mail. - // See https://github.com/romkatv/powerlevel10k/issues/216. - LOG(WARN) << "git_stash_foreach: " << GitError(); - return 0; -} - -git_reference* Head(git_repository* repo) { - git_reference* symbolic = nullptr; - switch (git_reference_lookup(&symbolic, repo, "HEAD")) { - case 0: - break; - case GIT_ENOTFOUND: - return nullptr; - default: - LOG(ERROR) << "git_reference_lookup: " << GitError(); - throw Exception(); - } - - git_reference* direct = nullptr; - if (git_reference_resolve(&direct, symbolic)) { - LOG(INFO) << "Empty git repo (no HEAD)"; - return symbolic; - } - git_reference_free(symbolic); - return direct; -} - -const char* LocalBranchName(const git_reference* ref) { - CHECK(ref); - git_reference_t type = git_reference_type(ref); - switch (type) { - case GIT_REFERENCE_DIRECT: { - return git_reference_is_branch(ref) ? git_reference_shorthand(ref) : ""; - } - case GIT_REFERENCE_SYMBOLIC: { - static constexpr char kHeadPrefix[] = "refs/heads/"; - const char* target = git_reference_symbolic_target(ref); - if (!target) return ""; - size_t len = std::strlen(target); - if (len < sizeof(kHeadPrefix)) return ""; - if (std::memcmp(target, kHeadPrefix, sizeof(kHeadPrefix) - 1)) return ""; - return target + (sizeof(kHeadPrefix) - 1); - } - case GIT_REFERENCE_INVALID: - case GIT_REFERENCE_ALL: - break; - } - LOG(ERROR) << "Invalid reference type: " << type; - throw Exception(); -} - -RemotePtr GetRemote(git_repository* repo, const git_reference* local) { - git_remote* remote; - git_buf symref = {}; - if (git_branch_remote(&remote, &symref, repo, git_reference_name(local))) return nullptr; - ON_SCOPE_EXIT(&) { - git_remote_free(remote); - git_buf_free(&symref); - }; - - git_reference* ref; - if (git_reference_lookup(&ref, repo, symref.ptr)) return nullptr; - ON_SCOPE_EXIT(&) { if (ref) git_reference_free(ref); }; - - const char* branch = nullptr; - std::string name = remote ? git_remote_name(remote) : "."; - if (git_branch_name(&branch, ref)) { - branch = ""; - } else if (remote) { - VERIFY(std::strstr(branch, name.c_str()) == branch); - VERIFY(branch[name.size()] == '/'); - branch += name.size() + 1; - } - - auto res = std::make_unique<Remote>(); - res->name = std::move(name); - res->branch = branch; - res->url = remote ? (git_remote_url(remote) ?: "") : ""; - res->ref = std::exchange(ref, nullptr); - return RemotePtr(res.release()); -} - -PushRemotePtr GetPushRemote(git_repository* repo, const git_reference* local) { - git_remote* remote; - git_buf symref = {}; - if (git_branch_push_remote(&remote, &symref, repo, git_reference_name(local))) return nullptr; - ON_SCOPE_EXIT(&) { - git_remote_free(remote); - git_buf_free(&symref); - }; - - git_reference* ref; - if (git_reference_lookup(&ref, repo, symref.ptr)) return nullptr; - ON_SCOPE_EXIT(&) { if (ref) git_reference_free(ref); }; - - std::string name = remote ? git_remote_name(remote) : "."; - - auto res = std::make_unique<PushRemote>(); - res->name = std::move(name); - res->url = remote ? (git_remote_url(remote) ?: "") : ""; - res->ref = std::exchange(ref, nullptr); - return PushRemotePtr(res.release()); -} - -} // namespace gitstatus |