1 | // 2007 Timothy Brownawell <tbrownaw@gmail.com>␊ |
2 | // GNU GPL V2 or later␊ |
3 | ␊ |
4 | #include "base.hh"␊ |
5 | #include "vector.hh"␊ |
6 | ␊ |
7 | #include "cert.hh"␊ |
8 | #include "database.hh"␊ |
9 | #include "project.hh"␊ |
10 | #include "revision.hh"␊ |
11 | #include "transforms.hh"␊ |
12 | #include "lua_hooks.hh"␊ |
13 | #include "keys.hh"␊ |
14 | #include "options.hh"␊ |
15 | ␊ |
16 | using std::string;␊ |
17 | using std::set;␊ |
18 | using std::vector;␊ |
19 | using std::multimap;␊ |
20 | using std::make_pair;␊ |
21 | ␊ |
22 | project_t::project_t(database & db)␊ |
23 | : db(db)␊ |
24 | {}␊ |
25 | ␊ |
26 | void␊ |
27 | project_t::get_branch_list(std::set<branch_name> & names,␊ |
28 | bool check_heads)␊ |
29 | {␊ |
30 | if (indicator.outdated())␊ |
31 | {␊ |
32 | std::vector<std::string> got;␊ |
33 | indicator = db.get_branches(got);␊ |
34 | branches.clear();␊ |
35 | multimap<revision_id, revision_id> inverse_graph_cache;␊ |
36 | ␊ |
37 | for (std::vector<std::string>::iterator i = got.begin();␊ |
38 | i != got.end(); ++i)␊ |
39 | {␊ |
40 | // check that the branch has at least one non-suspended head␊ |
41 | const branch_name branch(*i);␊ |
42 | std::set<revision_id> heads;␊ |
43 | ␊ |
44 | if (check_heads)␊ |
45 | get_branch_heads(branch, heads, false, &inverse_graph_cache);␊ |
46 | ␊ |
47 | if (!check_heads || !heads.empty())␊ |
48 | branches.insert(branch);␊ |
49 | }␊ |
50 | }␊ |
51 | ␊ |
52 | names = branches;␊ |
53 | }␊ |
54 | ␊ |
55 | void␊ |
56 | project_t::get_branch_list(globish const & glob,␊ |
57 | std::set<branch_name> & names,␊ |
58 | bool check_heads)␊ |
59 | {␊ |
60 | std::vector<std::string> got;␊ |
61 | db.get_branches(glob, got);␊ |
62 | names.clear();␊ |
63 | multimap<revision_id, revision_id> inverse_graph_cache;␊ |
64 | ␊ |
65 | for (std::vector<std::string>::iterator i = got.begin();␊ |
66 | i != got.end(); ++i)␊ |
67 | {␊ |
68 | // check that the branch has at least one non-suspended head␊ |
69 | const branch_name branch(*i);␊ |
70 | std::set<revision_id> heads;␊ |
71 | ␊ |
72 | if (check_heads)␊ |
73 | get_branch_heads(branch, heads, false, &inverse_graph_cache);␊ |
74 | ␊ |
75 | if (!check_heads || !heads.empty())␊ |
76 | names.insert(branch);␊ |
77 | }␊ |
78 | }␊ |
79 | ␊ |
80 | namespace␊ |
81 | {␊ |
82 | struct not_in_branch : public is_failure␊ |
83 | {␊ |
84 | database & db;␊ |
85 | branch_name const & branch;␊ |
86 | not_in_branch(database & db,␊ |
87 | branch_name const & branch)␊ |
88 | : db(db), branch(branch)␊ |
89 | {}␊ |
90 | virtual bool operator()(revision_id const & rid)␊ |
91 | {␊ |
92 | vector< revision<cert> > certs;␊ |
93 | db.get_revision_certs(rid,␊ |
94 | cert_name(branch_cert_name),␊ |
95 | cert_value(branch()),␊ |
96 | certs);␊ |
97 | erase_bogus_certs(db, certs);␊ |
98 | return certs.empty();␊ |
99 | }␊ |
100 | };␊ |
101 | ␊ |
102 | struct suspended_in_branch : public is_failure␊ |
103 | {␊ |
104 | database & db;␊ |
105 | branch_name const & branch;␊ |
106 | suspended_in_branch(database & db,␊ |
107 | branch_name const & branch)␊ |
108 | : db(db), branch(branch)␊ |
109 | {}␊ |
110 | virtual bool operator()(revision_id const & rid)␊ |
111 | {␊ |
112 | vector< revision<cert> > certs;␊ |
113 | db.get_revision_certs(rid,␊ |
114 | cert_name(suspend_cert_name),␊ |
115 | cert_value(branch()),␊ |
116 | certs);␊ |
117 | erase_bogus_certs(db, certs);␊ |
118 | return !certs.empty();␊ |
119 | }␊ |
120 | };␊ |
121 | }␊ |
122 | ␊ |
123 | void␊ |
124 | project_t::get_branch_heads(branch_name const & name,␊ |
125 | std::set<revision_id> & heads,␊ |
126 | bool ignore_suspend_certs,␊ |
127 | multimap<revision_id, revision_id> * inverse_graph_cache_ptr)␊ |
128 | {␊ |
129 | std::pair<branch_name, suspended_indicator>␊ |
130 | cache_index(name, ignore_suspend_certs);␊ |
131 | std::pair<outdated_indicator, std::set<revision_id> > &␊ |
132 | branch = branch_heads[cache_index];␊ |
133 | if (branch.first.outdated())␊ |
134 | {␊ |
135 | L(FL("getting heads of branch %s") % name);␊ |
136 | ␊ |
137 | branch.first = db.get_revisions_with_cert(cert_name(branch_cert_name),␊ |
138 | cert_value(name()),␊ |
139 | branch.second);␊ |
140 | ␊ |
141 | not_in_branch p(db, name);␊ |
142 | erase_ancestors_and_failures(db, branch.second, p,␊ |
143 | inverse_graph_cache_ptr);␊ |
144 | ␊ |
145 | if (!ignore_suspend_certs)␊ |
146 | {␊ |
147 | suspended_in_branch s(db, name);␊ |
148 | std::set<revision_id>::iterator it = branch.second.begin();␊ |
149 | while (it != branch.second.end())␊ |
150 | if (s(*it))␊ |
151 | branch.second.erase(it++);␊ |
152 | else␊ |
153 | it++;␊ |
154 | }␊ |
155 | ␊ |
156 | L(FL("found heads of branch %s (%s heads)")␊ |
157 | % name % branch.second.size());␊ |
158 | }␊ |
159 | heads = branch.second;␊ |
160 | }␊ |
161 | ␊ |
162 | bool␊ |
163 | project_t::revision_is_in_branch(revision_id const & id,␊ |
164 | branch_name const & branch)␊ |
165 | {␊ |
166 | vector<revision<cert> > certs;␊ |
167 | db.get_revision_certs(id, branch_cert_name, cert_value(branch()), certs);␊ |
168 | ␊ |
169 | int num = certs.size();␊ |
170 | ␊ |
171 | erase_bogus_certs(db, certs);␊ |
172 | ␊ |
173 | L(FL("found %d (%d valid) %s branch certs on revision %s")␊ |
174 | % num␊ |
175 | % certs.size()␊ |
176 | % branch␊ |
177 | % id);␊ |
178 | ␊ |
179 | return !certs.empty();␊ |
180 | }␊ |
181 | ␊ |
182 | void␊ |
183 | project_t::put_revision_in_branch(key_store & keys,␊ |
184 | revision_id const & id,␊ |
185 | branch_name const & branch)␊ |
186 | {␊ |
187 | cert_revision_in_branch(db, keys, id, branch);␊ |
188 | }␊ |
189 | ␊ |
190 | bool␊ |
191 | project_t::revision_is_suspended_in_branch(revision_id const & id,␊ |
192 | branch_name const & branch)␊ |
193 | {␊ |
194 | vector<revision<cert> > certs;␊ |
195 | db.get_revision_certs(id, suspend_cert_name, cert_value(branch()), certs);␊ |
196 | ␊ |
197 | int num = certs.size();␊ |
198 | ␊ |
199 | erase_bogus_certs(db, certs);␊ |
200 | ␊ |
201 | L(FL("found %d (%d valid) %s suspend certs on revision %s")␊ |
202 | % num␊ |
203 | % certs.size()␊ |
204 | % branch␊ |
205 | % id);␊ |
206 | ␊ |
207 | return !certs.empty();␊ |
208 | }␊ |
209 | ␊ |
210 | void␊ |
211 | project_t::suspend_revision_in_branch(key_store & keys,␊ |
212 | revision_id const & id,␊ |
213 | branch_name const & branch)␊ |
214 | {␊ |
215 | cert_revision_suspended_in_branch(db, keys, id, branch);␊ |
216 | }␊ |
217 | ␊ |
218 | ␊ |
219 | outdated_indicator␊ |
220 | project_t::get_revision_cert_hashes(revision_id const & rid,␊ |
221 | std::vector<id> & hashes)␊ |
222 | {␊ |
223 | return db.get_revision_certs(rid, hashes);␊ |
224 | }␊ |
225 | ␊ |
226 | outdated_indicator␊ |
227 | project_t::get_revision_certs(revision_id const & id,␊ |
228 | std::vector<revision<cert> > & certs)␊ |
229 | {␊ |
230 | return db.get_revision_certs(id, certs);␊ |
231 | }␊ |
232 | ␊ |
233 | outdated_indicator␊ |
234 | project_t::get_revision_certs_by_name(revision_id const & id,␊ |
235 | cert_name const & name,␊ |
236 | std::vector<revision<cert> > & certs)␊ |
237 | {␊ |
238 | outdated_indicator i = db.get_revision_certs(id, name, certs);␊ |
239 | erase_bogus_certs(db, certs);␊ |
240 | return i;␊ |
241 | }␊ |
242 | ␊ |
243 | outdated_indicator␊ |
244 | project_t::get_revision_branches(revision_id const & id,␊ |
245 | std::set<branch_name> & branches)␊ |
246 | {␊ |
247 | std::vector<revision<cert> > certs;␊ |
248 | outdated_indicator i = get_revision_certs_by_name(id, branch_cert_name, certs);␊ |
249 | branches.clear();␊ |
250 | for (std::vector<revision<cert> >::const_iterator i = certs.begin();␊ |
251 | i != certs.end(); ++i)␊ |
252 | branches.insert(branch_name(i->inner().value()));␊ |
253 | ␊ |
254 | return i;␊ |
255 | }␊ |
256 | ␊ |
257 | outdated_indicator␊ |
258 | project_t::get_branch_certs(branch_name const & branch,␊ |
259 | std::vector<revision<cert> > & certs)␊ |
260 | {␊ |
261 | return db.get_revision_certs(branch_cert_name, cert_value(branch()), certs);␊ |
262 | }␊ |
263 | ␊ |
264 | tag_t::tag_t(revision_id const & ident,␊ |
265 | utf8 const & name,␊ |
266 | rsa_keypair_id const & key)␊ |
267 | : ident(ident), name(name), key(key)␊ |
268 | {}␊ |
269 | ␊ |
270 | bool␊ |
271 | operator < (tag_t const & a, tag_t const & b)␊ |
272 | {␊ |
273 | if (a.name < b.name)␊ |
274 | return true;␊ |
275 | else if (a.name == b.name)␊ |
276 | {␊ |
277 | if (a.ident < b.ident)␊ |
278 | return true;␊ |
279 | else if (a.ident == b.ident)␊ |
280 | {␊ |
281 | if (a.key < b.key)␊ |
282 | return true;␊ |
283 | }␊ |
284 | }␊ |
285 | return false;␊ |
286 | }␊ |
287 | ␊ |
288 | outdated_indicator␊ |
289 | project_t::get_tags(set<tag_t> & tags)␊ |
290 | {␊ |
291 | std::vector<revision<cert> > certs;␊ |
292 | outdated_indicator i = db.get_revision_certs(tag_cert_name, certs);␊ |
293 | erase_bogus_certs(db, certs);␊ |
294 | tags.clear();␊ |
295 | for (std::vector<revision<cert> >::const_iterator i = certs.begin();␊ |
296 | i != certs.end(); ++i)␊ |
297 | tags.insert(tag_t(revision_id(i->inner().ident),␊ |
298 | utf8(i->inner().value()), i->inner().key));␊ |
299 | ␊ |
300 | return i;␊ |
301 | }␊ |
302 | ␊ |
303 | void␊ |
304 | project_t::put_tag(key_store & keys,␊ |
305 | revision_id const & id,␊ |
306 | string const & name)␊ |
307 | {␊ |
308 | cert_revision_tag(db, keys, id, name);␊ |
309 | }␊ |
310 | ␊ |
311 | ␊ |
312 | void␊ |
313 | project_t::put_standard_certs(key_store & keys,␊ |
314 | revision_id const & id,␊ |
315 | branch_name const & branch,␊ |
316 | utf8 const & changelog,␊ |
317 | date_t const & time,␊ |
318 | string const & author)␊ |
319 | {␊ |
320 | I(!branch().empty());␊ |
321 | I(!changelog().empty());␊ |
322 | I(time.valid());␊ |
323 | I(!author.empty());␊ |
324 | ␊ |
325 | cert_revision_in_branch(db, keys, id, branch);␊ |
326 | cert_revision_changelog(db, keys, id, changelog);␊ |
327 | cert_revision_date_time(db, keys, id, time);␊ |
328 | cert_revision_author(db, keys, id, author);␊ |
329 | }␊ |
330 | ␊ |
331 | void␊ |
332 | project_t::put_standard_certs_from_options(options const & opts,␊ |
333 | lua_hooks & lua,␊ |
334 | key_store & keys,␊ |
335 | revision_id const & id,␊ |
336 | branch_name const & branch,␊ |
337 | utf8 const & changelog)␊ |
338 | {␊ |
339 | date_t date;␊ |
340 | if (opts.date_given)␊ |
341 | date = opts.date;␊ |
342 | else␊ |
343 | date = date_t::now();␊ |
344 | ␊ |
345 | string author = opts.author();␊ |
346 | if (author.empty())␊ |
347 | {␊ |
348 | rsa_keypair_id key;␊ |
349 | get_user_key(opts, lua, db, keys, key);␊ |
350 | ␊ |
351 | if (!lua.hook_get_author(branch, key, author))␊ |
352 | author = key();␊ |
353 | }␊ |
354 | ␊ |
355 | put_standard_certs(keys, id, branch, changelog, date, author);␊ |
356 | }␊ |
357 | ␊ |
358 | void␊ |
359 | project_t::put_cert(key_store & keys,␊ |
360 | revision_id const & id,␊ |
361 | cert_name const & name,␊ |
362 | cert_value const & value)␊ |
363 | {␊ |
364 | put_simple_revision_cert(db, keys, id, name, value);␊ |
365 | }␊ |
366 | ␊ |
367 | ␊ |
368 | // Local Variables:␊ |
369 | // mode: C++␊ |
370 | // fill-column: 76␊ |
371 | // c-file-style: "gnu"␊ |
372 | // indent-tabs-mode: nil␊ |
373 | // End:␊ |
374 | // vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:␊ |
375 | ␊ |