# # patch "ChangeLog" # from [02d9f88ecd8c8f495bff7f366bfd5e0551292ec9] # to [20da57258f07e3fecb32253bcadcbfb237f81f6b] # # patch "app_state.cc" # from [976ea774c4fd1df5e9d63ee5b19f1a925899c12b] # to [8efdcd302100554f04d225c9e5ddfe9ddc1bff3a] # # patch "app_state.hh" # from [ad40f04b056e67723f755a752d17e0ab7107dac4] # to [15ba734efc432db709cc66ee01c7c104e5554e50] # # patch "commands.cc" # from [668364db356c8b18906474160174ee9b30d7d699] # to [41f74675806bc533e9ecc46b5dfb5c3ffb09d263] # # patch "diff_patch.cc" # from [fbef84d6f575c4f14850b8a8e7d78e42021a0e80] # to [022e125cb1265ea8d0a484289b952587060053cc] # # patch "diff_patch.hh" # from [18be28ae5d744c23da230988bd4a48f6556cb4b4] # to [f499e229bf13e49c06c4c9129a1e48b2b1a7ef65] # # patch "lua.cc" # from [a8af56ad7fe0d9baa85c265b05dd94877a806c19] # to [7f7d2cd8e90e9224d82fc66216093307306fa653] # # patch "lua.hh" # from [0c4f6966a60230b591f07d0a0519485bf451a349] # to [517f80335c5433b0134e70a53f0d26f9563151dc] # # patch "monotone.cc" # from [240b0908b7d873c84df7cd1ca676d44a490b778f] # to [46cbc3c75c039ef547e3d566c79fd33a2acdcf52] # # patch "monotone.texi" # from [80f97d74395a57fc85b24b54329d0c10f1639c99] # to [9e37ce22ceb10715bf1ed4efa1fe44f1b1d02a22] # # patch "options.hh" # from [2d21f8009f424d24e5513c3894c0ff321e79feb0] # to [814c3c354201a830e7bce20f0a8dc48d79b9cf8c] # # patch "std_hooks.lua" # from [072c95bc58425ade43dc08e8361c7aca49275dd4] # to [80a530bdeb7e4526a8b97c9f9d6c071a7b1f05e0] # # patch "tests/t_crlf.at" # from [ac04c64a00a9691b7599320562dacdb34641779c] # to [c77173aa37c0c6a9e628aa5528069ef3afddf6cb] # # patch "tests/t_restrictions.at" # from [be72348a94c89d89703de67b40c886edc2bef302] # to [84972130299ee9cc3449101f4a4135795cf863f0] # # patch "vocab.hh" # from [77bb3d7df9abc7e4e5202cb20b313c925dad2c13] # to [d6352245e0e2260db3f53cd0f7731a7bc07fd225] # --- ChangeLog +++ ChangeLog @@ -1,3 +1,22 @@ +2005-07-16 Vladimir Vukicevic + + * lua.{cc,hh} (hook_external_diff): New hook. + * std_hooks.lua (external_diff): Add default definition. + * monotone.texi (Hooks): Document external_diff hook. + * app_state.{cc,hh}, options.hh, monotone.cc: Add --context, + --external, --unified, --diff-args options. + * commands.cc (do_external_diff): New function. + (dump_diffs): Put a == line between each file's diffs. + Pass file_ids of pre- and post-states to make_diff. + (diff): Take new options. + (cdiff): Remove. + * diff_patch.{cc,hh} (make_diff): Print file ids in diff file + headers. + (unidiff_append_test): Update. + (enum diff_type): Move to... + * vocab.hh: ...here. + * tests/t_restrictions.at, tests/t_crlf.at: Update. + 2005-07-16 Nathaniel Smith * manifest.cc (build_restricted_manifest_map): Remove doubled --- app_state.cc +++ app_state.cc @@ -34,7 +34,7 @@ app_state::app_state() : branch_name(""), db(""), stdhooks(true), rcfiles(true), diffs(false), no_merges(false), set_default(false), verbose(false), search_root("/"), - depth(-1), last(-1) + depth(-1), last(-1), diff_format(unified_diff) { db.set_app(this); } @@ -352,6 +352,18 @@ } void +app_state::set_diff_format(diff_type dtype) +{ + diff_format = dtype; +} + +void +app_state::set_diff_args(utf8 const & args) +{ + diff_args = args; +} + +void app_state::set_stdhooks(bool b) { stdhooks = b; --- app_state.hh +++ app_state.hh @@ -50,6 +50,8 @@ long depth; long last; fs::path pidfile; + diff_type diff_format; + utf8 diff_args; void allow_working_copy(); void require_working_copy(std::string const & explanation = ""); @@ -82,6 +84,8 @@ void set_pidfile(utf8 const & pidfile); void add_revision(utf8 const & selector); void add_exclude(utf8 const & exclude_pattern); + void set_diff_format(diff_type dtype); + void set_diff_args(utf8 const & args); void set_stdhooks(bool b); void set_rcfiles(bool b); --- commands.cc +++ commands.cc @@ -2527,7 +2527,51 @@ ALIAS(ci, commit); +static void +do_external_diff(change_set::delta_map const & deltas, + app_state & app, + bool new_is_archived) +{ + for (change_set::delta_map::const_iterator i = deltas.begin(); + i != deltas.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(); + } + + 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); + } + + bool is_binary = false; + if (guess_binary(data_old()) || + guess_binary(data_new())) + is_binary = true; + + app.lua.hook_external_diff(delta_entry_path(i), + data_old, + data_new, + is_binary, + app.diff_args(), + delta_entry_src(i).inner()(), + delta_entry_dst(i).inner()()); + } +} + static void dump_diffs(change_set::delta_map const & deltas, app_state & app, @@ -2562,8 +2606,9 @@ split_into_lines(unpacked(), lines); if (! lines.empty()) { - cout << (F("--- %s\n") % delta_entry_path(i)) - << (F("+++ %s\n") % delta_entry_path(i)) + cout << "===============================================\n"; + cout << (F("--- %s\t%s\n") % delta_entry_path(i) % delta_entry_src(i)) + << (F("+++ %s\t%s\n") % delta_entry_path(i) % delta_entry_dst(i)) << (F("@@ -0,0 +1,%d @@\n") % lines.size()); for (vector::const_iterator j = lines.begin(); j != lines.end(); ++j) @@ -2603,6 +2648,8 @@ split_into_lines(data_new(), new_lines); make_diff(delta_entry_path(i)(), delta_entry_path(i)(), + delta_entry_src(i), + delta_entry_dst(i), old_lines, new_lines, cout, type); } @@ -2610,14 +2657,19 @@ } } -void do_diff(const string & name, - app_state & app, - vector const & args, - diff_type type) +CMD(diff, "informative", "[PATH]...", + "show current diffs on stdout.\n" + "If one revision is given, the diff between the working directory 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.", + OPT_BRANCH_NAME % OPT_REVISION % OPT_DEPTH % + OPT_UNIFIED_DIFF % OPT_CONTEXT_DIFF % OPT_EXTERNAL_DIFF % + OPT_EXTERNAL_DIFF_ARGS) { revision_set r_old, r_new; manifest_map m_new; bool new_is_archived; + diff_type type = app.diff_format; change_set composite; @@ -2726,29 +2778,12 @@ } cout << "# " << endl; - dump_diffs(composite.deltas, app, new_is_archived, type); + if (type == external_diff) { + do_external_diff(composite.deltas, app, new_is_archived); + } else + dump_diffs(composite.deltas, app, new_is_archived, type); } -CMD(cdiff, "informative", "[PATH]...", - "show current context diffs on stdout.\n" - "If one revision is given, the diff between the working directory and\n" - "that revision is shown. If two revisions are given, the diff between\n" - "them is given.", - OPT_BRANCH_NAME % OPT_REVISION % OPT_DEPTH) -{ - do_diff(name, app, args, context_diff); -} - -CMD(diff, "informative", "[PATH]...", - "show current unified diffs on stdout.\n" - "If one revision is given, the diff between the working directory and\n" - "that revision is shown. If two revisions are given, the diff between\n" - "them is given.", - OPT_BRANCH_NAME % OPT_REVISION % OPT_DEPTH) -{ - do_diff(name, app, args, unified_diff); -} - CMD(lca, "debug", "LEFT RIGHT", "print least common ancestor", OPT_NONE) { if (args.size() != 2) --- diff_patch.cc +++ diff_patch.cc @@ -1079,6 +1079,8 @@ void make_diff(string const & filename1, string const & filename2, + file_id const & id1, + file_id const & id2, vector const & lines1, vector const & lines2, ostream & ost, @@ -1110,8 +1112,9 @@ { case unified_diff: { - ost << "--- " << filename1 << endl; - ost << "+++ " << filename2 << endl; + ost << "===============================================" << endl; + ost << "--- " << filename1 << "\t" << id1 << endl; + ost << "+++ " << filename2 << "\t" << id2 << endl; unidiff_hunk_writer hunks(lines1, lines2, 3, ost); walk_hunk_consumer(lcs, left_interned, right_interned, hunks); @@ -1119,13 +1122,20 @@ } case context_diff: { - ost << "*** " << filename1 << endl; - ost << "--- " << filename2 << endl; + ost << "===============================================" << endl; + ost << "*** " << filename1 << "\t" << id1 << endl; + ost << "--- " << filename2 << "\t" << id2 << endl; cxtdiff_hunk_writer hunks(lines1, lines2, 3, ost); walk_hunk_consumer(lcs, left_interned, right_interned, hunks); break; } + default: + { + // should never reach this; the external_diff type is not + // handled by this function. + I(false); + } } } @@ -1195,8 +1205,9 @@ + "}\n" + "\n"); - string ud(string("--- hello.c\n") - + "+++ hello.c\n" + string ud(string("===============================================\n") + + "--- hello.c\t0123456789abcdef0123456789abcdef01234567\n" + + "+++ hello.c\tabcdef0123456789abcdef0123456789abcdef01\n" + "@@ -9,3 +9,9 @@\n" + " {\n" + " say_hello();\n" @@ -1212,7 +1223,11 @@ split_into_lines(src, src_lines); split_into_lines(dst, dst_lines); stringstream sst; - make_diff("hello.c", "hello.c", src_lines, dst_lines, sst, unified_diff); + make_diff("hello.c", "hello.c", + file_id(id("0123456789abcdef0123456789abcdef01234567")), + file_id(id("abcdef0123456789abcdef0123456789abcdef01")), + src_lines, dst_lines, sst, unified_diff); + cout << sst.str() << std::endl; BOOST_CHECK(sst.str() == ud); } --- diff_patch.hh +++ diff_patch.hh @@ -19,15 +19,10 @@ // this file is to contain some stripped down, in-process implementations // of GNU-diffutils-like things (diff, diff3, maybe patch..) - -enum diff_type -{ - unified_diff, - context_diff -}; - void make_diff(std::string const & filename1, std::string const & filename2, + file_id const & id1, + file_id const & id2, std::vector const & lines1, std::vector const & lines2, std::ostream & ost, --- lua.cc +++ lua.cc @@ -1023,7 +1023,41 @@ return ok; } +bool +lua_hooks::hook_external_diff(file_path const & path, + data const & data_old, + data const & data_new, + bool is_binary, + std::string const & diff_args, + std::string const & oldrev, + std::string const & newrev) +{ + Lua ll(st); + ll + .func("external_diff") + .push_str(path()); + + if (oldrev.length() != 0) + ll.push_str(data_old()); + else + ll.push_nil(); + + ll.push_str(data_new()); + + ll.push_bool(is_binary); + + if (diff_args.length() != 0) + ll.push_str(diff_args); + else + ll.push_nil(); + + ll.push_str(oldrev); + ll.push_str(newrev); + + return ll.call(7,0).ok(); +} + bool lua_hooks::hook_use_inodeprints() { --- lua.hh +++ lua.hh @@ -95,6 +95,14 @@ file_path const & b, file_path & res); + bool hook_external_diff(file_path const & path, + data const & data_old, + data const & data_new, + bool is_binary, + std::string const & diff_args, + std::string const & oldrev, + std::string const & newrev); + // working copy hooks bool hook_use_inodeprints(); --- monotone.cc +++ monotone.cc @@ -59,6 +59,10 @@ {"no-merges", 0, POPT_ARG_NONE, NULL, OPT_NO_MERGES, "skip merges when printing logs", NULL}, {"set-default", 0, POPT_ARG_NONE, NULL, OPT_SET_DEFAULT, "use the current arguments as the future default", NULL}, {"exclude", 0, POPT_ARG_STRING, &argstr, OPT_EXCLUDE, "leave out branches matching a pattern", NULL}, + {"unified", 0, POPT_ARG_NONE, NULL, OPT_UNIFIED_DIFF, "Use unified diff format", NULL}, + {"context", 0, POPT_ARG_NONE, NULL, OPT_CONTEXT_DIFF, "Use context diff format", NULL}, + {"external", 0, POPT_ARG_NONE, NULL, OPT_EXTERNAL_DIFF, "Use external diff hook for generating diffs", NULL}, + {"diff-args", 0, POPT_ARG_STRING, &argstr, OPT_EXTERNAL_DIFF_ARGS, "Argument to pass external diff hook", NULL}, { NULL, 0, 0, NULL, 0, NULL, NULL } }; @@ -407,6 +411,22 @@ my_poptStuffArgFile(ctx(), utf8(string(argstr))); break; + case OPT_UNIFIED_DIFF: + app.set_diff_format(unified_diff); + break; + + case OPT_CONTEXT_DIFF: + app.set_diff_format(context_diff); + break; + + case OPT_EXTERNAL_DIFF: + app.set_diff_format(external_diff); + break; + + case OPT_EXTERNAL_DIFF_ARGS: + app.set_diff_args(utf8(string(argstr))); + break; + case OPT_HELP: default: requested_help = true; --- monotone.texi +++ monotone.texi @@ -5835,6 +5835,20 @@ The @code{binary_file} function is also defined as a lua hook. See @ref{Default hooks}. address@hidden external_diff (@var{file_path}, @var{old_data}, @var{new_data}, @var{is_binary}, + @var{diff_args}, @var{old_rev}, @var{new_rev}) + +Called for each file when @command{diff} is given the address@hidden command. @var{file_path} is the pathname of the +file that is being diffed. @var{old_data} and @var{new_data} are the +data contents of the old and the new file. If the data is binary, address@hidden will be true, otherwise false. @var{old_rev} and address@hidden are the revision IDs of the old and new data. + +If an extra arguments are given via @option{--diff-args}, the string +will be passed in as @var{diff_args}. Otherwise @var{diff_args} will +be nil. + @end ftable @page --- options.hh +++ options.hh @@ -37,3 +37,7 @@ #define OPT_VERBOSE 28 #define OPT_SET_DEFAULT 29 #define OPT_EXCLUDE 30 +#define OPT_UNIFIED_DIFF 31 +#define OPT_CONTEXT_DIFF 32 +#define OPT_EXTERNAL_DIFF 33 +#define OPT_EXTERNAL_DIFF_ARGS 34 --- std_hooks.lua +++ std_hooks.lua @@ -610,3 +610,14 @@ function use_inodeprints() return false end + +-- default external diff, works for gnu diff +function external_diff(file_path, data_old, data_new, is_binary, diff_args, rev_old, rev_new) + local old_file = write_to_temporary_file(data_old); + local new_file = write_to_temporary_file(data_new); + + execute("diff", "-upNU8", "--label", file_path .. "\told", old_file, "--label", file_path .. "\tnew", new_file); + + os.remove (old_file); + os.remove (new_file); +end --- tests/t_crlf.at +++ tests/t_crlf.at @@ -12,6 +12,6 @@ AT_CHECK(MONOTONE diff, [], [stdout], [ignore]) LINES=`wc -l ; #endif +// diff type +enum diff_type +{ + unified_diff, + context_diff, + external_diff +}; + + #endif // __VOCAB_HH__