| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- Fix "mtn diff" output by handling the special cases of missing trailing
- newline at end of file. This makes the output compatible with GNU
- diffutils' diff(1) and especially allows it to be correctly applied with
- GNU patch(1) again, too.
- The source of the problem is that diff_patch:cc:make_diff() called the
- generic function simplestring_xform.cc:split_into_lines() for splitting
- the file data into individual lines, this way removed all(!) newlines at
- all and hence lost the information about the special case of a missing
- trailing newline.
- The least invasive fix is to already preserve the information in
- simplestring_xform.cc:split_into_lines() by representing the missing
- newline with the appended text "[\r]\n\\No newline at end of file" on
- the last line (notice that this is the only case were a line can still
- contain a newline after splitting).
- Additionally, diff_patch.cc:walk_hunk_consumer() for unknown reasons
- produces added before deleted lines (instead of the expection order of
- deleted before added lines) and hence also had to be fixed in order to
- produce output 100% compatible to GNU diff(1).
- Finally, two existing tests related to diff_patch.cc:walk_hunk_consumer()
- were adjusted and a new test suite was added for checking all four
- special cases related to the missing trailing newline. The complete
- Monotone test suite still succeeed with 0 failures after this change.
- Can be removed with Monotone >= 0.40!
- Index: diff_patch.cc
- --- diff_patch.cc e359a4c03c6ce548d6414dce11160fbcb6fcb831
- +++ diff_patch.cc daeb9be7d8c10d33781b54debd541027618dbfce
- @@ -1010,17 +1010,17 @@ void walk_hunk_consumer(vector<long, QA(
- while (idx(lines2,b) != *i)
- cons.insert_at(b++);
- }
- - if (b < lines2.size())
- + if (a < lines1.size())
- {
- cons.advance_to(a);
- - while(b < lines2.size())
- - cons.insert_at(b++);
- + while(a < lines1.size())
- + cons.delete_at(a++);
- }
- - if (a < lines1.size())
- + if (b < lines2.size())
- {
- cons.advance_to(a);
- - while(a < lines1.size())
- - cons.delete_at(a++);
- + while(b < lines2.size())
- + cons.insert_at(b++);
- }
- cons.flush_hunk(a);
- }
- @@ -1349,8 +1349,8 @@ make_diff(string const & filename1,
- }
-
- vector<string> lines1, lines2;
- - split_into_lines(data1(), lines1);
- - split_into_lines(data2(), lines2);
- + split_into_lines(data1(), lines1, true);
- + split_into_lines(data2(), lines2, true);
-
- vector<long, QA(long)> left_interned;
- vector<long, QA(long)> right_interned;
- Index: simplestring_xform.cc
- --- simplestring_xform.cc 5f2e4fcd288a2ec1fd59feb97ebc777b56597608
- +++ simplestring_xform.cc dcaa75eb0ed67ddc119ef62f06c21bd7d13bf5cb
- @@ -50,9 +50,24 @@ void split_into_lines(string const & in,
- }
-
- void split_into_lines(string const & in,
- + vector<string> & out,
- + bool diff_compat)
- +{
- + return split_into_lines(in, constants::default_encoding, out, diff_compat);
- +}
- +
- +void split_into_lines(string const & in,
- string const & encoding,
- vector<string> & out)
- {
- + return split_into_lines(in, encoding, out, false);
- +}
- +
- +void split_into_lines(string const & in,
- + string const & encoding,
- + vector<string> & out,
- + bool diff_compat)
- +{
- string lc_encoding = lowercase(encoding);
- out.clear();
-
- @@ -92,8 +107,16 @@ void split_into_lines(string const & in,
- break;
- end = in.find_first_of("\r\n", begin);
- }
- - if (begin < in.size())
- - out.push_back(in.substr(begin, in.size() - begin));
- + if (begin < in.size()) {
- + // special case: last line without trailing newline
- + string s = in.substr(begin, in.size() - begin);
- + if (diff_compat) {
- + // special handling: produce diff(1) compatible output
- + s += (in.find_first_of("\r") != string::npos ? "\r\n" : "\n");
- + s += "\\ No newline at end of file";
- + }
- + out.push_back(s);
- + }
- }
- else
- {
- Index: simplestring_xform.hh
- --- simplestring_xform.hh 0280d49b889bc0b7b2900d5d123cc8ec95a115eb
- +++ simplestring_xform.hh 564a305c99ca931c93956ac3ef903683dcb15db7
- @@ -13,6 +13,15 @@ void split_into_lines(std::string const
- std::string const & encoding,
- std::vector<std::string> & out);
-
- +void split_into_lines(std::string const & in,
- + std::vector<std::string> & out,
- + bool diff_compat);
- +
- +void split_into_lines(std::string const & in,
- + std::string const & encoding,
- + std::vector<std::string> & out,
- + bool diff_compat);
- +
- void join_lines(std::vector<std::string> const & in,
- std::string & out,
- std::string const & linesep);
- -----------------------------------------------------------------------------
- Fix merging in a special case.
- Can be removed with Monotone >= 0.40!
- --- roster_merge.cc d565f9299ca85d77bd1d7f2a29196d7161f0ea08
- +++ roster_merge.cc d113e5d648bd98bdc15ba7a53958496ea924bd2b
- @@ -525,15 +525,35 @@ roster_merge_result::report_duplicate_na
- left_roster.get_name(left_nid, left_name);
- right_roster.get_name(right_nid, right_name);
-
- - I(left_name == right_name);
- -
- shared_ptr<roster_t const> left_lca_roster, right_lca_roster;
- revision_id left_lca_rid, right_lca_rid;
-
- adaptor.get_ancestral_roster(left_nid, left_lca_rid, left_lca_roster);
- adaptor.get_ancestral_roster(right_nid, right_lca_rid, right_lca_roster);
-
- - P(F("conflict: duplicate name '%s'") % left_name);
- + // In most cases, the left_name equals the right_name. However, maybe
- + // a parent directory got renamed on one side. In that case, the names
- + // don't match, but it's still the same directory (by node id), to
- + // which we want to add the same file (by name).
- + if (left_name == right_name)
- + {
- + file_path dir;
- + path_component basename;
- + left_name.dirname_basename(dir, basename);
- + P(F("conflict: duplicate name '%s' for the directory '%s'") % basename % dir);
- + }
- + else
- + {
- + file_path left_dir, right_dir;
- + path_component left_basename, right_basename;
- + left_name.dirname_basename(left_dir, left_basename);
- + right_name.dirname_basename(right_dir, right_basename);
- + I(left_basename == right_basename);
- + P(F("conflict: duplicate name '%s' for the directory\n"
- + " named '%s' on the left and\n"
- + " named '%s' on the right.")
- + % left_basename % left_dir % right_dir);
- + }
-
- node_type left_type = get_type(left_roster, left_nid);
- node_type right_type = get_type(right_roster, right_nid);
|