Beispiel #1
0
        public bool Commit(IEnumerable <PendingChange> changes, PendingChangeCommitArgs args)
        {
            // Ok, to make a commit happen we have to take 'a few' steps
            IAnkhServiceEvents ci = GetService <IAnkhServiceEvents>();

            if (ci != null)
            {
                ci.OnLastChanged(new LastChangedEventArgs(null, null));
            }

            bool storeMessage = args.StoreMessageOnError;

            foreach (PendingCommitState state in GetCommitRoots(changes))
            {
                if (state == null)
                {
                    return(false);
                }

                try
                {
                    state.KeepLocks       = args.KeepLocks;
                    state.KeepChangeLists = args.KeepChangeLists;
                    state.LogMessage      = args.LogMessage;
                    state.IssueText       = args.IssueText;

                    if (!PreCommit_VerifySingleRoot(state)) // Verify single root 'first'
                    {
                        return(false);
                    }

                    // Verify this before verifying log message
                    // so that issue tracker integration has precedence
                    if (!PreCommit_VerifyIssueTracker(state))
                    {
                        return(false);
                    }

                    if (!PreCommit_VerifyLogMessage(state))
                    {
                        return(false);
                    }

                    if (!PreCommit_VerifyNoConflicts(state))
                    {
                        return(false);
                    }

                    if (!PreCommit_SaveDirty(state))
                    {
                        return(false);
                    }

                    if (!PreCommit_AddNewFiles(state))
                    {
                        return(false);
                    }

                    if (!PreCommit_HandleMissingFiles(state))
                    {
                        return(false);
                    }

                    state.FlushState();

                    if (!PreCommit_AddNeededParents(state))
                    {
                        return(false);
                    }

                    if (!PreCommit_VerifySingleRoot(state)) // Verify single root 'again'
                    {
                        return(false);
                    }

                    if (!PreCommit_VerifyTargetsVersioned(state))
                    {
                        return(false);
                    }
                    // if(!PreCommit_....())
                    //  return;


                    bool ok = false;
                    using (DocumentLock dl = GetService <IAnkhOpenDocumentTracker>().LockDocuments(state.CommitPaths, DocumentLockType.NoReload))
                        using (dl.MonitorChangesForReload()) // Monitor files that are changed by keyword expansion
                        {
                            if (Commit_CommitToRepository(state))
                            {
                                storeMessage = true;
                                ok           = true;
                            }
                        }

                    if (!ok)
                    {
                        return(false);
                    }
                }
                finally
                {
                    string msg = state.LogMessage;

                    state.Dispose();

                    if (storeMessage && msg != null && msg.Trim().Length > 0)
                    {
                        Config.GetRecentLogMessages().Add(msg);
                    }
                }
            }

            return(true);
        }
Beispiel #2
0
        /// <summary>
        /// Finalizes the action by committing to the repository
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        private bool Commit_CommitToRepository(PendingCommitState state)
        {
            bool            ok   = false;
            SvnCommitResult rslt = null;

            bool enableHooks = Config.Instance.EnableTortoiseSvnHooks;

            bool outOfDateError = false;
            bool otherError     = false;

            StringBuilder outOfDateMessage = null;

            state.GetService <IProgressRunner>().RunModal(PccStrings.CommitTitle,
                                                          delegate(object sender, ProgressWorkerArgs e)
            {
                string itemPath    = null;
                SvnCommitArgs ca   = new SvnCommitArgs();
                ca.Depth           = SvnDepth.Empty;
                ca.KeepLocks       = state.KeepLocks;
                ca.KeepChangeLists = state.KeepChangeLists;
                ca.LogMessage      = state.LogMessage;

                foreach (KeyValuePair <string, string> kv in state.CustomProperties)
                {
                    ca.LogProperties.Add(kv.Key, kv.Value);
                }

                ca.AddExpectedError(SvnErrorCode.SVN_ERR_WC_NOT_UP_TO_DATE);
                ca.AddExpectedError(SvnErrorCode.SVN_ERR_CLIENT_FORBIDDEN_BY_SERVER);
                ca.AddExpectedError(SvnErrorCode.SVN_ERR_CLIENT_NO_LOCK_TOKEN);
                ca.AddExpectedError(SvnErrorCode.SVN_ERR_IO_INCONSISTENT_EOL);
                ca.AddExpectedError(SvnErrorCode.SVN_ERR_FS_TXN_OUT_OF_DATE);
                ca.AddExpectedError(SvnErrorCode.SVN_ERR_RA_OUT_OF_DATE);
                ca.AddExpectedError(SvnErrorCode.SVN_ERR_WC_FOUND_CONFLICT);
                ca.AddExpectedError(SvnErrorCode.SVN_ERR_WC_PATH_NOT_FOUND);
                ca.Notify += delegate(object notifySender, SvnNotifyEventArgs notifyE)
                {
                    switch (notifyE.Action)
                    {
                    case SvnNotifyAction.FailedOutOfDate:
                        if (notifyE.Error != null)
                        {
                            ca.AddExpectedError(notifyE.Error.SvnErrorCode);                     // Don't throw an exception for this error
                        }
                        outOfDateError = true;
                        itemPath       = itemPath ?? notifyE.FullPath;
                        break;

                    case SvnNotifyAction.FailedConflict:
                    case SvnNotifyAction.FailedMissing:
                    case SvnNotifyAction.FailedNoParent:
                    case SvnNotifyAction.FailedLocked:
                    case SvnNotifyAction.FailedForbiddenByServer:
                        if (notifyE.Error != null)
                        {
                            ca.AddExpectedError(notifyE.Error.SvnErrorCode);                     // Don't throw an exception for this error
                        }
                        otherError = true;
                        itemPath   = itemPath ?? notifyE.FullPath;
                        break;
                    }
                };
                ca.RunTortoiseHooks = enableHooks;

                ok = e.Client.Commit(
                    state.CommitPaths,
                    ca, out rslt);

                if (!ok && ca.LastException != null)
                {
                    if (!outOfDateError && !otherError)
                    {
                        outOfDateError = true;     // Remaining errors are handled as exception
                    }
                    outOfDateMessage = new StringBuilder();
                    Exception ex     = ca.LastException;

                    while (ex != null)
                    {
                        outOfDateMessage.AppendLine(ex.Message);
                        ex = ex.InnerException;
                    }

                    if (!string.IsNullOrEmpty(itemPath))
                    {
                        outOfDateMessage.AppendLine();
                        outOfDateMessage.AppendFormat(PccStrings.WhileCommittingX, itemPath);
                    }
                }
            });

            if (outOfDateMessage != null)
            {
                state.MessageBox.Show(outOfDateMessage.ToString(),
                                      outOfDateError ? PccStrings.OutOfDateCaption : PccStrings.CommitFailedCaption,
                                      MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            if (rslt != null)
            {
                IAnkhServiceEvents ci = GetService <IAnkhServiceEvents>();

                if (ci != null)
                {
                    ci.OnLastChanged(new LastChangedEventArgs(PccStrings.CommittedPrefix, rslt.Revision.ToString()));
                }

                if (!string.IsNullOrEmpty(rslt.PostCommitError))
                {
                    state.MessageBox.Show(rslt.PostCommitError, PccStrings.PostCommitError, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }

                PostCommit_IssueTracker(state, rslt);
            }
            return(ok);
        }
        public override void OnExecute(CommandEventArgs e)
        {
            IAnkhServiceEvents ci = e.GetService <IAnkhServiceEvents>();

            if (ci != null)
            {
                ci.OnLastChanged(new LastChangedEventArgs(null, null));
            }

            SvnRevision rev;
            bool        allowUnversionedObstructions = false;
            bool        updateExternals  = true;
            bool        setDepthInfinity = true;

            IAnkhSolutionSettings settings = e.GetService <IAnkhSolutionSettings>();
            ISvnStatusCache       cache    = e.GetService <ISvnStatusCache>();
            IProjectFileMapper    mapper   = e.GetService <IProjectFileMapper>();
            Uri reposRoot = null;

            if (IsHeadCommand(e.Command) || e.DontPrompt)
            {
                rev = SvnRevision.Head;
            }
            else if (IsSolutionCommand(e.Command))
            {
                SvnItem projectItem = settings.ProjectRootSvnItem;

                Debug.Assert(projectItem != null, "Has item");

                using (UpdateDialog ud = new UpdateDialog())
                {
                    ud.ItemToUpdate = projectItem;
                    ud.Revision     = SvnRevision.Head;

                    if (ud.ShowDialog(e.Context) != DialogResult.OK)
                    {
                        return;
                    }

                    rev = ud.Revision;
                    allowUnversionedObstructions = ud.AllowUnversionedObstructions;
                    updateExternals  = ud.UpdateExternals;
                    setDepthInfinity = ud.SetDepthInfinty;
                }
            }
            else if (IsFolderCommand(e.Command))
            {
                SvnItem dirItem = EnumTools.GetFirst(e.Selection.GetSelectedSvnItems(false));

                Debug.Assert(dirItem != null && dirItem.IsDirectory && dirItem.IsVersioned);

                using (UpdateDialog ud = new UpdateDialog())
                {
                    ud.Text            = CommandStrings.UpdateFolder;
                    ud.FolderLabelText = CommandStrings.UpdateFolderLabel;
                    ud.ItemToUpdate    = dirItem;
                    ud.Revision        = SvnRevision.Head;

                    if (ud.ShowDialog(e.Context) != DialogResult.OK)
                    {
                        return;
                    }

                    rev = ud.Revision;
                    allowUnversionedObstructions = ud.AllowUnversionedObstructions;
                    updateExternals  = ud.UpdateExternals;
                    setDepthInfinity = ud.SetDepthInfinty;
                }
            }
            else
            {
                // We checked there was only a single repository to select a revision
                // from in OnUpdate, so we can suffice with only calculate the path

                SvnItem   si     = null;
                SvnOrigin origin = null;
                foreach (SccProject p in GetSelectedProjects(e))
                {
                    ISccProjectInfo pi = mapper.GetProjectInfo(p);
                    if (pi == null || pi.ProjectDirectory == null)
                    {
                        continue;
                    }

                    SvnItem item = cache[pi.ProjectDirectory];
                    if (!item.IsVersioned)
                    {
                        continue;
                    }

                    if (si == null && origin == null)
                    {
                        si        = item;
                        origin    = new SvnOrigin(item);
                        reposRoot = item.WorkingCopy.RepositoryRoot;
                    }
                    else
                    {
                        si = null;
                        string urlPath1 = origin.Uri.AbsolutePath;
                        string urlPath2 = item.Uri.AbsolutePath;

                        int i = 0;
                        while (i < urlPath1.Length && i < urlPath2.Length &&
                               urlPath1[i] == urlPath2[i])
                        {
                            i++;
                        }

                        while (i > 0 && urlPath1[i - 1] != '/')
                        {
                            i--;
                        }

                        origin = new SvnOrigin(new Uri(origin.Uri, urlPath1.Substring(0, i)), origin.RepositoryRoot);
                    }
                }

                Debug.Assert(origin != null);

                using (UpdateDialog ud = new UpdateDialog())
                {
                    ud.Text = CommandStrings.UpdateProject;

                    if (si != null)
                    {
                        ud.ItemToUpdate = si;
                    }
                    else
                    {
                        ud.SvnOrigin = origin;
                        ud.SetMultiple(true);
                    }

                    ud.Revision = SvnRevision.Head;

                    if (ud.ShowDialog(e.Context) != DialogResult.OK)
                    {
                        return;
                    }

                    rev = ud.Revision;
                    allowUnversionedObstructions = ud.AllowUnversionedObstructions;
                    updateExternals  = ud.UpdateExternals;
                    setDepthInfinity = ud.SetDepthInfinty;
                }
            }

            Dictionary <string, SvnItem>     itemsToUpdate = new Dictionary <string, SvnItem>(StringComparer.OrdinalIgnoreCase);
            SortedList <string, UpdateGroup> groups        = new SortedList <string, UpdateGroup>(StringComparer.OrdinalIgnoreCase);

            // Get a list of all documents below the specified paths that are open in editors inside VS
            HybridCollection <string> lockPaths       = new HybridCollection <string>(StringComparer.OrdinalIgnoreCase);
            IAnkhOpenDocumentTracker  documentTracker = e.GetService <IAnkhOpenDocumentTracker>();

            foreach (SvnItem item in GetAllUpdateRoots(e))
            {
                // GetAllUpdateRoots can (and probably will) return duplicates!

                if (itemsToUpdate.ContainsKey(item.FullPath) || !item.IsVersioned)
                {
                    continue;
                }

                SvnWorkingCopy wc = item.WorkingCopy;

                if (!IsHeadCommand(e.Command) && reposRoot != null)
                {
                    // Specific revisions are only valid on a single repository!
                    if (wc != null && wc.RepositoryRoot != reposRoot)
                    {
                        continue;
                    }
                }

                UpdateGroup group;

                if (!groups.TryGetValue(wc.FullPath, out group))
                {
                    group = new UpdateGroup(wc.FullPath);
                    groups.Add(wc.FullPath, group);
                }

                group.Nodes.Add(item.FullPath);
                itemsToUpdate.Add(item.FullPath, item);

                foreach (string file in documentTracker.GetDocumentsBelow(item.FullPath))
                {
                    if (!lockPaths.Contains(file))
                    {
                        lockPaths.Add(file);
                    }
                }
            }

            documentTracker.SaveDocuments(lockPaths); // Make sure all files are saved before updating/merging!

            using (DocumentLock lck = documentTracker.LockDocuments(lockPaths, DocumentLockType.NoReload))
                using (lck.MonitorChangesForReload())
                {
                    SvnUpdateResult updateResult = null;

                    ProgressRunnerArgs pa = new ProgressRunnerArgs();
                    pa.CreateLog = true;

                    string title;

                    if (IsSolutionCommand(e.Command))
                    {
                        title = CommandStrings.UpdatingSolution;
                    }
                    else if (IsFolderCommand(e.Command))
                    {
                        title = CommandStrings.UpdatingFolder;
                    }
                    else
                    {
                        title = CommandStrings.UpdatingProject;
                    }

                    e.GetService <IProgressRunner>().RunModal(title, pa,
                                                              delegate(object sender, ProgressWorkerArgs a)
                    {
                        PerformUpdate(e, a, rev, allowUnversionedObstructions, updateExternals, setDepthInfinity, groups.Values, out updateResult);
                    });

                    if (ci != null && updateResult != null && IsSolutionCommand(e.Command))
                    {
                        ci.OnLastChanged(new LastChangedEventArgs(CommandStrings.UpdatedToTitle, updateResult.Revision.ToString()));
                    }
                }
        }