BUGFIX: tf online <path> shouldn't croak if <path> is an add awaiting
[tfs.git] / tools / opentf / LsFilesCommand.cs
blobfb3740b9ffa6470a7b03693190a88ba9260354bd
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 ShowModifiedFiles(string itemPath, SortedList<string, string> itemList)
67 DirectoryInfo dir = new DirectoryInfo(itemPath);
68 MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
69 foreach (FileInfo file in dir.GetFiles("*", SearchOption.AllDirectories))
71 if (!itemList.ContainsKey(file.FullName)) continue;
73 using (FileStream fileStream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read))
75 md5.ComputeHash(fileStream);
76 string hash1 = Convert.ToBase64String(md5.Hash);
78 string hash2 = itemList[file.FullName];
79 if (hash1 != hash2)
80 Driver.WriteLine(file.FullName);
85 public void ShowOtherFiles(string itemPath, SortedList<string, string> itemList)
87 DirectoryInfo dir = new DirectoryInfo(itemPath);
88 foreach (FileInfo file in dir.GetFiles("*", SearchOption.AllDirectories))
90 if (!itemList.ContainsKey(file.FullName) && !IsExcludedFile(file.FullName))
92 Driver.WriteLine(file.FullName);
97 public void ShowWritableFiles(string itemPath)
99 DirectoryInfo dir = new DirectoryInfo(itemPath);
100 foreach (FileInfo file in dir.GetFiles("*", SearchOption.AllDirectories))
102 if (IsExcludedFile(file.FullName)) continue;
104 bool isReadOnly = (FileAttributes.ReadOnly == (File.GetAttributes(file.FullName) & FileAttributes.ReadOnly));
105 if (!isReadOnly) Driver.WriteLine(file.FullName);
109 public void ShowDeletedFiles(string itemPath, SortedList<string, string> itemList)
111 SortedList<string, bool> dirList = new SortedList<string, bool>();
112 DirectoryInfo dir = new DirectoryInfo(itemPath);
114 foreach (FileInfo file in dir.GetFiles("*", SearchOption.AllDirectories))
116 dirList.Add(file.FullName, true);
119 foreach (DirectoryInfo di in dir.GetDirectories("*", SearchOption.AllDirectories))
121 dirList.Add(di.FullName, true);
124 foreach (string key in itemList.Keys)
126 if (!dirList.ContainsKey(key))
128 Driver.WriteLine(key);
133 public void ShowOldFiles(Workspace workspace, ItemSpec itemSpec)
135 List<ItemSpec> itemSpecs = new List<ItemSpec>();
136 itemSpecs.Add(itemSpec);
138 ExtendedItem[][] items = workspace.GetExtendedItems(itemSpecs.ToArray(),
139 DeletedState.NonDeleted, ItemType.Any);
141 StringBuilder sb = new StringBuilder();
142 foreach (ExtendedItem[] itemArray in items)
144 foreach (ExtendedItem item in itemArray)
146 if (item.IsLatest || item.ItemType == ItemType.Folder) continue;
148 // new files will have a null local item
149 if (String.IsNullOrEmpty(item.LocalItem))
151 if (OptionAll)
152 sb.Append(String.Format("{0}\n", workspace.GetLocalItemForServerItem(item.SourceServerItem)));
154 else
155 Driver.WriteLine(item.LocalItem);
159 if (OptionAll)
161 Driver.WriteLine();
162 Driver.WriteLine("New files on the server:");
163 Driver.WriteLine();
164 Driver.WriteLine(sb.ToString());
168 public override void Run()
170 string path = Environment.CurrentDirectory;
171 if (Arguments.Length > 0)
172 path = Path.GetFullPath(Arguments[0]);
174 if (File.Exists(path))
176 // would need to fixup dir.GetDirectories calls if we wanted to support filenames
177 Console.WriteLine("Error: This command only takes paths as arguments, not file names.");
178 Environment.Exit((int)ExitCode.Failure);
181 char[] charsToTrim = { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar};
182 string itemPath = path.TrimEnd(charsToTrim);
184 if (OptionWritable)
186 ShowWritableFiles(itemPath);
187 Environment.Exit((int)ExitCode.Success);
190 Workspace workspace = GetWorkspaceFromCache();
191 workspace.RefreshMappings();
192 string serverPath = workspace.GetServerItemForLocalItem(itemPath);
194 // process command options
195 ItemSpec itemSpec = new ItemSpec(itemPath, RecursionType.Full);
197 if (OptionOld)
199 ShowOldFiles(workspace, itemSpec);
200 Environment.Exit((int)ExitCode.Success);
203 // pull item list based on WorkspaceVersion. otherwise might get
204 // new items on server that haven't been pulled yet in the list returned
205 WorkspaceVersionSpec version = new WorkspaceVersionSpec(workspace);
206 ItemSet itemSet = VersionControlServer.GetItems(itemSpec, version, DeletedState.NonDeleted, ItemType.Any, true);
208 Item[] items = itemSet.Items;
209 SortedList<string, string > itemList = new SortedList<string, string >(PathComparer);
211 foreach (Item item in items)
213 if (item.ServerItem.Length == serverPath.Length) continue;
214 string serverItem = item.ServerItem.Remove(0, serverPath.Length+1);
216 // server item paths are separated with '/', but on windows the file list below has '\' separated paths
217 if (Path.DirectorySeparatorChar != '/')
218 serverItem = serverItem.Replace('/', Path.DirectorySeparatorChar);
220 string fname = Path.Combine(itemPath, serverItem);
221 string hash = "";
223 if (item.ItemType == ItemType.File && item.HashValue != null)
224 hash = Convert.ToBase64String(item.HashValue);
226 itemList.Add(fname, hash);
229 if (OptionOthers) ShowOtherFiles(itemPath, itemList);
230 else if (OptionDeleted) ShowDeletedFiles(itemPath, itemList);
231 else if (OptionModified) ShowModifiedFiles(itemPath, itemList);
232 else
234 foreach (string key in itemList.Keys)
236 Driver.WriteLine(key);