# # patch "commands.cc" # from [775992428125d132d64e7e06b52b1363b5fb7194] # to [b68543359a4a4c5d831bf0771d5960abb0a43c51] # # patch "cset.hh" # from [138e97c86d28f67b6acea60fec121f71f6ce7705] # to [c76626e6e18c4b9651821cb9f636c1e36c05622b] # # patch "revision.cc" # from [6cfb7bcadf0fcdd8beb169288ade9f2e3d162469] # to [6ccee6812be509e8b56f84a7db4b66d7296fa129] # # patch "revision.hh" # from [5ec3410953f8d795b26becda98a5e975c5e2ee95] # to [a0449ad6861f9f989c1baab0aae2dfe9d47e9466] # # patch "roster.cc" # from [a7be1586ac974d7ef805e0019a624b99160fc60c] # to [1d370a23b03c11680f38e169f8bc135993cf67ae] # # patch "roster.hh" # from [d99dc357b2b4f6bb7cfc24c256eb6415960a7886] # to [6779389b327193c85af108eb2a231c1aa00e79d9] # ======================================================================== --- commands.cc 775992428125d132d64e7e06b52b1363b5fb7194 +++ commands.cc b68543359a4a4c5d831bf0771d5960abb0a43c51 @@ -745,74 +745,66 @@ // The changes_summary structure holds a list all of files and directories // affected in a revision, and is useful in the 'log' command to print this -// information easily. It has to be constructed from all change_set objects +// information easily. It has to be constructed from all cset objects // that belong to a revision. -/* -// FIXME_ROSTERS: disabled until rewritten to use rosters + struct changes_summary { - bool empty; - change_set::path_rearrangement rearrangement; - std::set modified_files; - + cset cs; changes_summary(void); - void add_change_set(change_set const & cs); + void add_change_set(cset const & cs); void print(std::ostream & os, size_t max_cols) const; }; -changes_summary::changes_summary(void) : empty(true) +changes_summary::changes_summary(void) { } void -changes_summary::add_change_set(change_set const & cs) +changes_summary::add_change_set(cset const & c) { if (cs.empty()) return; - empty = false; - change_set::path_rearrangement const & pr = cs.rearrangement; + // FIXME: not sure whether it matters for an informal summary + // object like this, but the pre-state names in deletes and renames + // are not really sensible to union; they refer to different trees + // so mixing them up in a single set is potentially ambiguous. - for (std::set::const_iterator i = pr.deleted_files.begin(); - i != pr.deleted_files.end(); i++) - rearrangement.deleted_files.insert(*i); + copy(c.nodes_deleted.begin(), c.nodes_deleted.end(), + inserter(cs.nodes_deleted, cs.nodes_deleted.begin())); - for (std::set::const_iterator i = pr.deleted_dirs.begin(); - i != pr.deleted_dirs.end(); i++) - rearrangement.deleted_dirs.insert(*i); + copy(c.files_added.begin(), c.files_added.end(), + inserter(cs.files_added, cs.files_added.begin())); - for (std::map::const_iterator - i = pr.renamed_files.begin(); i != pr.renamed_files.end(); i++) - rearrangement.renamed_files.insert(*i); + copy(c.dirs_added.begin(), c.dirs_added.end(), + inserter(cs.dirs_added, cs.dirs_added.begin())); - for (std::map::const_iterator - i = pr.renamed_dirs.begin(); i != pr.renamed_dirs.end(); i++) - rearrangement.renamed_dirs.insert(*i); + copy(c.nodes_renamed.begin(), c.nodes_renamed.end(), + inserter(cs.nodes_renamed, cs.nodes_renamed.begin())); - for (std::set::const_iterator i = pr.added_files.begin(); - i != pr.added_files.end(); i++) - rearrangement.added_files.insert(*i); + copy(c.deltas_applied.begin(), c.deltas_applied.end(), + inserter(cs.deltas_applied, cs.deltas_applied.begin())); - for (change_set::delta_map::const_iterator i = cs.deltas.begin(); - i != cs.deltas.end(); i++) - { - if (pr.added_files.find(i->first) == pr.added_files.end()) - modified_files.insert(i->first); - } + copy(c.attrs_cleared.begin(), c.attrs_cleared.end(), + inserter(cs.attrs_cleared, cs.attrs_cleared.begin())); + + copy(c.attrs_set.begin(), c.attrs_set.end(), + inserter(cs.attrs_set, cs.attrs_set.begin())); } static void print_indented_set(std::ostream & os, - set const & s, + set const & s, size_t max_cols) { size_t cols = 8; os << " "; - for (std::set::const_iterator i = s.begin(); + for (std::set::const_iterator i = s.begin(); i != s.end(); i++) { - const std::string str = boost::lexical_cast(*i); + const std::string str = boost::lexical_cast(file_path(*i)); if (cols > 8 && cols + str.size() + 1 >= max_cols) { cols = 8; @@ -827,50 +819,64 @@ void changes_summary::print(std::ostream & os, size_t max_cols) const { - if (! rearrangement.deleted_files.empty()) + if (! cs.nodes_deleted.empty()) { - os << "Deleted files:" << endl; - print_indented_set(os, rearrangement.deleted_files, max_cols); + os << "Deleted entries:" << endl; + print_indented_set(os, cs.nodes_deleted, max_cols); } - if (! rearrangement.deleted_dirs.empty()) + if (! cs.nodes_renamed.empty()) { - os << "Deleted directories:" << endl; - print_indented_set(os, rearrangement.deleted_dirs, max_cols); + os << "Renamed entries:" << endl; + for (std::map::const_iterator + i = cs.nodes_renamed.begin(); + i != cs.nodes_renamed.end(); i++) + os << " " << file_path(i->first) << " to " << file_path(i->second) << endl; } - if (! rearrangement.renamed_files.empty()) + if (! cs.files_added.empty()) { - os << "Renamed files:" << endl; - for (std::map::const_iterator - i = rearrangement.renamed_files.begin(); - i != rearrangement.renamed_files.end(); i++) - os << " " << i->first << " to " << i->second << endl; + std::set tmp; + for (std::map::const_iterator i = cs.files_added.begin(); + i != cs.files_added.end(); ++i) + tmp.insert(i->first); + os << "Added files:" << endl; + print_indented_set(os, tmp, max_cols); } - if (! rearrangement.renamed_dirs.empty()) + if (! cs.dirs_added.empty()) { - os << "Renamed directories:" << endl; - for (std::map::const_iterator - i = rearrangement.renamed_dirs.begin(); - i != rearrangement.renamed_dirs.end(); i++) - os << " " << i->first << " to " << i->second << endl; + os << "Added files:" << endl; + print_indented_set(os, cs.dirs_added, max_cols); } - if (! rearrangement.added_files.empty()) + if (! cs.deltas_applied.empty()) { - os << "Added files:" << endl; - print_indented_set(os, rearrangement.added_files, max_cols); + std::set tmp; + for (std::map >::const_iterator i = cs.deltas_applied.begin(); + i != cs.deltas_applied.end(); ++i) + tmp.insert(i->first); + os << "Modified files:" << endl; + print_indented_set(os, tmp, max_cols); } - if (! modified_files.empty()) + if (! cs.attrs_set.empty() || ! cs.attrs_cleared.empty()) { - os << "Modified files:" << endl; - print_indented_set(os, modified_files, max_cols); + std::set tmp; + for (std::set >::const_iterator i = cs.attrs_cleared.begin(); + i != cs.attrs_cleared.end(); ++i) + tmp.insert(i->first); + + for (std::map, attr_value>::const_iterator i = cs.attrs_set.begin(); + i != cs.attrs_set.end(); ++i) + tmp.insert(i->first.first); + + os << "Modified attrs:" << endl; + print_indented_set(os, tmp, max_cols); } } -*/ + CMD(genkey, N_("key and cert"), N_("KEYID"), N_("generate an RSA key-pair"), OPT_NONE) { if (args.size() != 1) @@ -2497,25 +2503,21 @@ ALIAS(ci, commit); -/* -// FIXME_ROSTERS: disabled until rewritten to use rosters static void -do_external_diff(change_set::delta_map const & deltas, +do_external_diff(cset const & cs, app_state & app, bool new_is_archived) { - for (change_set::delta_map::const_iterator i = deltas.begin(); - i != deltas.end(); ++i) + for (std::map >::const_iterator + i = cs.deltas_applied.begin(); + i != cs.deltas_applied.end(); ++i) { data data_old; data data_new; - if (!null_id(delta_entry_src(i))) - { - file_data f_old; - app.db.get_file_version(delta_entry_src(i), f_old); - data_old = f_old.inner(); - } + file_data f_old; + app.db.get_file_version(delta_entry_src(i), f_old); + data_old = f_old.inner(); if (new_is_archived) { @@ -2525,7 +2527,7 @@ } else { - read_localized_data(delta_entry_path(i), + read_localized_data(file_path(delta_entry_path(i)), data_new, app.lua); } @@ -2534,7 +2536,7 @@ guess_binary(data_new())) is_binary = true; - app.lua.hook_external_diff(delta_entry_path(i), + app.lua.hook_external_diff(file_path(delta_entry_path(i)), data_old, data_new, is_binary, @@ -2546,91 +2548,95 @@ } static void -dump_diffs(change_set::delta_map const & deltas, +dump_diffs(cset const & cs, app_state & app, bool new_is_archived, diff_type type) { // 60 is somewhat arbitrary, but less than 80 std::string patch_sep = std::string(60, '='); - for (change_set::delta_map::const_iterator i = deltas.begin(); - i != deltas.end(); ++i) + + for (std::map::const_iterator + i = cs.files_added.begin(); + i != cs.files_added.end(); ++i) { cout << patch_sep << "\n"; - if (null_id(delta_entry_src(i))) + data unpacked; + vector lines; + + if (new_is_archived) { - data unpacked; - vector lines; - - if (new_is_archived) + file_data dat; + app.db.get_file_version(i->second, dat); + unpacked = dat.inner(); + } + else + { + read_localized_data(file_path(i->first), + unpacked, app.lua); + } + + if (guess_binary(unpacked())) + cout << "# " << file_path(i->first) << " is binary\n"; + else + { + split_into_lines(unpacked(), lines); + if (! lines.empty()) { - file_data dat; - app.db.get_file_version(delta_entry_dst(i), dat); - unpacked = dat.inner(); - } - else - { - read_localized_data(delta_entry_path(i), - unpacked, app.lua); - } - - if (guess_binary(unpacked())) - cout << "# " << delta_entry_path(i) << " is binary\n"; - else - { - split_into_lines(unpacked(), lines); - if (! lines.empty()) + cout << (boost::format("--- %s\t%s\n") % file_path(i->first) % i->second) + << (boost::format("+++ %s\t%s\n") % file_path(i->first) % i->second) + << (boost::format("@@ -0,0 +1,%d @@\n") % lines.size()); + for (vector::const_iterator j = lines.begin(); + j != lines.end(); ++j) { - cout << (boost::format("--- %s\t%s\n") % delta_entry_path(i) % delta_entry_src(i)) - << (boost::format("+++ %s\t%s\n") % delta_entry_path(i) % delta_entry_dst(i)) - << (boost::format("@@ -0,0 +1,%d @@\n") % lines.size()); - for (vector::const_iterator j = lines.begin(); - j != lines.end(); ++j) - { - cout << "+" << *j << endl; - } + cout << "+" << *j << endl; } } } + } + + for (std::map >::const_iterator + i = cs.deltas_applied.begin(); + i != cs.deltas_applied.end(); ++i) + { + file_data f_old; + data data_old, data_new; + vector old_lines, new_lines; + + app.db.get_file_version(delta_entry_src(i), f_old); + data_old = f_old.inner(); + + if (new_is_archived) + { + file_data f_new; + app.db.get_file_version(delta_entry_dst(i), f_new); + data_new = f_new.inner(); + } else { - file_data f_old; - data data_old, data_new; - vector old_lines, new_lines; - - app.db.get_file_version(delta_entry_src(i), f_old); - data_old = f_old.inner(); - - if (new_is_archived) - { - file_data f_new; - app.db.get_file_version(delta_entry_dst(i), f_new); - data_new = f_new.inner(); - } - else - { - read_localized_data(delta_entry_path(i), - data_new, app.lua); - } - - if (guess_binary(data_new()) || - guess_binary(data_old())) - cout << "# " << delta_entry_path(i) << " is binary\n"; - else - { - split_into_lines(data_old(), old_lines); - split_into_lines(data_new(), new_lines); - make_diff(delta_entry_path(i).as_internal(), - delta_entry_path(i).as_internal(), - delta_entry_src(i), - delta_entry_dst(i), - old_lines, new_lines, - cout, type); - } + read_localized_data(file_path(delta_entry_path(i)), + data_new, app.lua); } + + if (guess_binary(data_new()) || + guess_binary(data_old())) + cout << "# " << file_path(delta_entry_path(i)) << " is binary\n"; + else + { + split_into_lines(data_old(), old_lines); + split_into_lines(data_new(), new_lines); + make_diff(file_path(delta_entry_path(i)).as_internal(), + file_path(delta_entry_path(i)).as_internal(), + delta_entry_src(i), + delta_entry_dst(i), + old_lines, new_lines, + cout, type); + } } } + /* + CMD(diff, N_("informative"), N_("[PATH]..."), N_("show current diffs on stdout.\n" "If one revision is given, the diff between the working directory and\n" @@ -2651,7 +2657,7 @@ F("--diff-args requires --external\n" "try adding --external or removing --diff-args?")); - change_set composite; + cset composite; // initialize before transaction so we have a database to work with @@ -3583,30 +3589,42 @@ L(F("annotate for file_id %s\n") % file_node->self); do_annotate(app, file_node, rid); } +*/ -CMD(log, N_("informative"), N_("[FILE]"), +CMD(log, N_("informative"), N_("[FILE] ..."), N_("print history in reverse order (filtering by 'FILE'). If one or more\n" "revisions are given, use them as a starting point."), OPT_LAST % OPT_REVISION % OPT_BRIEF % OPT_DIFFS % OPT_NO_MERGES) { - file_path file; - if (app.revision_selectors.size() == 0) app.require_working_copy("try passing a --revision to start at"); - if (args.size() > 1) - throw usage(name); + set nodes; if (args.size() > 0) - file = file_path_external(idx(args, 0)); // specified a file + { + // User wants to trace only specific files + roster_t old_roster, new_roster; + revision_set rev; + get_unrestricted_working_revision_and_rosters(app, rev, old_roster, new_roster); + for (size_t i = 0; i < args.size(); ++i) + { + file_path fp = file_path_external(idx(args, i)); + split_path sp; + fp.split(sp); + N(new_roster.has_node(sp), + F("Unknown file '%s' for log command") % fp); + nodes.insert(new_roster.get_node(sp)->self); + } + } - set< pair > frontier; + set frontier; if (app.revision_selectors.size() == 0) { revision_id rid; get_revision_id(rid); - frontier.insert(make_pair(file, rid)); + frontier.insert(rid); } else { @@ -3614,7 +3632,7 @@ i != app.revision_selectors.end(); i++) { revision_id rid; complete(app, (*i)(), rid); - frontier.insert(make_pair(file, rid)); + frontier.insert(rid); } } @@ -3631,15 +3649,14 @@ revision_set rev; while(! frontier.empty() && (last == -1 || last > 0)) { - set< pair > next_frontier; - for (set< pair >::const_iterator i = frontier.begin(); + set next_frontier; + + for (set::const_iterator i = frontier.begin(); i != frontier.end(); ++i) { - revision_id rid; - file = i->first; - rid = i->second; + revision_id rid = *i; - bool print_this = file.empty(); + bool print_this = nodes.empty(); set< revision > parents; vector< revision > tmp; @@ -3653,9 +3670,33 @@ continue; seen.insert(rid); + app.db.get_revision(rid, rev); - app.db.get_revision(rid, rev); + if (!nodes.empty()) + { + set nodes_changed; + set nodes_born; + bool any_node_hit = false; + select_nodes_modified_by_rev(rid, rev, + nodes_changed, + nodes_born, + app); + for (set::const_iterator n = nodes.begin(); n != nodes.end(); ++n) + { + if (nodes_changed.find(*n) != nodes_changed.end()) + { + any_node_hit = true; + break; + } + } + for (set::const_iterator n = nodes_born.begin(); n != nodes_born.end(); + ++n) + nodes.erase(*n); + if (!any_node_hit) + print_this = false; + } + changes_summary csum; set ancestors; @@ -3664,33 +3705,8 @@ e != rev.edges.end(); ++e) { ancestors.insert(edge_old_revision(e)); - - change_set const & cs = edge_changes(e); - if (! file.empty()) - { - if (cs.rearrangement.has_deleted_file(file) || - cs.rearrangement.has_renamed_file_src(file)) - { - print_this = false; - next_frontier.clear(); - break; - } - else - { - file_path old_file = apply_change_set_inverse(cs, file); - L(F("revision '%s' in '%s' maps to '%s' in %s\n") - % rid % file % old_file % edge_old_revision(e)); - if (!(old_file == file) || - cs.deltas.find(file) != cs.deltas.end()) - { - file = old_file; - print_this = true; - } - } - } - next_frontier.insert(std::make_pair(file, edge_old_revision(e))); - - csum.add_change_set(cs); + next_frontier.insert(edge_old_revision(e)); + csum.add_change_set(edge_changes(e)); } if (app.no_merges && rev.is_merge_node()) @@ -3721,7 +3737,7 @@ log_certs(app, rid, branch_name, "Branch: ", false); log_certs(app, rid, tag_name, "Tag: ", false); - if (! csum.empty) + if (! csum.cs.empty()) { cout << endl; csum.print(cout, 70); @@ -3737,8 +3753,7 @@ for (edge_map::const_iterator e = rev.edges.begin(); e != rev.edges.end(); ++e) { - dump_diffs(edge_changes(e).deltas, - app, true, unified_diff); + dump_diffs(edge_changes(e), app, true, unified_diff); } } @@ -3751,7 +3766,7 @@ frontier = next_frontier; } } -*/ + CMD(setup, N_("tree"), N_("DIRECTORY"), N_("setup a new working copy directory"), OPT_BRANCH_NAME) { ======================================================================== --- cset.hh 138e97c86d28f67b6acea60fec121f71f6ce7705 +++ cset.hh c76626e6e18c4b9651821cb9f636c1e36c05622b @@ -128,6 +128,7 @@ void dump(cset const & cs, std::string & out); + // Some helpers. template ======================================================================== --- revision.cc 6cfb7bcadf0fcdd8beb169288ade9f2e3d162469 +++ revision.cc 6ccee6812be509e8b56f84a7db4b66d7296fa129 @@ -708,6 +708,38 @@ } } +void +select_nodes_modified_by_rev(revision_id const & rid, + revision_set const & rev, + std::set & nodes_changed, + std::set & nodes_born, + app_state & app) +{ + roster_t new_roster; + marking_map mm; + nodes_changed.clear(); + nodes_born.clear(); + app.db.get_roster(rid, new_roster, mm); + + for (edge_map::const_iterator i = rev.edges.begin(); + i != rev.edges.end(); ++i) + { + std::set edge_nodes_changed, edge_nodes_born; + roster_t old_roster; + marking_map mm2; + app.db.get_roster(edge_old_revision(i), old_roster, mm2); + select_nodes_modified_by_cset(edge_changes(i), + old_roster, + new_roster, + edge_nodes_changed, + edge_nodes_born); + std::copy(edge_nodes_changed.begin(), edge_nodes_changed.end(), + inserter(nodes_changed, nodes_changed.begin())); + std::copy(edge_nodes_born.begin(), edge_nodes_born.end(), + inserter(nodes_born, nodes_born.begin())); + } +} + // Stuff related to rebuilding the revision graph. Unfortunately this is a // real enough error case that we need support code for it. ======================================================================== --- revision.hh 5ec3410953f8d795b26becda98a5e975c5e2ee95 +++ revision.hh a0449ad6861f9f989c1baab0aae2dfe9d47e9466 @@ -159,6 +159,16 @@ std::set & new_stuff, app_state & app); + +// FIXME: can probably optimize this passing a lookaside cache of the active +// frontier set of shared_ptrs, while traversing history. +void +select_nodes_modified_by_rev(revision_id const & rid, + revision_set const & rev, + std::set & nodes_changed, + std::set & nodes_born, + app_state & app); + /* void calculate_composite_cset(revision_id const & ancestor, ======================================================================== --- roster.cc a7be1586ac974d7ef805e0019a624b99160fc60c +++ roster.cc 1d370a23b03c11680f38e169f8bc135993cf67ae @@ -2104,6 +2104,85 @@ // FIXME: looped nodes here } + +void +select_nodes_modified_by_cset(cset const & cs, + roster_t const & old_roster, + roster_t const & new_roster, + std::set & nodes_changed, + std::set & nodes_born) +{ + nodes_changed.clear(); + nodes_born.clear(); + + set modified_prestate_nodes; + set modified_poststate_nodes; + + // Pre-state damage + + copy(cs.nodes_deleted.begin(), cs.nodes_deleted.end(), + inserter(modified_prestate_nodes, modified_prestate_nodes.begin())); + + for (std::map::const_iterator i = cs.nodes_renamed.begin(); + i != cs.nodes_renamed.end(); ++i) + modified_prestate_nodes.insert(i->first); + + // Post-state damage + + copy(cs.dirs_added.begin(), cs.dirs_added.end(), + inserter(modified_poststate_nodes, modified_poststate_nodes.begin())); + + for (std::map::const_iterator i = cs.files_added.begin(); + i != cs.files_added.end(); ++i) + modified_poststate_nodes.insert(i->first); + + for (std::map::const_iterator i = cs.nodes_renamed.begin(); + i != cs.nodes_renamed.end(); ++i) + modified_poststate_nodes.insert(i->second); + + for (std::map >::const_iterator i = cs.deltas_applied.begin(); + i != cs.deltas_applied.end(); ++i) + modified_poststate_nodes.insert(i->first); + + for (std::set >::const_iterator i = cs.attrs_cleared.begin(); + i != cs.attrs_cleared.end(); ++i) + modified_poststate_nodes.insert(i->first); + + for (std::map, attr_value>::const_iterator i = cs.attrs_set.begin(); + i != cs.attrs_set.end(); ++i) + modified_poststate_nodes.insert(i->first.first); + + // Finale + + for (set::const_iterator i = modified_prestate_nodes.begin(); + i != modified_prestate_nodes.end(); ++i) + { + I(old_roster.has_node(*i)); + nodes_changed.insert(old_roster.get_node(*i)->self); + } + + for (set::const_iterator i = modified_poststate_nodes.begin(); + i != modified_poststate_nodes.end(); ++i) + { + I(new_roster.has_node(*i)); + nodes_changed.insert(new_roster.get_node(*i)->self); + } + + for (std::set::const_iterator i = cs.dirs_added.begin(); + i != cs.dirs_added.end(); ++i) + { + I(new_roster.has_node(*i)); + nodes_born.insert(new_roster.get_node(*i)->self); + } + + for (std::map::const_iterator i = cs.files_added.begin(); + i != cs.files_added.end(); ++i) + { + I(new_roster.has_node(i->first)); + nodes_born.insert(new_roster.get_node(i->first)->self); + } +} + //////////////////////////////////////////////////////////////////// // getting rosters from the working copy //////////////////////////////////////////////////////////////////// ======================================================================== --- roster.hh d99dc357b2b4f6bb7cfc24c256eb6415960a7886 +++ roster.hh 6779389b327193c85af108eb2a231c1aa00e79d9 @@ -275,6 +275,13 @@ roster_t const & to, cset & cs); +void +select_nodes_modified_by_cset(cset const & cs, + roster_t const & old_roster, + roster_t const & new_roster, + std::set & nodes_changed, + std::set & nodes_born); + void update_restricted_roster_from_filesystem(roster_t & ros, app_state & app);