/// <summary>Standard Tree Node constructor for a given path and parent entry</summary> public DirectoryTreeEntryNode(string entryPath, DirectoryTreeEntryNode parentDirEntry) : this() { RootDirEntry = parentDirEntry.RootDirEntry; RootDirectoryTreeEntryNodeDictionary = RootDirEntry.RootDirectoryTreeEntryNodeDictionary; ParentDirEntry = parentDirEntry; SetPathAndGetInfo(entryPath, clearFirst: false); }
/// <summary>Resets the internal state of the manager so that it can be Setup again.</summary> private void Clear() { setupPerformed = false; setupFaultCode = ""; if (treeRootEntry == null) { treeRootEntry = new DirectoryTreeEntryNode(); } treeRootEntry.Clear(); BlockPruningForPeriod(TimeSpan.Zero); }
/// <summary>Resets the internal state of the manager so that it can be Setup again.</summary> private void Clear() { setupPerformed = false; setupFaultCode = ""; if (treeRootEntry == null) treeRootEntry = new DirectoryTreeEntryNode(); treeRootEntry.Clear(); BlockPruningForPeriod(TimeSpan.Zero); }
/// <summary> /// Appends a list of the DirectoryEntryInfo items for the tree item's that have been removed from the memory copy of the tree. /// Caller is expected to attempt to delete the actual files/directories. /// Performs UpdateTree prior to returning. /// </summary> public void AppendAndRemoveOldestTreeDirectory(List<DirectoryEntryInfo> pruneItemList, int maxEntriesToDeletePerIteration, Logging.IMesgEmitter issueEmitter = null) { issueEmitter = issueEmitter ?? Logging.NullEmitter; Stack<DirectoryTreeEntryNode> nodeStack = new Stack<DirectoryTreeEntryNode>(); DirectoryTreeEntryNode currentEntry = this; // create a stack of the entries from the root down to the oldest leaf (file or directory). // Each level in the stack retains the current entry at that level, the parent entry and the index in the parent entries content vector at which you will find the current entry while (currentEntry != null) { DirectoryTreeEntryNode nextEntryDown = currentEntry.OldestDirContentsNodeEntry; if (nextEntryDown != null) { nodeStack.Push(nextEntryDown); currentEntry = nextEntryDown; } else if (!currentEntry.IsRootNode) { break; // reached the bottom of the search path } else { // // we can never remove the root item - there is nothing further to prune. return; } } // start at the bottom of the stack and determine if that entry can be removed (or not). If so then: // A) added it to the list of entries to remove // B) remove it from its parrent's entry content vector // and then repeate for the each level up in the stack until an entry is encountered that cannot be deleted (is not an empty directory after the sub item has been removed.) while (nodeStack.Count != 0) { DirectoryTreeEntryNode topStackNode = nodeStack.Pop(); DirectoryTreeEntryNode topStackNodeParentItem = topStackNode.ParentDirEntry; bool isFile = topStackNode.IsFile; bool isNormalFile = topStackNode.IsExistingFile; bool isNormalDirectory = topStackNode.IsExistingDirectory; bool isEmptyDirectory = topStackNode.IsEmptyDirectory; string skipReason = null; if (!isNormalFile && !isNormalDirectory) skipReason = Fcns.CheckedFormat("Skipping non-normal node at path:'{0}'", Path); bool skipIt = (skipReason != null); if (skipIt) issueEmitter.Emit(skipReason); bool removeIt = (isNormalFile || isEmptyDirectory) && !skipIt; bool removeItFromTree = removeIt; if (!removeIt && !skipIt) break; // once we have reached a level where nothing more can be removed (ie it is not an empty directory), we stop iterating up the stack. if (removeItFromTree) { if (removeIt) pruneItemList.Add(topStackNode); // append a copy of the topStackNode as a DirectoryEntryInfo object onto the pruneItemList topStackNodeParentItem.sortedDirContentsNodeArray = null; topStackNodeParentItem.sortedDirContentsNodeSet.Remove(topStackNode); RootDirectoryTreeEntryNodeDictionary.Remove(topStackNode.Path); if (removeIt && isFile && maxEntriesToDeletePerIteration > 1) { // identify the other n oldest items in this directory and add them to the delete list while (pruneItemList.Count < maxEntriesToDeletePerIteration) { DirectoryTreeEntryNode nextOldestEntryInCurrentDir = topStackNodeParentItem.OldestDirContentsNodeEntry; if (nextOldestEntryInCurrentDir == null) break; // stop adding to the current list of items to delete once we reach any non-normal file - special cases will be covered on the next go around. if (!nextOldestEntryInCurrentDir.IsExistingFile) break; // append a copy of the nextEntryInCurrentDir as a DirectoryEntryInfo object pruneItemList.Add(nextOldestEntryInCurrentDir); // remove the pointer to the entry that just got added to the delete list and then delete the entry topStackNodeParentItem.sortedDirContentsNodeSet.Remove(nextOldestEntryInCurrentDir); RootDirectoryTreeEntryNodeDictionary.Remove(nextOldestEntryInCurrentDir.Path); if (topStackNodeParentItem.IsEmptyDirectory) break; } } topStackNodeParentItem.SetTreeUpdateNeeded(true); } } UpdateTree(issueEmitter); }
/// <summary> /// Addes a new node in the tree at the relative location under the given node produced by iteratavely concactinating the given list of relative path elements /// onto the full path to this node and treversing downward until the relative path elements have been used up. /// Performs UpdateTree prior to returning. /// </summary> public void AddRelativePath(IList<String> relativePathElementList, Logging.IMesgEmitter issueEmitter = null) { issueEmitter = issueEmitter ?? Logging.NullEmitter; int relativePathElementListSize = relativePathElementList.Count; if (relativePathElementListSize <= 0) { issueEmitter.Emit("AddRelativePath failed at node:'{0}': given relative path list is empty", Path); return; } DirectoryTreeEntryNode treeScanEntry = this; for (int rPathElemIdx = 0; ((treeScanEntry != null) && (rPathElemIdx < relativePathElementListSize)); rPathElemIdx++) { bool onLastRPathElement = (rPathElemIdx == (relativePathElementListSize - 1)); string leafName = relativePathElementList[rPathElemIdx]; string newEntryPath = System.IO.Path.Combine(treeScanEntry.Path, leafName); DirectoryTreeEntryNode subLeafNode = RootDirectoryTreeEntryNodeDictionary.SafeTryGetValue(newEntryPath); if (subLeafNode != null && subLeafNode.Name != leafName) subLeafNode = treeScanEntry.UpdateAndGetSortedDirContentsNodeArray().FirstOrDefault(item => item.Name == leafName); if (subLeafNode == null) { DirectoryTreeEntryNode newEntry = new DirectoryTreeEntryNode(newEntryPath, treeScanEntry); subLeafNode = newEntry; if (newEntry == null) { issueEmitter.Emit("Allocation Failure while attempting to added entry path:{0}", newEntryPath); } else { treeScanEntry.sortedDirContentsNodeArray = null; treeScanEntry.sortedDirContentsNodeSet.Add(newEntry); if (newEntry.IsExistingDirectory) { newEntry.BuildTree(issueEmitter: issueEmitter); } else if (newEntry.IsExistingFile) { // nothing more to do here } else { issueEmitter.Emit("Added entry path:{0} is neither a known file or directory object", newEntry.Path); } } } else { if (subLeafNode.IsFile) subLeafNode.Refresh(); if (!subLeafNode.IsExistingDirectory && !onLastRPathElement) { issueEmitter.Emit("Add relative path traverse error: partial path is not a directory at {0}", subLeafNode.Path); break; // cannot continue to go lower from this point down } } treeScanEntry.SetTreeUpdateNeeded(true); treeScanEntry = subLeafNode; } UpdateTree(issueEmitter: issueEmitter); }
/// <summary>Standard Tree Node constructor for a given path and parent entry</summary> public DirectoryTreeEntryNode(string entryPath, DirectoryTreeEntryNode parentDirEntry) : this() { ParentDirEntry = parentDirEntry; SetPathAndGetInfo(entryPath, false); }
/// <summary> /// Addes a new node in the tree at the relative location under the given node produced by iteratavely concactinating the given list of relative path elements /// onto the full path to this node and treversing downward until the relative path elements have been used up. /// Performs UpdateTree prior to returning. /// </summary> public void AddRelativePath(IList<String> relativePathElementList, Logging.IMesgEmitter issueEmitter) { int relativePathElementListSize = relativePathElementList.Count; if (relativePathElementListSize <= 0) { issueEmitter.Emit("AddRelativePath failed at node:'{0}': given relative path list is empty", Path); return; } DirectoryTreeEntryNode treeScanEntry = this; for (int rPathElemIdx = 0; ((treeScanEntry != null) && (rPathElemIdx < relativePathElementListSize)); rPathElemIdx++) { bool onLastRPathElement = (rPathElemIdx == (relativePathElementListSize - 1)); string leafName = relativePathElementList[rPathElemIdx]; int subLeafIdx = treeScanEntry.FindSubLeafName(leafName); if (subLeafIdx < 0) { subLeafIdx = (treeScanEntry.DirContentsNodeList.Count); string newEntryPath = System.IO.Path.Combine(treeScanEntry.Path, leafName); DirectoryTreeEntryNode newEntry = new DirectoryTreeEntryNode(newEntryPath, treeScanEntry); treeScanEntry.DirContentsNodeList.Add(newEntry); if (newEntry == null) { issueEmitter.Emit("Allocation Failure while attempting to added entry path:{0}", newEntryPath); } else { if (newEntry.IsExistingDirectory) { // generally should be a noop newEntry.BuildTree(issueEmitter); } else if (newEntry.IsExistingFile) { // nothing more to do here } else { issueEmitter.Emit("Added entry path:{0} is neither a known file or directory object", newEntry.Path); } } treeScanEntry.SetTreeUpdateNeeded(true); } else { DirectoryTreeEntryNode foundEntry = treeScanEntry.DirContentsNodeList[subLeafIdx]; if (foundEntry == null) { issueEmitter.Emit("Null pointer encountered while traversing tree to add new entry for leaf:'{0}' under path:'{1}'", leafName, Path); break; // cannot continue to go lower from this point down } else { if (foundEntry.IsFile) foundEntry.Refresh(); if (!foundEntry.IsExistingDirectory && !onLastRPathElement) { issueEmitter.Emit("Add relative path traverse error: partial path is not a directory at {0}", foundEntry.Path); break; // cannot continue to go lower from this point down } } treeScanEntry.SetTreeUpdateNeeded(true); } treeScanEntry = treeScanEntry.DirContentsNodeList[subLeafIdx]; } UpdateTree(issueEmitter); }