show the difference between two versions for a specified path
[tfs.git] / tools / opentf / LsFilesCommand.cs
blobd58b00db8b785f2d50d23e211b7b571d65f0fcc5
1 //
2 // LsFilesCommand.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.Security.Cryptography;
31 using System.Collections.Generic;
32 using System.IO;
33 using System.Text;
34 using Microsoft.TeamFoundation.Client;
35 using Microsoft.TeamFoundation.VersionControl.Common;
36 using Microsoft.TeamFoundation.VersionControl.Client;
37 using Mono.GetOptions;
39 [Command("ls-files", "Shows known, deleted, modified, old, or unknown files under the given path.",
40 "<path>")]
41 class LsFilesCommand : Command
43 [Option("Get all files, not just those out of date", "", "all")]
44 public bool OptionAll = false;
46 [Option("Look for deleted files.", "D", "deleted")]
47 public bool OptionDeleted = false;
49 [Option("Look for modified files.", "", "modified")]
50 public bool OptionModified = false;
52 [Option("Show out of date files (newer version on server)", "", "old")]
53 public bool OptionOld = false;
55 [Option("Show other/unknown files", "", "others")]
56 public bool OptionOthers = false;
58 [Option("Show writable files", "", "writable")]
59 public bool OptionWritable;
61 public LsFilesCommand(Driver driver, string[] args): base(driver, args)
65 public void PrintPath(string fullPath)
67 string p;
68 if (fullPath.StartsWith(Environment.CurrentDirectory))
69 p = fullPath.Substring(Environment.CurrentDirectory.Length+1);
70 else
71 p = fullPath;
73 // if on a unixbox or not running in cygwin
74 if (RunningOnUnix ||
75 String.IsNullOrEmpty(Environment.GetEnvironmentVariable("TERM")))
77 Driver.WriteLine(p);
78 return;
81 // make cygwin output more useful, e.g. for piping into another command
82 Driver.Write(p.Replace('\\', '/'));
83 Driver.Write("\n");
86 public void ShowModifiedFiles(string itemPath, SortedList<string, string> itemList)
88 DirectoryInfo dir = new DirectoryInfo(itemPath);
89 MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
90 foreach (FileInfo file in dir.GetFiles("*", SearchOption.AllDirectories))
92 if (!itemList.ContainsKey(file.FullName)) continue;
94 using (FileStream fileStream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read))
96 md5.ComputeHash(fileStream);
97 string hash1 = Convert.ToBase64String(md5.Hash);
99 string hash2 = itemList[file.FullName];
100 if (hash1 != hash2)
101 PrintPath(file.FullName);
106 public void ShowOtherFiles(string itemPath, SortedList<string, string> itemList)
108 DirectoryInfo dir = new DirectoryInfo(itemPath);
109 foreach (FileInfo file in dir.GetFiles("*", SearchOption.AllDirectories))
111 if (!itemList.ContainsKey(file.FullName) && !IsExcludedFile(file.FullName))
112 PrintPath(file.FullName);
116 public void ShowWritableFiles(string itemPath)
118 DirectoryInfo dir = new DirectoryInfo(itemPath);
119 foreach (FileInfo file in dir.GetFiles("*", SearchOption.AllDirectories))
121 if (IsExcludedFile(file.FullName)) continue;
123 bool isReadOnly = (FileAttributes.ReadOnly == (File.GetAttributes(file.FullName) & FileAttributes.ReadOnly));
124 if (!isReadOnly) PrintPath(file.FullName);
128 public void ShowDeletedFiles(string itemPath, SortedList<string, string> itemList)
130 SortedList<string, bool> dirList = new SortedList<string, bool>();
131 DirectoryInfo dir = new DirectoryInfo(itemPath);
133 foreach (FileInfo file in dir.GetFiles("*", SearchOption.AllDirectories))
135 dirList.Add(file.FullName, true);
138 foreach (DirectoryInfo di in dir.GetDirectories("*", SearchOption.AllDirectories))
140 dirList.Add(di.FullName, true);
143 foreach (string key in itemList.Keys)
145 if (!dirList.ContainsKey(key))
147 PrintPath(key);
152 public void ShowOldFiles(Workspace workspace, ItemSpec itemSpec)
154 List<ItemSpec> itemSpecs = new List<ItemSpec>();
155 itemSpecs.Add(itemSpec);
157 ExtendedItem[][] items = workspace.GetExtendedItems(itemSpecs.ToArray(),
158 DeletedState.NonDeleted, ItemType.Any);
160 StringBuilder sb = new StringBuilder();
161 foreach (ExtendedItem[] itemArray in items)
163 foreach (ExtendedItem item in itemArray)
165 if (item.IsLatest || item.ItemType == ItemType.Folder) continue;
167 // new files will have a null local item
168 if (String.IsNullOrEmpty(item.LocalItem))
170 if (OptionAll)
171 sb.Append(String.Format("{0}\n", workspace.GetLocalItemForServerItem(item.SourceServerItem)));
173 else
174 PrintPath(item.LocalItem);
178 if (OptionAll)
180 Driver.WriteLine();
181 Driver.WriteLine("New files on the server:");
182 Driver.WriteLine();
183 Driver.WriteLine(sb.ToString());
187 public override void Run()
189 string path = Environment.CurrentDirectory;
190 if (Arguments.Length > 0)
191 path = Path.GetFullPath(Arguments[0]);
193 if (File.Exists(path))
195 // would need to fixup dir.GetDirectories calls if we wanted to support filenames
196 Console.WriteLine("Error: This command only takes paths as arguments, not file names.");
197 Environment.Exit((int)ExitCode.Failure);
200 char[] charsToTrim = { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar};
201 string itemPath = path.TrimEnd(charsToTrim);
203 if (OptionWritable)
205 ShowWritableFiles(itemPath);
206 Environment.Exit((int)ExitCode.Success);
209 Workspace workspace = GetWorkspaceFromCache();
210 workspace.RefreshMappings();
211 string serverPath = workspace.GetServerItemForLocalItem(itemPath);
213 // process command options
214 ItemSpec itemSpec = new ItemSpec(itemPath, RecursionType.Full);
216 if (OptionOld)
218 ShowOldFiles(workspace, itemSpec);
219 Environment.Exit((int)ExitCode.Success);
222 // pull item list based on WorkspaceVersion. otherwise might get
223 // new items on server that haven't been pulled yet in the list returned
224 WorkspaceVersionSpec version = new WorkspaceVersionSpec(workspace);
225 ItemSet itemSet = VersionControlServer.GetItems(itemSpec, version, DeletedState.NonDeleted, ItemType.Any, true);
227 Item[] items = itemSet.Items;
228 SortedList<string, string > itemList = new SortedList<string, string >(PathComparer);
230 foreach (Item item in items)
232 if (item.ServerItem.Length == serverPath.Length) continue;
233 string serverItem = item.ServerItem.Remove(0, serverPath.Length+1);
235 // server item paths are separated with '/', but on windows the file list below has '\' separated paths
236 if (Path.DirectorySeparatorChar != '/')
237 serverItem = serverItem.Replace('/', Path.DirectorySeparatorChar);
239 string fname = Path.Combine(itemPath, serverItem);
240 string hash = "";
242 if (item.ItemType == ItemType.File && item.HashValue != null)
243 hash = Convert.ToBase64String(item.HashValue);
245 itemList.Add(fname, hash);
248 if (OptionOthers) ShowOtherFiles(itemPath, itemList);
249 else if (OptionDeleted) ShowDeletedFiles(itemPath, itemList);
250 else if (OptionModified) ShowModifiedFiles(itemPath, itemList);
251 else
253 foreach (string key in itemList.Keys)
255 PrintPath(key);