vs2008.compile.fixes
[tfs.git] / tools / opentf / DiffCommand.cs
blob2150451b7523634c741438857106a2a304dcf63a
1 using System;
2 using System.Security.Cryptography;
3 using System.IO;
4 using System.Collections;
5 using System.Collections.Generic;
6 using System.Text;
7 using Microsoft.TeamFoundation.Client;
8 using Microsoft.TeamFoundation.VersionControl.Common;
9 using Microsoft.TeamFoundation.VersionControl.Client;
10 using Mono.GetOptions;
11 using OpenTF.Common;
13 internal class FromToHash
15 public FromToHash(int itemId) { this.ItemId = itemId; }
17 public int ItemId;
18 public int FromChangesetId;
19 public int ToChangesetId;
20 public string FromHash;
21 public string ToHash;
24 [Command("difference", "Show pending changes, latest on server, a changeset, or local changes not pended as a unified diff.",
25 "<path>...", "diff")]
26 class DifferenceCommand : Command
28 [Option("Output only whether files differ", "q", "brief")]
29 public bool OptionBrief = false;
31 [Option("Look for modified files", "", "modified")]
32 public bool OptionModified = false;
34 [Option("Show out of date files (newer version on server)", "", "old")]
35 public bool OptionOld = false;
37 [Option("Ignore white space differences", "", "ignorespace")]
38 public bool OptionIgnoreWhiteSpace = false;
40 [Option("Owner name", "O", "owner")]
41 public string OptionOwner;
43 private MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
45 public DifferenceCommand(Driver driver, string[] args): base(driver, args)
49 protected DiffOptions GetDiffOptions()
51 DiffOptions options = new DiffOptions();
52 options.UseThirdPartyTool = false;
54 options.Flags = DiffOptionFlags.EnablePreambleHandling;
55 if (OptionIgnoreWhiteSpace) options.Flags |= DiffOptionFlags.IgnoreWhiteSpace;
57 options.OutputType = DiffOutputType.Unified;
58 options.TargetEncoding = Console.OutputEncoding;
59 options.SourceEncoding = Console.OutputEncoding;
60 options.StreamWriter = new StreamWriter(Console.OpenStandardOutput(),
61 Console.OutputEncoding);
62 options.StreamWriter.AutoFlush = true;
64 return options;
67 public void Usage()
69 Console.WriteLine("Usage: tf diff [path | <changeset id> | <server path> <from versionSpec> <to versionSpec> | /old | /modified ]");
70 Environment.Exit((int)ExitCode.Failure);
73 VersionSpec GetValidVersionSpec(string arg)
75 VersionSpec versionSpec = null;
77 try
79 versionSpec = VersionSpec.ParseSingleSpec(arg, OwnerFromString(OptionOwner));
81 catch (System.FormatException exception)
83 Console.WriteLine("Invalid version specification: " + arg);
84 Environment.Exit((int)ExitCode.Failure);
87 return versionSpec;
90 public void ShowModifiedFiles(Workspace workspace, string path)
92 char[] charsToTrim = { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar};
93 string itemPath = path.TrimEnd(charsToTrim);
95 workspace.RefreshMappings();
96 string serverPath = workspace.GetServerItemForLocalItem(itemPath);
98 // pull item list based on WorkspaceVersion. otherwise might get
99 // new items on server that haven't been pulled yet in the list returned
100 WorkspaceVersionSpec version = new WorkspaceVersionSpec(workspace);
102 // get item list from TFS server
103 ItemSpec itemSpec = new ItemSpec(itemPath, RecursionType.Full);
104 ItemSet itemSet = VersionControlServer.GetItems(itemSpec, version, DeletedState.NonDeleted, ItemType.Any, true);
105 Item[] items = itemSet.Items;
107 foreach (Item item in items)
109 if (item.ItemType != ItemType.File) continue;
110 if (item.ServerItem.Length == serverPath.Length) continue;
111 string serverItem = item.ServerItem.Remove(0, serverPath.Length+1);
113 // server item paths are separated with '/', but on windows the file list below has '\' separated paths
114 if (Path.DirectorySeparatorChar != '/')
115 serverItem = serverItem.Replace('/', Path.DirectorySeparatorChar);
117 // only looking for modifications, not deletes or adds
118 string fname = Path.Combine(itemPath, serverItem);
119 if (!File.Exists(fname)) continue;
120 if (FileAttributes.ReadOnly == (File.GetAttributes(fname) & FileAttributes.ReadOnly))
121 continue;
123 using (FileStream fileStream = new FileStream(fname, FileMode.Open, FileAccess.Read))
125 string localHash = Convert.ToBase64String(md5.ComputeHash(fileStream));
126 string itemHash = Convert.ToBase64String(item.HashValue);
127 if (itemHash == localHash) continue;
130 string p = fname.Substring(itemPath.Length+1);
131 if (OptionBrief)
133 Driver.WriteLine(CanonicalPath(p));
134 continue;
137 string tnameA = Path.GetTempFileName();
138 item.DownloadFile(tnameA);
139 IDiffItem a = new DiffItemLocalFile(tnameA, item.Encoding, DateTime.Now, false);
141 IDiffItem b = new DiffItemLocalFile(fname, item.Encoding, DateTime.Now, false);
143 Difference.DiffFiles(VersionControlServer, a, b,
144 GetDiffOptions(), p, true);
146 if (!String.IsNullOrEmpty(tnameA)) File.Delete(tnameA);
150 public void ShowOldFiles(Workspace workspace, string path)
152 // process command options
153 ItemSpec itemSpec = new ItemSpec(path, RecursionType.Full);
155 List<ItemSpec> itemSpecs = new List<ItemSpec>();
156 itemSpecs.Add(itemSpec);
158 ExtendedItem[][] items = workspace.GetExtendedItems(itemSpecs.ToArray(),
159 DeletedState.NonDeleted, ItemType.Any);
161 foreach (ExtendedItem[] itemArray in items)
163 foreach (ExtendedItem item in itemArray)
165 if (item.IsLatest) continue;
167 string p = item.LocalItem.Substring(path.Length);
168 if (OptionBrief)
170 Driver.WriteLine(p);
171 continue;
174 IDiffItem a = new DiffItemNull();
175 IDiffItem b = new DiffItemNull();
177 if ((item.ChangeType & ChangeType.Add) != ChangeType.Add)
179 a = new DiffItemLocalFile(item.LocalItem, item.Encoding,
180 DateTime.Now, false);
183 if ((item.ChangeType & ChangeType.Delete) != ChangeType.Delete)
185 b = new DiffItemVersionedFile(VersionControlServer,
186 item.ItemId, item.VersionLatest, item.LocalItem);
189 Difference.DiffFiles(VersionControlServer, a, b,
190 GetDiffOptions(), p, true);
195 void ShowChangesBetweenVersions(VersionSpec fromVersionSpec,
196 VersionSpec toVersionSpec, string serverPath)
198 SortedList<string, FromToHash> itemHashes = new SortedList<string, FromToHash>(StringComparer.CurrentCultureIgnoreCase);
200 ItemSet fromItemSet = VersionControlServer.GetItems(serverPath, fromVersionSpec,
201 RecursionType.Full);
202 Item[] fromItems = fromItemSet.Items;
204 foreach (Item item in fromItems)
206 if (item.ItemType != ItemType.File) continue;
207 if (item.ServerItem.Length == serverPath.Length) continue;
209 FromToHash fromToHash = new FromToHash(item.ItemId);
210 fromToHash.FromHash = Convert.ToBase64String(item.HashValue);
211 fromToHash.FromChangesetId = item.ChangesetId;
213 itemHashes.Add(item.ServerItem, fromToHash);
216 ItemSet toItemSet = VersionControlServer.GetItems(serverPath, toVersionSpec,
217 RecursionType.Full);
218 Item[] toItems = toItemSet.Items;
220 foreach (Item item in toItems)
222 if (item.ItemType != ItemType.File) continue;
223 if (item.ServerItem.Length == serverPath.Length) continue;
225 string hash = Convert.ToBase64String(item.HashValue);
226 if (!itemHashes.ContainsKey(item.ServerItem))
228 FromToHash fromToHash = new FromToHash(item.ItemId);
229 fromToHash.ToHash = hash;
230 fromToHash.ToChangesetId = item.ChangesetId;
231 itemHashes.Add(item.ServerItem, fromToHash);
233 else
235 FromToHash fromToHash = itemHashes[item.ServerItem];
236 fromToHash.ToHash = hash;
237 fromToHash.ToChangesetId = item.ChangesetId;
241 foreach (string key in itemHashes.Keys)
243 FromToHash fromToHash = itemHashes[key];
244 if (fromToHash.FromHash == fromToHash.ToHash) continue;
246 if (OptionBrief)
248 Driver.WriteLine(key);
249 continue;
252 IDiffItem a = new DiffItemNull();
253 IDiffItem b = new DiffItemNull();
255 if (!String.IsNullOrEmpty(fromToHash.FromHash))
257 a = new DiffItemVersionedFile(VersionControlServer,
258 fromToHash.ItemId, fromToHash.FromChangesetId, key);
261 if (!String.IsNullOrEmpty(fromToHash.ToHash))
263 b = new DiffItemVersionedFile(VersionControlServer,
264 fromToHash.ItemId, fromToHash.ToChangesetId, key);
267 string p = key.Substring(2);
268 Difference.DiffFiles(VersionControlServer, a, b,
269 GetDiffOptions(), p, true);
273 void ShowPendingChanges(Workspace workspace, string[] paths)
275 PendingChange[] pendingChanges = workspace.GetPendingChanges(paths, RecursionType.Full, true);
276 if (pendingChanges.Length == 0)
278 Console.WriteLine("No pending changes.");
279 Environment.Exit((int)ExitCode.PartialSuccess);
282 string cwd = Environment.CurrentDirectory;
283 foreach (PendingChange change in pendingChanges)
285 string p = change.LocalItem;
286 if (p.StartsWith(cwd)) p = p.Substring(cwd.Length+1);
288 if (OptionBrief)
290 Driver.WriteLine(CanonicalPath(p));
291 continue;
294 IDiffItem a = new DiffItemNull();
295 IDiffItem b = new DiffItemNull();
297 string tname = null;
298 if (!change.IsAdd)
300 tname = Path.GetTempFileName();
301 change.DownloadBaseFile(tname);
303 a = new DiffItemLocalFile(tname, change.Encoding,
304 change.CreationDate, true);
307 if (!change.IsDelete)
309 b = new DiffItemLocalFile(change.LocalItem, change.Encoding,
310 change.CreationDate, false);
313 Difference.DiffFiles(VersionControlServer, a, b,
314 GetDiffOptions(), p, true);
316 if (!String.IsNullOrEmpty(tname))
317 File.Delete(tname);
321 public void ProcessOldAndModified(Workspace workspace)
323 string path = Environment.CurrentDirectory;
324 if (Arguments.Length > 0)
326 path = Path.GetFullPath(Arguments[0]);
329 if (OptionOld) ShowOldFiles(workspace, path);
330 else ShowModifiedFiles(workspace, path);
333 public override void Run()
335 Workspace workspace = GetWorkspaceFromCache();
336 if (OptionOld || OptionModified)
338 ProcessOldAndModified(workspace);
339 Environment.Exit((int)ExitCode.Success);
342 if (Arguments.Length == 0 || File.Exists(Arguments[0])
343 || Directory.Exists(Arguments[0]))
345 List<string> paths;
346 paths = VerifiedFullPaths(Arguments);
347 if (paths.Count == 0) paths.Add(Environment.CurrentDirectory);
348 ShowPendingChanges(workspace, paths.ToArray());
349 Environment.Exit((int)ExitCode.Success);
352 if (Arguments.Length == 1)
354 string arg = Arguments[0];
355 VersionSpec versionSpec = GetValidVersionSpec(arg);
357 if (versionSpec is ChangesetVersionSpec)
358 DiffHelper.ShowChangeset(VersionControlServer,
359 versionSpec as ChangesetVersionSpec,
360 OptionBrief, GetDiffOptions());
361 Environment.Exit((int)ExitCode.Success);
364 VersionSpec fromVersionSpec = GetValidVersionSpec(Arguments[0]);
365 VersionSpec toVersionSpec = GetValidVersionSpec(Arguments[1]);
367 if (fromVersionSpec == null || toVersionSpec == null)
368 Usage();
370 string localPath = Environment.CurrentDirectory;
371 string serverPath = null;
372 if (Arguments.Length > 2)
374 if (VersionControlPath.IsServerItem(Arguments[2]))
375 serverPath = Arguments[2];
376 else
377 localPath = Path.GetFullPath(Arguments[2]);
380 if (String.IsNullOrEmpty(serverPath))
382 workspace.RefreshMappings();
383 serverPath = workspace.GetServerItemForLocalItem(localPath);
386 ShowChangesBetweenVersions(fromVersionSpec, toVersionSpec, serverPath);