dont.pass.subcommand.name.to.Command.classes
[tfs.git] / tools / tf / OnlineCommand.cs
blob4bdbbd324df1430008b37b2c04923fd9a2452261
1 //
2 // OnlineCommand.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 System.Text.RegularExpressions;
35 using Microsoft.TeamFoundation.Client;
36 using Microsoft.TeamFoundation.VersionControl.Common;
37 using Microsoft.TeamFoundation.VersionControl.Client;
38 using Mono.GetOptions;
40 [Command("online", "Finds all writable files and marks them as pending changes on the server.")]
41 class OnlineCommand : Command
43 [Option("Look for added files.", "", "added")]
44 public bool OptionAdded = 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("Preview", "", "preview")]
53 public bool OptionPreview = false;
55 [Option("Recursive", "R", "recursive")]
56 public bool OptionRecursive = false;
58 private List<string> addedFiles = new List<string>();
59 private List<string> editedFiles = new List<string>();
60 private List<string> deletedFiles = new List<string>();
61 private Workspace workspace;
62 private MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
64 public OnlineCommand(Driver driver, string[] args): base(driver, args)
68 private void ProcessFile(SortedList<string, byte[]> itemList, string path)
70 bool isReadOnly = (FileAttributes.ReadOnly == (File.GetAttributes(path) & FileAttributes.ReadOnly));
72 if (!itemList.ContainsKey(path))
74 if (OptionAdded)
76 Console.WriteLine("Added: " + path);
77 addedFiles.Add(path);
80 else if (!isReadOnly && OptionModified)
82 string itemHash = Convert.ToBase64String(itemList[path]);
84 using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
86 md5.ComputeHash(fileStream);
87 string localHash = Convert.ToBase64String(md5.Hash);
88 if (itemHash != localHash)
90 editedFiles.Add(path);
91 Console.WriteLine("Modified: " + path);
97 private void ProcessFileList(List<string> files)
99 List<ItemSpec> itemSpecs = new List<ItemSpec>();
100 foreach (string file in files)
102 itemSpecs.Add(new ItemSpec(file, RecursionType.None));
105 // pull item list based on WorkspaceVersion. otherwise might get
106 // new items on server that haven't been pulled yet in the list returned
107 WorkspaceVersionSpec version = new WorkspaceVersionSpec(workspace);
108 ItemSet itemSet = VersionControlServer.GetItems(itemSpecs.ToArray(), version, DeletedState.NonDeleted, ItemType.File, true);
110 // get item list from TFS server
111 Item[] items = itemSet.Items;
112 SortedList<string, byte[] > itemList = new SortedList<string, byte[] >(PathComparer);
114 foreach (Item item in items)
116 Console.WriteLine(item.ToString());
120 private void ProcessDirectory(string path)
122 char[] charsToTrim = { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar};
123 string itemPath = path.TrimEnd(charsToTrim);
125 // must get server<->local mappings for GetServerItemForLocalItem
126 workspace.RefreshMappings();
127 string serverPath = workspace.GetServerItemForLocalItem(itemPath);
129 // pull item list based on WorkspaceVersion. otherwise might get
130 // new items on server that haven't been pulled yet in the list returned
131 WorkspaceVersionSpec version = new WorkspaceVersionSpec(workspace);
133 // process recursion settings
134 RecursionType rtype = OptionRecursive ? RecursionType.Full : RecursionType.OneLevel;
135 bool recursionSetting = Settings.Current.GetAsBool("Online.Recursive");
136 if (recursionSetting) rtype = RecursionType.Full;
137 SearchOption searchType = (rtype == RecursionType.Full) ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
139 // process command options
140 ItemSpec itemSpec = new ItemSpec(itemPath, rtype);
141 ItemSet itemSet = VersionControlServer.GetItems(itemSpec, version, DeletedState.NonDeleted, ItemType.Any, true);
143 // get item list from TFS server
144 Item[] items = itemSet.Items;
145 SortedList<string, byte[] > itemList = new SortedList<string, byte[] >(PathComparer);
147 foreach (Item item in items)
149 if (item.ServerItem.Length == serverPath.Length) continue;
150 string serverItem = item.ServerItem.Remove(0, serverPath.Length+1);
152 // server item paths are separated with '/', but on windows the file list below has '\' separated paths
153 if (Path.DirectorySeparatorChar != '/')
154 serverItem = serverItem.Replace('/', Path.DirectorySeparatorChar);
156 string fname = Path.Combine(itemPath, serverItem);
157 //Console.WriteLine(serverItem + " : " + fname);
159 itemList.Add(fname, item.HashValue);
162 DirectoryInfo dir = new DirectoryInfo(path);
163 FileInfo[] localFiles = dir.GetFiles("*", searchType);
165 SortedList<string, bool> dirList = new SortedList<string, bool>();
167 // should we ignore/exclude any thing?
168 Regex excludes = WildcardToRegex(Settings.Current.Get("File.Excludes"));
170 // by default, if nothing specified we process all changes
171 if ((!OptionModified) && (!OptionDeleted) && (!OptionAdded))
173 OptionModified = OptionAdded = OptionDeleted = true;
176 foreach (FileInfo file in localFiles)
178 // skip files we're not interested in
179 if (excludes.IsMatch(file.Name)) continue;
181 dirList.Add(file.FullName, true);
182 ProcessFile(itemList, file.FullName);
185 foreach (DirectoryInfo di in dir.GetDirectories("*", SearchOption.AllDirectories))
187 dirList.Add(di.FullName, true);
190 if (OptionDeleted)
192 foreach (string key in itemList.Keys)
194 // skip files that exist or we're not interested in
195 if (dirList.ContainsKey(key)) continue;
196 if (excludes.IsMatch(key)) continue;
198 Console.WriteLine("Deleted: " + key);
199 deletedFiles.Add(key);
204 private void Online(string[] args)
206 if (args.Length == 0)
208 ProcessDirectory(Environment.CurrentDirectory);
209 return;
212 List<string> files = new List<string>();
213 foreach (string arg in args)
215 string path = Path.GetFullPath(arg);
216 if (Directory.Exists(path)) ProcessDirectory(path);
217 else files.Add(path);
220 if (files.Count > 0) ProcessFileList(files);
223 public override void Run()
225 workspace = GetWorkspaceFromCache();
227 Online(Arguments);
228 if (OptionPreview) return;
230 int changes = 0;
231 changes += workspace.PendAdd(addedFiles.ToArray(), false);
232 changes += workspace.PendEdit(editedFiles.ToArray(), RecursionType.None);
233 changes += workspace.PendDelete(deletedFiles.ToArray(), RecursionType.None);
234 Console.WriteLine("{0} pending changes.", changes);