5 // Joel Reed (joelwreed@gmail.com)
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
;
34 using Microsoft
.TeamFoundation
.Client
;
35 using Microsoft
.TeamFoundation
.VersionControl
.Client
;
36 using Microsoft
.TeamFoundation
.VersionControl
.Common
;
37 using Mono
.GetOptions
;
40 class OwnerStat
: IComparable
<OwnerStat
>
42 public OwnerStat(string owner
, int count
)
48 public int CompareTo(OwnerStat other
)
50 return other
.Count
.CompareTo(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
);
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;
112 changesByOwner
.Add(owner
, 1);
117 List
<OwnerStat
> ownerStats
= new List
<OwnerStat
>();
118 foreach (string owner
in changesByOwner
.Keys
)
120 ownerStats
.Add(new OwnerStat(owner
, changesByOwner
[owner
]));
124 foreach (OwnerStat stat
in ownerStats
)
126 Console
.WriteLine(stat
.Owner
.PadRight(maxOwnerLen
) + ": " + stat
.Count
);
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.");
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("~");
168 version
= VersionSpec
.ParseSingleSpec(OptionVersion
, Driver
.Username
);
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
);
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
),
245 Console
.WriteLine(line
);
246 if (!includeChanges
) continue;
248 foreach (Change change
in changeSet
.Changes
)
250 Console
.WriteLine(" " + ChangeTypeToString(change
.ChangeType
) + " " + change
.Item
.ServerItem
);