diff options
-rw-r--r-- | gentoobrowse-api/api/impl.cpp | 4 | ||||
-rw-r--r-- | gentoobrowse-api/api/maintenance.ice | 1 | ||||
-rw-r--r-- | gentoobrowse-api/service/maintenanceGitOperations.cpp | 26 | ||||
-rw-r--r-- | gentoobrowse-api/service/utils/git.cpp | 89 | ||||
-rw-r--r-- | gentoobrowse-api/service/utils/git.h | 47 |
5 files changed, 144 insertions, 23 deletions
diff --git a/gentoobrowse-api/api/impl.cpp b/gentoobrowse-api/api/impl.cpp index f032c3a..9c21c98 100644 --- a/gentoobrowse-api/api/impl.cpp +++ b/gentoobrowse-api/api/impl.cpp @@ -2,10 +2,10 @@ #include <compileTimeFormatter.h> namespace Gentoo { - AdHocFormatter(GitErrorMessage, "Git Error: %? (code %?, class %?)"); + AdHocFormatter(GitErrorMessage, "Git Error: %?: %? (code %?, class %?)"); void GitError::ice_print(std::ostream & s) const { - GitErrorMessage::write(s, message, errorCode, errorClass); + GitErrorMessage::write(s, operation, message, errorCode, errorClass); } } diff --git a/gentoobrowse-api/api/maintenance.ice b/gentoobrowse-api/api/maintenance.ice index 736b913..335cd7e 100644 --- a/gentoobrowse-api/api/maintenance.ice +++ b/gentoobrowse-api/api/maintenance.ice @@ -3,6 +3,7 @@ module Gentoo { ["cpp:ice_print"] exception GitError { + string operation; int errorCode; int errorClass; string message; diff --git a/gentoobrowse-api/service/maintenanceGitOperations.cpp b/gentoobrowse-api/service/maintenanceGitOperations.cpp index 7c1ef81..84fe352 100644 --- a/gentoobrowse-api/service/maintenanceGitOperations.cpp +++ b/gentoobrowse-api/service/maintenanceGitOperations.cpp @@ -10,19 +10,12 @@ #include <sql/maintenance/changeLogInsert.sql.h> #include <sql/maintenance/changeLogRepoCommits.sql.h> #include <portage-models.h> +#include "utils/git.h" #include "converters.h" namespace Gentoo { namespace Service { - static - void - gitSafe(int func) - { - if (int _giterror = func < 0) { - const git_error * e = giterr_last(); - throw GitError(_giterror, e->klass, e->message); - } - } + using namespace Utils::Git; static int @@ -42,15 +35,6 @@ namespace Gentoo { return 0; } - template<typename R, typename ... P, typename ... A> - std::unique_ptr<R, void(*)(R*)> - gitSafeGet(int(*get)(R**, P...), void(*release)(R*), A ... p) - { - R * r = nullptr; - gitSafe(get(&r, p...)); - return std::unique_ptr<R, void(*)(R*)>(r, release); - } - void Maintenance::refreshChangeLogs(const Ice::Current & c) { @@ -76,12 +60,12 @@ namespace Gentoo { auto startref = c.adapter->getCommunicator()->getProperties() ->getProperty("GentooBrowseAPI.ChangeLogStart." + repoName); if (startref.empty()) { - gitSafe(git_revwalk_push_head(walker.get())); + gitSafe(git_revwalk_push_head, walker.get()); } else { git_oid oid; - gitSafe(git_oid_fromstr(&oid, startref.c_str())); - gitSafe(git_revwalk_push(walker.get(), &oid)); + gitSafe(git_oid_fromstr, &oid, startref.c_str()); + gitSafe(git_revwalk_push, walker.get(), &oid); } git_revwalk_sorting(walker.get(), GIT_SORT_TIME); diff --git a/gentoobrowse-api/service/utils/git.cpp b/gentoobrowse-api/service/utils/git.cpp new file mode 100644 index 0000000..095c9c2 --- /dev/null +++ b/gentoobrowse-api/service/utils/git.cpp @@ -0,0 +1,89 @@ +#include "git.h" +#include <maintenance.h> +#include <execinfo.h> +#include <compileTimeFormatter.h> + +namespace Gentoo { + namespace Utils { + namespace Git { + void + throwError(void * const func, int err) + { + const git_error * e = giterr_last(); + fprintf(stderr, "func %p\n", func); + char ** fn = backtrace_symbols(&func, 1); + throw ::Gentoo::GitError(*fn, err, e->klass, e->message); + } + + int show(const git_transfer_progress * p, void *) + { + fprintf(stderr, "%u / %u\n", p->total_objects, p->received_objects); + return 0; + } + + AdHocFormatter(RefSpec, "refs/heads/%?:refs/remotes/%?/%?"); + std::unique_ptr<git_annotated_commit, void (*)(git_annotated_commit*)> + gitFetch(git_repository * repo, git_remote * remote, const char * remoteBranchName) + { + git_fetch_options opts = GIT_FETCH_OPTIONS_INIT; + opts.prune = GIT_FETCH_PRUNE; + opts.update_fetchhead = 1; + opts.callbacks.transfer_progress = show; + auto localBranch = gitSafeGet(git_repository_head, git_reference_free, repo); + auto localBranchName = gitSafeGet(git_branch_name, localBranch.get()); + // auto remoteBranch = gitSafeGet(git_branch_upstream, git_reference_free, localBranch.get()); + // auto remoteBranchName = gitSafeGet(git_branch_name, remoteBranch.get()); + // auto remoteBranchName = gitSafeGet(git_remote_default_branch, remote); + // auto remoteBranchName = "stable"; + auto refspec = RefSpec::get(localBranchName, git_remote_name(remote), remoteBranchName); + // fprintf(stderr, "localBranch %s\n", localBranchName); + // fprintf(stderr, "remoteBranch %s\n", remoteBranchName.size); + fprintf(stderr, "refspec %s\n", refspec.c_str()); + char * s[] = { &refspec.front() }; + git_strarray refs = { s, 1 }; + //(void)refs; + gitSafe(git_remote_fetch, remote, &refs, &opts, nullptr); + return gitSafeGet(git_annotated_commit_from_revspec, git_annotated_commit_free, repo, "FETCH_HEAD"); + } + + git_oid + gitFastForward(git_repository * repo, git_annotated_commit * fetch_head) + { + // Test fast-forward is possible + const git_annotated_commit * heads[] = { fetch_head }; + git_merge_analysis_t analysis = GIT_MERGE_ANALYSIS_NONE; + git_merge_preference_t preference = GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY; + gitSafe(git_merge_analysis, &analysis, &preference, repo, heads, 1); + + auto head = gitSafeGet(git_repository_head, git_reference_free, repo); + if (analysis == GIT_MERGE_ANALYSIS_UP_TO_DATE) { + return *git_reference_target(head.get()); + } + if (!(analysis & (GIT_MERGE_ANALYSIS_NORMAL | GIT_MERGE_ANALYSIS_FASTFORWARD))) { + throw GitError("Merge analysis", 0, 0, "Could not fast-forward branch"); + } + + // Perform fast-forward + auto fetch_head_id = *git_annotated_commit_id(fetch_head); + auto fetch_head_object = gitSafeGet(git_object_lookup, git_object_free, repo, &fetch_head_id, GIT_OBJ_ANY); + gitSafeGet(git_reference_set_target, git_reference_free, head.get(), &fetch_head_id, "fast-forward"); + + // Checkout new head + auto checkout_options = gitSafeGet(git_checkout_init_options, 0u + GIT_CHECKOUT_OPTIONS_VERSION); + checkout_options.checkout_strategy = GIT_CHECKOUT_FORCE; + gitSafe(git_checkout_head, repo, &checkout_options); + return fetch_head_id; + } + + void + updateRepository(const std::string & path, const std::string & upstream, const std::string & branch) + { + auto repo = gitSafeGet(git_repository_open, git_repository_free, path.c_str()); + auto origin = gitSafeGet(git_remote_lookup, git_remote_free, repo.get(), upstream.c_str()); + auto fetchHead = gitFetch(repo.get(), origin.get(), branch.c_str()); + gitFastForward(repo.get(), fetchHead.get()); + } + + } + } +} diff --git a/gentoobrowse-api/service/utils/git.h b/gentoobrowse-api/service/utils/git.h new file mode 100644 index 0000000..8e70074 --- /dev/null +++ b/gentoobrowse-api/service/utils/git.h @@ -0,0 +1,47 @@ +#include <memory> +#include <git2.h> + +namespace Gentoo { + namespace Utils { + namespace Git { + void throwError(void * const func, int err); + + template<typename ... P, typename ... A> + void + gitSafe(int (*func)(P...), A ... p) + { + if (int _giterror = func(p...) < 0) { + throwError(&func, _giterror); + } + } + + template<typename R, typename ... P, typename ... A> + std::unique_ptr<R, void(*)(R*)> + gitSafeGet(int(*get)(R**, P...), void(*release)(R*), A ... p) + { + R * r = nullptr; + gitSafe(get, &r, p...); + return std::unique_ptr<R, void(*)(R*)>(r, release); + } + + template<typename R, typename ... P, typename ... A> + R + gitSafeGet(int(*get)(R*, P...), A ... p) + { + R r; + gitSafe(get, &r, p...); + return r; + } + + std::unique_ptr<git_annotated_commit, void (*)(git_annotated_commit*)> + gitFetch(git_repository * repo, git_remote * remote, const char * branch); + + git_oid + gitFastForward(git_repository * repo, git_annotated_commit * fetch_head); + + void + updateRepository(const std::string & path, const std::string & upstream, const std::string & branch); + } + } +} + |