private void RemoveMissingItemsWhichAreChildrenOfRenamedItem(FolderMetaData root) { foreach (string item in renamedItemsToBeCheckedForDeletedChildren) { RemoveMissingItemsWhichAreChildrenOfRenamedItem(item, root); } }
public void CalculateDiff(string checkoutRootPath, int versionTo, int versionFrom, FolderMetaData checkoutRoot, UpdateReportData updateReportData) { clientExistingFiles = GetClientExistingFiles(checkoutRootPath, updateReportData); clientMissingFiles = GetClientDeletedFiles(checkoutRootPath, updateReportData); string projectRootPath = GetProjectRoot(checkoutRootPath); if (updateReportData.Entries != null) { foreach (EntryData data in updateReportData.Entries) { int itemVersionFrom = int.Parse(data.Rev); if (itemVersionFrom < versionFrom) { string rootPath = checkoutRootPath; if (updateReportData.UpdateTarget != null) { rootPath += "/" + updateReportData.UpdateTarget; } string targetPath = rootPath + "/" + data.path; if (targetPath.StartsWith("/")) { targetPath = targetPath.Substring(1); } CalculateChangeBetweenVersions(projectRootPath, targetPath, itemVersionFrom, checkoutRoot, itemVersionFrom, versionFrom); } } } if (versionFrom != versionTo) { // we have to calculate the difference from the project root // this is because we may have a file move from below the checkoutRootPath, // which we still need to consider FolderMetaData projectRoot = checkoutRoot; if (projectRootPath != checkoutRootPath) { projectRoot = (FolderMetaData)sourceControlProvider.GetItems(versionTo, projectRootPath, Recursion.None); string path = checkoutRootPath.Substring(0, checkoutRootPath.LastIndexOf('/')); path = path.Substring(path.IndexOf('/') + 1); FolderMetaData result = (FolderMetaData)FindItemOrCreateItem(projectRoot, projectRootPath, path, versionTo, Recursion.None); result.Items.Add(checkoutRoot); } CalculateChangeBetweenVersions(projectRootPath, -1, projectRoot, versionFrom, versionTo); } foreach (string missingItem in clientMissingFiles.Values) { if (sourceControlProvider.ItemExists(checkoutRootPath + "/" + missingItem, versionTo)) { FindItemOrCreateItem(checkoutRoot, checkoutRootPath, missingItem, versionTo, Recursion.Full); } } FlattenDeletedFolders(checkoutRoot); RemoveMissingItemsWhichAreChildrenOfRenamedItem(checkoutRoot); VerifyNoMissingItemMetaDataRemained(checkoutRoot); }
private static void VerifyNoMissingItemMetaDataRemained(FolderMetaData root) { foreach (ItemMetaData item in root.Items) { if (item is MissingItemMetaData) { throw new InvalidOperationException("Found missing item:" + item + " but those should not be returned from UpdateDiffCalculator"); } if (item is FolderMetaData) { VerifyNoMissingItemMetaDataRemained((FolderMetaData)item); } } }
private void ProcessDeletedItem(string remoteName, SourceItemChange change) { bool alreadyChangedInCurrentClientState = IsChangeAlreadyCurrentInClientState(ChangeType.Delete, remoteName, change.Item.RemoteChangesetId, clientExistingFiles, clientMissingFiles); if (alreadyChangedInCurrentClientState) { RemoveMissingItem(remoteName, _root); return; } string folderName = _checkoutRootPath; string remoteNameStart = remoteName.StartsWith(_checkoutRootPath) ? _checkoutRootPath : folderName; string[] nameParts = remoteName.Substring(remoteNameStart.Length) .Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); FolderMetaData folder = _root; for (int i = 0; i < nameParts.Length; i++) { bool isLastNamePart = i == nameParts.Length - 1; if (folderName != "" && !folderName.EndsWith("/")) { folderName += "/" + nameParts[i]; } else { folderName += nameParts[i]; } bool fullyHandled = HandleDeleteItem(remoteName, change, folderName, ref folder, isLastNamePart); if (fullyHandled) { break; } } if (nameParts.Length == 0)//we have to delete the checkout root itself { HandleDeleteItem(remoteName, change, folderName, ref folder, true); } }
public UpdateDiffEngine(FolderMetaData root, string checkoutRootPath, int targetVersion, TFSSourceControlProvider sourceControlProvider, Dictionary <string, int> clientExistingFiles, Dictionary <string, string> clientMissingFiles, Dictionary <ItemMetaData, bool> additionForPropertyChangeOnly, List <string> renamedItemsToBeCheckedForDeletedChildren) { this._root = root; this._checkoutRootPath = checkoutRootPath; this._targetVersion = targetVersion; this.sourceControlProvider = sourceControlProvider; this.clientExistingFiles = clientExistingFiles; this.clientMissingFiles = clientMissingFiles; this.additionForPropertyChangeOnly = additionForPropertyChangeOnly; this.renamedItemsToBeCheckedForDeletedChildren = renamedItemsToBeCheckedForDeletedChildren; }
/// This method ensures that we are not sending useless deletes to the client /// if a folder is to be deleted, all its children are as well, which we remove /// at this phase. private static void FlattenDeletedFolders(FolderMetaData parentFolder) { foreach (ItemMetaData item in parentFolder.Items) { FolderMetaData folder = item as FolderMetaData; if (folder == null) { continue; } if (folder is DeleteFolderMetaData) { folder.Items.Clear(); } else { FlattenDeletedFolders(folder); } } }
private ItemMetaData FindItemOrCreateItem(FolderMetaData root, string pathRoot, string path, int targetVersion, Recursion recursion) { FolderMetaData folder = root; string[] parts = path.Split('/'); string itemName = pathRoot; ItemMetaData item = null; for (int i = 0; i < parts.Length; i++) { if (itemName != "" && !itemName.EndsWith("/")) { itemName += "/" + parts[i]; } else { itemName += parts[i]; } item = folder.FindItem(itemName); bool lastNamePart = i == parts.Length - 1; if (item == null) { if (lastNamePart) { item = sourceControlProvider.GetItems(targetVersion, itemName, recursion); } else { FolderMetaData subFolder = (FolderMetaData)sourceControlProvider.GetItems(targetVersion, itemName, recursion); item = subFolder; } item = item ?? new MissingItemMetaData(itemName, targetVersion, false); folder.Items.Add(item); } if (lastNamePart == false) { folder = (FolderMetaData)item; } } return(item); }
private bool RemoveMissingItem(string name, FolderMetaData folder) { foreach (ItemMetaData item in folder.Items) { if (item.Name == name && item is MissingItemMetaData) { folder.Items.Remove(item); return(true); } FolderMetaData subFolder = item as FolderMetaData; if (subFolder != null) { if (RemoveMissingItem(name, subFolder)) { return(true); } } } return(false); }
public ItemMetaData FindItem(string name) { if (string.Equals(name, this.Name, StringComparison.InvariantCultureIgnoreCase)) { return(this); } foreach (ItemMetaData item in Items) { if (string.Equals(item.Name, name, StringComparison.InvariantCultureIgnoreCase)) { return(item); } FolderMetaData subFolder = item as FolderMetaData; if (subFolder != null) { ItemMetaData result = subFolder.FindItem(name); if (result != null) { return(result); } } } return(null); }
private static void RemoveMissingItemsWhichAreChildrenOfRenamedItem(string itemName, FolderMetaData root) { if (itemName.StartsWith("/")) { itemName = itemName.Substring(1); } foreach (ItemMetaData data in new List <ItemMetaData>(root.Items)) { string nameMatchingSourceItemConvention = data.Name; if (data.Name.StartsWith("/")) { nameMatchingSourceItemConvention = data.Name.Substring(1); } // a child of the currently renamed item if (data is MissingItemMetaData && nameMatchingSourceItemConvention.StartsWith(itemName, StringComparison.InvariantCultureIgnoreCase)) { root.Items.Remove(data); continue; } if (data is FolderMetaData) { RemoveMissingItemsWhichAreChildrenOfRenamedItem(itemName, (FolderMetaData)data); } } }
private void CalculateChangeBetweenVersions(string checkoutRootPath, string changePath, int changeVersion, FolderMetaData root, int sourceVersion, int targetVersion) { bool updatingForwardInTime = sourceVersion <= targetVersion; int lastVersion = sourceVersion; while (targetVersion != lastVersion) { int previousLoopLastVersion = lastVersion; LogItem logItem = sourceControlProvider.GetLog( changePath, changeVersion, Math.Min(lastVersion, targetVersion) + 1, Math.Max(lastVersion, targetVersion), Recursion.Full, 256); foreach (SourceItemHistory history in Helper.SortHistories(updatingForwardInTime, logItem.History)) { lastVersion = history.ChangeSetID; if (updatingForwardInTime == false) { lastVersion -= 1; } // we need to go over the changeset in reverse order so we will process // all the files first, and build the folder hierarchy that way for (int i = history.Changes.Count - 1; i >= 0; i--) { UpdateDiffEngine engine = new UpdateDiffEngine(root, checkoutRootPath, targetVersion, sourceControlProvider, clientExistingFiles, clientMissingFiles, additionForPropertyChangeOnly, renamedItemsToBeCheckedForDeletedChildren); SourceItemChange change = history.Changes[i]; if (ShouldBeIgnored(change.Item.RemoteName)) { continue; } if (IsAddOperation(change, updatingForwardInTime)) { engine.Add(change); } else if (IsDeleteOperation(change, updatingForwardInTime)) { engine.Delete(change); } else if (IsEditOperation(change)) { // We may have edit & rename operations if (IsRenameOperation(change)) { engine.Rename(change, updatingForwardInTime); } if (updatingForwardInTime == false) { change.Item.RemoteChangesetId -= 1; // we turn the edit around, basically } engine.Edit(change); } else if (IsRenameOperation(change)) { engine.Rename(change, updatingForwardInTime); } else { throw new NotSupportedException("Unsupported change type " + change.ChangeType); } } } // No change was made, break out if (previousLoopLastVersion == lastVersion) { break; } } }
private void CalculateChangeBetweenVersions(string checkoutRootPath, int checkoutRootVersion, FolderMetaData root, int sourceVersion, int targetVersion) { CalculateChangeBetweenVersions(checkoutRootPath, checkoutRootPath, checkoutRootVersion, root, sourceVersion, targetVersion); }
public NoNullAllowedItemsCollection(FolderMetaData parent) { this.parent = parent; }
private bool HandleDeleteItem(string remoteName, SourceItemChange change, string folderName, ref FolderMetaData folder, bool isLastNamePart) { ItemMetaData item = folder.FindItem(folderName); if (item is DeleteFolderMetaData || item is DeleteMetaData) { return(true); } if (item == null) { if (isLastNamePart) { if (change.Item.ItemType == ItemType.File) { item = new DeleteMetaData(); } else { item = new DeleteFolderMetaData(); } item.Name = remoteName; item.ItemRevision = change.Item.RemoteChangesetId; } else { item = sourceControlProvider.GetItemsWithoutProperties(_targetVersion, folderName, Recursion.None); if (item == null) { item = new DeleteFolderMetaData(); item.Name = folderName; item.ItemRevision = _targetVersion; } } folder.Items.Add(item); } else if (isLastNamePart) // we need to revert the item addition { if (item.OriginallyDeleted) // convert back into a delete { folder.Items.Remove(item); if (change.Item.ItemType == ItemType.File) { item = new DeleteMetaData(); } else { item = new DeleteFolderMetaData(); } item.Name = remoteName; item.ItemRevision = change.Item.RemoteChangesetId; folder.Items.Add(item); } else if (item is StubFolderMetaData) { DeleteFolderMetaData removeFolder = new DeleteFolderMetaData(); removeFolder.Name = item.Name; removeFolder.ItemRevision = _targetVersion; folder.Items.Remove(item); folder.Items.Add(removeFolder); } else if (additionForPropertyChangeOnly.ContainsKey(item) && additionForPropertyChangeOnly[item]) { ItemMetaData removeFolder = item is FolderMetaData ? (ItemMetaData) new DeleteFolderMetaData() : new DeleteMetaData(); removeFolder.Name = item.Name; removeFolder.ItemRevision = _targetVersion; folder.Items.Remove(item); folder.Items.Add(removeFolder); } else if (item is MissingItemMetaData && ((MissingItemMetaData)item).Edit == true) { ItemMetaData removeFolder = new DeleteMetaData(); removeFolder.Name = item.Name; removeFolder.ItemRevision = _targetVersion; folder.Items.Remove(item); folder.Items.Add(removeFolder); } else { folder.Items.Remove(item); } } folder = (item as FolderMetaData) ?? folder; return(false); }
private void ProcessAddedOrUpdatedItem(string remoteName, SourceItemChange change, bool propertyChange, bool edit) { bool alreadyInClientCurrentState = IsChangeAlreadyCurrentInClientState(ChangeType.Add, remoteName, change.Item.RemoteChangesetId, clientExistingFiles, clientMissingFiles); if (alreadyInClientCurrentState) { return; } if (string.Equals(remoteName, _checkoutRootPath, StringComparison.InvariantCultureIgnoreCase)) { ItemMetaData item = sourceControlProvider.GetItems(_targetVersion, remoteName, Recursion.None); if (item != null) { _root.Properties = item.Properties; } } else { FolderMetaData folder = _root; string itemName = _checkoutRootPath; string[] nameParts; if (_checkoutRootPath != "") { nameParts = remoteName.Substring(_checkoutRootPath.Length + 1).Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); } else { nameParts = remoteName.Split('/'); } for (int i = 0; i < nameParts.Length; i++) { bool lastNamePart = false; if (i == nameParts.Length - 1) { lastNamePart = true; } if (itemName != "" && !itemName.EndsWith("/")) { itemName += "/" + nameParts[i]; } else { itemName += nameParts[i]; } ItemMetaData item = folder.FindItem(itemName); if (item == null || ( lastNamePart && item.Revision < change.Item.RemoteChangesetId && !(item is DeleteFolderMetaData) && !(item is DeleteMetaData) ) ) { if (item != null) { folder.Items.Remove(item); } item = sourceControlProvider.GetItems(_targetVersion, itemName, Recursion.None); if (item == null) { // TFS will report renames even for deleted items, // since TFS reported that this was renamed, but it doesn't exists // in this revision, we know it is a case of renaming a deleted file. // We can safely ignore this and any of its children. if (IsRenameOperation(change)) { return; } if (lastNamePart && propertyChange) { return; } item = new MissingItemMetaData(itemName, _targetVersion, edit); } if (!lastNamePart) { StubFolderMetaData stubFolder = new StubFolderMetaData(); stubFolder.RealFolder = (FolderMetaData)item; stubFolder.Name = item.Name; stubFolder.ItemRevision = item.ItemRevision; stubFolder.PropertyRevision = item.PropertyRevision; stubFolder.LastModifiedDate = item.LastModifiedDate; stubFolder.Author = item.Author; item = stubFolder; } folder.Items.Add(item); SetAdditionForPropertyChangeOnly(item, propertyChange); } else if ((item is StubFolderMetaData) && lastNamePart) { folder.Items.Remove(item); folder.Items.Add(((StubFolderMetaData)item).RealFolder); } else if (((item is DeleteFolderMetaData) || (item is DeleteMetaData)) && IsAddOperation(change)) { if (!propertyChange) { folder.Items.Remove(item); item = sourceControlProvider.GetItems(change.Item.RemoteChangesetId, itemName, Recursion.None); item.OriginallyDeleted = true; folder.Items.Add(item); } } if (lastNamePart == false) { folder = (FolderMetaData)item; } } } }
public void SetParent(FolderMetaData parentFolder) { parent = parentFolder; }