#include "maintenanceimpl.h" #include #include #include #include #include #include #include #include #include #include #include #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); } } static int onFile(const git_diff_delta * delta, float, void * fileset) { static_cast(fileset)->push_back(delta->old_file.path); static_cast(fileset)->push_back(delta->new_file.path); return 0; } static int onBinaryFile(const git_diff_delta * delta, const git_diff_binary *, void * fileset) { static_cast(fileset)->push_back(delta->old_file.path); static_cast(fileset)->push_back(delta->new_file.path); return 0; } template std::unique_ptr gitSafeGet(int(*get)(R**, P...), void(*release)(R*), A ... p) { R * r = nullptr; gitSafe(get(&r, p...)); return std::unique_ptr(r, release); } void Maintenance::refreshChangeLogs(const Ice::Current & c) { git_libgit2_init(); AdHoc::ScopeExit shutdownlibgit2(&git_libgit2_shutdown); auto dbc = db->get(); DB::TransactionScope tx(dbc.get()); auto cli = dbc->modify(sql::maintenance::changeLogInsert.getSql()); dbc->select(sql::maintenance::changeLogRoots.getSql())->forEachRow([&cli,&c,&dbc](auto repoId, const auto & repoName, const auto & repoRoot) { std::set processedChanges; { auto changes = dbc->select(sql::maintenance::changeLogRepoCommits.getSql()); changes->bindParamI(0, repoId); changes->forEachRow([&processedChanges](const auto & c) { processedChanges.insert(c); }); } cli->bindParamI(0, repoId); // Open repository auto repo = gitSafeGet(git_repository_open_ext, git_repository_free, repoRoot.c_str(), 0, nullptr); // Set up walker auto walker = gitSafeGet(git_revwalk_new, git_revwalk_free, repo.get()); auto startref = c.adapter->getCommunicator()->getProperties() ->getProperty("GentooBrowseAPI.ChangeLogStart." + repoName); if (startref.empty()) { 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)); } git_revwalk_sorting(walker.get(), GIT_SORT_TIME); git_oid oid; char str[GIT_OID_HEXSZ + 1]; // Walk through revisions for (; !git_revwalk_next(&oid, walker.get()); ) { git_oid_tostr(str, sizeof(str), &oid); auto i = processedChanges.find(str); if (i != processedChanges.end()) { processedChanges.erase(i); continue; } // Get commit auto commit = gitSafeGet(git_commit_lookup, git_commit_free, repo.get(), &oid); // Get commit's tree auto currentTree = gitSafeGet(git_commit_tree, git_tree_free, commit.get()); // Collect all files change in commit from all parents std::unique_ptr parentTree(nullptr, git_tree_free); if (git_commit_parentcount(commit.get()) > 0) { auto parentCommit = gitSafeGet(git_commit_parent, git_commit_free, commit.get(), 0); // Get parent tree parentTree = gitSafeGet(git_commit_tree, git_tree_free, parentCommit.get()); } // Get tree to tree diff auto diff = gitSafeGet(git_diff_tree_to_tree, git_diff_free, repo.get(), currentTree.get(), parentTree.get(), nullptr); // Compare trees StringList fs; git_diff_foreach(diff.get(), onFile, onBinaryFile, nullptr, nullptr, &fs); // Remove duplicate mentions of files std::sort(fs.begin(), fs.end()); fs.erase(std::unique(fs.begin(), fs.end()), fs.end()); // Insert commit into DB cli->bindParamS(1, str); auto sig = git_commit_author(commit.get()); cli->bindParamT(2, boost::posix_time::from_time_t(sig->when.time)); cli->bindParamS(3, git_commit_summary(commit.get())); Utils::Database::bindOptionalS(cli.get(), 4, git_commit_body(commit.get())); cli->bindParamS(5, sig->name); cli->bindParamS(6, sig->email); cli->bindParamS(7, Slicer::packPqTextArray(fs)); cli->execute(); } }); } } }