# # # patch "cert.cc" # from [933a1fcb6c13e927cc06754f7c24207b8fae3dc6] # to [a9e316071a5d773e6a7c0477f840889bc64073dd] # # patch "cert.hh" # from [f9a33063ada94aee63e595e5802d9b1d51edf728] # to [0fb047d90d13c230b6d3a616052b294624718819] # # patch "database.cc" # from [5087d1394d533e4daddc1122c55f9be269eccf7e] # to [d0ded2d9538a90fe25499878bf110ff83ffa32e3] # # patch "project.cc" # from [9ecb5f265fcd7d41708c9c316b68c9bb5df13b4d] # to [42bcaef19ba936f2c0f40da3ceaf005b48b984c6] # # patch "project.hh" # from [b9dcc29acb8d05085dcbdda44ed6dabdaed85d9f] # to [004e43c04a1873b95043b80bb1f2ce9ec7178553] # # patch "revision.cc" # from [e5aa240e16df288d32284a9679bf86053ea139a1] # to [503184eea9f736512bb7e0b7d41813e9cbc7a80a] # # patch "update.cc" # from [0bb59dfbee3507f85c6e200792174425d2a9073f] # to [1156e90e7af700ce1b0b3ea7f2bc21c2a3915380] # ============================================================ --- cert.cc 933a1fcb6c13e927cc06754f7c24207b8fae3dc6 +++ cert.cc a9e316071a5d773e6a7c0477f840889bc64073dd @@ -542,7 +542,16 @@ cert_revision_in_branch(revision_id cons app); } +void +cert_revision_suspended_in_branch(revision_id const & rev, + branch_name const & branch, + app_state & app) +{ + put_simple_revision_cert (rev, suspend_cert_name, cert_value(branch()), + app); +} + // "standard certs" void ============================================================ --- cert.hh f9a33063ada94aee63e595e5802d9b1d51edf728 +++ cert.hh 0fb047d90d13c230b6d3a616052b294624718819 @@ -116,8 +116,14 @@ guess_branch(revision_id const & id, app #define changelog_cert_name cert_name("changelog") #define comment_cert_name cert_name("comment") #define testresult_cert_name cert_name("testresult") +#define suspend_cert_name cert_name("suspend") void +cert_revision_suspended_in_branch(revision_id const & ctx, + branch_name const & branchname, + app_state & app); + +void cert_revision_date_time(revision_id const & m, date_t const & t, app_state & app); ============================================================ --- database.cc 5087d1394d533e4daddc1122c55f9be269eccf7e +++ database.cc d0ded2d9538a90fe25499878bf110ff83ffa32e3 @@ -2925,6 +2925,8 @@ void database::complete(selector_type ty __app->get_project().get_branch_list(globish(i->second), branch_names); } + L(FL("found %d matching branches") % branch_names.size()); + // for each branch name, get the branch heads set heads; for (set::const_iterator bn = branch_names.begin(); ============================================================ --- project.cc 9ecb5f265fcd7d41708c9c316b68c9bb5df13b4d +++ project.cc 42bcaef19ba936f2c0f40da3ceaf005b48b984c6 @@ -29,7 +29,14 @@ project_t::get_branch_list(std::set::iterator i = got.begin(); i != got.end(); ++i) { - branches.insert(branch_name(*i)); + // check that the branch has at least one non-suspended head + const branch_name branch(*i); + std::set heads; + + get_branch_heads(branch, heads); + + if (!heads.empty()) + branches.insert(branch); } } @@ -46,7 +53,14 @@ project_t::get_branch_list(globish const for (std::vector::iterator i = got.begin(); i != got.end(); ++i) { - names.insert(branch_name(*i)); + // check that the branch has at least one non-suspended head + const branch_name branch(*i); + std::set heads; + + get_branch_heads(branch, heads); + + if (!heads.empty()) + names.insert(branch); } } @@ -71,6 +85,26 @@ namespace return certs.empty(); } }; + + struct suspended_in_branch : public is_failure + { + app_state & app; + base64 const & branch_encoded; + suspended_in_branch(app_state & app, + base64 const & branch_encoded) + : app(app), branch_encoded(branch_encoded) + {} + virtual bool operator()(revision_id const & rid) + { + vector< revision > certs; + app.db.get_revision_certs(rid, + cert_name(suspend_cert_name), + branch_encoded, + certs); + erase_bogus_certs(certs, app); + return !certs.empty(); + } + }; } void @@ -90,6 +124,12 @@ project_t::get_branch_heads(branch_name not_in_branch p(app, branch_encoded); erase_ancestors_and_failures(branch.second, p, app); + + suspended_in_branch s(app, branch_encoded); + for(std::set::iterator it = branch.second.begin(); it != branch.second.end(); it++) + if (s(*it)) + branch.second.erase(*it); + L(FL("found heads of branch %s (%s heads)") % name % branch.second.size()); } @@ -126,7 +166,37 @@ project_t::put_revision_in_branch(revisi cert_revision_in_branch(id, branch, app); } +bool +project_t::revision_is_suspended_in_branch(revision_id const & id, + branch_name const & branch) +{ + base64 branch_encoded; + encode_base64(cert_value(branch()), branch_encoded); + vector > certs; + app.db.get_revision_certs(id, suspend_cert_name, branch_encoded, certs); + + int num = certs.size(); + + erase_bogus_certs(certs, app); + + L(FL("found %d (%d valid) %s suspend certs on revision %s") + % num + % certs.size() + % branch + % id); + + return !certs.empty(); +} + +void +project_t::suspend_revision_in_branch(revision_id const & id, + branch_name const & branch) +{ + cert_revision_suspended_in_branch(id, branch, app); +} + + outdated_indicator project_t::get_revision_cert_hashes(revision_id const & rid, std::vector > & hashes) ============================================================ --- project.hh b9dcc29acb8d05085dcbdda44ed6dabdaed85d9f +++ project.hh 004e43c04a1873b95043b80bb1f2ce9ec7178553 @@ -44,6 +44,10 @@ public: void put_revision_in_branch(revision_id const & id, branch_name const & branch); + bool revision_is_suspended_in_branch(revision_id const & id, branch_name const & branch); + void suspend_revision_in_branch(revision_id const & id, + branch_name const & branch); + outdated_indicator get_revision_cert_hashes(revision_id const & rid, std::vector > & hashes); outdated_indicator get_revision_certs(revision_id const & id, ============================================================ --- revision.cc e5aa240e16df288d32284a9679bf86053ea139a1 +++ revision.cc 503184eea9f736512bb7e0b7d41813e9cbc7a80a @@ -439,7 +439,7 @@ accumulate_strict_ancestors(revision_id } // this call is equivalent to running: -// remove_if(candidates.begin(), candidates.end(), p); +// erase(remove_if(candidates.begin(), candidates.end(), p)); // erase_ancestors(candidates, app); // however, by interleaving the two operations, it can in common cases make // many fewer calls to the predicate, which can be a significant speed win. ============================================================ --- update.cc 0bb59dfbee3507f85c6e200792174425d2a9073f +++ update.cc 1156e90e7af700ce1b0b3ea7f2bc21c2a3915380 @@ -35,8 +35,9 @@ // and add it to the candidate set if so // - this gives a set containing every descendent that we might want to // update to. -// - run erase_ancestors on that set, to get just the heads; this is our -// real candidate set. +// - run erase_ancestors on that set, to get just the heads +// - If there are any non-suspended revisions in the set, then remove the +// suspended revisions. // the idea is that this should be correct even in the presence of // discontinuous branches, test results that go from good to bad to good to // bad to good, etc. @@ -105,7 +106,30 @@ acceptable_descendent(branch_name const } } +namespace +{ + struct suspended_in_branch : public is_failure + { + app_state & app; + base64 const & branch_encoded; + suspended_in_branch(app_state & app, + base64 const & branch_encoded) + : app(app), branch_encoded(branch_encoded) + {} + virtual bool operator()(revision_id const & rid) + { + vector< revision > certs; + app.db.get_revision_certs(rid, + cert_name(suspend_cert_name), + branch_encoded, + certs); + erase_bogus_certs(certs, app); + return !certs.empty(); + } + }; +} + static void calculate_update_set(revision_id const & base, branch_name const & branch, @@ -150,6 +174,27 @@ calculate_update_set(revision_id const & } erase_ancestors(candidates, app); + + bool have_non_suspended_rev = false; + + for (set::const_iterator it = candidates.begin(); it != candidates.end(); it++) + { + if (!app.get_project().revision_is_suspended_in_branch(*it, branch)) + { + have_non_suspended_rev = true; + break; + } + } + if (have_non_suspended_rev) + { + // remove all suspended revisions + base64 branch_encoded; + encode_base64(cert_value(branch()), branch_encoded); + suspended_in_branch s(app, branch_encoded); + for(std::set::iterator it = candidates.begin(); it != candidates.end(); it++) + if (s(*it)) + candidates.erase(*it); + } }