2 // Microsoft.TeamFoundation.VersionControl.Client.Difference
5 // Joel Reed (joelwreed@gmail.com)
7 // Copyright (C) 2007 Joel Reed
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System
.Collections
;
31 using System
.Collections
.Generic
;
35 using Microsoft
.TeamFoundation
.VersionControl
.Common
;
37 namespace Microsoft
.TeamFoundation
.VersionControl
.Client
39 public static class Difference
41 internal static readonly int CONTEXT
= 3;
43 internal static void WriteHunkSet(StreamWriter stream
,
44 string[] a
, string[] b
, List
<Hunk
> hunkSet
)
46 if (hunkSet
.Count
== 0) return;
48 Hunk hunk1
= hunkSet
[0];
49 DiffItem item1
= hunk1
.Item
;
51 int ctxStartA
= Math
.Max(item1
.StartA
- CONTEXT
, -1);
52 int ctxStartB
= Math
.Max(item1
.StartB
- CONTEXT
, -1);
57 foreach (Hunk hunk
in hunkSet
)
59 linesA
+= hunk
.LinesA
;
60 linesB
+= hunk
.LinesB
;
63 string header
= String
.Format("@@ -{0},{1} +",
66 header
+= String
.Format("{0},", ctxStartB
+1);
67 header
+= String
.Format("{0} @@", linesB
);
69 // header += String.Format("{0},{1},{2},{3}",
70 // item1.StartA, item1.deletedA, item1.StartB, item1.insertedB);
72 stream
.WriteLine(header
);
74 foreach (Hunk hunk
in hunkSet
)
76 stream
.Write(hunk
.ToString(a
, b
));
80 internal static void WriteUnified(StreamWriter stream
,
81 string[] a
, string[] b
, DiffItem
[] items
)
83 List
<Hunk
> hunkSet
= new List
<Hunk
>();
84 for (int x
= 0; x
< items
.Length
; x
++)
86 DiffItem item
= items
[x
];
88 int prevDist
= CONTEXT
;
89 if (x
> 0) prevDist
= Math
.Min(CONTEXT
, item
.StartA
- (items
[x
-1].StartA
+ items
[x
-1].deletedA
));
91 int nextDist
= CONTEXT
;
92 if (x
< items
.Length
- 1) nextDist
= Math
.Min(CONTEXT
, items
[x
+1].StartA
- item
.StartA
- 1);
94 Hunk hunk
= new Hunk(item
, prevDist
, nextDist
, a
.Length
, b
.Length
);
97 if (nextDist
== CONTEXT
)
99 WriteHunkSet(stream
, a
, b
, hunkSet
);
104 WriteHunkSet(stream
, a
, b
, hunkSet
);
107 internal static void WriteNewFile(StreamWriter stream
,
110 DiffItem item
= new DiffItem();
111 item
.StartA
= 0; item
.StartB
= 0; item
.deletedA
= 0; item
.insertedB
= b
.Length
;
113 stream
.WriteLine(String
.Format("@@ -0,0 +1,{0} @@", b
.Length
));
114 Hunk hunk
= new Hunk(item
, 0, 0, 0, b
.Length
);
115 stream
.Write(hunk
.ToString(new string[0], b
));
118 internal static void WriteHeader(DiffItemUtil aItem
, DiffItemUtil bItem
,
119 DiffOptions diffOpts
)
121 StreamWriter stream
= diffOpts
.StreamWriter
;
122 stream
.Write("diff --tfs " + aItem
.Name
+ " ");
123 if (!String
.IsNullOrEmpty(diffOpts
.SourceLabel
))
124 stream
.Write(diffOpts
.SourceLabel
+ " ");
126 stream
.Write(bItem
.Name
);
127 if (!String
.IsNullOrEmpty(diffOpts
.TargetLabel
))
128 stream
.Write("@" + diffOpts
.TargetLabel
);
132 // the trailing tabs below help diffutils grok filenames with spaces
133 stream
.WriteLine("--- " + aItem
.Name
+ "\t");
134 stream
.WriteLine("+++ " + bItem
.Name
+ "\t");
137 public static void DiffFiles (VersionControlServer versionControl
,
138 IDiffItem source
, IDiffItem target
,
139 DiffOptions diffOpts
, string fileNameForHeader
,
142 DiffItemUtil aItem
= new DiffItemUtil('a', fileNameForHeader
, source
.GetFile());
143 DiffItemUtil bItem
= new DiffItemUtil('b', fileNameForHeader
, target
.GetFile());
144 StreamWriter stream
= diffOpts
.StreamWriter
;
146 // short circuit for binary file comparisions
147 if (source
.GetEncoding() == RepositoryConstants
.EncodingBinary
&& target
.GetEncoding() == RepositoryConstants
.EncodingBinary
)
149 stream
.WriteLine("Binary files {0} and {1} differ", aItem
.Name
, bItem
.Name
);
154 Gnome
.Vfs
.MimeType mimeType
= new Gnome
.Vfs
.MimeType(Gnome
.Vfs
.Mime
.TypeFromName(fileNameForHeader
));
155 if (!mimeType
.CanBeExecutable
)
157 stream
.WriteLine("Binary files {0} and {1} differ", aItem
.Name
, bItem
.Name
);
162 WriteHeader(aItem
, bItem
, diffOpts
);
164 // short circuit new files
165 if (aItem
.Length
== 0)
167 WriteNewFile(stream
, bItem
.Lines
);
171 Hashtable hashtable
= new Hashtable(aItem
.Length
+ bItem
.Length
);
172 bool ignoreWhiteSpace
= (diffOpts
.Flags
& DiffOptionFlags
.IgnoreWhiteSpace
) == DiffOptionFlags
.IgnoreWhiteSpace
;
174 DiffItem
[] items
= DiffUtil
.DiffText(hashtable
, aItem
.Lines
, bItem
.Lines
,
175 ignoreWhiteSpace
, ignoreWhiteSpace
, false);
177 WriteUnified(stream
, aItem
.Lines
, bItem
.Lines
, items
);