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
|
#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 <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, boost::optional<std::string>>([&cli,&c](auto repoId, const auto & repoName, const auto & repoRoot, const auto & lastCommitId) {
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);
if (lastCommitId && *lastCommitId == str) {
break;
}
// 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()));
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();
}
});
}
}
}
|