public IEnumerable<IChangeReport> GetChangeRecords(Revision revision)
        {
            var changes = new List<IChangeReport>();
            revision.EnsureParentRevisionInfo();

            if (!revision.HasAtLeastOneParent)
            {
                //describe the contents of the initial checkin
                foreach (var fileInRevision in Repository.GetFilesInRevision(revision))
                {
                    CollectChangesInFile(fileInRevision, null, changes);
                }
            }

            else
            {
                IEnumerable<RevisionNumber> parentRevs = revision.GetLocalNumbersOfParents();
                foreach (RevisionNumber parentRev in parentRevs)
                {
                    foreach (var fileInRevision in Repository.GetFilesInRevision(revision)
                        .Where(fileInRevision => parentRevs.Count() == 1
                            || fileInRevision.FullPath.ToLowerInvariant().EndsWith(".chorusnotes")))
                    {
                        CollectChangesInFile(fileInRevision, parentRev.LocalRevisionNumber, changes);
                    }
                }
                if (parentRevs.Count() > 1)
                    changes = new List<IChangeReport>(changes.Distinct());
            }

            return changes;
        }
		public void Synchronizer_DoesNotReportOldChangeOnOtherBranch()
		{
			string savedSettings = "";
			var rev1 = new Revision(null, "default", "Fred", "1234", "hash1234", "change something");
			// The first revision we see on another branch doesn't produce a warning...it might be something old everyone has upgraded from.
			var revs = new[] { rev1 };
			Assert.That(LiftSynchronizerAdjunct.GetRepositoryBranchCheckData(revs, "7.2.1", ref savedSettings), Is.Null);
			//Assert.That(savedSettings, Is.EqualTo("default:1234")); // Don't really care what is here as long as it works

			var rev2 = new Revision(null, "default", "Fred", "1234", "hash1234", "change something else");
			revs = new[] { rev2 };
			Assert.That(LiftSynchronizerAdjunct.GetRepositoryBranchCheckData(revs, "7.2.1", ref savedSettings), Is.Null);
		}
Example #3
0
 public bool IsDirectDescendantOf(Revision revision)
 {
     EnsureParentRevisionInfo();
     //TODO: this is only checking direct descendant
     return(Parents.Any(p => p.Hash == revision.Number.Hash));
 }
		private static string RevisionId(Revision revision)
		{
			return revision.Number.LocalRevisionNumber;
		}
		private void HistoryPageRevisionSelectionChanged(object sender, RevisionEventArgs e)
		{
			_currentRevision = e.Revision;
		}
Example #6
0
        /// <summary>
        /// There may be more, but for now: take care of the case where one guy has a file not
        /// modified (and not checked in), and the other guy is going to hammer it (with a remove
        /// or change).
        /// </summary>
        private void RemoveMergeObstacles(Revision rev1, Revision rev2)
        {
            /* this has proved a bit hard to get right.
             * when a file is in a recently brought in changeset, and also local (but untracked), status --rev ___ lists the file twice:
             *
             * >hg status --rev 14
             * R test.txt
             * ? test.txt
             *
             */

            //todo: push down to hgrepository
            var files = Repository.GetFilesInRevisionFromQuery(rev1 /*this param is bogus*/, "status -ru --rev " + rev2.Number.LocalRevisionNumber);

            foreach (var file in files)
            {
                if (file.ActionThatHappened == FileInRevision.Action.Deleted)// listed with 'R'
                {
                    //is it also listed as unknown?
                    if (files.Any(f => f.FullPath == file.FullPath && f.ActionThatHappened == FileInRevision.Action.Unknown))
                    {
                        try
                        {
                            var newPath = file.FullPath + "-" + Path.GetRandomFileName() + ".ChorusRescuedFile";

                            _progress.WriteWarning(
                                "Renamed {0} to {1} because it is not part of {2}'s repository but it is part of {3}'s, and this would otherwise prevent a merge.",
                                file.FullPath, Path.GetFileName(newPath), rev1.UserId, rev2.UserId);

                            if (!File.Exists(file.FullPath))
                            {
                                _progress.WriteError("The file marked for rescuing didn't actually exist.  Please report this bug in Chorus.");
                                continue;
                            }
                            File.Move(file.FullPath, newPath);
                        }
                        catch (Exception error)
                        {
                            _progress.WriteError("Could not move the file. Error follows.");
                            _progress.WriteException(error);
                            throw;
                        }
                    }
                }
            }
        }
Example #7
0
 /// <returns>false if nothing needed to be merged, true if the merge was done. Throws exception if there is an error.</returns>
 private bool MergeTwoChangeSets(Revision head, Revision theirHead)
 {
     string chorusMergeFilePath = Path.Combine(ExecutionEnvironment.DirectoryOfExecutingAssembly, "ChorusMerge.exe");
     #if MONO
     // The replace is only useful for use with the MonoDevelop environment whcih doesn't honor $(Configuration) in the csproj files.
     // When this is exported as an environment var it needs escaping to prevent the shell from replacing it with an empty string.
     // When MonoDevelop is fixed this can be removed.
     chorusMergeFilePath = chorusMergeFilePath.Replace("$(Configuration)", "\\$(Configuration)");
     #endif
     using (new ShortTermEnvironmentalVariable("HGMERGE", '"' + chorusMergeFilePath + '"'))
     {
         // Theory has it that is a tossup on who ought to win, unless there is some more principled way to decide.
         // If 'they' end up being the right answer, or if it ends up being more exotic,
         // then be sure to change the alpha and beta info in the MergeSituation class.
         //using (new ShortTermEnvironmentalVariable(MergeOrder.kConflictHandlingModeEnvVarName, MergeOrder.ConflictHandlingModeChoices.TheyWin.ToString()))
         // Go with 'WeWin', since that is the default and that is how the alpha and beta data of MergeSituation is set, right before this method is called.
         using (new ShortTermEnvironmentalVariable(MergeOrder.kConflictHandlingModeEnvVarName, MergeOrder.ConflictHandlingModeChoices.WeWin.ToString()))
         {
             var didMerge = Repository.Merge(_localRepositoryPath, theirHead.Number.LocalRevisionNumber);
             FailureSimulator.IfTestRequestsItThrowNow("SychronizerAdjunct");
             return didMerge;
         }
     }
 }
Example #8
0
        /// <summary>
        /// This method handles post merge tasks including the commit after the merge
        /// </summary>
        /// <param name="head"></param>
        /// <param name="peopleWeMergedWith"></param>
        private void DoPostMergeCommit(Revision head)
        {
            //that merge may have generated notes files where they didn't exist before,
            //and we want these merged
            //version + updated/created notes files to go right back into the repository

            //  args.Append(" -X " + SurroundWithQuotes(Path.Combine(_pathToRepository, "**.ChorusRescuedFile")));

            AppendAnyNewNotes(_localRepositoryPath);

            _sychronizerAdjunct.PrepareForPostMergeCommit(_progress);

            AddAndCommitFiles(GetMergeCommitSummary(head.UserId, Repository));
        }
        private void AddRow(Revision rev)
        {
            var dateString = rev.DateString;
            DateTime when;

            //TODO: this is all a guess and a mess
            //I haven't figured out how/why hg uses this strange date format,
            //nor if it is going to do it on all machines, or will someday
            //change.
            if (DateTime.TryParseExact(dateString, "ddd MMM dd HH':'mm':'ss yyyy zzz",
                                       null, DateTimeStyles.AssumeUniversal, out when))
            {
                when = when.ToLocalTime();
                dateString = when.ToShortDateString()+" "+when.ToShortTimeString();
            }

            object image;
            if (rev.Summary.ToLower().Contains("conflict"))
                image = HistoryRowIcons.Warning;
            else if (rev.Parents.Count > 1)
                image = HistoryRowIcons.Merge;
            else
            {
                var colonLocation = rev.Summary.IndexOf(':');
                string appName = rev.Summary;
                if (colonLocation > 0)
                {
                    appName = appName.Substring(0, colonLocation);
                }
                var bracketLocation = appName.IndexOf(']');
                if (bracketLocation > 0)
                {
                    appName = appName.Substring(0, bracketLocation);
                }
                appName = appName.Trim(new char[] { '[', '+' }); // there was a bug in chorus that introduced the +
                //temp hack... the app has now been fixed to not include this
                appName = appName.Replace("0.5", "");

                switch (appName.Trim())
                {
                    case "WeSay":
                        image = HistoryRowIcons.WeSay;
                        break;
                    case "WeSay Configuration Tool":
                        image = HistoryRowIcons.WeSayConfiguration;
                        break;
                    case "FieldWorks":
                        image = HistoryRowIcons.FieldWorks;
                        break;
                    case "Bloom":
                        image = HistoryRowIcons.Bloom16x16;
                        break;
                    default:
                        image = HistoryRowIcons.GenericCheckin;
                        break;
                }

            }
            int nIndex = _historyGrid.Rows.Add(new [] { image, false, false, dateString, rev.UserId, GetDescriptionForListView(rev) });
            var row = _historyGrid.Rows[nIndex];
            row.Tag = rev;
            row.Cells[0].ToolTipText = rev.Number.LocalRevisionNumber + ": " + rev.Number.Hash;

            var idx = row.Cells.Count - _extraColumns.Count;
            foreach (var extraColumn in _extraColumns)
            {
                row.Cells[idx++].Value = extraColumn.StringSupplier.Invoke(rev);
            }
        }
 private string GetDescriptionForListView(Revision rev)
 {
     var s = rev.Summary.Substring(rev.Summary.IndexOf(']')+1).Trim();
     if(s=="auto")
         return string.Empty;
     return s;
 }
 public void SelectedRevisionChanged(Revision descriptor)
 {
     if (_revisionSelectedEvent!=null)
         _revisionSelectedEvent.Raise(descriptor);
 }
Example #12
0
 public ServerRevision(string id, Revision rev)
 {
     RemoteId = id;
     Revision = rev;
 }
Example #13
0
 public bool IsMatchingStub(Revision stub)
 {
     return stub.Summary.Contains(string.Format("({0} partial from", UserId));
 }
Example #14
0
 public bool IsDirectDescendantOf(Revision revision)
 {
     EnsureParentRevisionInfo();
     //TODO: this is only checking direct descendant
     return Parents.Any(p => p.Hash == revision.Number.Hash);
 }
Example #15
0
 /// <returns>false if nothing needed to be merged, true if the merge was done. Throws exception if there is an error.</returns>
 private bool MergeTwoChangeSets(Revision head, Revision theirHead)
 {
     // Theory has it that is a tossup on who ought to win, unless there is some more principled way to decide.
     // If 'they' end up being the right answer, or if it ends up being more exotic,
     // then be sure to change the alpha and beta info in the MergeSituation class.
     //using (new ShortTermEnvironmentalVariable(MergeOrder.kConflictHandlingModeEnvVarName, MergeOrder.ConflictHandlingModeChoices.TheyWin.ToString()))
     // Go with 'WeWin', since that is the default and that is how the alpha and beta data of MergeSituation is set, right before this method is called.
     using (new ShortTermEnvironmentalVariable(MergeOrder.kConflictHandlingModeEnvVarName, MergeOrder.ConflictHandlingModeChoices.WeWin.ToString()))
     {
         var didMerge = Repository.Merge(_localRepositoryPath, theirHead.Number.LocalRevisionNumber);
         FailureSimulator.IfTestRequestsItThrowNow("SychronizerAdjunct");
         return didMerge;
     }
 }
		public void Synchronizer_HandlesBothDefaultBranchOptions()
		{
			// Revisions can come in with both default or empty string on the default branch depending on OS
			string savedSettings = "";
			var rev1 = new Revision(null, "default", "Fred", "1234", "hash1234", "change something");
			// The first revision we see on another branch doesn't produce a warning...it might be something old everyone has upgraded from.
			var revs = new[] { rev1 };
			Assert.That(LiftSynchronizerAdjunct.GetRepositoryBranchCheckData(revs, "", ref savedSettings), Is.Null);

			var rev2 = new Revision(null, "", "Joe", "1235", "hash1235", "change something else");
			// To get the right result this time, the list of revisions must include both branches we are pretending are in the repo.
			revs = new[] { rev1, rev2 };
			Assert.That(LiftSynchronizerAdjunct.GetRepositoryBranchCheckData(revs, "default", ref savedSettings), Is.Null); // first change we've seen on this branch

			var rev3 = new Revision(null, "default", "Fred", "1236", "hash1236", "Fred's second change");
			revs = new[] { rev2, rev3 };
			Assert.That(LiftSynchronizerAdjunct.GetRepositoryBranchCheckData(revs, "default", ref savedSettings), Is.Null);

			var rev4 = new Revision(null, "", "Joe", "1236", "hash1237", "Joe's second change");
			revs = new[] { rev3, rev4 };
			Assert.That(LiftSynchronizerAdjunct.GetRepositoryBranchCheckData(revs, "", ref savedSettings), Is.Null);
		}
Example #17
0
 private bool CheckAndWarnIfNoCommonAncestor(Revision a, Revision b )
 {
     if (null ==Repository.GetCommonAncestorOfRevisions(a.Number.Hash,b.Number.Hash))
     {
         _progress.WriteWarning(
             "This repository has an anomaly:  the two heads we want to merge have no common ancestor.  You should get help from the developers of this application.");
         _progress.WriteWarning("1) \"{0}\" on {1} by {2} ({3}). ", a.GetHashCode(), a.Summary, a.DateString, a.UserId);
         _progress.WriteWarning("2) \"{0}\" on {1} by {2} ({3}). ", b.GetHashCode(), b.Summary, b.DateString, b.UserId);
         return true;
     }
     return false;
 }
 private void SetRevision(Revision descriptor)
 {
     Cursor.Current = Cursors.WaitCursor;
     if (descriptor != null)
     {
         Changes = _revisionInspector.GetChangeRecords(descriptor);
     }
     else
     {
         Changes = null;
     }
     if(UpdateDisplay !=null)
     {
         UpdateDisplay.Invoke(this, null);
     }
     Cursor.Current = Cursors.Default;
 }
Example #19
0
 private void MergeHeadsOrRollbackAndThrow(HgRepository repo, Revision workingRevBeforeSync)
 {
     try
     {
         MergeHeads();
     }
     catch (Exception error)
     {
         foreach (var chorusMergeProcess in Process.GetProcessesByName("ChorusMerge"))
         {
             _progress.WriteWarning(string.Format("Killing ChorusMerge Process: '{0}'...", chorusMergeProcess.Id));
             chorusMergeProcess.Kill();
         }
         _progress.WriteException(error);
         _progress.WriteError("Rolling back...");
         UpdateToTheDescendantRevision(repo, workingRevBeforeSync); //rollback
         throw;
     }
 }
        internal void SelectedRevisionChanged(Revision descriptor)
        {
            // This was a public method, but it was changed to internal, since the whole model instance is effectively internal,
            // since it is not exposed beyond its view, which is also not exposed to anyone.

            // In an ideal world, the RevisionSelectedEvent instance in _revisionSelectedEvent would allow client code to add new subscribers,
            // but that world doesn't exist yet, so the view has added a kludge Windows event and calls it, after callinng this method.
            if (_revisionSelectedEvent!=null)
                _revisionSelectedEvent.Raise(descriptor);
        }
Example #21
0
        /// <summary>
        /// Sets up everything necessary for a call out to the ChorusMerge executable
        /// </summary>
        /// <param name="targetHead"></param>
        /// <param name="sourceHead"></param>
        private void PrepareForMergeAttempt(Revision targetHead, Revision sourceHead)
        {
            //this is for posterity, on other people's machines, so use the hashes instead of local numbers
            MergeSituation.PushRevisionsToEnvironmentVariables(targetHead.UserId, targetHead.Number.Hash,
                                                               sourceHead.UserId, sourceHead.Number.Hash);

            MergeOrder.PushToEnvironmentVariables(_localRepositoryPath);
            _progress.WriteMessage("Merging {0} and {1}...", targetHead.UserId, sourceHead.UserId);
            _progress.WriteVerbose("   Revisions {0}:{1} with {2}:{3}...", targetHead.Number.LocalRevisionNumber, targetHead.Number.Hash,
                                   sourceHead.Number.LocalRevisionNumber, sourceHead.Number.Hash);
            RemoveMergeObstacles(targetHead, sourceHead);
        }
Example #22
0
 public BookMark(HgRepository repository)
 {
     _repository = repository;
     _revision = _repository.GetRevisionWorkingSetIsBasedOn();
 }
Example #23
0
        /// <summary>
        /// If everything got merged, then this is trivial. But in case of a merge failure,
        /// the "tip" might be the other guy's unmergable data (maybe because he has a newer
        /// version of some application than we do) We don't want to switch to that!
        ///
        /// So if there are more than one head out there, we update to the one that is a descendant
        /// of our latest checkin (which in the simple merge failure case is the the checkin itself,
        /// but in a 3-or-more source scenario could be the result of a merge with a more cooperative
        /// revision).
        /// </summary>
        private void UpdateToTheDescendantRevision(HgRepository repository, Revision parent)
        {
            try
            {
                var heads = repository.GetHeads();
                //if there is only one head for the branch we started from just update
                if (heads.Count(rev => rev.Branch == parent.Branch) == 1)
                {
                    repository.Update(); //update to the tip
                    _sychronizerAdjunct.SimpleUpdate(_progress, false);
                    return;
                }
                if (heads.Count == 0)
                {
                    return;//nothing has been checked in, so we're done! (this happens during some UI tests)
                }

                //  when there are more than 2 people merging and there's a failure or a no-op merge happened
                foreach (var head in heads)
                {
                    if (parent.Number.Hash == head.Number.Hash || (head.Branch == parent.Branch && head.IsDirectDescendantOf(parent)))
                    {
                        repository.RollbackWorkingDirectoryToRevision(head.Number.LocalRevisionNumber);
                        _sychronizerAdjunct.SimpleUpdate(_progress, true);
                        return;
                    }
                }

                _progress.WriteWarning("Staying at previous-tip (unusual). Other users recent changes will not be visible.");
            }
            catch (UserCancelledException)
            {
                throw;
            }
            catch (Exception error)
            {
                  ExplainAndThrow(error, "Could not update.");
            }
        }
Example #24
0
 private bool ShowRevisionPredicate(Revision revision)
 {
     return !revision.Summary.ToLower().Contains("hide");
 }
		private static string BranchName(Revision revision)
		{
			var name = revision.Branch;
			return string.IsNullOrWhiteSpace(name) ? @"default" : name;
		}
		public void SynchronizerWithOnlyCurrentBranchRevision_ReportsNothing()
		{
			var rev1 = new Revision(null, "default", "Fred", "1234", "hash1234", "change something");
			var revs = new[] { rev1 };
			string savedSettings = "";
			Assert.That(LiftSynchronizerAdjunct.GetRepositoryBranchCheckData(revs, "default", ref savedSettings), Is.Null);
			Assert.That(savedSettings,Is.EqualTo(""));

			// Even if we have remembered a previous revision on our own branch, we don't report problems on the current branch.
			var rev2 = new Revision(null, "default", "Fred", "1235", "hash1234", "change something else");
			revs = new[] { rev2 };
			savedSettings = "default";
			Assert.That(LiftSynchronizerAdjunct.GetRepositoryBranchCheckData(revs, "default", ref savedSettings), Is.Null);
			Assert.That(savedSettings, Is.EqualTo("")); // still no revs on other branches to save.
		}
		/// <summary>
		/// Do a no-op merge. (See: http://mercurial.selenic.com/wiki/PruningDeadBranches#No-Op_Merges)
		/// </summary>
		private void NoopMerge(HgRepository repo, Revision keeperRevision, Revision gonerRevision)
		{
			string optionalComment = null;
			using (var optionalCommentDlg = new OptionalCommentDlg())
			{
				if (optionalCommentDlg.ShowDialog(this) == DialogResult.OK && !string.IsNullOrWhiteSpace(optionalCommentDlg.OptionalComment))
				{
					optionalComment = optionalCommentDlg.OptionalComment.Trim();
				}
			}

			// Merge goner into keeper.
			repo.Merge(_repoFolder, gonerRevision.Number.LocalRevisionNumber);

			// Revert the merge.
			repo.Execute(repo.SecondsBeforeTimeoutOnMergeOperation, "revert", "-a", "-r", keeperRevision.Number.LocalRevisionNumber);

			// Commit
			var comment = string.Format(@"No-Op Merge: Revert repository to revision '{0}'", keeperRevision.Number.LocalRevisionNumber);
			if (!string.IsNullOrWhiteSpace(optionalComment))
				comment = string.Format(@"{0}. {1}", comment, optionalComment);
			repo.Commit(true, comment);
		}
Example #28
0
 public bool IsMatchingStub(Revision stub)
 {
     return(stub.Summary.Contains(string.Format("({0} partial from", UserId)));
 }