# # # rename "tests/automate_automate_version" # to "tests/automate_interface_version" # # add_dir "tests/automate_content_diff" # # add_file "tests/automate_content_diff/__driver__.lua" # content [49eb0b60c12eefb624af0e586d6bd860ac03cfb4] # # patch "ChangeLog" # from [583ce8666abd871071e00cf3631b8b993ba61e40] # to [dd5e7168804946f27d9e43ca27d3e3f35a3690ea] # # patch "automate.cc" # from [092f5069e1ce9988dc6260f868f3a9cd7f14e187] # to [a6332c5bb3ceb42b9829830ae0935794086e3f2a] # # patch "cmd_diff_log.cc" # from [0eee6f1675c850932e53b7a0214235ae0dc65ad4] # to [ad597a711af534bd952b3753d0af247f9e8c1223] # # patch "commands.cc" # from [01337415288f19b925c2097f54cb3fe05fce3ced] # to [a46a10ed30eab12e318db1db9b48d100f1009ce1] # # patch "monotone.texi" # from [18658fe14fa458d5592b1810fc8b353551d14719] # to [7212dc67eee89e3f633aaf15f44ef3e265010a92] # # patch "testsuite.lua" # from [67b5f8eb1b321452edafe257ac5f61e82c85c856] # to [ee3dadaa84390b8be6919ce41c9c5e6c4e3b4881] # ============================================================ --- tests/automate_content_diff/__driver__.lua 49eb0b60c12eefb624af0e586d6bd860ac03cfb4 +++ tests/automate_content_diff/__driver__.lua 49eb0b60c12eefb624af0e586d6bd860ac03cfb4 @@ -0,0 +1,36 @@ + +mtn_setup() + +-- check output if there are no changes +check(mtn("automate", "content_diff"), 0, true, true) +check(fsize("stdout") == 0 and fsize("stderr") == 0) + +-- check non-existing path +check(mtn("automate", "content_diff", "non_existing"), 1, true, true) + + +-- check existing path against current workspace +addfile("existing", "foo bar") +-- do not restrict here, since '' (the root) has not yet been committed +check(mtn("automate", "content_diff"), 0, true, true) +check(fsize("stdout") ~= 0) + +-- add three more revisions and test for correct revid handling +commit() +R1=base_revision() +writefile("existing", "foo foo") +commit() +R2=base_revision() +writefile("existing", "foo foo bar") +commit() +R3=base_revision() + +-- one and two revisions should work +check(mtn("automate", "content_diff", "-r", R1), 0, true, true) +check(fsize("stdout") ~= 0) +check(mtn("automate", "content_diff", "-r", R1, "-r", R2), 0, true, true) +check(fsize("stdout") ~= 0) + +-- three and more should not +check(mtn("automate", "content_diff", "-r", R1, "-r", R2, "-r", R3), 1, true, true) + ============================================================ --- ChangeLog 583ce8666abd871071e00cf3631b8b993ba61e40 +++ ChangeLog dd5e7168804946f27d9e43ca27d3e3f35a3690ea @@ -1,3 +1,15 @@ +2006-11-14 Thomas Keller + + * new automate content_diff command which is basically + the same like mtn diff (also uses most of its infrastructure) + minus the display of the basic_io revision header + * tests/automate_content_diff: test for that + * tests/automate_automate_version test renamed to + automate_interface_version + * monotone.texi: list formatting for automate attributes + documentation, docs for automate content_diff + * fixed commented version number for two commands + 2006-11-14 Richard Levitte NOTE: I bumped the Debian version number to 0.31-90.1 in this ============================================================ --- automate.cc 092f5069e1ce9988dc6260f868f3a9cd7f14e187 +++ automate.cc a6332c5bb3ceb42b9829830ae0935794086e3f2a @@ -1499,7 +1499,7 @@ AUTOMATE(get_option, N_("OPTION"), optio // Arguments: // 1: a revision ID // 2: a file name -// Added in: 3.2 +// Added in: 3.1 // Purpose: Returns a list of revision IDs in which the content // was most recently changed, relative to the revision ID specified // in argument 1. This equates to a content mark following @@ -1556,7 +1556,7 @@ AUTOMATE(get_content_changed, N_("REV FI // 1: a source revision ID // 2: a file name (in the source revision) // 3: a target revision ID -// Added in: 3.2 +// Added in: 3.1 // Purpose: Given a the file name in the source revision, a filename // will if possible be returned naming the file in the target revision. // This allows the same file to be matched between revisions, accounting ============================================================ --- cmd_diff_log.cc 0eee6f1675c850932e53b7a0214235ae0dc65ad4 +++ cmd_diff_log.cc ad597a711af534bd952b3753d0af247f9e8c1223 @@ -222,6 +222,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) { @@ -235,7 +236,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; @@ -261,7 +262,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; @@ -283,7 +284,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(); @@ -317,38 +318,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) @@ -356,6 +352,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; @@ -457,10 +456,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); @@ -469,7 +489,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"; @@ -483,9 +503,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, @@ -763,8 +807,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 01337415288f19b925c2097f54cb3fe05fce3ced +++ commands.cc a46a10ed30eab12e318db1db9b48d100f1009ce1 @@ -12,7 +12,9 @@ #include "transforms.hh" #include "simplestring_xform.hh" +#include "localized_file_io.hh" #include "charset.hh" +#include "diff_patch.hh" #include "inodeprint.hh" #include "cert.hh" #include "ui.hh" @@ -24,6 +26,8 @@ using std::cin; #endif using std::cin; +using std::map; +using std::ostream; using std::pair; using std::set; using std::string; ============================================================ --- monotone.texi 18658fe14fa458d5592b1810fc8b353551d14719 +++ monotone.texi 7212dc67eee89e3f633aaf15f44ef3e265010a92 @@ -6762,20 +6762,22 @@ @section Automation Each attribute stanza also contains another entry which tells the status of attribute. This entry can have one of the following four values: address@hidden address@hidden 'added': the attribute has just been added to the file - address@hidden 'dropped': the attribute has just been dropped from the file - address@hidden 'unchanged': the attribute has not been changed since the last revision - address@hidden 'changed': the attribute has been changed since the last revision address@hidden itemize The status 'changed' can come up if an attribute foo has been dropped and added afterwards with another value, like @verbatim -# foo has the value "bar" -$ mtn attr drop foo ; mtn attr set foo baz +$ mtn attr drop file.txt foo ; mtn attr set file.txt foo baz @end verbatim If an attribute has been dropped, the output will still return the previously @@ -6802,6 +6804,69 @@ @section Automation @end table address@hidden mtn automate content_diff address@hidden address@hidden address@hidden ...] + address@hidden @strong address@hidden Arguments: + +One or more @var{file} arguments restrict the diff output to these files, +otherwise all changed files in the given revision(s) and/or current workspace +are considered. + +If zero or more revisions are given, the command behaves as follows: + address@hidden address@hidden +no revision: the diff is done between the workspace revision and the +parent (base) revision of this workspace address@hidden +one revision: the diff is done between the workspace revision and the +given revision @option{id1}, address@hidden +two revisions: the diff is done between @option{id1} and @option{id2}; no +workspace is needed in this case. address@hidden itemize + address@hidden Added in: + +4.0 + address@hidden Purpose: + +Prints the content changes between two revisions or a revision and the current +workspace. This command differs from @command{mtn diff} in that way that it only +outputs content changes and keeps quite on renames or drops, as the header of address@hidden diff} is omitted (this is what @command{mtn automate get_revision} +already provides). + address@hidden Sample output: + address@hidden +============================================================ +--- guitone/res/i18n/guitone_de.ts 9857927823e1d6a0339b531c120dcaadd22d25e9 ++++ guitone/res/i18n/guitone_de.ts 0b4715dc296b1955b0707923d45d79ca7769dd3f +@@ -1,6 +1,14 @@ + + + ++ AncestryGraph ++ +[...] address@hidden verbatim + address@hidden Output format: + +The GNU unified diff format. If there have been no content changes, the output +is empty. + address@hidden Error conditions: + +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. + address@hidden table + @item mtn automate get_file @var{id} @table @strong ============================================================ --- testsuite.lua 67b5f8eb1b321452edafe257ac5f61e82c85c856 +++ testsuite.lua ee3dadaa84390b8be6919ce41c9c5e6c4e3b4881 @@ -425,7 +425,7 @@ table.insert(tests, "db_load_must_create table.insert(tests, "update_no-ops_when_no_parent_revision") table.insert(tests, "branch-based_checkout") table.insert(tests, "db_load_must_create_a_new_db") -table.insert(tests, "automate_automate_version") +table.insert(tests, "automate_interface_version") table.insert(tests, "automate_heads") table.insert(tests, "merge_normalization_edge_case") table.insert(tests, "(todo)_undo_update_command") @@ -687,3 +687,4 @@ table.insert(tests, "add_ignored") table.insert(tests, "db_check_(heights)") table.insert(tests, "disapproving_with_message") table.insert(tests, "add_ignored") +table.insert(tests, "automate_content_diff")