unset.perms.too
[tfs.git] / class / Microsoft.TeamFoundation.VersionControl.Client / Workspace.cs
blob7af677009ad0d9e42ae629abe9c2ac88c8ee3efa
1 //
2 // Microsoft.TeamFoundation.VersionControl.Client.Workspace
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.Collections.Generic;
31 using System.IO;
32 using System.Net;
33 using System.Text;
34 using System.Xml;
35 using System.Web.Services;
36 using Microsoft.TeamFoundation.VersionControl.Common;
38 namespace Microsoft.TeamFoundation.VersionControl.Client
40 public sealed class Workspace : IComparable
42 private string comment;
43 private string computer;
44 private string name;
45 private string ownerName;
46 private DateTime lastAccessDate;
47 private WorkingFolder[] folders;
48 private VersionControlServer versionControlServer;
49 internal bool readWriteSetting;
51 internal Workspace(VersionControlServer versionControlServer, string name,
52 string ownerName, string comment,
53 WorkingFolder[] folders, string computer)
55 this.versionControlServer = versionControlServer;
56 this.name = name;
57 this.ownerName = ownerName;
58 this.comment = comment;
59 this.folders = folders;
60 this.computer = computer;
62 readWriteSetting = Workstation.Settings["File.ReadWrite"];
65 internal Workspace(VersionControlServer versionControlServer,
66 WorkspaceInfo info)
68 this.versionControlServer = versionControlServer;
69 this.name = info.Name;
70 this.ownerName = info.OwnerName;
71 this.comment = info.Comment;
72 this.folders = new WorkingFolder[0];
73 this.computer = info.Computer;
75 readWriteSetting = Workstation.Settings["File.ReadWrite"];
78 public int CheckIn(PendingChange[] changes, string comment)
80 if (changes.Length == 0) return 0;
82 List<string> serverItems = new List<string>();
83 foreach (PendingChange change in changes)
85 // upload new or changed files only
86 if ((change.ItemType == ItemType.File) &&
87 (change.IsAdd || change.IsEdit ))
89 Repository.UploadFile(Name, OwnerName, change);
90 SetFileAttributes(change.LocalItem);
93 serverItems.Add(change.ServerItem);
96 return Repository.CheckIn(this, serverItems.ToArray(), comment);
99 public int CompareTo (object o)
101 Workspace a = this, b = (Workspace)o;
103 int r0 = a.VersionControlServer.ServerGuid.CompareTo (b.VersionControlServer.ServerGuid);
104 if (r0 != 0) return r0;
106 int r1 = a.Name.CompareTo (b.Name);
107 if (r1 != 0) return r1;
109 int r2 = a.OwnerName.CompareTo (b.OwnerName);
110 return r2;
113 public PendingChange[] GetPendingChanges()
115 return GetPendingChanges(VersionControlPath.RootFolder, RecursionType.Full);
118 public PendingChange[] GetPendingChanges(string item)
120 return GetPendingChanges(item, RecursionType.None);
123 public PendingChange[] GetPendingChanges(string item, RecursionType rtype)
125 return GetPendingChanges(item, rtype, false);
128 public PendingChange[] GetPendingChanges(string item, RecursionType rtype,
129 bool includeDownloadInfo)
131 string[] items = new string[1];
132 items[0] = item;
133 return GetPendingChanges(items, rtype, includeDownloadInfo);
136 public PendingChange[] GetPendingChanges(string[] items, RecursionType rtype)
138 return GetPendingChanges(items, rtype, false);
141 public PendingChange[] GetPendingChanges(string[] items, RecursionType rtype,
142 bool includeDownloadInfo)
144 List<ItemSpec> itemSpecs = new List<ItemSpec>();
145 foreach (string item in items)
147 itemSpecs.Add(new ItemSpec(item, rtype));
150 Failure[] failures = null;
151 PendingChange[] changes = Repository.QueryPendingSets(Name, OwnerName, Name, OwnerName,
152 itemSpecs.ToArray(), includeDownloadInfo,
153 out failures);
154 foreach (Failure failure in failures)
156 Console.WriteLine(failure.ToString());
159 return changes;
162 public void Delete()
164 Repository.DeleteWorkspace(Name, OwnerName);
165 Workstation.Current.RemoveCachedWorkspaceInfo(VersionControlServer.Uri, Name);
168 public GetStatus Get()
170 return Get(VersionSpec.Latest, GetOptions.None);
173 public GetStatus Get(VersionSpec versionSpec, GetOptions options)
175 GetRequest request = new GetRequest(versionSpec);
176 return Get(request, GetOptions.None, null, null);
179 public GetStatus Get(GetRequest request, GetOptions options)
181 return Get(request, options, null, null);
184 public GetStatus Get(GetRequest[] requests, GetOptions options)
186 return Get(requests, options, null, null);
189 public GetStatus Get(GetRequest request, GetOptions options,
190 GetFilterCallback filterCallback, object userData)
192 GetRequest[] requests = new GetRequest[1];
193 requests[0] = request;
194 return Get(requests, options, filterCallback, userData);
197 public GetStatus Get (string[] items, VersionSpec version,
198 RecursionType recursion, GetOptions options)
200 List<GetRequest> requests = new List<GetRequest>();
201 foreach (string item in items)
203 requests.Add(new GetRequest(item, recursion, version));
206 return Get(requests.ToArray(), options, null, null);
209 public GetStatus Get(GetRequest[] requests, GetOptions options,
210 GetFilterCallback filterCallback, object userData)
212 bool force = ((GetOptions.Overwrite & options) == GetOptions.Overwrite);
213 bool noGet = ! ((GetOptions.GetAll & options) == GetOptions.GetAll);
215 GetOperation[] getOperations = Repository.Get(Name, OwnerName, requests, force, noGet);
216 if (null != filterCallback) filterCallback(this, getOperations, userData);
218 UpdateLocalVersionQueue updates = new UpdateLocalVersionQueue(this);
219 foreach (GetOperation getOperation in getOperations)
221 string uPath = null;
222 GettingEventArgs args = new GettingEventArgs(this, getOperation);
224 //Console.WriteLine(getOperation.ToString());
226 if (getOperation.DeletionId != 0)
228 if ((getOperation.ItemType == ItemType.Folder)&&
229 (Directory.Exists(getOperation.SourceLocalItem)))
231 Directory.Delete(getOperation.SourceLocalItem, true);
233 else if ((getOperation.ItemType == ItemType.File)&&
234 (File.Exists(getOperation.SourceLocalItem)))
236 UnsetFileAttributes(getOperation.SourceLocalItem);
237 File.Delete(getOperation.SourceLocalItem);
240 else if ((!String.IsNullOrEmpty(getOperation.TargetLocalItem))&&
241 (!String.IsNullOrEmpty(getOperation.SourceLocalItem))&&
242 (getOperation.SourceLocalItem != getOperation.TargetLocalItem))
244 uPath = getOperation.TargetLocalItem;
247 File.Move(getOperation.SourceLocalItem, getOperation.TargetLocalItem);
249 catch (IOException)
251 args.Status = OperationStatus.TargetIsDirectory;
254 else if (getOperation.ChangeType == ChangeType.None)
256 uPath = getOperation.TargetLocalItem;
257 string directory = uPath;
259 if (getOperation.ItemType == ItemType.File)
260 directory = Path.GetDirectoryName(uPath);
262 if (!Directory.Exists(directory))
263 Directory.CreateDirectory(directory);
265 if (getOperation.ItemType == ItemType.File)
267 DownloadFile.WriteTo(uPath, Repository, getOperation.ArtifactUri);
268 SetFileAttributes(uPath);
272 versionControlServer.OnDownloading(args);
273 updates.QueueUpdate(getOperation.ItemId, uPath, getOperation.VersionServer);
276 updates.Flush();
277 return new GetStatus(getOperations.Length);
280 public ExtendedItem[][] GetExtendedItems (ItemSpec[] itemSpecs,
281 DeletedState deletedState,
282 ItemType itemType)
284 return Repository.QueryItemsExtended(Name, OwnerName,
285 itemSpecs, deletedState, itemType);
288 public string GetServerItemForLocalItem(string localItem)
290 string item = TryGetServerItemForLocalItem(localItem);
291 if (item == null)
292 throw new ItemNotMappedException(localItem);
293 return item;
296 public string GetLocalItemForServerItem(string serverItem)
298 string item = TryGetLocalItemForServerItem(serverItem);
299 if (item == null)
300 throw new ItemNotMappedException(serverItem);
301 return item;
304 public bool IsLocalPathMapped(string localPath)
306 foreach (WorkingFolder workingFolder in Folders)
308 if (workingFolder.LocalItem == localPath) return true;
311 return false;
314 public bool IsServerPathMapped(string serverPath)
316 foreach (WorkingFolder workingFolder in Folders)
318 if (workingFolder.ServerItem == serverPath) return true;
321 return false;
324 public void Map(string teamProject, string sourceProject) {
325 WorkingFolder[] folders = new WorkingFolder[1];
326 folders[0] = new WorkingFolder(sourceProject, teamProject);
327 Update(Name, OwnerName, folders);
330 public int PendAdd(string path)
332 return PendAdd(path, false);
335 public int PendAdd(string path, bool isRecursive)
337 string[] paths = new string[1];
338 paths[0] = path;
339 return PendAdd(paths, isRecursive);
342 public int PendAdd(string[] paths, bool isRecursive)
344 List<ChangeRequest> changes = new List<ChangeRequest>();
346 foreach (string path in paths)
348 ItemType itemType = ItemType.File;
349 if (Directory.Exists(path)) itemType = ItemType.Folder;
350 changes.Add(new ChangeRequest(path, RequestType.Add, itemType));
352 if (!isRecursive || itemType != ItemType.Folder) continue;
354 DirectoryInfo dir = new DirectoryInfo(path);
355 FileInfo[] localFiles = dir.GetFiles("*", SearchOption.AllDirectories);
357 foreach (FileInfo file in localFiles)
358 changes.Add(new ChangeRequest(file.FullName, RequestType.Add, ItemType.File));
361 if (changes.Count == 0) return 0;
363 GetOperation[] operations = Repository.PendChanges(this, changes.ToArray());
364 return operations.Length;
367 public int PendDelete(string path)
369 return PendDelete(path, RecursionType.None);
372 public int PendDelete(string path, RecursionType recursionType)
374 string[] paths = new string[1];
375 paths[0] = path;
377 return PendDelete(paths, recursionType);
380 public int PendDelete(string[] paths, RecursionType recursionType)
382 List<ChangeRequest> changes = new List<ChangeRequest>();
383 foreach (string path in paths)
385 ItemType itemType = ItemType.File;
386 if (Directory.Exists(path)) itemType = ItemType.Folder;
387 changes.Add(new ChangeRequest(path, RequestType.Delete, itemType));
390 if (changes.Count == 0) return 0;
392 GetOperation[] operations = Repository.PendChanges(this, changes.ToArray());
393 UpdateLocalVersionQueue updates = new UpdateLocalVersionQueue(this);
395 foreach (GetOperation operation in operations)
397 if (File.Exists(operation.SourceLocalItem))
399 UnsetFileAttributes(operation.SourceLocalItem);
400 File.Delete(operation.SourceLocalItem);
402 else
404 DirectoryInfo dir = new DirectoryInfo(operation.SourceLocalItem);
405 FileInfo[] localFiles = dir.GetFiles("*", SearchOption.AllDirectories);
406 foreach (FileInfo file in localFiles)
407 UnsetFileAttributes(file.FullName);
409 Directory.Delete(operation.SourceLocalItem, true);
412 updates.QueueUpdate(operation.ItemId, null, operation.VersionServer);
415 updates.Flush();
416 return operations.Length;
419 public int PendEdit(string path)
421 // Annotation[] annotations = Repository.QueryAnnotation("ExclusiveCheckout",
422 // path, 0);
423 // foreach (Annotation annotation in annotations)
424 // {
425 // Console.WriteLine(annotation.ToString());
426 // }
428 return PendEdit(path, RecursionType.None);
431 public int PendEdit(string path, RecursionType recursionType)
433 string[] paths = new string[1];
434 paths[0] = path;
436 return PendEdit(paths, recursionType);
439 public int PendEdit(string[] paths, RecursionType recursionType)
441 List<ChangeRequest> changes = new List<ChangeRequest>();
442 foreach (string path in paths)
444 changes.Add(new ChangeRequest(path, RequestType.Edit, ItemType.File));
447 if (changes.Count == 0) return 0;
449 GetOperation[] getOperations = Repository.PendChanges(this, changes.ToArray());
450 foreach (GetOperation getOperation in getOperations)
452 UnsetFileAttributes(getOperation.TargetLocalItem);
455 return getOperations.Length;
458 public int PendRename(string oldPath, string newPath)
460 string newServerPath;
461 if (VersionControlPath.IsServerItem(newPath)) newServerPath = GetServerItemForLocalItem(newPath);
462 else newServerPath = newPath;
464 ItemType itemType = ItemType.File;
465 if (Directory.Exists(oldPath)) itemType = ItemType.Folder;
467 List<ChangeRequest> changes = new List<ChangeRequest>();
468 changes.Add(new ChangeRequest(oldPath, newServerPath, RequestType.Rename, itemType));
470 GetOperation[] getOperations = Repository.PendChanges(this, changes.ToArray());
472 UpdateLocalVersionQueue updates = new UpdateLocalVersionQueue(this);
473 foreach (GetOperation getOperation in getOperations)
475 File.Move(oldPath, getOperation.TargetLocalItem);
476 updates.QueueUpdate(getOperation.ItemId, getOperation.TargetLocalItem, getOperation.VersionServer);
479 updates.Flush();
480 return 1;
483 internal static Workspace FromXml(Repository repository, XmlReader reader)
485 string elementName = reader.Name;
487 string computer = reader.GetAttribute("computer");
488 string name = reader.GetAttribute("name");
489 string owner = reader.GetAttribute("owner");
491 string comment = "";
492 DateTime lastAccessDate = DateTime.Now;
493 List<WorkingFolder> folders = new List<WorkingFolder>();
495 while (reader.Read())
497 if (reader.NodeType == XmlNodeType.EndElement && reader.Name == elementName)
498 break;
500 if (reader.NodeType == XmlNodeType.Element)
502 switch (reader.Name)
504 case "WorkingFolder":
505 folders.Add(WorkingFolder.FromXml(repository, reader));
506 break;
507 case "Comment":
508 comment = reader.ReadString();
509 break;
510 case "LastAccessDate":
511 lastAccessDate = reader.ReadElementContentAsDateTime();
512 break;
517 Workspace w = new Workspace(repository.VersionControlServer, name, owner, comment, folders.ToArray(), computer);
518 w.lastAccessDate = lastAccessDate;
519 return w;
522 internal void ToXml(XmlWriter writer, string element)
524 writer.WriteStartElement(element);
525 writer.WriteAttributeString("computer", Computer);
526 writer.WriteAttributeString("name", Name);
527 writer.WriteAttributeString("owner", OwnerName);
528 writer.WriteElementString("Comment", Comment);
530 if (folders != null)
532 writer.WriteStartElement("Folders");
534 foreach (WorkingFolder folder in folders)
536 folder.ToXml(writer, element);
539 writer.WriteEndElement();
542 writer.WriteEndElement();
545 public override string ToString()
547 StringBuilder sb = new StringBuilder();
549 sb.Append("Workspace instance ");
550 sb.Append(GetHashCode());
552 sb.Append("\n Comment: ");
553 sb.Append(Comment);
555 sb.Append("\n LastAccessDate: ");
556 sb.Append(LastAccessDate);
558 sb.Append("\n Folders: ");
559 if (folders != null)
561 foreach (WorkingFolder folder in folders)
563 sb.Append(folder.ToString());
567 sb.Append("\n Computer: ");
568 sb.Append(Computer);
570 sb.Append("\n Name: ");
571 sb.Append(Name);
573 sb.Append("\n OwnerName: ");
574 sb.Append(OwnerName);
576 return sb.ToString();
579 public string TryGetServerItemForLocalItem(string localItem)
581 foreach (WorkingFolder folder in folders)
583 if (!localItem.StartsWith(folder.LocalItem, StringComparison.InvariantCultureIgnoreCase)) continue;
584 string suffix = localItem.Substring(folder.LocalItem.Length);
585 return String.Format("{0}{1}", folder.ServerItem, suffix);
588 return null;
591 public string TryGetLocalItemForServerItem(string serverItem)
593 foreach (WorkingFolder folder in folders)
595 if (!serverItem.StartsWith(folder.ServerItem, StringComparison.InvariantCultureIgnoreCase)) continue;
596 string suffix = serverItem.Substring(folder.ServerItem.Length);
597 return String.Format("{0}{1}", folder.LocalItem, suffix);
600 return null;
603 public WorkingFolder TryGetWorkingFolderForServerItem(string serverItem)
605 int maxPath = 0;
606 WorkingFolder workingFolder = null;
608 foreach (WorkingFolder folder in folders)
610 if (!serverItem.StartsWith(folder.ServerItem, StringComparison.InvariantCultureIgnoreCase)) continue;
612 if (folder.LocalItem.Length > maxPath)
614 workingFolder = folder;
615 maxPath = folder.LocalItem.Length;
619 return workingFolder;
622 public int Undo(string path)
624 return Undo(path, RecursionType.None);
627 public int Undo(string path, RecursionType recursionType)
629 string[] paths = new string[1];
630 paths[0] = path;
631 return Undo(paths, recursionType);
634 public int Undo(string[] paths, RecursionType recursionType)
636 List<ItemSpec> specs = new List<ItemSpec>();
638 foreach (string path in paths)
640 specs.Add(new ItemSpec(path, recursionType));
643 // is this the same logic as a workspace Get?
644 // can we make one function to handle both cases?
646 GetOperation[] getOperations = Repository.UndoPendingChanges(Name, OwnerName, specs.ToArray());
647 foreach (GetOperation getOperation in getOperations)
649 if (getOperation.ChangeType == ChangeType.Edit ||
650 getOperation.ChangeType == ChangeType.Delete)
652 string uPath = getOperation.TargetLocalItem;
653 string directory = uPath;
655 if (getOperation.ItemType == ItemType.File)
656 directory = Path.GetDirectoryName(uPath);
658 if (!Directory.Exists(directory))
659 Directory.CreateDirectory(directory);
661 if (getOperation.ItemType == ItemType.File)
663 DownloadFile.WriteTo(uPath, Repository, getOperation.ArtifactUri);
664 SetFileAttributes(uPath);
669 return getOperations.Length;
672 public void Update (string newName, string newComment, WorkingFolder[] newMappings)
674 Workspace w1 = new Workspace(VersionControlServer, newName, OwnerName,
675 newComment, newMappings, Computer);
676 Workspace w2 = Repository.UpdateWorkspace(Name, OwnerName, w1);
678 Workstation.Current.UpdateCachedWorkspaceInfo(VersionControlServer.Uri,
679 w2, newMappings);
681 folders = w2.Folders;
684 public void RefreshMappings ()
686 Workspace w = Repository.QueryWorkspace(Name, OwnerName);
687 this.folders = w.folders;
690 public string Comment
692 get { return comment; }
695 public string Computer
697 get { return computer; }
700 public WorkingFolder[] Folders
702 get { return folders; }
705 public string Name
707 get { return name; }
710 public DateTime LastAccessDate
712 get { return lastAccessDate; }
715 public string OwnerName
717 get { return ownerName; }
720 public VersionControlServer VersionControlServer
722 get { return versionControlServer; }
725 internal Repository Repository
727 get { return versionControlServer.Repository; }
730 internal void SetFileAttributes(string path)
732 if (!readWriteSetting)
733 File.SetAttributes(path, FileAttributes.ReadOnly);
736 internal void UnsetFileAttributes(string path)
738 if (!readWriteSetting)
739 File.SetAttributes(path, FileAttributes.Normal);