Bug 150591 - [Patch] Team -> Apply Patch and line endings
Summary: [Patch] Team -> Apply Patch and line endings
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Compare (show other bugs)
Version: 3.1.2   Edit
Hardware: PC Windows XP
: P3 major with 2 votes (vote)
Target Milestone: 3.5 M5   Edit
Assignee: Pawel Pogorzelski CLA
QA Contact:
URL:
Whiteboard:
Keywords: bugday, helpwanted
: 230888 (view as bug list)
Depends on:
Blocks:
 
Reported: 2006-07-13 22:10 EDT by Jayson CLA
Modified: 2009-06-03 11:22 EDT (History)
8 users (show)

See Also:


Attachments
Screenshot of the Apply Patch preview, about to change the line endings from Windows to UNIX (156.85 KB, image/png)
2007-09-17 08:43 EDT, Chris Paton CLA
no flags Details
Proposed patch against CVS head (710 bytes, patch)
2008-02-16 18:20 EST, Chris Paton CLA
pawel.pogorzelski1: iplog+
Details | Diff
Test cases (13.48 KB, patch)
2008-08-11 06:51 EDT, Tomasz Zarna CLA
no flags Details | Diff
Patch v01 (2.23 KB, patch)
2008-08-11 06:54 EDT, Tomasz Zarna CLA
no flags Details | Diff
mylyn/context/zip (40.34 KB, application/octet-stream)
2008-08-11 06:54 EDT, Tomasz Zarna CLA
no flags Details
Chris' patch updated (735 bytes, patch)
2008-09-29 10:12 EDT, Tomasz Zarna CLA
no flags Details | Diff
Patch for test cases (1.26 KB, patch)
2008-12-11 07:49 EST, Pawel Pogorzelski CLA
pawel.pogorzelski1: iplog+
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jayson CLA 2006-07-13 22:10:40 EDT
Greetings,

It seems that when you use the Team -> Apply Patch feature in Eclipse, there is a bug that modifies the line-endings in the file. 

Example: 

afile.txt is an ascii file with \n line endings

You apply a patch that is also an ascii file with \n line endings

The result is that afile.txt now has \r\n line endings on every line in the file, even the lines not modified by the patch (there should only be \n endings). This is unexpected behavior and can lead to much grief later. 

One problem this causes is that when you later do a compare against CVS, the whole file appears to be one big change, which is not good. The file must be converted back to its original line endings (using something like dos2unix) before comparisons are useful again. 

I have looked in my settings and the only thing that seemed relevant was the "Convert text files to use platform line ending" option under Team -> CVS -> Files and Folders, and it is unchecked. 

Am I doing something wrong?
Comment 1 Michael Valenta CLA 2006-07-14 08:59:27 EDT
The problem is that the Apply Patch wizard probably uses a Reader and Writer for accessing and writting file contents. Readers will break on any well known line break character but Writers (at least by default) use the platform line ending. Correcting the problem would require that the Apply Patch wizard look at the line endings in the file and preserve them when writing the patched version back out.
Comment 2 Michael Valenta CLA 2006-07-14 11:04:09 EDT
There is also a File>Convert Line Delimeters submenu in Eclipse which allows use to convert line delimeters as well.
Comment 3 Chris Paton CLA 2007-09-17 08:40:56 EDT
Just wanted to report that this is still an issue with Eclipse 3.3, and occurs on Linux as well as Windows.

In my case, I:
1. Ran Eclipse 3.3 on Linux (with my workspace set to use default line endings)
2. Created a file and used File | Convert Line Delimiters To Windows
3. Created a patch for the file (also using Windows delimiters)
4. Applied the patch using Team | Apply Patch
5. Noted in the preview that all the line endings in the "After Patch" pane have been changed to UNIX line endings (see attached screenshot)

I did try changing the workspace line ending setting to Windows in case this setting was being used by the Apply Patch wizard. This is not the case; the platform line endings are always used, which lends weight to Michael's theory in comment #2.

If someone can point me in the right direction (I've not done any community development before) then I'd be happy to have a look into this since I feel it's an important bug. As it stands, the apply patch functionality is useless when working with files that have line endings that differ from that of the current platform---a fairly common scenario these days.

Comment 4 Chris Paton CLA 2007-09-17 08:43:16 EDT
Created attachment 78544 [details]
Screenshot of the Apply Patch preview, about to change the line endings from Windows to UNIX
Comment 5 Michael Valenta CLA 2007-09-17 09:17:04 EDT
Chris, thanks for you offer to help. The code in question is found in the org.eclipse.compare plug-in in the repository :pserver:anonymous@dev.eclipse.org:/cvsroot/eclipse. The class/method that handles patch application is org.eclipse.compare.internal.patch.Patcher#applyAll.
Comment 6 Chris Paton CLA 2008-02-16 18:20:19 EST
Created attachment 89918 [details]
Proposed patch against CVS head

I finally got around to looking at this like I said I would, although it took me long enough!

Anyway, Patcher.isPreserveLineDelimeters() is used in 4 places (Patcher.applyAll and WorkspacePatcher.applyAll) where the code stores the results of applying a diff into a file. It's also used in PatchFileTypedElement.getContents() when loading the left/right/ancestor files from disk.

My patch very simply changes Patcher.isPreserveLineDelimeters() to return true instead of false; this resolves the bug for me. Browsing the code, I don't think that this is likely to cause any ill-effects, but I'm keen to get feedback from folk.
Comment 7 Tomasz Zarna CLA 2008-02-19 07:42:50 EST
Thanks for the patch Chris, it coulnd't be more straightforward. I've got one concern though. I'm afraid that the code looks and works like this for a reason, is that right Michael? 

I must admit it would work better with your patch, but sometimes things aren't that easy. I think we should keep backward compatibility even for stuff which doesn't work perfectly. In other words, some people might got used to this "unexpected behaviour". This is how it should be done, but in my opinion we can apply the patch and probably get away with it.

An answer to this issue could be a preference called (surprisingly) "Preserve line delimiters". It could be used for applying and copying (left to right and vice versa) in a compare editor. But still, we will need to decide whether the option should be on by default.

How does it sound? Michael, what do you think?
Comment 8 Chris Paton CLA 2008-04-17 17:22:58 EDT
Any further thoughts on this?

From my perspective, I can't imagine why anyone would expect/desire the apply patch wizard to convert all the line endings to the current platform's line ending style. So in that respect the simplest solution is just to go with my patch. ;-)

However, if the consensus is that people are relying on the existing behaviour then I'd be happy to try and implement a compatibility option. That said, I've never done any serious SWT/JFace work so I'll have to see how far I get!
Comment 9 Michael Valenta CLA 2008-04-22 12:03:36 EDT
Sorry, I didn't realize this was gated on my response. When applying a patch, I think that the line endings in the target file should be preserved. If that's all that the change in the patch does, then I think it is the right thing to do (i.e. we need to make sure there are no other side effects). 
Comment 10 Tomasz Zarna CLA 2008-04-23 07:27:16 EDT
Assigning to myself so I won't forget to double check the patch and release it.
Comment 11 Tomasz Zarna CLA 2008-08-11 06:44:25 EDT
The patch looks fine, however it doesn't cover all the cases. In comment 0, it's mentioned that if there is a file with \n line endings and you apply a patch with \n line endings you will get a patched file with \r\n. Turning the isPreserveLineDelimeters flag to true does fix this issue, the problem is that it does it only when saving a patched file to disk (or displaying the result in UI[1]). IMO having it fixed on a lower level would be much better (and easier to test). For example changing the value returned by isPreserveLineDelimiters method doesn't affect the result kept in FileDiffResult object, which still contains patched lines with invalid delimiters.

The other thing which concerns me, is the way isPreserveLineDelimiters changes the patched file. It does either replace all line endings to a standard one for the given platform or leave them as they are. It works fine if a file to patch and a patch file have the same delimiters. If they are different (eg lf for file and crlf for patch) you will end up with a patched file with mixed endings. A desired result would kept the line delimiter from the original file and set it for the whole file (eg lf for the previous example).

I will send my proposition of the patch + test cases in a minute.

[1] org.eclipse.compare.internal.patch.PatchFileTypedElement.getContents()
Comment 12 Tomasz Zarna CLA 2008-08-11 06:51:50 EDT
Created attachment 109644 [details]
Test cases

These are different configuration of line endings for a file to patch, patch file and expected result. The assumption is that the line endings should be the same in the original file as in the one with expected result. Neither the patching mechanism nor the line endings in the patch should change it.

PS. I'm afraid that the patch won't work when applied since it has all line endings replaced with CRLF by CVS :/ I hope that commiting it from my workspace will preserve the line delimiters.
Comment 13 Tomasz Zarna CLA 2008-08-11 06:54:22 EDT
Created attachment 109645 [details]
Patch v01
Comment 14 Tomasz Zarna CLA 2008-08-11 06:54:26 EDT
Created attachment 109646 [details]
mylyn/context/zip
Comment 15 Tomasz Zarna CLA 2008-08-11 06:56:43 EDT
(In reply to comment #12)
> PS. I'm afraid that the patch won't work when applied since it has all line
> endings replaced with CRLF by CVS :/ I hope that committing it from my workspace
> will preserve the line delimiters.

This is tracked by by bug 107650.
Comment 16 Tomasz Zarna CLA 2008-08-11 07:16:11 EDT
*** Bug 230888 has been marked as a duplicate of this bug. ***
Comment 17 Tomasz Zarna CLA 2008-09-09 06:20:39 EDT
Tests and patch released to HEAD.
Comment 18 Pawel Pogorzelski CLA 2008-09-18 12:35:03 EDT
I tried to verify the fix on I20080918-0100. However I found a scenario in which the fix doesn't work.

OS: Windows XP
Steps:
1. Add two lines at the end of some file (lets say a.txt).
2. Create a patch.
3. Replace the a.txt with the latest from HEAD.
4. Change line delimeters in a.txt and the patch to be Unix.
5. Apply patch.

Expected result:
6a. File a.txt has Unix line delimeters.

Actual result:
6b. File a.txt has Windows line delimeters.
Comment 19 Szymon Brandys CLA 2008-09-18 12:36:23 EDT
See Pawel's comment above.
Comment 20 Tomasz Zarna CLA 2008-09-19 07:56:00 EDT
Pawel has offered his help here. Assigning to him.
Comment 21 Pawel Pogorzelski CLA 2008-09-19 10:35:52 EDT
Tomasz, you have to apply the patch provided by Chris in comment 4 for the fix to be complete.

The fix you released prevents from mixing line delimiters in case path and file being patched have different ones. But without Chris' patch this work gets ignored.

Tests have to be updated in order to catch this behaviour. Right now tests compare patched file in memory, without writing it onto disk. So, they cannot catch errors occurred while writing the result onto disk.
Comment 22 Pawel Pogorzelski CLA 2008-09-19 10:38:04 EDT
>> Tomasz, you have to apply the patch provided by Chris in comment 4 for the 
>> fix to be complete.

Actually it was in comment 6:)
Comment 23 Tomasz Zarna CLA 2008-09-29 10:09:43 EDT
I guess you're right, only when both patches are applied the patcher works as expected. But still I think it would be great if you could have a look at our tests and update them. I will release Chris' patch as soon as we have tests ready. Let's try to take advantage of test-first programming here.
Comment 24 Tomasz Zarna CLA 2008-09-29 10:12:30 EDT
Created attachment 113741 [details]
Chris' patch updated
Comment 25 Pawel Pogorzelski CLA 2008-10-31 09:11:20 EDT
We run out of time in 3.5 M3, changing target milestone to M4.
Comment 26 Pawel Pogorzelski CLA 2008-12-11 07:49:02 EST
Created attachment 120188 [details]
Patch for test cases

This is a fix to test cases suite that converts output of the patcher to the form that is used when writing onto disk. This is equal to comparing patched file to the expected file byte after byte (as they are stored on disk).

Tom, you have to change the property of all the files in patchdata in org.eclipse.compare.tests to binary. Right now I can't even determine line delimiters used in these files because they are changed on the fly wile serving them back to client.
Comment 27 Tomasz Zarna CLA 2008-12-11 08:43:01 EST
(In reply to comment #26)
> Tom, you have to change the property of all the files in patchdata in
> org.eclipse.compare.tests to binary.

Done. I've changed the properties to Binary, released the updated test from you and Chris' patch at the same time. Thanks Pawel!