void Ankh.Scc.ISvnStatusCache.RefreshItem(SvnItem item, SvnNodeKind nodeKind) { if (item == null) { throw new ArgumentNullException("item"); } RefreshPath(item.FullPath, nodeKind); ISvnItemUpdate updateItem = (ISvnItemUpdate)item; if (!updateItem.IsStatusClean()) { // Ok, the status update did not refresh the item requesting to be refreshed // That means the item is not here or RefreshPath would have added it SvnItem other; if (_map.TryGetValue(item.FullPath, out other) && other != item) { updateItem.RefreshTo(other); // This item is no longer current; but we have the status anyway } else { Debug.Assert(false, "RefreshPath did not deliver up to date information", "The RefreshPath public api promises delivering up to date data, but none was received"); updateItem.RefreshTo(item.Exists ? NoSccStatus.NotVersioned : NoSccStatus.NotExisting, SvnNodeKind.Unknown); } } Debug.Assert(updateItem.IsStatusClean(), "The item requesting to be updated is updated"); }
/// <summary> /// Refreshes the specified path using the specified depth /// </summary> /// <param name="path">A normalized path</param> /// <param name="pathKind"></param> /// <param name="depth"></param> /// <remarks> /// If the path is a file and depth is greater that <see cref="SvnDepth.Empty"/> the parent folder is walked instead. /// /// <para>This method guarantees that after calling it at least one up-to-date item exists /// in the statusmap for <paramref name="path"/>. If we can not find information we create /// an unspecified item /// </para> /// </remarks> void RefreshPath(string path, SvnNodeKind pathKind) { if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException("path"); } var walkPath = path; var walkingDirectory = false; switch (pathKind) { case SvnNodeKind.Directory: walkingDirectory = true; break; case SvnNodeKind.File: walkPath = SvnTools.GetNormalizedDirectoryName(path); walkingDirectory = true; break; default: try { if (File.Exists(path)) // ### Not long path safe { pathKind = SvnNodeKind.File; goto case SvnNodeKind.File; } } catch (PathTooLongException) { /* Fall through */ } break; } var args = new SvnStatusArgs(); args.Depth = SvnDepth.Children; args.RetrieveAllEntries = true; args.RetrieveIgnoredEntries = true; args.ThrowOnError = false; lock (_lock) { ISvnDirectoryUpdate updateDir; SvnItem walkItem = null; // We get more information for free, lets use that to update other items DirectoryMap.TryGetValue(walkPath, out var directory); if (null != directory) { updateDir = directory; updateDir.TickAll(); } else { // No existing directory instance, let's create one directory = new SvnDirectory(walkPath); updateDir = directory = GetDirectory(walkPath); DirectoryMap[walkPath] = directory; } bool ok; var statSelf = false; var noWcAtAll = false; // Don't retry file open/read operations on failure. These would only delay the result // (default number of delays = 100) using (new SharpSvn.Implementation.SvnFsOperationRetryOverride(0)) { ok = _client.Status(walkPath, args, RefreshCallback); } if (directory != null) { walkItem = directory.Directory; // Might have changed via casing } if (!statSelf && null != walkItem) { if (((ISvnItemUpdate)walkItem).ShouldRefresh()) { statSelf = true; } else if (walkingDirectory && !walkItem.IsVersioned) { statSelf = true; } } if (statSelf) { // Svn did not stat the items for us.. Let's make something up if (walkingDirectory) { StatDirectory(walkPath, directory, noWcAtAll); } else { // Just stat the item passed and nothing else in the Depth.Empty case if (walkItem == null) { var truepath = SvnTools.GetTruePath(walkPath); // Gets the on-disk casing if it exists StoreItem(walkItem = CreateItem(truepath ?? walkPath, (truepath != null) ? NoSccStatus.NotVersioned : NoSccStatus.NotExisting, SvnNodeKind.Unknown)); } else { ((ISvnItemUpdate)walkItem).RefreshTo(walkItem.Exists ? NoSccStatus.NotVersioned : NoSccStatus.NotExisting, SvnNodeKind.Unknown); } } } if (directory != null) { foreach (ISvnItemUpdate item in directory) { if (item.IsItemTicked()) // These items were not found in the stat calls { item.RefreshTo(NoSccStatus.NotExisting, SvnNodeKind.Unknown); } } if (updateDir.ScheduleForCleanup) { ScheduleForCleanup(directory); // Handles removing already deleted items } // We keep them cached for the current command only } SvnItem pathItem; // We promissed to return an updated item for the specified path; check if we updated it if (!Map.TryGetValue(path, out pathItem)) { // We did not; it does not even exist in the cache StoreItem(pathItem = CreateItem(path, NoSccStatus.NotExisting)); if (directory != null) { updateDir.Store(pathItem); ScheduleForCleanup(directory); } } else { ISvnItemUpdate update = pathItem; if (!update.IsStatusClean()) { update.RefreshTo(NoSccStatus.NotExisting, SvnNodeKind.Unknown); // We did not see it in the walker if (directory != null) { ((ISvnDirectoryUpdate)directory).Store(pathItem); ScheduleForCleanup(directory); } } } } }
/// <summary> /// Refreshes the specified path using the specified depth /// </summary> /// <param name="path">A normalized path</param> /// <param name="pathKind"></param> /// <param name="depth"></param> /// <remarks> /// If the path is a file and depth is greater that <see cref="SvnDepth.Empty"/> the parent folder is walked instead. /// /// <para>This method guarantees that after calling it at least one up-to-date item exists /// in the statusmap for <paramref name="path"/>. If we can not find information we create /// an unspecified item /// </para> /// </remarks> void RefreshPath(string path, SvnNodeKind pathKind) { if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException("path"); } string walkPath = path; bool walkingDirectory = false; switch (pathKind) { case SvnNodeKind.Directory: walkingDirectory = true; break; case SvnNodeKind.File: walkPath = SvnTools.GetNormalizedDirectoryName(path); walkingDirectory = true; break; default: try { if (File.Exists(path)) // ### Not long path safe { pathKind = SvnNodeKind.File; goto case SvnNodeKind.File; } } catch (PathTooLongException) { /* Fall through */ } break; } SvnStatusArgs args = new SvnStatusArgs(); args.Depth = SvnDepth.Children; args.RetrieveAllEntries = true; args.RetrieveIgnoredEntries = true; args.ThrowOnError = false; lock (_lock) { SvnDirectory directory; ISvnDirectoryUpdate updateDir; SvnItem walkItem; // We get more information for free, lets use that to update other items if (_dirMap.TryGetValue(walkPath, out directory)) { updateDir = directory; updateDir.TickAll(); } else { // No existing directory instance, let's create one updateDir = directory = new SvnDirectory(Context, walkPath); _dirMap[walkPath] = directory; } walkItem = directory.Directory; bool ok; bool statSelf = false; bool noWcAtAll = false; // Don't retry file open/read operations on failure. These would only delay the result // (default number of delays = 100) using (new SharpSvn.Implementation.SvnFsOperationRetryOverride(0)) { ok = _client.Status(walkPath, args, RefreshCallback); } if (!ok) { if (args.LastException != null) { switch (args.LastException.SvnErrorCode) { case SvnErrorCode.SVN_ERR_WC_UNSUPPORTED_FORMAT: if (CommandService != null) { CommandService.PostExecCommand(AnkhCommand.NotifyWcToNew, walkPath); } break; case SvnErrorCode.SVN_ERR_WC_UPGRADE_REQUIRED: _enableUpgrade = true; if (updateDir != null) { updateDir.SetNeedsUpgrade(); } if (!_sendUpgrade && CommandService != null) { _sendUpgrade = true; CommandService.PostExecCommand(AnkhCommand.NotifyUpgradeRequired, walkPath); } break; case SvnErrorCode.SVN_ERR_WC_NOT_WORKING_COPY: // Status only reports this error if there is no ancestor working copy // We should avoid statting all parent directories again for .IsVersionable noWcAtAll = true; break; case SvnErrorCode.SVN_ERR_WC_CLEANUP_REQUIRED: if (updateDir != null) { updateDir.SetNeedsCleanup(); } break; } } statSelf = true; } else if (directory != null) { walkItem = directory.Directory; // Might have changed via casing } if (!statSelf) { if (((ISvnItemUpdate)walkItem).ShouldRefresh()) { statSelf = true; } else if (walkingDirectory && !walkItem.IsVersioned) { statSelf = true; } } if (statSelf) { // Svn did not stat the items for us.. Let's make something up if (walkingDirectory) { StatDirectory(walkPath, directory, noWcAtAll); } else { // Just stat the item passed and nothing else in the Depth.Empty case if (walkItem == null) { string truepath = SvnTools.GetTruePath(walkPath); // Gets the on-disk casing if it exists StoreItem(walkItem = CreateItem(truepath ?? walkPath, (truepath != null) ? NoSccStatus.NotVersioned : NoSccStatus.NotExisting, SvnNodeKind.Unknown)); } else { ((ISvnItemUpdate)walkItem).RefreshTo(walkItem.Exists ? NoSccStatus.NotVersioned : NoSccStatus.NotExisting, SvnNodeKind.Unknown); } } } if (directory != null) { foreach (ISvnItemUpdate item in directory) { if (item.IsItemTicked()) // These items were not found in the stat calls { item.RefreshTo(NoSccStatus.NotExisting, SvnNodeKind.Unknown); } } if (updateDir.ScheduleForCleanup) { ScheduleForCleanup(directory); // Handles removing already deleted items } // We keep them cached for the current command only } SvnItem pathItem; // We promissed to return an updated item for the specified path; check if we updated it if (!_map.TryGetValue(path, out pathItem)) { // We did not; it does not even exist in the cache StoreItem(pathItem = CreateItem(path, NoSccStatus.NotExisting)); if (directory != null) { updateDir.Store(pathItem); ScheduleForCleanup(directory); } } else { ISvnItemUpdate update = pathItem; if (!update.IsStatusClean()) { update.RefreshTo(NoSccStatus.NotExisting, SvnNodeKind.Unknown); // We did not see it in the walker if (directory != null) { ((ISvnDirectoryUpdate)directory).Store(pathItem); ScheduleForCleanup(directory); } } } } }