# # # rename "tests/resolve_content_conflict/resolve-conflicts-1" # to "tests/resolve_content_conflict/conflicts-2" # # add_dir "tests/resolve_conflicts_errors" # # add_file "tests/resolve_conflicts_errors/__driver__.lua" # content [41bff950ca73088c3ca483457851be730ae78e60] # # add_file "tests/resolve_conflicts_errors/conflicts-attr-show-1" # content [95e79397fd05058b226d7feeef81834b1b146256] # # add_file "tests/resolve_conflicts_errors/conflicts-attr-show-2" # content [1246f7f1f61862561d92b9a5b8b9b7e006b690ac] # # add_file "tests/resolve_conflicts_errors/conflicts-attr-store-1" # content [1246f7f1f61862561d92b9a5b8b9b7e006b690ac] # # add_file "tests/resolve_conflicts_errors/conflicts-attr-store-2" # content [500ec44e9f9534091546581601cf58927137d359] # # patch "cmd_conflicts.cc" # from [df7b2a3dc45d5ed89b083ea582641ff87da8d9c0] # to [4cadb787981f0b6bf5bba88ca7d31f2866bcaf5d] # # patch "cmd_merging.cc" # from [8e40c6a97219656dfdd2b59d68c3ad24091a61e6] # to [c95a99bd3587fa5aaf335a79cc92f787a456e238] # # patch "monotone.texi" # from [e891b5331c7fde716a6be89f2e67f4dc06a7bd72] # to [ecedcde4c73e4cfb2db1d8ec74077ef5abe65a54] # # patch "options_list.hh" # from [45a1d98927261c0e8611fdfb5eddb5c35378a980] # to [3bb5b9b1bd536dfe468700f54e22603ddc0abb92] # # patch "paths.cc" # from [405a09a6039e554e4ad159085187e96911bd2f41] # to [d30042845862fd402860f11161e5ac9623399f50] # # patch "paths.hh" # from [ee9b6c715a8513cb94717e9c0a4af998fa4c7827] # to [edb57b0c1b475e6c1fa9605b04cc78bf09b92f29] # # patch "roster_merge.cc" # from [419c804d77584c03819e2e6a611b0f67444368b3] # to [76d7a8b6130772c5b0da6ca8db48856d6cae0463] # # patch "roster_merge.hh" # from [8eb079ece2445e93680f9a7f5821da6066e1c52a] # to [122f23807d016675871888e41ef496f4fdc352a9] # # patch "tests/resolve_conflicts_all_merge_commands/__driver__.lua" # from [d544bcdd64081b676047e33257159bcecc88329b] # to [2e45edb822bc1b3bbc09e50e7b8e542e0cf6432d] # # patch "tests/resolve_conflicts_all_resolutions/__driver__.lua" # from [8342870d88378e1df4e10f20f10aae3554727620] # to [51025b5e3e0cfd195b905975cae905939a95ce94] # # patch "tests/resolve_content_conflict/__driver__.lua" # from [abb091bca68a0823b1636225d3f40069d539b986] # to [765e3324aa792233c9aff67c452731295c929c46] # # patch "tests/resolve_content_conflict/conflicts-1" # from [a22968fd0a299175d4444e778b712bbcf8a4377a] # to [97fe0c8dfc0a80ab005b6799ed04a949eebad177] # # patch "tests/resolve_content_conflict/conflicts-2" # from [3eb53a39fb89990b37289518600c27530a2f543f] # to [257ff33f262f63e892785c5b98f5f998ca8e6adf] # # patch "tests/resolve_content_conflict/merge-1" # from [a1052f7f29160f099cd7781b8c4f4feabeba0551] # to [f25a8a6d4928ed2ff4c6101d6003e823842df02d] # # patch "tests/resolve_content_conflict/update-1" # from [b0c1d97b8941efb8fae0cbc51b76db27d6ee91e6] # to [6442c128317eb0b4b8597c8ed25188937c572f1b] # # patch "tests/resolve_duplicate_name_conflict/__driver__.lua" # from [de6ac22eec67432fccd8a0a2cddac622b639e7c3] # to [895b0ad5b991fe29dac9dd64a849d2be7a2535b6] # # set "tests/resolve_conflicts_errors/__driver__.lua" # attr "mtn:execute" # value "true" # # set "tests/resolve_conflicts_errors/conflicts-attr-store-1" # attr "mtn:execute" # value "true" # ============================================================ --- tests/resolve_conflicts_errors/__driver__.lua 41bff950ca73088c3ca483457851be730ae78e60 +++ tests/resolve_conflicts_errors/__driver__.lua 41bff950ca73088c3ca483457851be730ae78e60 @@ -0,0 +1,37 @@ +-- Test that typical user errors with 'conflicts' give good error messages. + +mtn_setup() + +-- Conflict that is not supported; attribute +addfile("simple_file", "simple\none\ntwo\nthree\n") +commit("testbranch", "base") +base = base_revision() + +check(mtn("attr", "set", "simple_file", "foo", "1"), 0, nil, nil) +commit("testbranch", "left") +left = base_revision() + +revert_to(base) + +check(mtn("attr", "set", "simple_file", "foo", "2"), 0, nil, nil) +commit("testbranch", "right") +right = base_revision() + +check(mtn("conflicts", "store", left, right), 0, nil, true) +canonicalize("stderr") +check(samefilestd("conflicts-attr-store-1", "stderr")) + +check(mtn("conflicts", "show_remaining"), 0, nil, true) +canonicalize("stderr") +check(samefilestd("conflicts-attr-show-1", "stderr")) + +check(mtn("conflicts", "show_first"), 0, nil, true) +canonicalize("stderr") +check(samefilestd("conflicts-attr-show-2", "stderr")) + +-- specify conflicts file not in bookkeeping dir +check(mtn("conflicts", "--conflicts-file", "conflicts", "store", left, right), 1, nil, true) +canonicalize("stderr") +check(samefilestd("conflicts-attr-store-2", "stderr")) + +-- end of file ============================================================ --- tests/resolve_conflicts_errors/conflicts-attr-show-1 95e79397fd05058b226d7feeef81834b1b146256 +++ tests/resolve_conflicts_errors/conflicts-attr-show-1 95e79397fd05058b226d7feeef81834b1b146256 @@ -0,0 +1,4 @@ +mtn: warning: 1 conflict with no supported resolutions. +mtn: conflict: multiple values for attribute 'foo' on file 'simple_file' from revision 30c20be14d4d18c404bc4c121bb0232c9c9b975f +mtn: set to '1' on left file 'simple_file' +mtn: set to '2' on right file 'simple_file' ============================================================ --- tests/resolve_conflicts_errors/conflicts-attr-show-2 1246f7f1f61862561d92b9a5b8b9b7e006b690ac +++ tests/resolve_conflicts_errors/conflicts-attr-show-2 1246f7f1f61862561d92b9a5b8b9b7e006b690ac @@ -0,0 +1 @@ +mtn: warning: 1 conflict with no supported resolutions. ============================================================ --- tests/resolve_conflicts_errors/conflicts-attr-store-1 1246f7f1f61862561d92b9a5b8b9b7e006b690ac +++ tests/resolve_conflicts_errors/conflicts-attr-store-1 1246f7f1f61862561d92b9a5b8b9b7e006b690ac @@ -0,0 +1 @@ +mtn: warning: 1 conflict with no supported resolutions. ============================================================ --- tests/resolve_conflicts_errors/conflicts-attr-store-2 500ec44e9f9534091546581601cf58927137d359 +++ tests/resolve_conflicts_errors/conflicts-attr-store-2 500ec44e9f9534091546581601cf58927137d359 @@ -0,0 +1 @@ +mtn: misuse: conflicts file must be under _MTN ============================================================ --- cmd_conflicts.cc df7b2a3dc45d5ed89b083ea582641ff87da8d9c0 +++ cmd_conflicts.cc 4cadb787981f0b6bf5bba88ca7d31f2866bcaf5d @@ -27,7 +27,7 @@ struct conflicts_t boost::shared_ptr right_roster; marking_map left_marking, right_marking; - conflicts_t(database & db, system_path file): + conflicts_t(database & db, bookkeeping_path const & file): left_roster(boost::shared_ptr(new roster_t())), right_roster(boost::shared_ptr(new roster_t())) { @@ -38,7 +38,7 @@ struct conflicts_t *right_roster, right_marking); }; - void write (database & db, lua_hooks & lua, system_path file) + void write (database & db, lua_hooks & lua, bookkeeping_path const & file) { result.write_conflict_file (db, lua, file, ancestor_rid, left_rid, right_rid, @@ -184,7 +184,7 @@ set_duplicate_name_conflict(resolve_conf { N(args.size() == 2, F("wrong number of arguments")); resolution.first = resolve_conflicts::content_user; - resolution.second = resolve_conflicts::new_optimal_path(idx(args,1)()); + resolution.second = new_optimal_path(idx(args,1)(), false); } else N(false, F(conflict_resolution_not_supported_msg) % idx(args,0) % "duplicate_name"); @@ -241,7 +241,7 @@ set_first_conflict(side_t side, conflict N(args.size() == 2, F("wrong number of arguments")); conflict.resolution.first = resolve_conflicts::content_user; - conflict.resolution.second = resolve_conflicts::new_optimal_path(idx(args,1)()); + conflict.resolution.second = new_optimal_path(idx(args,1)(), false); } else { @@ -274,7 +274,7 @@ set_first_conflict(side_t side, conflict /// commands -// CMD(store) is in cmd_merging, since it needs access to +// CMD(store) is in cmd_merging.cc, since it needs access to // show_conflicts_core, and doesn't need conflicts_t. CMD(show_first, "show_first", "", CMD_REF(conflicts), @@ -349,8 +349,8 @@ CMD(clean, "clean", "", CMD_REF(conflict "", options::opts::none) { - bookkeeping_path conflicts_file("conflicts"); - bookkeeping_path resolutions_dir("resolutions"); + bookkeeping_path conflicts_file("_MTN/conflicts"); + bookkeeping_path resolutions_dir("_MTN/resolutions"); if (path_exists(conflicts_file)) delete_file(conflicts_file); ============================================================ --- cmd_merging.cc 8e40c6a97219656dfdd2b59d68c3ad24091a61e6 +++ cmd_merging.cc c95a99bd3587fa5aaf335a79cc92f787a456e238 @@ -1039,7 +1039,7 @@ CMD(store, "store", "", CMD_REF(conflict show_conflicts_core(db, app.lua, left_id, right_id, true, true, output); data dat(output.str()); - write_data(system_path(app.opts.conflicts_file), dat, system_path("_MTN")); + write_data(app.opts.conflicts_file, dat); } CMD_AUTOMATE(file_merge, N_("LEFT_REVID LEFT_FILENAME RIGHT_REVID RIGHT_FILENAME"), ============================================================ --- monotone.texi e891b5331c7fde716a6be89f2e67f4dc06a7bd72 +++ monotone.texi ecedcde4c73e4cfb2db1d8ec74077ef5abe65a54 @@ -3023,7 +3023,8 @@ @section Merge Conflicts In addition, the @command{conflicts} set of commands can be used to specify resolutions for some conflicts. The resolutions are stored in a file, and given to the @command{merge} command via the address@hidden option; see @xref{Conflicts}. address@hidden or address@hidden option; see @xref{Conflicts}. The @command{merge} command normally will perform as many merges as necessary to merge all current heads of a branch. However, when @@ -4662,11 +4663,17 @@ @subsection Conflicts conflict resolutions, and avoids losing work when a merge is aborted due to a complicated conflict. +These commands require a workspace, to provide a place to store the +conflicts and user resolution files. + For all of these commands, if the @command{--conflicts-file} option is -not given, the file @file{_MTN/conflicts} is used. +not given, the file @file{_MTN/conflicts} is used. If the address@hidden option is given, the file must be in the +bookkeeping directory. -Except for @command{conflicts clean}, these commands do not require a -workspace, unless the default conflicts file is used. +Files given in these commands are relative to the current working +directory, or absolute. In the conflict file, they are relative to the +workspace root, or absolute. @ftable @command @item mtn conflicts address@hidden store @var{left_rev_id} @var{right_rev_id} ============================================================ --- options_list.hh 45a1d98927261c0e8611fdfb5eddb5c35378a980 +++ options_list.hh 3bb5b9b1bd536dfe468700f54e22603ddc0abb92 @@ -637,37 +637,39 @@ OPTSET(resolve_conflicts_opts) #endif OPTSET(resolve_conflicts_opts) -OPTVAR(resolve_conflicts_opts, utf8, resolve_conflicts_file, ) -OPTVAR(resolve_conflicts_opts, std::string, resolve_conflicts, ) +OPTVAR(resolve_conflicts_opts, bookkeeping_path, resolve_conflicts_file, ) +OPTVAR(resolve_conflicts_opts, bool, resolve_conflicts, ) OPTION(resolve_conflicts_opts, resolve_conflicts_file, true, "resolve-conflicts-file", gettext_noop("use file to resolve conflicts")) #ifdef option_bodies { - N(!resolve_conflicts_given, - F("only one of --resolve-conflicts or --resolve-conflicts-file may be given")); - resolve_conflicts_file = utf8(arg); + N(bookkeeping_path::external_string_is_bookkeeping_path(utf8(arg)), + F("conflicts file must be under _MTN")); + resolve_conflicts_file = bookkeeping_path(arg); } #endif -OPTION(resolve_conflicts_opts, resolve_conflicts, true, "resolve-conflicts", - gettext_noop("use argument to resolve conflicts")) +OPTION(resolve_conflicts_opts, resolve_conflicts, false, "resolve-conflicts", + gettext_noop("use _MTN/conflicts to resolve conflicts")) #ifdef option_bodies { N(!resolve_conflicts_file_given, F("only one of --resolve-conflicts or --resolve-conflicts-file may be given")); - resolve_conflicts = arg; + resolve_conflicts_file = bookkeeping_path("_MTN/conflicts"); } #endif OPTSET(conflicts_opts) -OPTVAR(conflicts_opts, system_path, conflicts_file, system_path("_MTN/conflicts")) +OPTVAR(conflicts_opts, bookkeeping_path, conflicts_file, bookkeeping_path("_MTN/conflicts")) OPTION(conflicts_opts, conflicts_file, true, "conflicts-file", gettext_noop("file in which to store conflicts")) #ifdef option_bodies { - conflicts_file = system_path(utf8(arg)); + N(bookkeeping_path::external_string_is_bookkeeping_path(utf8(arg)), + F("conflicts file must be under _MTN")); + conflicts_file = bookkeeping_path(arg); } #endif ============================================================ --- paths.cc 405a09a6039e554e4ad159085187e96911bd2f41 +++ paths.cc d30042845862fd402860f11161e5ac9623399f50 @@ -1,3 +1,4 @@ +// Copyright (C) 2008 Stephen Leake // Copyright (C) 2005 Nathaniel Smith // // This program is made available under the GNU GPL version 2.0 or @@ -351,7 +352,7 @@ static void } static void -normalize_external_path(string const & path, string & normalized) +normalize_external_path(string const & path, string & normalized, bool to_workspace_root) { if (!initial_rel_path.initialized) { @@ -370,7 +371,11 @@ normalize_external_path(string const & p string base; try { - base = initial_rel_path.get(); + if (to_workspace_root) + base = ""; + else + base = initial_rel_path.get(); + if (base == "") normalized = normalize_path(path); else @@ -434,14 +439,14 @@ template <> void dump(path_component con // complete paths to files within a working directory /////////////////////////////////////////////////////////////////////////// -file_path::file_path(file_path::source_type type, string const & path) +file_path::file_path(file_path::source_type type, string const & path, bool to_workspace_root) { MM(path); I(utf8_validate(utf8(path))); if (type == external) { string normalized; - normalize_external_path(path, normalized); + normalize_external_path(path, normalized, to_workspace_root); N(!in_bookkeeping_dir(normalized), F("path '%s' is in bookkeeping dir") % normalized); data = normalized; @@ -452,14 +457,14 @@ file_path::file_path(file_path::source_t I(is_valid_internal(data)); } -file_path::file_path(file_path::source_type type, utf8 const & path) +file_path::file_path(file_path::source_type type, utf8 const & path, bool to_workspace_root) { MM(path); I(utf8_validate(path)); if (type == external) { string normalized; - normalize_external_path(path(), normalized); + normalize_external_path(path(), normalized, to_workspace_root); N(!in_bookkeeping_dir(normalized), F("path '%s' is in bookkeeping dir") % normalized); data = normalized; @@ -484,7 +489,7 @@ bookkeeping_path::external_string_is_boo string normalized; try { - normalize_external_path(path(), normalized); + normalize_external_path(path(), normalized, true); } catch (informative_failure &) { @@ -806,6 +811,27 @@ system_path::system_path(utf8 const & pa data = const_system_path(utf8(path)); } +boost::shared_ptr +new_optimal_path(std::string path, bool to_workspace_root) +{ + utf8 const utf8_path = utf8(path); + string normalized; + try + { + normalize_external_path(utf8_path(), normalized, to_workspace_root); + } + catch (informative_failure &) + { + // not in workspace + return boost::shared_ptr(new system_path(path)); + } + + if (in_bookkeeping_dir(normalized)) + return boost::shared_ptr(new bookkeeping_path(normalized)); + else + return boost::shared_ptr(new file_path(file_path_internal(normalized))); +}; + /////////////////////////////////////////////////////////////////////////// // workspace (and path root) handling /////////////////////////////////////////////////////////////////////////// ============================================================ --- paths.hh ee9b6c715a8513cb94717e9c0a4af998fa4c7827 +++ paths.hh edb57b0c1b475e6c1fa9605b04cc78bf09b92f29 @@ -1,6 +1,7 @@ #ifndef __PATHS_HH__ #define __PATHS_HH__ +// Copyright (C) 2008 Stephen Leake // Copyright (C) 2005 Nathaniel Smith // // This program is made available under the GNU GPL version 2.0 or @@ -82,8 +83,10 @@ // representing this path for internal use. for instance, this is the // string that should be embedded into the text of revisions. // -- a method .as_external(), which returns a std::string suitable for -// passing to filesystem interface functions. in practice, this means -// that it is recoded into an appropriate character set, etc. +// passing to filesystem interface functions. in practice, this means +// that it is recoded into an appropriate character set, etc. For +// bookkeeping_path and file_path, .as_external() is relative to the +// workspace root. // -- a operator<< for ostreams. this should always be used when writing // out paths for display to the user. at the moment it just calls one // of the above functions, but this is _not_ correct. there are @@ -98,6 +101,8 @@ // i.e., nothing fancy necessary, for purposes of F() just treat it like // it were a string +#include + class any_path; class file_path; class roster_t; @@ -258,15 +263,17 @@ private: // external paths: // -- are converted to internal syntax (/ rather than \, etc.) // -- normalized - // -- assumed to be relative to the user's cwd, and munged - // to become relative to root of the workspace instead + // -- if not 'to_workspace_root', assumed to be relative to the user's + // cwd, and munged to become relative to root of the workspace + // instead // internal and external paths: // -- are confirmed to be normalized and relative // -- not to be in _MTN/ - file_path(source_type type, std::string const & path); - file_path(source_type type, utf8 const & path); + file_path(source_type type, std::string const & path, bool to_workspace_root); + file_path(source_type type, utf8 const & path, bool to_workspace_root); friend file_path file_path_internal(std::string const & path); friend file_path file_path_external(utf8 const & path); + friend file_path file_path_external_ws(utf8 const & path); // private substring constructor, does no validation. used by dirname() // and operator/ with a path_component. @@ -281,16 +288,23 @@ private: friend class roster_t; }; -// these are the public file_path constructors +// these are the public file_path constructors. path is relative to the +// current working directory. inline file_path file_path_internal(std::string const & path) { - return file_path(file_path::internal, path); + return file_path(file_path::internal, path, false); } inline file_path file_path_external(utf8 const & path) { - return file_path(file_path::external, path); + return file_path(file_path::external, path, false); } +// path is relative to the workspace root +inline file_path file_path_external_ws(utf8 const & path) +{ + return file_path(file_path::external, path, true); +} + class bookkeeping_path : public any_path { public: @@ -378,6 +392,12 @@ template <> void dump(system_path const template <> void dump(bookkeeping_path const & sp, std::string & out); template <> void dump(system_path const & sp, std::string & out); +// Return a file_path, bookkeeping_path, or system_path, as appropriate. +// 'path' is an external path. If to_workspace_root, path is relative to +// workspace root, or absolute. Otherwise, it is relative to the current +// working directory, or absolute. +boost::shared_ptr new_optimal_path(std::string path, bool to_workspace_root); + // record the initial path. must be called before any use of system_path. void save_initial_path(); ============================================================ --- roster_merge.cc 419c804d77584c03819e2e6a611b0f67444368b3 +++ roster_merge.cc 76d7a8b6130772c5b0da6ca8db48856d6cae0463 @@ -37,23 +37,7 @@ namespace resolve_conflicts return boost::shared_ptr(new file_path(file_path_external(utf8(path)))); }; - boost::shared_ptr - new_optimal_path(std::string path) - { - if (bookkeeping_path::external_string_is_bookkeeping_path(utf8(path))) - return boost::shared_ptr(new bookkeeping_path(path)); - else - try - { - return new_file_path(path); - } - catch (informative_failure &) - { - return boost::shared_ptr(new system_path(path)); - } - }; - - static char * const + static char const * const image(resolve_conflicts::resolution_t resolution) { switch (resolution) @@ -1599,8 +1583,9 @@ roster_merge_result::report_file_content { basic_io::stanza st; - if (auto_merge_succeeds(lua, conflict, adaptor, left_roster, right_roster)) - conflict.resolution.first = resolve_conflicts::content_internal; + if (conflict.resolution.first == resolve_conflicts::none) + if (auto_merge_succeeds(lua, conflict, adaptor, left_roster, right_roster)) + conflict.resolution.first = resolve_conflicts::content_internal; st.push_str_pair(syms::conflict, syms::content); put_content_conflict (st, left_roster, right_roster, adaptor, conflict); @@ -1930,14 +1915,14 @@ read_duplicate_name_conflict(basic_io::p { conflict.left_resolution.first = resolve_conflicts::content_user; pars.sym(); - conflict.left_resolution.second = resolve_conflicts::new_optimal_path(pars.token); + conflict.left_resolution.second = new_optimal_path(pars.token, true); pars.str(); } else if (pars.symp (syms::resolved_user_right)) { conflict.right_resolution.first = resolve_conflicts::content_user; pars.sym(); - conflict.right_resolution.second = resolve_conflicts::new_optimal_path(pars.token); + conflict.right_resolution.second = new_optimal_path(pars.token, true); pars.str(); } else @@ -2143,7 +2128,7 @@ read_file_content_conflict(basic_io::par { conflict.resolution.first = resolve_conflicts::content_user; pars.sym(); - conflict.resolution.second = resolve_conflicts::new_optimal_path(pars.token); + conflict.resolution.second = new_optimal_path(pars.token, true); pars.str(); } else @@ -2255,7 +2240,7 @@ roster_merge_result::read_conflict_file( void roster_merge_result::read_conflict_file(database & db, - system_path const file_name, + bookkeeping_path const & file_name, revision_id & ancestor_rid, revision_id & left_rid, revision_id & right_rid, @@ -2294,7 +2279,7 @@ roster_merge_result::write_conflict_file void roster_merge_result::write_conflict_file(database & db, lua_hooks & lua, - system_path const file_name, + bookkeeping_path const & file_name, revision_id const & ancestor_rid, revision_id const & left_rid, revision_id const & right_rid, @@ -2331,66 +2316,10 @@ roster_merge_result::write_conflict_file report_file_content_conflicts(lua, *left_roster, *right_roster, adaptor, true, output); data dat(output.str()); - write_data(file_name, dat, system_path("_MTN")); + write_data(file_name, dat); } // roster_merge_result::write_conflict_file -static void -parse_resolve_conflicts_str(basic_io::parser & pars, roster_merge_result & result) -{ - char const * error_message_1 = "can't specify a %s conflict resolution for more than one conflict"; - char const * error_message_2 = "conflict resolution %s is not appropriate for current conflicts"; - - // We don't detect all cases of inappropriate resolutions here; that would - // be too hard to maintain as more conflicts and/or resolutions are added. - // If the single resolution specified is not appropriate for some - // conflict, that conflict will not be resolved, which will be reported - // later. Then the user will need to use a conflict resolution file. - while (pars.tok.in.lookahead != EOF) - { - // resolution alphabetical order - if (pars.symp (syms::resolved_rename_left)) - { - N(result.duplicate_name_conflicts.size() == 1, - F(error_message_1) % syms::resolved_rename_left); - - duplicate_name_conflict & conflict = *result.duplicate_name_conflicts.begin(); - - conflict.left_resolution.first = resolve_conflicts::rename; - pars.sym(); - conflict.left_resolution.second = resolve_conflicts::new_file_path(pars.token); - pars.str(); - } - else if (pars.symp (syms::resolved_rename_right)) - { - N(result.duplicate_name_conflicts.size() == 1, - F(error_message_1) % syms::resolved_rename_right); - - duplicate_name_conflict & conflict = *result.duplicate_name_conflicts.begin(); - - conflict.right_resolution.first = resolve_conflicts::rename; - pars.sym(); - conflict.right_resolution.second = resolve_conflicts::new_file_path(pars.token); - pars.str(); - } - else if (pars.symp (syms::resolved_user)) - { - N(result.file_content_conflicts.size() == 1, - F(error_message_1) % syms::resolved_user); - - file_content_conflict & conflict = *result.file_content_conflicts.begin(); - - conflict.resolution.first = resolve_conflicts::content_user; - pars.sym(); - conflict.resolution.second = resolve_conflicts::new_optimal_path(pars.token); - pars.str(); - } - else - N(false, F("%s is not a supported conflict resolution") % pars.token); - - } // while -} // parse_resolve_conflicts_str - void parse_resolve_conflicts_opts (options const & opts, roster_t const & left_roster, @@ -2398,28 +2327,15 @@ parse_resolve_conflicts_opts (options co roster_merge_result & result, bool & resolutions_given) { - if (opts.resolve_conflicts_given) +if (opts.resolve_conflicts_given || opts.resolve_conflicts_file_given) { resolutions_given = true; - basic_io::input_source src(opts.resolve_conflicts, "resolve_conflicts string"); - basic_io::tokenizer tok(src); - basic_io::parser pars(tok); - - parse_resolve_conflicts_str(pars, result); - - if (src.lookahead != EOF) - pars.err("invalid conflict resolution syntax"); - } - else if (opts.resolve_conflicts_file_given) - { - resolutions_given = true; - data dat; - read_data (system_path(opts.resolve_conflicts_file()), dat); + read_data (system_path(opts.resolve_conflicts_file), dat); - basic_io::input_source src(dat(), opts.resolve_conflicts_file()); + basic_io::input_source src(dat(), opts.resolve_conflicts_file.as_external()); basic_io::tokenizer tok(src); basic_io::parser pars(tok); ============================================================ --- roster_merge.hh 8eb079ece2445e93680f9a7f5821da6066e1c52a +++ roster_merge.hh 122f23807d016675871888e41ef496f4fdc352a9 @@ -35,9 +35,6 @@ namespace resolve_conflicts boost::shared_ptr new_file_path(std::string path); - // Return a file_path, bookkeeping_path, or system_path, as appropriate. - // This keeps the file names in the conflict file relative if possible. - boost::shared_ptr new_optimal_path(std::string path); } // renaming the root dir allows these: @@ -252,7 +249,7 @@ struct roster_merge_result // If validate, compare file contents to existing conflicts, and add // resolutions. Otherwise just read into conflicts. void read_conflict_file(database & db, - system_path const file_name, + bookkeeping_path const & file_name, revision_id & ancestor_rid, revision_id & left_rid, revision_id & right_rid, @@ -263,7 +260,7 @@ struct roster_merge_result void write_conflict_file(database & db, lua_hooks & lua, - system_path const file_name, + bookkeeping_path const & file_name, revision_id const & ancestor_rid, revision_id const & left_rid, revision_id const & right_rid, ============================================================ --- tests/resolve_conflicts_all_merge_commands/__driver__.lua d544bcdd64081b676047e33257159bcecc88329b +++ tests/resolve_conflicts_all_merge_commands/__driver__.lua 2e45edb822bc1b3bbc09e50e7b8e542e0cf6432d @@ -32,7 +32,6 @@ branch = "content-attached" end branch = "content-attached" -resolution = "resolved_user \"foo\"" setup(branch) addfile("foo", branch .. "-foo") @@ -50,18 +49,21 @@ second = base_revision() commit(branch .. "-propagate") second = base_revision() -check(mtn("propagate", branch , branch .. "-propagate", "--resolve-conflicts", resolution), 0, nil, true) +check(mtn("conflicts", "store", "h:" .. branch , "h:" .. branch .. "-propagate"), 0, nil, true) +check(mtn("conflicts", "resolve_first", "user", "foo"), 0, nil, nil) + +check(mtn("propagate", branch , branch .. "-propagate", "--resolve-conflicts"), 0, nil, true) merged = merged_revision() check(mtn("db", "kill_rev_locally", merged), 0, nil, true) -check(mtn("explicit_merge", first, second, branch, "--resolve-conflicts", resolution), 0, nil, true) -merged = merged_revision() +check(mtn("explicit_merge", first, second, branch, +"--resolve-conflicts"), 0, nil, true) merged = merged_revision() check(mtn("db", "kill_rev_locally", merged), 0, nil, true) -- create a second head on 'branch' writefile("foo", branch .. "-foo third revision") commit(branch) -check(mtn("merge", "--branch", branch, "--resolve-conflicts", resolution), 0, nil, true) +check(mtn("merge", "--branch", branch, "--resolve-conflicts"), 0, nil, true) merged = merged_revision() check(mtn("db", "kill_rev_locally", merged), 0, nil, true) ============================================================ --- tests/resolve_conflicts_all_resolutions/__driver__.lua 8342870d88378e1df4e10f20f10aae3554727620 +++ tests/resolve_conflicts_all_resolutions/__driver__.lua 51025b5e3e0cfd195b905975cae905939a95ce94 @@ -45,51 +45,51 @@ mkdir("resolutions") -- Don't use _MTN/conflicts, to test that capability mkdir("resolutions") -check (mtn("conflicts", "--conflicts-file=resolutions/conflicts", "store", abe_1, beth_1), 0, nil, nil) -check(samefilestd("conflicts-1", "resolutions/conflicts")) +check (mtn("conflicts", "--conflicts-file=_MTN/conflicts-1", "store", abe_1, beth_1), 0, nil, nil) +check(samefilestd("conflicts-1", "_MTN/conflicts-1")) -check(mtn("conflicts", "--conflicts-file=resolutions/conflicts", "show_remaining"), 0, nil, true) +check(mtn("conflicts", "--conflicts-file=_MTN/conflicts-1", "show_remaining"), 0, nil, true) canonicalize("stderr") check(samefilestd("show_remaining-checkout_left", "stderr")) -check(mtn("conflicts", "--conflicts-file=resolutions/conflicts", "show_first"), 0, nil, true) +check(mtn("conflicts", "--conflicts-file=_MTN/conflicts-1", "show_first"), 0, nil, true) canonicalize("stderr") check(samefilestd("show_first-checkout_left", "stderr")) writefile("resolutions/checkout_left.sh", "checkout_left.sh beth 2") -check(mtn("conflicts", "--conflicts-file=resolutions/conflicts", "resolve_first_left", "drop"), 0, nil, nil) -check(mtn("conflicts", "--conflicts-file=resolutions/conflicts", "resolve_first_right", "user", "resolutions/checkout_left.sh"), 0, nil, nil) +check(mtn("conflicts", "--conflicts-file=_MTN/conflicts-1", "resolve_first_left", "drop"), 0, nil, nil) +check(mtn("conflicts", "--conflicts-file=_MTN/conflicts-1", "resolve_first_right", "user", "resolutions/checkout_left.sh"), 0, nil, nil) -check(mtn("conflicts", "--conflicts-file=resolutions/conflicts", "show_first"), 0, nil, true) +check(mtn("conflicts", "--conflicts-file=_MTN/conflicts-1", "show_first"), 0, nil, true) canonicalize("stderr") check(samefilestd("show_first-checkout_right", "stderr")) writefile("resolutions/checkout_right.sh", "checkout_right.sh beth 2") -check(mtn("conflicts", "--conflicts-file=resolutions/conflicts", "resolve_first_right", "drop"), 0, nil, nil) -check(mtn("conflicts", "--conflicts-file=resolutions/conflicts", "resolve_first_left", "user", "resolutions/checkout_right.sh"), 0, nil, nil) +check(mtn("conflicts", "--conflicts-file=_MTN/conflicts-1", "resolve_first_right", "drop"), 0, nil, nil) +check(mtn("conflicts", "--conflicts-file=_MTN/conflicts-1", "resolve_first_left", "user", "resolutions/checkout_right.sh"), 0, nil, nil) -check(mtn("conflicts", "--conflicts-file=resolutions/conflicts", "show_remaining"), 0, nil, true) +check(mtn("conflicts", "--conflicts-file=_MTN/conflicts-1", "show_remaining"), 0, nil, true) canonicalize("stderr") check(samefilestd("show_remaining-thermostat", "stderr")) -check(mtn("conflicts", "--conflicts-file=resolutions/conflicts", "show_first"), 0, nil, true) +check(mtn("conflicts", "--conflicts-file=_MTN/conflicts-1", "show_first"), 0, nil, true) canonicalize("stderr") check(samefilestd("show_first-thermostat", "stderr")) -check(mtn("conflicts", "--conflicts-file=resolutions/conflicts", "resolve_first_left", "rename", "thermostat-westinghouse.c"), 0, nil, nil) -check(mtn("conflicts", "--conflicts-file=resolutions/conflicts", "resolve_first_right", "rename", "thermostat-honeywell.c"), 0, nil, nil) +check(mtn("conflicts", "--conflicts-file=_MTN/conflicts-1", "resolve_first_left", "rename", "thermostat-westinghouse.c"), 0, nil, nil) +check(mtn("conflicts", "--conflicts-file=_MTN/conflicts-1", "resolve_first_right", "rename", "thermostat-honeywell.c"), 0, nil, nil) -check(mtn("conflicts", "--conflicts-file=resolutions/conflicts", "show_first"), 0, nil, true) +check(mtn("conflicts", "--conflicts-file=_MTN/conflicts-1", "show_first"), 0, nil, true) canonicalize("stderr") check(samefilestd("show_first-user", "stderr")) writefile("resolutions/user_file", "user_file merged") -check(mtn("conflicts", "--conflicts-file=resolutions/conflicts", "resolve_first", "user", "resolutions/user_file"), 0, nil, nil) +check(mtn("conflicts", "--conflicts-file=_MTN/conflicts-1", "resolve_first", "user", "resolutions/user_file"), 0, nil, nil) -check(samefilestd("conflicts-resolved", "resolutions/conflicts")) +check(samefilestd("conflicts-resolved", "_MTN/conflicts-1")) -- This succeeds -check(mtn("merge", "--resolve-conflicts-file", "resolutions/conflicts"), 0, nil, true) +check(mtn("merge", "--resolve-conflicts-file", "_MTN/conflicts-1"), 0, nil, true) canonicalize("stderr") check(samefilestd("merge-1", "stderr")) ============================================================ --- tests/resolve_content_conflict/__driver__.lua abb091bca68a0823b1636225d3f40069d539b986 +++ tests/resolve_content_conflict/__driver__.lua 765e3324aa792233c9aff67c452731295c929c46 @@ -1,38 +1,45 @@ -- Demonstrate content conflict resolutions +-- +-- All files in 'files' directory, all commands invoked there, to show +-- that 'conflicts store' uses the right bookkeeping directory. + mtn_setup() -addfile("foo", "foo") -addfile("bar", "bar\none\ntwo\nthree") -addfile("baz", "baz\naaa\nbbb\nccc") +mkdir("files") +addfile("files/foo", "foo") +addfile("files/bar", "bar\none\ntwo\nthree") +addfile("files/baz", "baz\naaa\nbbb\nccc") commit("testbranch", "base") base = base_revision() -writefile("foo", "foo\nfirst\nrevision") -writefile("bar", "bar\nzero\none\ntwo\nthree") -writefile("baz", "baz\nAAA\nbbb\nccc") +writefile("files/foo", "foo\nfirst\nrevision") +writefile("files/bar", "bar\nzero\none\ntwo\nthree") +writefile("files/baz", "baz\nAAA\nbbb\nccc") commit("testbranch", "first") first = base_revision() revert_to(base) -writefile("foo", "foo\nsecond\nrevision") -writefile("bar", "bar\none\ntwo\nthree\nfour") -writefile("baz", "baz\nAaa\nbbb\nCCC") +writefile("files/foo", "foo\nsecond\nrevision") +writefile("files/bar", "bar\none\ntwo\nthree\nfour") +writefile("files/baz", "baz\nAaa\nbbb\nCCC") commit("testbranch", "second") second = base_revision() -check(mtn("automate", "show_conflicts", first, second), 0, true, nil) -canonicalize("stdout") -check(samefilestd("conflicts-1", "stdout")) +check(indir("files", mtn("conflicts", "store", first, second)), 0, nil, nil) +check(samefilestd("conflicts-1", "_MTN/conflicts")) -writefile("foo", "foo\nmerged\nrevision") +-- foo and baz can't be handled by the internal line merger. We +-- specify one user file in _MTN, one out, to ensure mtn handles both. +writefile("files/foo", "foo\nmerged\nrevision") mkdir("_MTN/result") writefile("_MTN/result/baz", "baz\nAaa\nBbb\nCcc") --- foo and baz can't be handled by the internal line merger. We --- specify one user file in _MTN, one out, to ensure mtn handles both. -check(get("resolve-conflicts-1", "_MTN/conflicts")) -check(mtn("merge", "--resolve-conflicts-file=_MTN/conflicts"), 0, nil, true) +check(indir("files", mtn("conflicts", "resolve_first", "user", "../_MTN/result/baz")), 0, nil, nil) +check(indir("files", mtn("conflicts", "resolve_first", "user", "foo")), 0, nil, nil) +check(samefilestd("conflicts-2", "_MTN/conflicts")) + +check(mtn("merge", "--resolve-conflicts"), 0, nil, true) canonicalize("stderr") check(samefilestd("merge-1", "stderr")) @@ -40,7 +47,7 @@ check(samefilestd("update-1", "stderr")) canonicalize("stderr") check(samefilestd("update-1", "stderr")) -check(readfile("foo") == "foo\nmerged\nrevision") -check(readfile("bar") == "bar\nzero\none\ntwo\nthree\nfour\n") -check(readfile("baz") == "baz\nAaa\nBbb\nCcc") +check(readfile("files/foo") == "foo\nmerged\nrevision") +check(readfile("files/bar") == "bar\nzero\none\ntwo\nthree\nfour\n") +check(readfile("files/baz") == "baz\nAaa\nBbb\nCcc") -- end of file ============================================================ --- tests/resolve_content_conflict/conflicts-1 a22968fd0a299175d4444e778b712bbcf8a4377a +++ tests/resolve_content_conflict/conflicts-1 97fe0c8dfc0a80ab005b6799ed04a949eebad177 @@ -1,31 +1,31 @@ - left [c28c3c0f5a7f9cde848be91f79d86a6dd63e88ca] - right [92bba9973b061f3617638edbc32610f7712b7a51] -ancestor [4c059d3a8bbe8e624e46a50b298b4f301caf380d] + left [36cfb5960784df07636cc9d119617326fe87c3f6] + right [be155249f011e658f913c109bafd743b1bfea0fe] +ancestor [574e08409c35c5c0eb6e929bf1e3abf49a8bacd4] conflict content node_type "file" - ancestor_name "bar" + ancestor_name "files/bar" ancestor_file_id [fc8a40f0b775e86503c7522399f309f6ac298348] - left_name "bar" + left_name "files/bar" left_file_id [bf227d19bccee7740bb58219910ff0930b6200c1] - right_name "bar" + right_name "files/bar" right_file_id [5fd4e3cf64e24e969cfcd2380cf244aee9e52d5d] resolved_internal conflict content node_type "file" - ancestor_name "baz" + ancestor_name "files/baz" ancestor_file_id [ae708173915e11248629c18d16c96c3a34f87d16] - left_name "baz" + left_name "files/baz" left_file_id [c438704db55b0d6f819e7e79c1622e5d757b926b] - right_name "baz" + right_name "files/baz" right_file_id [b87f48c43f61d258cc0b12d07bd53a7ddde357a9] conflict content node_type "file" - ancestor_name "foo" + ancestor_name "files/foo" ancestor_file_id [0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33] - left_name "foo" + left_name "files/foo" left_file_id [841e3d2ada1a56123f9efe9db0d0c045ff9e6d8f] - right_name "foo" + right_name "files/foo" right_file_id [3506995775abf41d3cdeb1e0417bdd3bcf059395] ============================================================ --- tests/resolve_content_conflict/resolve-conflicts-1 3eb53a39fb89990b37289518600c27530a2f543f +++ tests/resolve_content_conflict/conflicts-2 257ff33f262f63e892785c5b98f5f998ca8e6adf @@ -1,33 +1,33 @@ - left [c28c3c0f5a7f9cde848be91f79d86a6dd63e88ca] - right [9340b41fa26b20293292cb37449cc722b1b55a5a] -ancestor [4c059d3a8bbe8e624e46a50b298b4f301caf380d] + left [36cfb5960784df07636cc9d119617326fe87c3f6] + right [be155249f011e658f913c109bafd743b1bfea0fe] +ancestor [574e08409c35c5c0eb6e929bf1e3abf49a8bacd4] conflict content node_type "file" - ancestor_name "bar" + ancestor_name "files/bar" ancestor_file_id [fc8a40f0b775e86503c7522399f309f6ac298348] - left_name "bar" + left_name "files/bar" left_file_id [bf227d19bccee7740bb58219910ff0930b6200c1] - right_name "bar" + right_name "files/bar" right_file_id [5fd4e3cf64e24e969cfcd2380cf244aee9e52d5d] -resolved_internal +resolved_internal - conflict content - node_type "file" - ancestor_name "baz" - ancestor_file_id [ae708173915e11248629c18d16c96c3a34f87d16] - left_name "baz" - left_file_id [c438704db55b0d6f819e7e79c1622e5d757b926b] - right_name "baz" - right_file_id [f0ef173c31428d85dcca6399de12c6352f8b72b3] -resolved_user "_MTN/result/baz" + conflict content + node_type "file" + ancestor_name "files/baz" +ancestor_file_id [ae708173915e11248629c18d16c96c3a34f87d16] + left_name "files/baz" + left_file_id [c438704db55b0d6f819e7e79c1622e5d757b926b] + right_name "files/baz" + right_file_id [b87f48c43f61d258cc0b12d07bd53a7ddde357a9] + resolved_user "_MTN/result/baz" conflict content node_type "file" - ancestor_name "foo" + ancestor_name "files/foo" ancestor_file_id [0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33] - left_name "foo" + left_name "files/foo" left_file_id [841e3d2ada1a56123f9efe9db0d0c045ff9e6d8f] - right_name "foo" + right_name "files/foo" right_file_id [3506995775abf41d3cdeb1e0417bdd3bcf059395] -resolved_user "foo" + resolved_user "files/foo" ============================================================ --- tests/resolve_content_conflict/merge-1 a1052f7f29160f099cd7781b8c4f4feabeba0551 +++ tests/resolve_content_conflict/merge-1 f25a8a6d4928ed2ff4c6101d6003e823842df02d @@ -1,10 +1,10 @@ mtn: calculating best pair of heads to m mtn: 2 heads on branch 'testbranch' mtn: merge 1 / 1: mtn: calculating best pair of heads to merge next -mtn: [left] 92bba9973b061f3617638edbc32610f7712b7a51 -mtn: [right] c28c3c0f5a7f9cde848be91f79d86a6dd63e88ca -mtn: merged bar, bar -mtn: replacing content of baz, baz with _MTN/result/baz -mtn: replacing content of foo, foo with foo -mtn: [merged] ad3e91f197b102b27435049513a87778550dfd89 +mtn: [left] 36cfb5960784df07636cc9d119617326fe87c3f6 +mtn: [right] be155249f011e658f913c109bafd743b1bfea0fe +mtn: merged files/bar, files/bar +mtn: replacing content of files/baz, files/baz with _MTN/result/baz +mtn: replacing content of files/foo, files/foo with files/foo +mtn: [merged] d18cecd65445fa5b10732c6ca8a8bbdac2a6610a mtn: note: your workspaces have not been updated ============================================================ --- tests/resolve_content_conflict/update-1 b0c1d97b8941efb8fae0cbc51b76db27d6ee91e6 +++ tests/resolve_content_conflict/update-1 6442c128317eb0b4b8597c8ed25188937c572f1b @@ -1,7 +1,7 @@ mtn: updating along branch 'testbranch' mtn: updating along branch 'testbranch' -mtn: selected update target ad3e91f197b102b27435049513a87778550dfd89 -mtn: [left] 97cdd788b32b8b7c3a43883a39ff8e213960eb42 -mtn: [right] ad3e91f197b102b27435049513a87778550dfd89 -mtn: modifying bar -mtn: modifying baz -mtn: updated to base revision ad3e91f197b102b27435049513a87778550dfd89 +mtn: selected update target d18cecd65445fa5b10732c6ca8a8bbdac2a6610a +mtn: [left] e9d684d80d320d181793766e43a2feb525d254f8 +mtn: [right] d18cecd65445fa5b10732c6ca8a8bbdac2a6610a +mtn: modifying files/bar +mtn: modifying files/baz +mtn: updated to base revision d18cecd65445fa5b10732c6ca8a8bbdac2a6610a ============================================================ --- tests/resolve_duplicate_name_conflict/__driver__.lua de6ac22eec67432fccd8a0a2cddac622b639e7c3 +++ tests/resolve_duplicate_name_conflict/__driver__.lua 895b0ad5b991fe29dac9dd64a849d2be7a2535b6 @@ -76,7 +76,7 @@ check(samefilestd("conflicts-resolved", check(samefilestd("conflicts-resolved", "_MTN/conflicts")) -- This succeeds -check(mtn("merge", "--resolve-conflicts-file", "_MTN/conflicts"), 0, nil, true) +check(mtn("merge", "--resolve-conflicts"), 0, nil, true) canonicalize("stderr") check(samefilestd("merge-1", "stderr"))