show the difference between two versions for a specified path
[tfs.git] / tools / opentf / HistoryCommand.cs
blob20748e6ed3e7c7541ae24bcb4198520d00737367
1 //
2 // HistoryCommand.cs
3 //
4 // Authors:
5 // Joel Reed (joelwreed@gmail.com)
6 //
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
29 using System;
30 using System.Collections;
31 using System.Collections.Generic;
32 using System.IO;
33 using System.Text;
34 using Microsoft.TeamFoundation.Client;
35 using Microsoft.TeamFoundation.VersionControl.Client;
36 using Microsoft.TeamFoundation.VersionControl.Common;
37 using Mono.GetOptions;
38 using OpenTF.Common;
40 class OwnerStat : IComparable<OwnerStat>
42 public OwnerStat(string owner, int count)
44 Owner = owner;
45 Count = count;
48 public int CompareTo(OwnerStat other)
50 return other.Count.CompareTo(Count);
53 public string Owner;
54 public int Count;
57 [Command("history", "Display changelog history for specified file.", "<path>...", "hist")]
58 class HistoryCommand : Command
60 [Option("Format \"brief\", \"detailed\", \"byowner\"", "F", "format")]
61 public string OptionFormat = "";
63 [Option("Recursive", "R", "recursive")]
64 public bool OptionRecursive = false;
66 [Option("Limit the number of changesets shown", "", "stopafter")]
67 public int OptionStopAfter = -1;
69 [Option("Version of item for which to show the history", "V", "version")]
70 public string OptionVersion;
72 [Option("Username for filtering history results", "", "user")]
73 public string OptionUser;
75 [Option("Format of date/time output.", "", "datetime")]
76 public String OptionDateTimeFormat = "d";
78 public HistoryCommand(Driver driver, string[] args): base(driver, args)
82 private string StripDomainPrefix(string name)
84 int slash = name.IndexOf('\\');
85 if (-1 == slash) return name;
87 return name.Substring(slash + 1);
90 public void ByOwnerOutput(IEnumerable changeSets, int stopAfter)
92 Console.WriteLine("This could take some time... processing up to {0} changesets\n", stopAfter);
94 int total = 0;
95 int maxOwnerLen = 0;
97 DateTime maxTime = new DateTime();
98 Dictionary<string, int> changesByOwner = new Dictionary<string, int>();
100 Changeset lastChangeSet = null;
101 foreach (Changeset changeSet in changeSets)
103 if (total == 0) maxTime = changeSet.CreationDate;
104 lastChangeSet = changeSet;
106 string owner = StripDomainPrefix(changeSet.Owner);
107 if (owner.Length > maxOwnerLen) maxOwnerLen = owner.Length;
109 if (changesByOwner.ContainsKey(owner))
110 changesByOwner[owner] += 1;
111 else
112 changesByOwner.Add(owner, 1);
114 total++;
117 List<OwnerStat> ownerStats = new List<OwnerStat>();
118 foreach (string owner in changesByOwner.Keys)
120 ownerStats.Add(new OwnerStat(owner, changesByOwner[owner]));
123 ownerStats.Sort();
124 foreach (OwnerStat stat in ownerStats)
126 Console.WriteLine(stat.Owner.PadRight(maxOwnerLen) + ": " + stat.Count);
129 Console.WriteLine();
130 Console.WriteLine("{0}: {1} to {2}", "Time Span".PadRight(maxOwnerLen),
131 lastChangeSet.CreationDate.ToString("d"), maxTime.ToString("d"));
132 Console.WriteLine("{0}: {1}", "Total".PadRight(maxOwnerLen), total);
135 public override void Run()
137 bool defaultCwdSetting = Settings.Current.GetAsBool("History.DefaultToCwd");
138 string path = Environment.CurrentDirectory;
140 if (Arguments.Length > 0) path = Arguments[0];
141 else if (!defaultCwdSetting)
143 Console.WriteLine("The history command takes exactly one item.");
144 return;
147 if (!VersionControlPath.IsServerItem(path)) path = Path.GetFullPath(path);
149 RecursionType rtype = OptionRecursive ? RecursionType.Full : RecursionType.None;
150 bool histSetting = Settings.Current.GetAsBool("History.Recursive");
151 if (histSetting) rtype = RecursionType.Full;
153 bool includeChanges = Settings.Current.GetAsBool("History.Detailed");
154 if (!String.IsNullOrEmpty(OptionFormat))
155 includeChanges = OptionFormat.Equals("detailed", StringComparison.InvariantCultureIgnoreCase);
157 int stopAfter = Settings.Current.GetAsInt("History.StopAfter");
158 if (OptionStopAfter != -1) stopAfter = OptionStopAfter;
160 VersionSpec version = VersionSpec.Latest;
161 VersionSpec toVersion = null;
162 VersionSpec fromVersion = null;
164 if (!String.IsNullOrEmpty(OptionVersion))
166 int tilda = OptionVersion.IndexOf("~");
167 if (tilda == -1)
168 version = VersionSpec.ParseSingleSpec(OptionVersion, Driver.Username);
169 else
171 string from = OptionVersion.Substring(0, tilda);
172 if (!String.IsNullOrEmpty(from))
173 fromVersion = VersionSpec.ParseSingleSpec(from, Driver.Username);
175 string to = OptionVersion.Substring(tilda + 1);
176 if (!String.IsNullOrEmpty(to))
177 toVersion = VersionSpec.ParseSingleSpec(to, Driver.Username);
181 IEnumerable changeSets = VersionControlServer.QueryHistory(path, version, 0, rtype, OptionUser,
182 fromVersion, toVersion,
183 stopAfter, includeChanges, false, false);
185 if (OptionFormat.Equals("byowner", StringComparison.InvariantCultureIgnoreCase))
187 ByOwnerOutput(changeSets, stopAfter);
188 Environment.Exit((int)ExitCode.Success);
191 int maxId = "Changeset".Length, maxOwner = 5, maxDate = 6;
192 foreach (Changeset changeSet in changeSets)
194 string id = Convert.ToString(changeSet.ChangesetId);
195 if (id.Length > maxId) maxId = id.Length;
197 string date = changeSet.CreationDate.ToString(OptionDateTimeFormat);
198 if (date.Length > maxDate) maxDate = date.Length;
200 string name = StripDomainPrefix(changeSet.Owner);
201 int ownerNameLen = name.Length;
203 if (ownerNameLen > maxOwner)
205 maxOwner = ownerNameLen;
209 int maxComment = WindowWidth - maxId - maxOwner - maxDate - 5;
211 string line = String.Format("{0} {1} {2} {3}",
212 "Changeset".PadRight(maxId),
213 "User".PadRight(maxOwner),
214 "Date".PadRight(maxDate),
215 "Comment".PadRight(maxComment));
216 Console.WriteLine(line);
218 line = String.Format("{0} {1} {2} {3}",
219 "-".PadRight(maxId, '-'),
220 "-".PadRight(maxOwner, '-'),
221 "-".PadRight(maxDate, '-'),
222 "-".PadRight(maxComment, '-'));
224 Console.WriteLine(line);
226 foreach (Changeset changeSet in changeSets)
228 string comment = "none";
229 if (changeSet.Comment != null)
231 if (changeSet.Comment.Length > maxComment)
232 comment = changeSet.Comment.Remove(maxComment);
233 else
234 comment = changeSet.Comment;
237 // domain is stripped on output
238 string owner = StripDomainPrefix(changeSet.Owner);
239 line = String.Format("{0} {1} {2} {3}",
240 Convert.ToString(changeSet.ChangesetId).PadRight(maxId),
241 owner.PadRight(maxOwner),
242 changeSet.CreationDate.ToString(OptionDateTimeFormat).PadRight(maxDate),
243 comment);
245 Console.WriteLine(line);
246 if (!includeChanges) continue;
248 foreach (Change change in changeSet.Changes)
250 Console.WriteLine(" " + ChangeTypeToString(change.ChangeType) + " " + change.Item.ServerItem);