/// <summary>
        /// Fixes working copies which are invalidated by a rename operation
        /// </summary>
        /// <param name="rgszMkOldNames"></param>
        /// <param name="rgszMkNewNames"></param>
        private void FixWorkingCopyAfterRenames(string[] rgszMkOldNames, string[] rgszMkNewNames)
        {
            if (rgszMkNewNames == null || rgszMkOldNames == null || rgszMkOldNames.Length != rgszMkNewNames.Length)
                return;

            for (int i = 0; i < rgszMkOldNames.Length; i++)
            {
                string oldName = rgszMkOldNames[i];
                string newName = rgszMkNewNames[i];

                if (string.IsNullOrEmpty(oldName) || !GitItem.IsValidPath(oldName))
                    continue;

                oldName = GitTools.GetNormalizedFullPath(oldName);
                newName = GitTools.GetNormalizedFullPath(newName);

                string oldDir;
                string newDir;
                bool safeRename =false;

                if (!Directory.Exists(newName))
                {
                    // Try to fix the parent of the new item
                     oldDir = GitTools.GetNormalizedDirectoryName(oldName);
                     newDir = GitTools.GetNormalizedDirectoryName(newName);
                }
                else
                {
                    // The item itself is the directory to fix
                    oldDir = oldName;
                    newDir = newName;
                    safeRename = true;
                }

                if (Directory.Exists(oldDir))
                    continue; // Nothing to fix up

                string parent = GitTools.GetNormalizedDirectoryName(oldDir);
                if (!Directory.Exists(parent))
                {
                    continue; // We can't fix up more than one level at this time
                    // We probably fix it with one of the following renames; as paths are included too
                }

                GitItem item = StatusCache[oldDir];

                if (!item.IsVersioned && item.Status.State != GitStatus.Missing)
                    continue; // Item was not cached as versioned or now-missing (Missing implicits Versioned)

                StatusCache.MarkDirty(oldDir);
                StatusCache.MarkDirty(newDir);

                item = StatusCache[oldDir];

                if (item.Status.State != GitStatus.Missing)
                    continue;

                GitItem newItem = StatusCache[newDir];

                using (GitSccContext git = new GitSccContext(Context))
                {
                    GitStatusEventArgs wa = git.SafeGetEntry(newDir);
                    string newParent = GitTools.GetNormalizedDirectoryName(newDir);

                    if (wa != null)
                        continue; // Not an unexpected WC root
                    else if (!GitTools.IsBelowManagedPath(newDir))
                        continue; // Not a wc root at all

                    git.SafeWcDirectoryCopyFixUp(oldDir, newDir, safeRename); // Recreate the old WC directory

                    _delayedDeletes.Add(oldDir); // Delete everything in the old wc when done
                    // TODO: Once Git understands true renames, fixup the renames in the delayed hook
                    RegisterForSccCleanup();

                    // We have all files of the old wc directory unversioned in the new location now

                    StatusCache.MarkDirtyRecursive(oldDir);
                    StatusCache.MarkDirtyRecursive(newDir);
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="cProjects"></param>
        /// <param name="cDirectories"></param>
        /// <param name="rgpProjects"></param>
        /// <param name="rgFirstIndices"></param>
        /// <param name="rgpszMkDocuments"></param>
        /// <param name="rgFlags"></param>
        /// <returns></returns>
        /// <remarks>Deny a query only if allowing the operation would compromise your stable state</remarks>
        public int OnAfterAddDirectoriesEx(int cProjects, int cDirectories, IVsProject[] rgpProjects, int[] rgFirstIndices, string[] rgpszMkDocuments, VSADDDIRECTORYFLAGS[] rgFlags)
        {
            if (rgpProjects == null || rgpszMkDocuments == null)
                return VSConstants.E_POINTER;

            for (int i = 0; i < cDirectories; i++)
            {
                string dir = rgpszMkDocuments[i];

                if (string.IsNullOrEmpty(dir) || !GitItem.IsValidPath(dir))
                    continue;

                dir = GitTools.GetNormalizedFullPath(dir);

                StatusCache.MarkDirty(dir);

                GitItem item = StatusCache[dir];

                if (!item.Exists || !item.IsDirectory || !GitTools.IsBelowManagedPath(dir))
                    continue;

                if ((DateTime.UtcNow - GetCreated(item)) > new TimeSpan(0, 1, 0))
                    continue; // Directory is older than one minute.. Not just copied

                using (GitSccContext git = new GitSccContext(Context))
                {
                    // Ok; we have a 'new' directory here.. Lets check if VS broke the Git working copy
                    GitStatusEventArgs entry = git.SafeGetEntry(dir);

                    if (entry != null && entry.NodeKind == GitNodeKind.Directory) // Entry exists, valid dir
                        continue;

                    // VS Added a versioned dir below our project -> Unversion the directory to allow adding files

                    // Don't unversion the directory if the parent is not versioned
                    string parentDir = GitTools.GetNormalizedDirectoryName(dir);
                    if (parentDir == null || !GitTools.IsBelowManagedPath(parentDir))
                        continue;

                    git.UnversionRecursive(dir);
                }
            }

            for (int iProject = 0, iDir=0; (iProject < cProjects) && (iDir < cDirectories); iProject++)
            {
                int iLastDirectoryThisProject = (iProject < cProjects - 1) ? rgFirstIndices[iProject + 1] : cDirectories;

                IVsSccProject2 sccProject = rgpProjects[iProject] as IVsSccProject2;

                bool track = SccProvider.TrackProjectChanges(sccProject);

                for (; iDir < iLastDirectoryThisProject; iDir++)
                {
                    if (!track)
                        continue;

                    string dir = rgpszMkDocuments[iDir];

                    if (string.IsNullOrEmpty(dir) || !GitItem.IsValidPath(dir))
                        continue;

                    dir = GitTools.GetNormalizedFullPath(dir);

                    if (sccProject != null)
                        SccProvider.OnProjectDirectoryAdded(sccProject, dir, rgFlags[iDir]);
                }
            }

            return VSConstants.S_OK;
        }