# # # patch "automate.cc" # from [bb30bc5300eb1122eea7a7dfe61243fa3a66ad43] # to [a6332c5bb3ceb42b9829830ae0935794086e3f2a] # # patch "cmd.hh" # from [ae4b970f75027655babaacefccb0a728f8d3d59d] # to [b603bd9f4ad5e79d24d128694352376d0d5719a6] # # patch "cmd_diff_log.cc" # from [766a76697c3022279965f4cb07984e31f514ca9b] # to [2b848f58ff52b3f13273a5656bec6ee8d8a046e1] # # patch "commands.cc" # from [eb83a4f403b88c60d9c3578048cf99e608845cb9] # to [a46a10ed30eab12e318db1db9b48d100f1009ce1] # # patch "monotone.texi" # from [5dec4ac656075d1ed469184567fe6ac019f336b0] # to [7212dc67eee89e3f633aaf15f44ef3e265010a92] # ============================================================ --- automate.cc bb30bc5300eb1122eea7a7dfe61243fa3a66ad43 +++ automate.cc a6332c5bb3ceb42b9829830ae0935794086e3f2a @@ -1612,126 +1612,6 @@ AUTOMATE(get_corresponding_path, N_("REV output.write(prt.buf.data(), prt.buf.size()); } -// Name: content_diff -// Arguments: -// 1: (optional) one or more files to include -// 2: (optional) if given, left rev is workspace and right is this rev -// 3: (optional) if given, 2) is left rev and this is the right rev -// Added in: 3.2 -// Purpose: Availability of mtn diff as automate command. -// -// Output format: Like mtn diff, but with the header part omitted (as this is -// doubles the output of automate get_revision). If no content changes happened, -// the output is empty. All file operations beside mtn add are omitted, -// as they don't change the content of the file. -AUTOMATE(content_diff, N_("[FILE [...] [REV1 [REV2]]]")) -{ - vector rev_ids; - vector other_args; - revision_id ident; - - // check for revision and file arguments, go from right to left - for (int i=args.size()-1; i>=0; i--) - { - ident = revision_id(idx(args,i)()); - if (app.db.revision_exists(ident)) - { - rev_ids.insert(rev_ids.begin(), ident); - continue; - } - - // then maybe this is a path...? - other_args.insert(other_args.begin(), utf8(idx(args,i)())); - } - - int rev_count = rev_ids.size(); - - // check if we got more than the expected two revids - N(rev_count <= 2, - F("expected zero, one or two REVISION arguments")); - - // if we didn't receive two revision ids, we require a workspace against - // we can diff - if (rev_count < 2) - app.require_workspace(); - - temp_node_id_source nis; - cset included, excluded; - bool new_is_archived; - - // - // What follows is pretty much copied from cmd_diff_log.cc:CMD(diff,...) - // with some slight adaptions noted with separate FIXMEs - // TODO: someone with a better overview should probably factor this - // out somewhere - // - if (rev_count == 0) - { - roster_t new_roster, old_roster; - revision_id old_rid; - - app.work.get_base_and_current_roster_shape(old_roster, new_roster, nis); - app.work.get_revision_id(old_rid); - - //node_restriction mask(args_to_paths(args), - node_restriction mask(args_to_paths(other_args), - args_to_paths(app.exclude_patterns), - app.depth, - old_roster, new_roster, app); - - app.work.update_current_roster_from_filesystem(new_roster, mask); - make_restricted_csets(old_roster, new_roster, - included, excluded, mask); - check_restricted_cset(old_roster, included); - - new_is_archived = false; - } - else if (rev_count == 1) - { - roster_t new_roster, old_roster; - - app.work.get_base_and_current_roster_shape(old_roster, new_roster, nis); - // Clobber old_roster with the one specified - app.db.get_roster(rev_ids.at(0), old_roster); - - // FIXME: handle no ancestor case - // N(r_new.edges.size() == 1, F("current revision has no ancestor")); - - //node_restriction mask(args_to_paths(args), - node_restriction mask(args_to_paths(other_args), - args_to_paths(app.exclude_patterns), - app.depth, - old_roster, new_roster, app); - - app.work.update_current_roster_from_filesystem(new_roster, mask); - make_restricted_csets(old_roster, new_roster, - included, excluded, mask); - check_restricted_cset(old_roster, included); - - new_is_archived = false; - } - else - { - roster_t new_roster, old_roster; - - app.db.get_roster(rev_ids.at(0), old_roster); - app.db.get_roster(rev_ids.at(1), new_roster); - - node_restriction mask(args_to_paths(other_args), - args_to_paths(app.exclude_patterns), - app.depth, - old_roster, new_roster, app); - - make_restricted_csets(old_roster, new_roster, - included, excluded, mask); - check_restricted_cset(old_roster, included); - - new_is_archived = true; - } - - dump_diffs(included, app, new_is_archived, output); -} - // Local Variables: // mode: C++ // fill-column: 76 ============================================================ --- cmd.hh ae4b970f75027655babaacefccb0a728f8d3d59d +++ cmd.hh b603bd9f4ad5e79d24d128694352376d0d5719a6 @@ -68,25 +68,6 @@ void revision_id const & id); void -dump_diffs(cset const & cs, - app_state & app, - bool new_is_archived, - std::ostream & output); - -void -dump_diffs(cset const & cs, - app_state & app, - bool new_is_archived, - std::ostream & output, - std::set const & paths, - bool limit_paths=false); - -void -do_external_diff(cset const & cs, - app_state & app, - bool new_is_archived); - -void complete(app_state & app, std::string const & str, revision_id & completion, ============================================================ --- cmd_diff_log.cc 766a76697c3022279965f4cb07984e31f514ca9b +++ cmd_diff_log.cc 2b848f58ff52b3f13273a5656bec6ee8d8a046e1 @@ -220,6 +220,7 @@ dump_diffs(cset const & cs, dump_diffs(cset const & cs, app_state & app, bool new_is_archived, + std::ostream & output, set const & paths, bool limit_paths = false) { @@ -233,7 +234,7 @@ dump_diffs(cset const & cs, if (limit_paths && paths.find(i->first) == paths.end()) continue; - cout << patch_sep << "\n"; + output << patch_sep << "\n"; data unpacked; vector lines; @@ -259,7 +260,7 @@ dump_diffs(cset const & cs, i->second, i->second, data(), unpacked, - cout, app.opts.diff_format, pattern); + output, app.opts.diff_format, pattern); } map reverse_rename_map; @@ -281,7 +282,7 @@ dump_diffs(cset const & cs, file_data f_old; data data_old, data_new; - cout << patch_sep << "\n"; + output << patch_sep << "\n"; app.db.get_file_version(delta_entry_src(i), f_old); data_old = f_old.inner(); @@ -315,38 +316,33 @@ dump_diffs(cset const & cs, delta_entry_src(i), delta_entry_dst(i), data_old, data_new, - cout, app.opts.diff_format, pattern); + output, app.opts.diff_format, pattern); } } static void dump_diffs(cset const & cs, app_state & app, - bool new_is_archived) + bool new_is_archived, + std::ostream & output) { set dummy; - dump_diffs(cs, app, new_is_archived, dummy); + dump_diffs(cs, app, new_is_archived, output, dummy); } -CMD(diff, N_("informative"), N_("[PATH]..."), - N_("show current diffs on stdout.\n" - "If one revision is given, the diff between the workspace and\n" - "that revision is shown. If two revisions are given, the diff between\n" - "them is given. If no format is specified, unified is used by default."), - options::opts::revision | options::opts::depth | options::opts::exclude - | options::opts::diff_options) +// common functionality for diff and automate content_diff to determine +// revisions and rosters which should be diffed +static void +prepare_diff(cset & included, + app_state & app, + std::vector args, + bool & new_is_archived, + std::string & revheader) { - bool new_is_archived; - ostringstream header; temp_node_id_source nis; + ostringstream header; + cset excluded; - if (app.opts.external_diff_args_given) - N(app.opts.diff_format == external_diff, - F("--diff-args requires --external\n" - "try adding --external or removing --diff-args?")); - - cset included, excluded; - // initialize before transaction so we have a database to work with. if (app.opts.revision_selectors.size() == 0) @@ -354,6 +350,9 @@ CMD(diff, N_("informative"), N_("[PATH]. else if (app.opts.revision_selectors.size() == 1) app.require_workspace(); + N(app.opts.revision_selectors.size() <= 2, + F("more than two revisions given")); + if (app.opts.revision_selectors.size() == 0) { roster_t new_roster, old_roster; @@ -455,10 +454,31 @@ CMD(diff, N_("informative"), N_("[PATH]. } else { - throw usage(name); + I(false); } + revheader = header.str(); +} +CMD(diff, N_("informative"), N_("[PATH]..."), + N_("show current diffs on stdout.\n" + "If one revision is given, the diff between the workspace and\n" + "that revision is shown. If two revisions are given, the diff between\n" + "them is given. If no format is specified, unified is used by default."), + options::opts::revision | options::opts::depth | options::opts::exclude + | options::opts::diff_options) +{ + if (app.opts.external_diff_args_given) + N(app.opts.diff_format == external_diff, + F("--diff-args requires --external\n" + "try adding --external or removing --diff-args?")); + + cset included; + std::string revs; + bool new_is_archived; + + prepare_diff(included, app, args, new_is_archived, revs); + data summary; write_cset(included, summary); @@ -467,7 +487,7 @@ CMD(diff, N_("informative"), N_("[PATH]. cout << "# " << "\n"; if (summary().size() > 0) { - cout << header.str() << "# " << "\n"; + cout << revs << "# " << "\n"; for (vector::iterator i = lines.begin(); i != lines.end(); ++i) cout << "# " << *i << "\n"; @@ -481,9 +501,33 @@ CMD(diff, N_("informative"), N_("[PATH]. if (app.opts.diff_format == external_diff) { do_external_diff(included, app, new_is_archived); } else - dump_diffs(included, app, new_is_archived); + dump_diffs(included, app, new_is_archived, cout); } + +// Name: content_diff +// Arguments: +// (optional) one or more files to include +// Added in: 4.0 +// Purpose: Availability of mtn diff as automate command. +// +// Output format: Like mtn diff, but with the header part omitted (as this is +// doubles the output of automate get_revision). If no content changes happened, +// the output is empty. All file operations beside mtn add are omitted, +// as they don't change the content of the file. +AUTOMATE(content_diff, N_("[FILE [...]]"), + options::opts::revision | options::opts::depth | options::opts::exclude) +{ + cset included; + std::string dummy_header; + bool new_is_archived; + + prepare_diff(included, app, args, new_is_archived, dummy_header); + + dump_diffs(included, app, new_is_archived, output); +} + + static void log_certs(app_state & app, revision_id id, cert_name name, string label, string separator, @@ -728,8 +772,8 @@ CMD(log, N_("informative"), N_("[FILE] . for (edge_map::const_iterator e = rev.edges.begin(); e != rev.edges.end(); ++e) { - dump_diffs(edge_changes(e), app, true, diff_paths, - !mask.empty()); + dump_diffs(edge_changes(e), app, true, cout, + diff_paths, !mask.empty()); } } ============================================================ --- commands.cc eb83a4f403b88c60d9c3578048cf99e608845cb9 +++ commands.cc a46a10ed30eab12e318db1db9b48d100f1009ce1 @@ -511,165 +511,6 @@ process_commit_message_args(bool & given given = false; } -void -do_external_diff(cset const & cs, - app_state & app, - bool new_is_archived) -{ - for (map >::const_iterator - i = cs.deltas_applied.begin(); - i != cs.deltas_applied.end(); ++i) - { - data data_old; - data data_new; - - file_data f_old; - 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(file_path(delta_entry_path(i)), - data_new, app.lua); - } - - bool is_binary = false; - if (guess_binary(data_old()) || - guess_binary(data_new())) - is_binary = true; - - app.lua.hook_external_diff(file_path(delta_entry_path(i)), - data_old, - data_new, - is_binary, - app.diff_args_provided, - app.diff_args(), - delta_entry_src(i).inner()(), - delta_entry_dst(i).inner()()); - } -} - -void -dump_diffs(cset const & cs, - app_state & app, - bool new_is_archived, - ostream & output, - set const & paths, - bool limit_paths) -{ - // 60 is somewhat arbitrary, but less than 80 - string patch_sep = string(60, '='); - - for (map::const_iterator - i = cs.files_added.begin(); - i != cs.files_added.end(); ++i) - { - if (limit_paths && paths.find(i->first) == paths.end()) - continue; - - output << patch_sep << "\n"; - 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); - } - - std::string pattern(""); - if (app.diff_show_encloser) - app.lua.hook_get_encloser_pattern(file_path(i->first), - pattern); - - make_diff(file_path(i->first).as_internal(), - file_path(i->first).as_internal(), - i->second, - i->second, - data(), unpacked, - output, app.diff_format, pattern); - } - - map reverse_rename_map; - - for (map::const_iterator - i = cs.nodes_renamed.begin(); - i != cs.nodes_renamed.end(); ++i) - { - reverse_rename_map.insert(make_pair(i->second, i->first)); - } - - for (map >::const_iterator - i = cs.deltas_applied.begin(); - i != cs.deltas_applied.end(); ++i) - { - if (limit_paths && paths.find(i->first) == paths.end()) - continue; - - file_data f_old; - data data_old, data_new; - - output << patch_sep << "\n"; - - 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(file_path(delta_entry_path(i)), - data_new, app.lua); - } - - split_path dst_path = delta_entry_path(i); - split_path src_path = dst_path; - map::const_iterator re; - re = reverse_rename_map.find(dst_path); - if (re != reverse_rename_map.end()) - src_path = re->second; - - std::string pattern(""); - if (app.diff_show_encloser) - app.lua.hook_get_encloser_pattern(file_path(src_path), - pattern); - - make_diff(file_path(src_path).as_internal(), - file_path(dst_path).as_internal(), - delta_entry_src(i), - delta_entry_dst(i), - data_old, data_new, - output, app.diff_format, pattern); - } -} - -void -dump_diffs(cset const & cs, - app_state & app, - bool new_is_archived, - ostream & output) -{ - set dummy; - dump_diffs(cs, app, new_is_archived, output, dummy); -} - - // Local Variables: // mode: C++ // fill-column: 76 ============================================================ --- monotone.texi 5dec4ac656075d1ed469184567fe6ac019f336b0 +++ monotone.texi 7212dc67eee89e3f633aaf15f44ef3e265010a92 @@ -6804,7 +6804,7 @@ @section Automation @end table address@hidden mtn automate content_diff address@hidden [...] address@hidden address@hidden address@hidden mtn automate content_diff address@hidden address@hidden address@hidden ...] @table @strong @item Arguments: @@ -6813,7 +6813,7 @@ @section Automation otherwise all changed files in the given revision(s) and/or current workspace are considered. -Furthermore zero, one or two revisions can be given as last arguments, where for +If zero or more revisions are given, the command behaves as follows: @itemize @item @@ -6821,15 +6821,15 @@ @section Automation parent (base) revision of this workspace @item one revision: the diff is done between the workspace revision and the -given revision @var{rev1}, +given revision @option{id1}, @item -two revisions: the diff is done between @var{rev1} and @var{rev2}; no +two revisions: the diff is done between @option{id1} and @option{id2}; no workspace is needed in this case. @end itemize @item Added in: -3.2 +4.0 @item Purpose: @@ -6861,10 +6861,9 @@ @section Automation @item Error conditions: -If an incorrect number of revisions are given or a workspace is required, but -not found, prints to stderr and exits with status 1. If a certain given revision -does not exist, it is interpreted as file restriction. If one or more file -restrictions can't be applied, the command prints to stderr and exits, too. +If more than two revisions are given or a workspace is required, but +not found, prints to stderr and exits with status 1. If one or more file +restrictions can't be applied, the command prints to stderr and exits as well. @end table