예제 #1
0
        internal void OnSccCleanup(CommandEventArgs e)
        {
            _registeredSccCleanup = false;

            if ((_ensureIcons || _syncMap) && IsActive)
            {
                // Enable our custom glyphs when we are set active
                IAnkhSolutionExplorerWindow solutionExplorer = GetService<IAnkhSolutionExplorerWindow>();

                if (solutionExplorer != null)
                    solutionExplorer.EnableAnkhIcons(true);
            }

            if (_syncMap)
            {
                _syncMap = false;

                foreach (SccProjectData pd in _projectMap.Values)
                    pd.Load();
            }

            if (_delayedDelete != null)
            {
                List<string> files = _delayedDelete;
                _delayedDelete = null;

                using (SvnSccContext svn = new SvnSccContext(Context))
                {
                    foreach (string file in files)
                    {
                        if (!File.Exists(file))
                        {
                            svn.SafeDeleteFile(file);
                            MarkDirty(file);
                        }
                    }
                }
            }

            if (_delayedMove != null)
            {
                List<FixUp> files = _delayedMove;
                _delayedMove = null;

                using (SvnSccContext svn = new SvnSccContext(Context))
                {
                    foreach (FixUp fu in files)
                    {
                        if (!svn.IsUnversioned(fu.From) && svn.IsUnversioned(fu.To))
                        {
                            svn.SafeWcMoveFixup(fu.From, fu.To);
                        }
                    }
                }
            }
            if (_backupMap.Count > 0)
            {
                using (SvnSccContext svn = new SvnSccContext(Context))
                {
                    foreach (KeyValuePair<string, string> dir in _backupMap)
                    {
                        string originalDir = dir.Key;
                        string backupDir = dir.Value;

                        if (!Directory.Exists(backupDir))
                            continue; // No backupdir, we can't delete or move it

                        if (Directory.Exists(originalDir))
                        {
                            // The original has not been deleted by visual studio, must be an exclude.
                            svn.DeleteDirectory(backupDir);
                        }
                        else
                        {
                            // Original is gone, must be a delete, put back backup so we can svn-delete it
                            SvnSccContext.RetriedRename(backupDir, originalDir); // Use retried rename, to prevent virus-scanner locks
                            svn.WcDelete(originalDir);
                        }
                    }
                }
                _backupMap.Clear();
            }
        }
예제 #2
0
 protected bool SvnCanAddPath(string fullpath, SvnNodeKind nodeKind)
 {
     using (SvnSccContext svn = new SvnSccContext(Context))
     {
         // Determine if we could add fullname
         if (!svn.CouldAdd(fullpath, nodeKind))
         {
             if (svn.BelowAdminDir(fullpath))
                 _batchErrors.Add(string.Format(Resources.SvnPathXBlocked, fullpath));
             else
                 _batchErrors.Add(string.Format(Resources.PathXBlocked, fullpath));
             return false;
         }
         else
             return true;
     }
 }
예제 #3
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) || !SvnItem.IsValidPath(dir))
                    continue;

                dir = SvnTools.GetNormalizedFullPath(dir);

                StatusCache.MarkDirty(dir);

                SvnItem item = StatusCache[dir];

                if (!item.Exists || !item.IsDirectory || !SvnTools.IsManagedPath(dir))
                    continue;

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

                using (SvnSccContext svn = new SvnSccContext(Context))
                {
                    // Ok; we have a 'new' directory here.. Lets check if VS broke the subversion working copy
                    SvnWorkingCopyEntryEventArgs entry = svn.SafeGetEntry(dir);

                    if (entry != null && entry.NodeKind == SvnNodeKind.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 = SvnTools.GetNormalizedDirectoryName(dir);
                    if (parentDir == null || !SvnTools.IsManagedPath(parentDir))
                        continue;

                    svn.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) || !SvnItem.IsValidPath(dir))
                        continue;

                    dir = SvnTools.GetNormalizedFullPath(dir);

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

            return VSConstants.S_OK;
        }
예제 #4
0
        /// <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) || !SvnItem.IsValidPath(oldName))
                    continue;

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

                string oldDir;
                string newDir;
                bool safeRename =false;

                if (!Directory.Exists(newName))
                {
                    // Try to fix the parent of the new item
                     oldDir = SvnTools.GetNormalizedDirectoryName(oldName);
                     newDir = SvnTools.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 = SvnTools.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
                }

                SvnItem item = StatusCache[oldDir];

                if (!item.IsVersioned && item.Status.LocalContentStatus != SvnStatus.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.LocalContentStatus != SvnStatus.Missing)
                    continue;

                SvnItem newItem = StatusCache[newDir];

                using (SvnSccContext svn = new SvnSccContext(Context))
                {
                    SvnWorkingCopyEntryEventArgs wa = svn.SafeGetEntry(newDir);
                    string newParent = SvnTools.GetNormalizedDirectoryName(newDir);

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

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

                    _delayedDeletes.Add(oldDir); // Delete everything in the old wc when done
                    // TODO: Once Subversion 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);
                }
            }
        }
예제 #5
0
        /// <summary>
        /// This method notifies the client after a project has added files.
        /// </summary>
        /// <param name="cProjects">[in] Number of projects to which files were added.</param>
        /// <param name="cFiles">[in] Number of files that were added.</param>
        /// <param name="rgpProjects">[in] Array of projects to which files were added.</param>
        /// <param name="rgFirstIndices">[in] Array of first indices identifying which project each file belongs to. For more information, see IVsTrackProjectDocumentsEvents2.</param>
        /// <param name="rgpszMkDocuments">[in] Array of paths for the files that were processed. This is the same size as cFiles.</param>
        /// <param name="rgFlags">[in] Array of flags. For a list of rgFlags values, see <see cref="VSADDFILEFLAGS" />.</param>
        /// <returns></returns>
        public int OnAfterAddFilesEx(int cProjects, int cFiles, IVsProject[] rgpProjects, int[] rgFirstIndices, string[] rgpszMkDocuments, VSADDFILEFLAGS[] rgFlags)
        {
            int iFile = 0;
            RegisterForSccCleanup(); // Clear the origins table after adding

            List<string> selectedFiles = null;
            SortedList<string, string> copies = null;

            bool sccActive = SccProvider.IsActive;

            for (int iProject = 0; (iProject < cProjects) && (iFile < cFiles); iProject++)
            {
                int iLastFileThisProject = (iProject < cProjects - 1) ? rgFirstIndices[iProject + 1] : cFiles;

                IVsSccProject2 sccProject = rgpProjects[iProject] as IVsSccProject2;

                bool trackCopies;
                bool track = SccProvider.TrackProjectChanges(sccProject, out trackCopies);

                for (; iFile < iLastFileThisProject; iFile++)
                {
                    if (!track)
                        continue; // Not handled by our provider

                    string origin = null;
                    string newName = rgpszMkDocuments[iFile];

                    if (string.IsNullOrEmpty(newName) || !SvnItem.IsValidPath(newName))
                        continue;

                    newName = SvnTools.GetNormalizedFullPath(rgpszMkDocuments[iFile]);

                    if (sccActive && _solutionLoaded)
                    {
                        StatusCache.MarkDirty(newName);
                        TryFindOrigin(newName, ref selectedFiles, out origin);
                    }

                    // We do this before the copies to make sure a failed copy doesn't break the project
                    SccProvider.OnProjectFileAdded(sccProject, newName, origin, rgFlags[iFile]);

                    if (sccActive && trackCopies &&
                        !string.IsNullOrEmpty(origin) &&
                        StatusCache[origin].HasCopyableHistory)
                    {
                        if (copies == null)
                            copies = new SortedList<string, string>(StringComparer.OrdinalIgnoreCase);

                        copies[newName] = origin;
                    }
                }
            }

            if (copies != null)
                using (SvnSccContext svn = new SvnSccContext(Context))
                {
                    while (copies.Count > 0)
                    {
                        string toFile = copies.Keys[0];
                        string fromFile = copies.Values[0];
                        string dir = SvnTools.GetNormalizedDirectoryName(toFile);

                        copies.RemoveAt(0);
                        Guid addGuid;

                        if (!svn.TryGetRepositoryId(dir, out addGuid))
                        {
                            continue; // No repository to fix up
                        }

                        Guid fileGuid;

                        if (!svn.TryGetRepositoryId(fromFile, out fileGuid) || fileGuid != addGuid)
                            continue; // Can't fix history for this file

                        if (string.Equals(Path.GetFileName(fromFile), Path.GetFileName(toFile), StringComparison.OrdinalIgnoreCase))
                        {
                            // If the names are the same we can handle all files to the same directory
                            // without a sleep penalty
                            SortedList<string, string> now = new SortedList<string, string>(StringComparer.OrdinalIgnoreCase);
                            now.Add(toFile, fromFile);

                            for (int i = 0; i < copies.Count; i++)
                            {
                                string fl = copies.Keys[i];
                                string tl = copies.Values[i];

                                if (string.Equals(SvnTools.GetNormalizedDirectoryName(fl), dir, StringComparison.OrdinalIgnoreCase) &&
                                    string.Equals(Path.GetFileName(fl), Path.GetFileName(tl), StringComparison.OrdinalIgnoreCase))
                                {
                                    Guid fromGuid;
                                    if (svn.TryGetRepositoryId(tl, out fromGuid) && (fromGuid == addGuid))
                                        now.Add(fl, tl); // We can copy this item at the same time
                                    // else
                                    // This copy comes from another repository, no history to save

                                    copies.RemoveAt(i--);
                                }
                            }

                            // Now contains all the files we are receiving in a single directory
                            if (now.Count > 0)
                                svn.SafeWcCopyToDirFixup(now, dir);
                            else
                                svn.SafeWcCopyFixup(fromFile, toFile);
                        }
                        else
                            svn.SafeWcCopyFixup(fromFile, toFile);
                    }
                }

            return VSConstants.S_OK;
        }
예제 #6
0
        /// <summary>
        /// Called when a file in a project is renamed
        /// </summary>
        /// <param name="project">The SCC project.</param>
        /// <param name="oldName">The old name.</param>
        /// <param name="newName">The new name.</param>
        /// <param name="flags">The flags.</param>
        internal void OnProjectRenamedFile(IVsSccProject2 project, string oldName, string newName, VSRENAMEFILEFLAGS flags)
        {
            SccProjectData data;
            if (!_projectMap.TryGetValue(project, out data))
                return; // Not managed by us
            else
                data.CheckProjectRename(project, oldName, newName); // Just to be sure (should be handled by other event)

            data.RemovePath(oldName);
            data.AddPath(newName);

            if (!IsActive)
                return;

            using (SvnSccContext svn = new SvnSccContext(Context))
            {
                if (!svn.IsUnversioned(oldName))
                {
                    if (!Directory.Exists(newName)) // Fails if the new name is a directory!
                        svn.SafeWcMoveFixup(oldName, newName);
                }

                MarkDirty(new string[] { oldName, newName }, true);
            }
        }
예제 #7
0
        internal void OnSolutionRenamedFile(string oldName, string newName, VSRENAMEFILEFLAGS flags)
        {
            if (!IsActive)
                return;

            _solutionDirectory = _solutionFile = null; // Get new data after this rename

            using (SvnSccContext svn = new SvnSccContext(Context))
            {
                if (!svn.IsUnversioned(oldName))
                {
                    try
                    {
                        svn.SafeWcMoveFixup(oldName, newName);
                    }
                    catch (IOException)
                    {
                        if (_delayedMove == null)
                            _delayedMove = new List<FixUp>();
                        _delayedMove.Add(new FixUp(oldName, newName));

                        RegisterForSccCleanup();
                    }

                    MarkDirty(new string[] { oldName, newName }, true);
                }
            }

            Monitor.ScheduleGlyphUpdate(SolutionFilename);
        }
예제 #8
0
        /// <summary>
        /// Called when a file is removed from a project
        /// </summary>
        /// <param name="project">The project.</param>
        /// <param name="filename">The filename.</param>
        /// <param name="flags">The flags.</param>
        internal void OnProjectFileRemoved(IVsSccProject2 project, string filename, VSREMOVEFILEFLAGS flags)
        {
            SccProjectData data;
            if (!_projectMap.TryGetValue(project, out data))
                return; // Not managed by us

            data.RemovePath(filename);

            if (!IsActive)
                return; // Let the other SCC package manage it

            MarkDirty(filename);

            if (SvnUpdatesDisabled || !StatusCache[filename].IsVersioned)
                return; // Don't bother

            using (SvnSccContext svn = new SvnSccContext(Context))
            {
                if (File.Exists(filename))
                {
                    // The file was only removed from the project. We should not touch it

                    // Some projects delete the file before (C#) and some after (C++) calling OnProjectFileRemoved
                    if (_delayedDelete == null)
                        _delayedDelete = new List<string>();

                    if (!_delayedDelete.Contains(filename))
                        _delayedDelete.Add(filename);

                    RegisterForSccCleanup();
                    return;
                }

                if (svn.IsUnversioned(filename))
                    return;

                svn.SafeDeleteFile(filename);
            }
        }
예제 #9
0
        internal void OnBeforeSolutionRenameFile(string oldName, string newName, VSQUERYRENAMEFILEFLAGS flags, out bool ok)
        {
            ok = true;
            if (!IsActive)
                return;

            //if (IsProjectFileOrSolution(oldName))
            //{
            //    // TODO: Is enlisted -> Ask user!
            //}

            using (SvnSccContext svn = new SvnSccContext(Context))
            {
                if (!svn.CouldAdd(newName, SvnNodeKind.File))
                {
                    ok = false;
                    return;
                }

                if (svn.IsUnversioned(oldName))
                    return;
            }
        }
예제 #10
0
        internal void OnBeforeRemoveDirectory(IVsSccProject2 project, string fullPath, out bool ok)
        {
            ok = true;
            SccProjectData data;
            if (!_projectMap.TryGetValue(project, out data))
                return; // Not managed by us
            else if (!IsActive)
                return;

            if (_backupMap.ContainsKey(fullPath))
            {
                // Don't backup twice
                string oldBackup = _backupMap[fullPath];
                _backupMap.Remove(fullPath);
                using (SvnSccContext svn = new SvnSccContext(this))
                {
                    svn.DeleteDirectory(oldBackup);
                }
            }
            else
            {
                SvnItem dir = StatusCache[fullPath];

                if (!dir.IsVersioned)
                    return; // Nothing to do for us
            }

            using (SvnSccContext svn = new SvnSccContext(this))
            {
                _backupMap.Add(fullPath, svn.MakeBackup(fullPath));
            }

            RegisterForSccCleanup();
        }
예제 #11
0
        /// <summary>
        /// Called just before a file in a project is renamed
        /// </summary>
        /// <param name="project">The SCC project.</param>
        /// <param name="oldName">The old name.</param>
        /// <param name="newName">The new name.</param>
        /// <param name="flags">The flags.</param>
        /// <param name="ok">if set to <c>true</c> [ok].</param>
        internal void OnBeforeProjectRenameFile(IVsSccProject2 project, string oldName, string newName, VSQUERYRENAMEFILEFLAGS flags, out bool ok)
        {
            ok = true;

            if (!_projectMap.ContainsKey(project))
                return; // Not managed by us

            if (!IsActive)
                return;

            using (SvnSccContext svn = new SvnSccContext(Context))
            {
                if (!svn.CouldAdd(newName, SvnNodeKind.File))
                {
                    ok = false;
                    return;
                }

                if (svn.IsUnversioned(oldName))
                    return;
            }
        }
예제 #12
0
        internal void OnSccCleanup(CommandEventArgs e)
        {
            _registeredSccCleanup = false;
            _collectHints = false;

            _fileHints.Clear();
            _fileOrigins.Clear();

            if (_delayedDeletes.Count > 0)
            {
                using (SvnSccContext svn = new SvnSccContext(Context))
                {
                    foreach (string d in _delayedDeletes.ToArray())
                    {
                        _delayedDeletes.Remove(d);
                        svn.WcDelete(d);
                    }
                }
            }
        }