1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
#include "maintenanceimpl.h"
#include <Ice/ObjectAdapter.h>
#include <Ice/Communicator.h>
#include <boost/lexical_cast.hpp>
#include <selectcommandUtil.impl.h>
#include <utils/dbUtils.h>
#include <git2.h>
#include <scopeExit.h>
#include <sql/maintenance/changeLogRoots.sql.h>
#include <sql/maintenance/changeLogInsert.sql.h>
#include <sql/maintenance/changeLogRepoCommits.sql.h>
#include <portage-models.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);
}
}
static
int
onFile(const git_diff_delta * delta, float, void * fileset)
{
static_cast<StringList *>(fileset)->push_back(delta->old_file.path);
static_cast<StringList *>(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<StringList *>(fileset)->push_back(delta->old_file.path);
static_cast<StringList *>(fileset)->push_back(delta->new_file.path);
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)
{
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<int64_t, std::string, std::string>([&cli,&c,&dbc](auto repoId, const auto & repoName, const auto & repoRoot) {
std::set<std::string> processedChanges;
{
auto changes = dbc->select(sql::maintenance::changeLogRepoCommits.getSql());
changes->bindParamI(0, repoId);
changes->forEachRow<std::string>([&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<git_tree, void(*)(git_tree*)> 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()));
cli->bindParamS(4, git_commit_body(commit.get()));
cli->bindParamS(5, sig->name);
cli->bindParamS(6, sig->email);
cli->bindParamS(7, Slicer::packPqTextArray(fs));
cli->execute();
}
});
}
}
}
|