public void RefreshItem(GitItem item, SvnNodeKind nodeKind) { if (item == null) { throw new ArgumentNullException("item"); } RefreshPath(item.FullPath, nodeKind); IGitItemUpdate updateItem = (IGitItemUpdate)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 GitItem 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"); }
private void StatDirectory(string walkPath, GitDirectory directory, bool noWcAtAll) { // Note: There is a lock(_lock) around this in our caller bool canRead; string adminName = GitClient.AdministrativeDirectoryName; NoSccStatus noSccStatus = noWcAtAll ? NoSccStatus.NotVersionable : NoSccStatus.NotVersioned; foreach (SccFileSystemNode node in SccFileSystemNode.GetDirectoryNodes(walkPath, out canRead)) { if (string.Equals(node.Name, adminName, StringComparison.OrdinalIgnoreCase) || node.IsHiddenOrSystem) { continue; } GitItem item; if (node.IsFile) { if (!_map.TryGetValue(node.FullPath, out item)) { StoreItem(CreateItem(node.FullPath, noSccStatus, SvnNodeKind.File)); } else { IGitItemUpdate updateItem = item; if (updateItem.ShouldRefresh()) { updateItem.RefreshTo(noSccStatus, SvnNodeKind.File); } } } else { if (!_map.TryGetValue(node.FullPath, out item)) { StoreItem(CreateItem(node.FullPath, noSccStatus, SvnNodeKind.Directory)); } // Don't clear state of a possible working copy } } if (canRead) // The directory exists { GitItem item; if (!_map.TryGetValue(walkPath, out item)) { StoreItem(CreateItem(walkPath, NoSccStatus.NotVersioned, SvnNodeKind.Directory)); // Mark it as existing if we are sure } else { IGitItemUpdate updateItem = item; if (updateItem.ShouldRefresh()) { updateItem.RefreshTo(NoSccStatus.NotVersioned, SvnNodeKind.Directory); } } } // Note: There is a lock(_lock) around this in our caller }
/// <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="GitDepth.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; } GitStatusArgs args = new GitStatusArgs(); args.IncludeUnversioned = true; args.IncludeUnmodified = true; args.IncludeIgnored = true; //args.IncludeDirectories = true; args.IncludeSubmodules = true; args.GenerateVersionedDirs = true; lock (_lock) { GitDirectory directory; IGitDirectoryUpdate updateDir; GitItem 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 GitDirectory(Context, walkPath); _dirMap[walkPath] = directory; } walkItem = directory.Directory; bool ok; bool statSelf = false; bool noWcAtAll = false; string[] root; // Don't retry file open/read operations on failure. These would only delay the result // (default number of delays = 100) //using (new SharpGit.Implementation.GitFsOperationRetryOverride(0)) try { _root = null; ok = _client.Status(walkPath, args, RefreshCallback); } catch { ok = false; } finally { root = _root; } if (!ok) { statSelf = true; } else if (directory != null) { walkItem = directory.Directory; // Might have changed via casing } if (!statSelf) { if (((IGitItemUpdate)walkItem).ShouldRefresh()) { statSelf = true; } else if (walkingDirectory && !walkItem.IsVersioned) { statSelf = true; } } if (statSelf) { // Git 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 { ((IGitItemUpdate)walkItem).RefreshTo(walkItem.Exists ? NoSccStatus.NotVersioned : NoSccStatus.NotExisting, SvnNodeKind.Unknown); } } } if (directory != null) { foreach (IGitItemUpdate 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 } GitItem 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 { IGitItemUpdate update = pathItem; if (!update.IsStatusClean()) { update.RefreshTo(NoSccStatus.NotExisting, SvnNodeKind.Unknown); // We did not see it in the walker if (directory != null) { ((IGitDirectoryUpdate)directory).Store(pathItem); ScheduleForCleanup(directory); } } } } }