1 | ␊ |
2 | // copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com>␊ |
3 | // all rights reserved.␊ |
4 | // licensed to the public under the terms of the GNU GPL (>= 2)␊ |
5 | // see the file COPYING for details␊ |
6 | ␊ |
7 | #include <set>␊ |
8 | #include <map>␊ |
9 | #include <vector>␊ |
10 | #include <string>␊ |
11 | #include <boost/lexical_cast.hpp>␊ |
12 | ␊ |
13 | #include "app_state.hh"␊ |
14 | #include "database.hh"␊ |
15 | #include "manifest.hh"␊ |
16 | #include "sanity.hh"␊ |
17 | #include "cert.hh"␊ |
18 | #include "transforms.hh"␊ |
19 | #include "ui.hh"␊ |
20 | #include "update.hh"␊ |
21 | #include "vocab.hh"␊ |
22 | ␊ |
23 | // these functions just encapsulate the (somewhat complex) logic behind␊ |
24 | // picking an update target. the actual updating takes place in␊ |
25 | // commands.cc, along with most other file-modifying actions.␊ |
26 | ␊ |
27 | using boost::lexical_cast;␊ |
28 | ␊ |
29 | using namespace std;␊ |
30 | ␊ |
31 | static void ␊ |
32 | get_test_results_for_manifest(manifest_id const & id,␊ |
33 | ␉␉␉ map<rsa_keypair_id, bool> & results,␊ |
34 | ␉␉␉ app_state & app)␊ |
35 | {␊ |
36 | vector< manifest<cert> > certs;␊ |
37 | app.db.get_manifest_certs(id, testresult_cert_name, certs);␊ |
38 | erase_bogus_certs(certs, app);␊ |
39 | for (vector< manifest<cert> >::const_iterator i = certs.begin();␊ |
40 | i != certs.end(); ++i)␊ |
41 | {␊ |
42 | cert_value cv;␊ |
43 | decode_base64(i->inner().value, cv);␊ |
44 | try ␊ |
45 | ␉{␊ |
46 | ␉ bool test_ok = lexical_cast<bool>(cv());␊ |
47 | ␉ results.insert(make_pair(i->inner().key, test_ok));␊ |
48 | ␉}␊ |
49 | catch(boost::bad_lexical_cast & e)␊ |
50 | ␉{␊ |
51 | ␉ W(F("failed to decode boolean testresult cert value '%s'\n") % cv);␊ |
52 | ␉}␊ |
53 | }␊ |
54 | }␊ |
55 | ␊ |
56 | static void ␊ |
57 | find_deepest_acceptable_descendent(manifest_id const & base,␊ |
58 | ␉␉␉␉ cert_value const & branch,␊ |
59 | ␉␉␉␉ app_state & app,␊ |
60 | ␉␉␉␉ set<manifest_id> & chosen)␊ |
61 | {␊ |
62 | chosen.clear();␊ |
63 | chosen.insert(base);␊ |
64 | ␊ |
65 | set<manifest_id> visited;␊ |
66 | set<manifest_id> frontier = chosen;␊ |
67 | while(! frontier.empty())␊ |
68 | {␉ ␊ |
69 | set<manifest_id> next_frontier;␊ |
70 | set<manifest_id> selected_children;␊ |
71 | ␊ |
72 | for (set<manifest_id>::const_iterator i = frontier.begin();␊ |
73 | ␉ i != frontier.end(); ++i)␊ |
74 | ␉{␊ |
75 | ␉ // quick check to prevent cycles␊ |
76 | ␉ if (visited.find(*i) != visited.end())␊ |
77 | ␉ continue;␊ |
78 | ␉ visited.insert(*i);␊ |
79 | ␊ |
80 | ␉ // step 1: get children of i␊ |
81 | ␉ base64<cert_value> val;␊ |
82 | ␉ vector< manifest<cert> > certs;␊ |
83 | ␉ set<manifest_id> children;␊ |
84 | ␊ |
85 | ␉ encode_base64(cert_value(i->inner()()), val);␊ |
86 | ␉ app.db.get_manifest_certs(ancestor_cert_name, val, certs);␊ |
87 | ␉ erase_bogus_certs(certs, app);␊ |
88 | ␉ for(vector< manifest<cert> >::const_iterator j = certs.begin();␊ |
89 | ␉ j != certs.end(); ++j)␊ |
90 | ␉ {␊ |
91 | ␉ children.insert(manifest_id(j->inner().ident));␊ |
92 | ␉ }␊ |
93 | ␊ |
94 | ␉ // step 2: weed out edges which cross a branch boundary␊ |
95 | ␉ set<manifest_id> same_branch_children;␊ |
96 | ␉ encode_base64(branch, val);␊ |
97 | ␉ for (set<manifest_id>::const_iterator j = children.begin();␊ |
98 | ␉ j != children.end(); ++j)␊ |
99 | ␉ {␊ |
100 | ␉ app.db.get_manifest_certs(*j, branch_cert_name, val, certs);␊ |
101 | ␉ erase_bogus_certs(certs, app);␊ |
102 | ␉ if (certs.empty())␊ |
103 | ␉␉W(F("update edge %s -> %s ignored since it exits branch %s\n")␊ |
104 | ␉␉ % *i % *j % branch);␊ |
105 | ␉ else␊ |
106 | ␉␉same_branch_children.insert(*j);␊ |
107 | ␉ }␊ |
108 | ␊ |
109 | ␉ // step 3: weed out disapproved edges␊ |
110 | ␉ for (set<manifest_id>::const_iterator j = same_branch_children.begin();␊ |
111 | ␉ j != same_branch_children.end(); ++j)␊ |
112 | ␉ {␊ |
113 | ␉ encode_base64(cert_value(i->inner()()), val);␊ |
114 | ␉ app.db.get_manifest_certs(*j, disapproval_cert_name, val, certs);␊ |
115 | ␉ erase_bogus_certs(certs, app);␊ |
116 | ␉ if (certs.empty())␊ |
117 | ␉␉next_frontier.insert(*j);␊ |
118 | ␉ else␊ |
119 | ␉␉W(F("update edge %s -> %s ignored due to %d valid disapproval certs\n")␊ |
120 | ␉␉ % *i % *j % certs.size());␊ |
121 | ␉ }␊ |
122 | ␉ ␊ |
123 | ␉ // step 4: pull aside acceptable testresult changes␊ |
124 | ␉ map<rsa_keypair_id, bool> old_results;␊ |
125 | ␉ get_test_results_for_manifest(*i, old_results, app);␊ |
126 | ␉ for (set<manifest_id>::const_iterator j = next_frontier.begin();␊ |
127 | ␉ j != next_frontier.end(); ++j)␊ |
128 | ␉ {␊ |
129 | ␉ map<rsa_keypair_id, bool> new_results;␊ |
130 | ␉ get_test_results_for_manifest(*j, new_results, app);␊ |
131 | ␉ if (app.lua.hook_accept_testresult_change(old_results, new_results))␊ |
132 | ␉␉selected_children.insert(*j);␊ |
133 | ␉ else␊ |
134 | ␉␉W(F("update edge %s -> %s ignored due to unacceptable testresults\n")␊ |
135 | ␉␉ % *i % *j);␊ |
136 | ␉ }␊ |
137 | ␉}␊ |
138 | ␊ |
139 | if (! selected_children.empty())␊ |
140 | ␉chosen = selected_children;␊ |
141 | ␊ |
142 | frontier = next_frontier;␊ |
143 | }␊ |
144 | }␊ |
145 | ␊ |
146 | void pick_update_target(manifest_id const & base_ident,␊ |
147 | ␉␉␉app_state & app,␊ |
148 | ␉␉␉manifest_id & chosen)␊ |
149 | {␊ |
150 | set<manifest_id> chosen_set;␊ |
151 | N(app.branch_name() != "",␊ |
152 | F("cannot determine branch for update"));␊ |
153 | ␊ |
154 | find_deepest_acceptable_descendent(base_ident, cert_value(app.branch_name()),␊ |
155 | ␉␉␉␉ app, chosen_set);␊ |
156 | ␊ |
157 | N(chosen_set.size() != 0,␊ |
158 | F("no candidates remain after selection"));␊ |
159 | ␊ |
160 | N(chosen_set.size() == 1,␊ |
161 | F("multiple candidates remain after selection"));␊ |
162 | ␊ |
163 | chosen = *(chosen_set.begin());␊ |
164 | }␊ |
165 | ␊ |
166 | ␊ |