show the difference between two versions for a specified path
[tfs.git] / tools / opentf / OnlineCommand.cs
blob80f91d4617da56ee80d29de1f43c9a91b778d4bf
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;
39 using OpenTF.Common;
41 [Command("online", "Finds all writable files and marks them as pending changes on the server.", "<path>...")]
42 class OnlineCommand : Command
44 [Option("Look for added files.", "", "added")]
45 public bool OptionAdded = false;
47 [Option("Look for deleted files.", "D", "deleted")]
48 public bool OptionDeleted = false;
50 [Option("Look for modified files.", "", "modified")]
51 public bool OptionModified = false;
53 [Option("Preview", "", "preview")]
54 public bool OptionPreview = false;
56 [Option("Recursive", "R", "recursive")]
57 public bool OptionRecursive = false;
59 private List<string> addedFiles = new List<string>();
60 private List<string> editedFiles = new List<string>();
61 private List<string> deletedFiles = new List<string>();
62 private Workspace workspace;
63 private MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
65 public OnlineCommand(Driver driver, string[] args): base(driver, args)
69 private void ProcessFile(SortedList<string, byte[]> itemList, string path)
71 bool isReadOnly = (FileAttributes.ReadOnly == (File.GetAttributes(path) & FileAttributes.ReadOnly));
73 if (!itemList.ContainsKey(path))
75 if (OptionAdded)
77 Console.WriteLine("Added: " + path);
78 addedFiles.Add(path);
81 return;
84 // if a path is in the itemList but has a null hash skip any further processing
85 // the file is an add awaiting its first checkin
86 if (itemList[path] == null)
88 Console.WriteLine("Previously added: " + path);
89 return;
92 if (!OptionModified) return;
93 if (isReadOnly) return;
95 string itemHash = Convert.ToBase64String(itemList[path]);
97 using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
99 md5.ComputeHash(fileStream);
100 string localHash = Convert.ToBase64String(md5.Hash);
101 if (itemHash != localHash)
103 editedFiles.Add(path);
104 Console.WriteLine("Modified: " + path);
109 private void ProcessFileList(SortedList<string, bool> files)
111 List<ItemSpec> itemSpecs = new List<ItemSpec>();
112 foreach (string file in files.Keys)
113 itemSpecs.Add(new ItemSpec(file, RecursionType.None));
115 // pull item list based on WorkspaceVersion. otherwise might get
116 // new items on server that haven't been pulled yet in the list returned
117 WorkspaceVersionSpec version = new WorkspaceVersionSpec(workspace);
118 SortedList<string, byte[] > itemList = new SortedList<string, byte[] >(PathComparer);
120 // get item list from TFS server
121 ItemSet[] itemSets = VersionControlServer.GetItems(itemSpecs.ToArray(), version, DeletedState.NonDeleted, ItemType.File, true);
122 foreach (ItemSet itemSet in itemSets)
124 foreach (Item item in itemSet.Items)
126 string localItem = workspace.GetLocalItemForServerItem(item.ServerItem);
127 itemList.Add(localItem, item.HashValue);
131 // process adds and edits
132 foreach (string file in files.Keys)
134 // skip files we're not interested in here
135 if (IsExcludedFile(file)) continue;
137 if (!File.Exists(file))
139 if (OptionDeleted && itemList.ContainsKey(file))
141 Console.WriteLine("Deleted: " + file);
142 deletedFiles.Add(file);
144 continue;
147 ProcessFile(itemList, file);
151 private void ProcessDirectory(string path)
153 char[] charsToTrim = { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar};
154 string itemPath = path.TrimEnd(charsToTrim);
155 string serverPath = workspace.GetServerItemForLocalItem(itemPath);
157 // pull item list based on WorkspaceVersion. otherwise might get
158 // new items on server that haven't been pulled yet in the list returned
159 WorkspaceVersionSpec version = new WorkspaceVersionSpec(workspace);
161 // process recursion settings
162 RecursionType rtype = OptionRecursive ? RecursionType.Full : RecursionType.OneLevel;
163 bool recursionSetting = Settings.Current.GetAsBool("Online.Recursive");
164 if (recursionSetting) rtype = RecursionType.Full;
165 SearchOption searchType = (rtype == RecursionType.Full) ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
167 // process command options
168 ItemSpec itemSpec = new ItemSpec(itemPath, rtype);
169 ItemSet itemSet = VersionControlServer.GetItems(itemSpec, version, DeletedState.NonDeleted, ItemType.Any, true);
171 // get item list from TFS server
172 Item[] items = itemSet.Items;
173 SortedList<string, byte[] > itemList = new SortedList<string, byte[] >(PathComparer);
175 foreach (Item item in items)
177 if (item.ServerItem.Length == serverPath.Length) continue;
178 string serverItem = item.ServerItem.Remove(0, serverPath.Length+1);
180 // server item paths are separated with '/', but on windows the file list below has '\' separated paths
181 if (Path.DirectorySeparatorChar != '/')
182 serverItem = serverItem.Replace('/', Path.DirectorySeparatorChar);
184 string fname = Path.Combine(itemPath, serverItem);
185 //Console.WriteLine(serverItem + " : " + fname);
187 itemList.Add(fname, item.HashValue);
190 DirectoryInfo dir = new DirectoryInfo(path);
191 FileInfo[] localFiles = dir.GetFiles("*", searchType);
193 SortedList<string, bool> dirList = new SortedList<string, bool>();
194 foreach (FileInfo file in localFiles)
196 // skip files we're not interested in
197 if (IsExcludedFile(file.FullName)) continue;
199 dirList.Add(file.FullName, true);
200 ProcessFile(itemList, file.FullName);
203 foreach (DirectoryInfo di in dir.GetDirectories("*", SearchOption.AllDirectories))
205 dirList.Add(di.FullName, true);
208 if (!OptionDeleted) return;
210 foreach (string key in itemList.Keys)
212 // skip files that exist or we're not interested in
213 if (dirList.ContainsKey(key)) continue;
214 if (IsExcludedFile(key)) continue;
216 Console.WriteLine("Deleted: " + key);
217 deletedFiles.Add(key);
221 private void Online(string[] args)
223 if (args.Length == 0)
225 ProcessDirectory(Environment.CurrentDirectory);
226 return;
229 SortedList<string, bool> files = new SortedList<string, bool>();
230 foreach (string arg in args)
232 string path = Path.GetFullPath(arg);
233 if (Directory.Exists(path)) ProcessDirectory(path);
234 else files.Add(path, true);
237 if (files.Count > 0) ProcessFileList(files);
240 public override void Run()
242 // must get server<->local mappings for GetServerItemForLocalItem
243 workspace = GetWorkspaceFromCache();
244 workspace.RefreshMappings();
246 // by default, if nothing specified we process all changes
247 if ((!OptionModified) && (!OptionDeleted) && (!OptionAdded))
249 OptionModified = OptionAdded = OptionDeleted = true;
252 Online(Arguments);
253 if (OptionPreview) return;
255 int changes = 0;
256 changes += workspace.PendAdd(addedFiles.ToArray(), false);
257 changes += workspace.PendEdit(editedFiles.ToArray(), RecursionType.None);
258 changes += workspace.PendDelete(deletedFiles.ToArray(), RecursionType.None);
259 Console.WriteLine("{0} pending changes.", changes);