public bool ApplyChanges(IEnumerable<PendingChange> changes, PendingChangeApplyArgs args)
        {
            using (PendingCommitState state = new PendingCommitState(Context, changes))
            {
                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;

                return true;
            }
        }
        /// <summary>
        /// Verifies if the log message is valid for the current policy
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        private bool PreCommit_VerifyLogMessage(PendingCommitState state)
        {
            if (String.IsNullOrWhiteSpace(state.LogMessage))
            {
                DialogResult result = state.MessageBox.Show(PccStrings.NoMessageProvided,
                    "",
                    MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

                if (result == DialogResult.No)
                    return false;
            }

            if (state.LogMessage == null)
                return true; // Skip checks

            // And after checking whether the message is valid: Normalize the message the way the CLI would
            // * No whitespace at the end of lines
            // * Always a newline at the end

            StringBuilder sb = new StringBuilder();
            foreach (string line in state.LogMessage.Replace("\r", "").Split('\n'))
            {
                sb.AppendLine(line.TrimEnd());
            }

            string msg = sb.ToString();

            // And make sure the log message ends with a single newline
            state.LogMessage = msg.TrimEnd() + Environment.NewLine;

            return true; // Logmessage always ok for now
        }
        /// <summary>
        /// Save all documents in the selection
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        private bool PreCommit_SaveDirty(PendingCommitState state)
        {
            IVisualGitOpenDocumentTracker tracker = state.GetService<IVisualGitOpenDocumentTracker>();

            if (!tracker.SaveDocuments(state.CommitPaths))
            {
                state.MessageBox.Show(PccStrings.FailedToSaveBeforeCommit, "", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Exclamation);
                return false;
            }

            return true;
        }
        private bool PreCommit_VerifyConfiguration(PendingCommitState state)
        {
            using (GitPoolClient client = state.GetService<IGitClientPool>().GetNoUIClient())
            {
                IGitConfig config = client.GetUserConfig();

                if (
                    String.IsNullOrEmpty(config.GetString("user", null, "name")) ||
                    String.IsNullOrEmpty(config.GetString("user", null, "email"))
                ) {
                    state.MessageBox.Show(PccStrings.NameOrEmailNotSet,
                        "",
                        MessageBoxButtons.OK, MessageBoxIcon.Warning);

                    return false;
                }
            }

            return true;
        }
        /// <summary>
        /// Adds all files which are marked as to be added to Git
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        private bool PreCommit_AddNewFiles(PendingCommitState state)
        {
            foreach (PendingChange pc in state.Changes)
            {
                if (pc.Change != null && pc.Change.State == PendingChangeKind.New)
                {
                    GitItem item = pc.GitItem;

                    // HACK: figure out why PendingChangeKind.New is still true
                    if (item.IsVersioned)
                        continue; // No need to add

                    GitAddArgs a = new GitAddArgs();
                    a.AddParents = true;
                    a.Depth = GitDepth.Empty;

                    try
                    {
                        state.Client.Add(pc.FullPath, a);
                    }
                    catch (GitException ex)
                    {
                        GetService<IVisualGitErrorHandler>().OnWarning(ex);
                        return false;
                    }
                }
            }
            return true;
        }
        /// <summary>
        /// Fixes up missing files by fixing their casing or deleting them
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        private bool PreCommit_HandleMissingFiles(PendingCommitState state)
        {
            foreach (string path in new List<string>(state.CommitPaths))
            {
                GitItem item = state.Cache[path];

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

                if (item.IsCasingConflicted)
                {
                    string correctCasing = GetGitCasing(item);
                    string actualCasing = GitTools.GetTruePath(item.FullPath);

                    if (correctCasing == null || actualCasing == null || !string.Equals(correctCasing, actualCasing, StringComparison.OrdinalIgnoreCase))
                        continue; // Nothing to fix here :(

                    string correctFile = Path.GetFileName(correctCasing);
                    string actualFile = Path.GetFileName(actualCasing);

                    if (correctFile == actualFile)
                        continue; // Casing issue is not in the file; can't fix :(

                    IVisualGitOpenDocumentTracker odt = GetService<IVisualGitOpenDocumentTracker>();
                    using (odt.LockDocument(correctCasing, DocumentLockType.NoReload))
                    using (odt.LockDocument(actualCasing, DocumentLockType.NoReload))
                    {
                        try
                        {
                            File.Move(actualCasing, correctCasing);

                            // Fix the name in the commit list
                            state.CommitPaths[state.CommitPaths.IndexOf(path)] = actualCasing;
                        }
                        catch
                        { }
                        finally
                        {
                            item.MarkDirty();
                            GetService<IFileStatusMonitor>().ScheduleGlyphUpdate(item.FullPath);
                        }
                    }
                }
                else if (!item.Exists)
                {
                    GitDeleteArgs da = new GitDeleteArgs();
                    da.KeepLocal = true;

                    try
                    {
                        state.Client.Delete(path, da);
                    }
                    catch (GitException ex)
                    {
                        GetService<IVisualGitErrorHandler>().OnWarning(ex);
                        return false;
                    }
                }
            }

            return true;
        }
        /// <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;
            GitCommitResult rslt = null;

            GitDepth depth = state.CalculateCommitDepth();

            if (depth == GitDepth.Unknown)
                return false;

            ProgressRunnerResult r = state.GetService<IProgressRunner>().RunModal(PccStrings.CommitTitle,
                delegate(object sender, ProgressWorkerArgs e)
                {
                    GitCommitArgs ca = new GitCommitArgs();
                    ca.Depth = depth;
                    ca.LogMessage = state.LogMessage;
                    ca.AmendLastCommit = state.AmendLastCommit;

                    try
                    {
                        ok = e.Client.Commit(
                            state.CommitPaths,
                            ca, out rslt);
                    }
                    catch (GitException ex)
                    {
                        GetService<IVisualGitErrorHandler>().OnWarning(ex);
                        ok = false;
                    }
                });

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

                if (ci != null && rslt.Revision != null)
                    ci.SetLastChange(PccStrings.CommittedPrefix, rslt.Revision.ToString());
            }

            return ok;
        }
Example #8
0
        private void PostCommit_IssueTracker(PendingCommitState state, SvnCommitResult result)
        {
            IAnkhIssueService iService = GetService<IAnkhIssueService>();
            if (iService != null)
            {
                IssueRepository iRepo = iService.CurrentIssueRepository;
                if (iRepo != null)
                {
                    List<Uri> uris = new List<Uri>();
                    foreach (PendingChange pc in state.Changes)
                    {
                        uris.Add(pc.Uri);
                    }

                    PostCommitArgs pca = new PostCommitArgs(uris.ToArray(), result.Revision, state.LogMessage);
                    try
                    {
                        iRepo.PostCommit(pca);
                    }
                    catch { };
                }
            }
        }
Example #9
0
        /// <summary>
        /// Verifies if the log message is valid for the current policy
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        private bool PreCommit_VerifyLogMessage(PendingCommitState state)
        {
            if (state.LogMessage == null)
                return true; // Skip checks

            // And after checking whether the message is valid: Normalize the message the way the CLI would
            // * No whitespace at the end of lines
            // * Always a newline at the end

            StringBuilder sb = new StringBuilder();
            foreach (string line in state.LogMessage.Replace("\r", "").Split('\n'))
            {
                sb.AppendLine(line.TrimEnd());
            }

            string msg = sb.ToString();

            // Use the project commit settings class to add an issue number (if available)
            IProjectCommitSettings pcs = state.GetService<IProjectCommitSettings>();
            if (pcs.WarnIfNoIssue && pcs.ShowIssueBox && string.IsNullOrEmpty(state.IssueText) &&
                state.MessageBox.Show(PccStrings.NoIssueNumber, "",
                                      MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
            {
                return false;
            }
            msg = pcs.BuildLogMessage(msg, state.IssueText);

            // And make sure the log message ends with a single newline
            state.LogMessage = msg.TrimEnd() + Environment.NewLine;

            return true; // Logmessage always ok for now
        }
        public bool CreatePatch(IEnumerable<PendingChange> changes, PendingChangeCreatePatchArgs args)
        {
            using (PendingCommitState state = new PendingCommitState(Context, changes))
            {
                if (!PreCommit_VerifySingleRoot(state)) // Verify single root 'first'
                    return false;

                if (!PreCommit_SaveDirty(state))
                    return false;

                if (args.AddUnversionedFiles)
                {
                    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;
            }

            string relativeToPath = args.RelativeToPath;
            string relativeToPathP = relativeToPath.EndsWith("\\") ? relativeToPath : (relativeToPath + "\\");
            string fileName = args.FileName;
            GitRevisionRange revRange = new GitRevisionRange(GitRevision.Base, GitRevision.Working);

            GitDiffArgs a = new GitDiffArgs();
            a.IgnoreAncestry = true;
            a.NoDeleted = false;
            a.Depth = GitDepth.Empty;

            using (MemoryStream stream = new MemoryStream())
            {
                GetService<IProgressRunner>().RunModal(PccStrings.DiffTitle,
                    delegate(object sender, ProgressWorkerArgs e)
                    {
                        foreach (PendingChange pc in changes)
                        {
                            GitItem item = pc.GitItem;
                            GitWorkingCopy wc;
                            if (!string.IsNullOrEmpty(relativeToPath)
                                && item.FullPath.StartsWith(relativeToPathP, StringComparison.OrdinalIgnoreCase))
                                a.RelativeToPath = relativeToPath;
                            else if ((wc = item.WorkingCopy) != null)
                                a.RelativeToPath = wc.FullPath;
                            else
                                a.RelativeToPath = null;

                            e.Client.Diff(item.FullPath, revRange, a, stream);
                        }

                        stream.Flush();
                        stream.Position = 0;
                    });
                using (StreamReader sr = new StreamReader(stream))
                {
                    string line;

                    // Parse to lines to resolve EOL issues
                    using (StreamWriter sw = File.CreateText(fileName))
                    {
                        while (null != (line = sr.ReadLine()))
                            sw.WriteLine(line);
                    }
                }
            }
            return true;
        }
Example #11
0
 private bool PreCommit_VerifyIssueTracker(PendingCommitState state)
 {
     IAnkhIssueService iService = state.GetService<IAnkhIssueService>();
     if (iService != null)
     {
         IssueRepository iRepo = iService.CurrentIssueRepository;
         if (iRepo != null)
         {
             List<Uri> uris = new List<Uri>();
             foreach (PendingChange pc in state.Changes)
             {
                 uris.Add(pc.Uri);
             }
             PreCommitArgs args = new PreCommitArgs(uris.ToArray(), 1);
             args.CommitMessage = state.LogMessage;
             iRepo.PreCommit(args);
             if (args.Cancel) { return false; }
             state.LogMessage = args.CommitMessage;
         }
     }
     return true;
 }
Example #12
0
        /// <summary>
        /// Fixes up missing files by fixing their casing or deleting them
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        private bool PreCommit_HandleMissingFiles(PendingCommitState state)
        {
            foreach (string path in new List<string>(state.CommitPaths))
            {
                SvnItem item = state.Cache[path];

                if (item.Status.LocalContentStatus != SvnStatus.Missing)
                    continue;

                if (item.IsCasingConflicted)
                {
                    string correctCasing = GetSvnCasing(item);
                    string actualCasing = SvnTools.GetTruePath(item.FullPath);

                    if (correctCasing == null || actualCasing == null || !string.Equals(correctCasing, actualCasing, StringComparison.OrdinalIgnoreCase))
                        continue; // Nothing to fix here :(

                    string correctFile = Path.GetFileName(correctCasing);
                    string actualFile = Path.GetFileName(actualCasing);

                    if (correctFile == actualFile)
                        continue; // Casing issue is not in the file; can't fix :(

                    IAnkhOpenDocumentTracker odt = GetService<IAnkhOpenDocumentTracker>();
                    using (odt.LockDocument(correctCasing, DocumentLockType.NoReload))
                    using (odt.LockDocument(actualCasing, DocumentLockType.NoReload))
                    {
                        try
                        {
                            File.Move(actualCasing, correctCasing);

                            // Fix the name in the commit list
                            state.CommitPaths[state.CommitPaths.IndexOf(path)] = actualCasing;
                        }
                        catch
                        { }
                        finally
                        {
                            item.MarkDirty();
                            GetService<IFileStatusMonitor>().ScheduleGlyphUpdate(item.FullPath);
                        }
                    }
                }
                else if (!item.Exists)
                {
                    SvnDeleteArgs da = new SvnDeleteArgs();
                    da.KeepLocal = true;
                    da.ThrowOnError = false;

                    if (!state.Client.Delete(path, da))
                    {
                        state.MessageBox.Show(da.LastException.Message, "", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                        return false;
                    }
                }
            }

            return true;
        }
Example #13
0
        /// <summary>
        /// Adds all files which are marked as to be added to subversion
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        private bool PreCommit_AddNewFiles(PendingCommitState state)
        {
            foreach (PendingChange pc in state.Changes)
            {
                if (pc.Change != null && pc.Change.State == PendingChangeKind.New)
                {
                    SvnItem item = pc.SvnItem;

                    // HACK: figure out why PendingChangeKind.New is still true
                    if (item.IsVersioned)
                        continue; // No need to add

                    SvnAddArgs a = new SvnAddArgs();
                    a.AddParents = true;
                    a.Depth = SvnDepth.Empty;
                    a.ThrowOnError = false;

                    if (!state.Client.Add(pc.FullPath, a))
                    {
                        if (a.LastException != null && a.LastException.SvnErrorCode == SvnErrorCode.SVN_ERR_WC_UNSUPPORTED_FORMAT)
                        {
                            state.MessageBox.Show(a.LastException.Message + Environment.NewLine + Environment.NewLine
                                + PccStrings.YouCanDownloadAnkh, "", MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                            return false;
                        }
                        else if (state.MessageBox.Show(a.LastException.Message, "", MessageBoxButtons.OKCancel, System.Windows.Forms.MessageBoxIcon.Error) == DialogResult.Cancel)
                            return false;
                    }
                }
            }
            return true;
        }
        private bool PreCommit_VerifyNoConflicts(PendingCommitState state)
        {
            foreach (PendingChange pc in state.Changes)
            {
                GitItem item = pc.GitItem;

                if(item.IsConflicted)
                {
                    state.MessageBox.Show(PccStrings.OneOrMoreItemsConflicted,
                        "",
                        MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

                    return false;
                }
            }

            return true;
        }
        /// <summary>
        /// Adds all new parents of files to add to Git
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        private bool PreCommit_AddNeededParents(PendingCommitState state)
        {
            foreach (string path in new List<string>(state.CommitPaths))
            {
                GitItem item = state.Cache[path];

                if (item.IsNewAddition)
                {
                    GitItem parent = item.Parent;
                    GitWorkingCopy wc = item.WorkingCopy;

                    if (wc == null)
                    {
                        // This should be impossible. A node can't be added and not in a WC
                        item.MarkDirty();
                        continue;
                    }

                    string wcPath = wc.FullPath;

                    while (parent != null &&
                           !string.Equals(parent.FullPath, wcPath, StringComparison.OrdinalIgnoreCase)
                           && parent.IsNewAddition)
                    {
                        if (!state.CommitPaths.Contains(parent.FullPath))
                            state.CommitPaths.Add(parent.FullPath);

                        parent = parent.Parent;
                    }
                }
            }
            return true;
        }
        private bool PreCommit_VerifySingleRoot(PendingCommitState state)
        {
            GitWorkingCopy wc = null;
            foreach (PendingChange pc in state.Changes)
            {
                GitItem item = pc.GitItem;

                if (item.IsVersioned || item.IsVersionable)
                {
                    GitWorkingCopy w = item.WorkingCopy;

                    if (wc == null)
                        wc = w;
                    else if (w != null && w != wc)
                    {
                        StringBuilder sb = new StringBuilder();
                        sb.AppendLine(PccStrings.CommitSingleWc);
                        sb.AppendFormat(PccStrings.WorkingCopyX, wc.FullPath);
                        sb.AppendLine();
                        sb.AppendFormat(PccStrings.WorkingCopyX, w.FullPath);
                        sb.AppendLine();

                        state.MessageBox.Show(sb.ToString(), "", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

                        return false;
                    }
                }
            }
            return true;
        }
Example #17
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;

            SvnDepth depth = state.CalculateCommitDepth();

            if (depth == SvnDepth.Unknown)
                return false;

            StringBuilder outOfDateMessage = null;
            ProgressRunnerResult r = state.GetService<IProgressRunner>().RunModal(PccStrings.CommitTitle,
                delegate(object sender, ProgressWorkerArgs e)
                {
                    SvnCommitArgs ca = new SvnCommitArgs();
                    ca.Depth = depth;
                    ca.KeepLocks = state.KeepLocks;
                    ca.KeepChangeLists = state.KeepChangeLists;
                    ca.LogMessage = state.LogMessage;
                    ca.AddExpectedError(SvnErrorCode.SVN_ERR_RA_OUT_OF_DATE);
                    ca.AddExpectedError(SvnErrorCode.SVN_ERR_WC_NOT_UP_TO_DATE);
                    ca.AddExpectedError(SvnErrorCode.SVN_ERR_FS_TXN_OUT_OF_DATE);

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

                    if(!ok && ca.LastException != null)
                    {
                        switch (ca.LastException.SvnErrorCode)
                        {
                            case SvnErrorCode.SVN_ERR_WC_NOT_UP_TO_DATE:
                            case SvnErrorCode.SVN_ERR_RA_OUT_OF_DATE:
                            case SvnErrorCode.SVN_ERR_FS_TXN_OUT_OF_DATE:
                                outOfDateMessage = new StringBuilder();
                                Exception ex = ca.LastException;

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

                                break;
                        }
                    }
                });

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

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

                if (ci != null)
                    ci.SetLastChange(PccStrings.CommittedPrefix, rslt.Revision.ToString());

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