Exemple #1
0
        private int ProcessMods(Cache cache, MergeOrder order, List <string> modFilter = null)
        {
            mLogger.Information("Processing mods");

            var filteredMods = new List <(int Index, ModInfo ModInfo)>();

            // Iterate over mods
            foreach (var mod in mModDb.Mods)
            {
                // TODO: maybe use a GUID instead of the title for matching
                if (modFilter == null || modFilter.Contains(mod.Title))
                {
                    var index = modFilter.FindIndex(x => x.Equals(mod.Title, StringComparison.InvariantCultureIgnoreCase));
                    filteredMods.Add((index, mod));
                }
            }

            // Order the mods we collected based on their index in the filter list
            var orderedMods = order == MergeOrder.TopToBottom ?
                              filteredMods.OrderBy(x => x.Index) :
                              filteredMods.OrderByDescending(x => x.Index);

            foreach (var mod in orderedMods)
            {
                mLogger.Information($"Processing mod {mod.ModInfo.Title}");
                var modFilesDir = new DirectoryFileSystem(mLogger, mod.ModInfo.FilesDir);
                ProcessModDir(mod.ModInfo, modFilesDir, cache, ".", ModDirectoryType.Normal);
            }

            return(filteredMods.Count);
        }
Exemple #2
0
        private static void DoMerge(IChorusFileTypeHandler fileHandler, int ours)
        {
            TempFile ourFile;
            TempFile commonFile;
            TempFile theirFile;

            FieldWorksTestServices.SetupTempFilesWithExtension(".ModelVersion", out ourFile, out commonFile, out theirFile);

            try
            {
                var baseModelVersion = ours - 1;
                File.WriteAllText(commonFile.Path, FormatModelVersionData(baseModelVersion));
                File.WriteAllText(ourFile.Path, FormatModelVersionData(ours));
                File.WriteAllText(theirFile.Path, FormatModelVersionData(baseModelVersion));

                var listener   = new ListenerForUnitTests();
                var mergeOrder = new MergeOrder(ourFile.Path, commonFile.Path, theirFile.Path, new NullMergeSituation())
                {
                    EventListener = listener
                };
                fileHandler.Do3WayMerge(mergeOrder);
            }
            finally
            {
                FieldWorksTestServices.RemoveTempFiles(ref ourFile, ref commonFile, ref theirFile);
            }
        }
        /// <summary>
        /// Do a 3-file merge, placing the result over the "ours" file and returning an error status
        /// </summary>
        /// <remarks>Implementations can exit with an exception, which the caller will catch and deal with.
        /// The must not have any UI, no interaction with the user.</remarks>
        public void Do3WayMerge(MergeOrder mergeOrder)
        {
            Guard.AgainstNull(mergeOrder, "mergeOrder");

            if (mergeOrder == null)
            {
                throw new ArgumentNullException("mergeOrder");
            }

            var merger = new XmlMerger(mergeOrder.MergeSituation);

            SetupElementStrategies(merger);

            merger.EventListener = mergeOrder.EventListener;

            using (var oursXml = new HtmlFileForMerging(mergeOrder.pathToOurs))
                using (var theirsXml = new HtmlFileForMerging(mergeOrder.pathToTheirs))
                    using (var ancestorXml = new HtmlFileForMerging(mergeOrder.pathToCommonAncestor))
                    {
                        var result = merger.MergeFiles(oursXml.GetPathToXHtml(), theirsXml.GetPathToXHtml(), ancestorXml.GetPathToXHtml());

                        CarefullyWriteOutResultingXml(oursXml, result);

                        //now convert back to html
                        oursXml.SaveHtml();
                    }
        }
        /// <summary>
        /// Do a 3-file merge, placing the result over the "ours" file and returning an error status
        /// </summary>
        /// <remarks>Implementations can exit with an exception, which the caller will catch and deal with.
        /// The must not have any UI, no interaction with the user.</remarks>
        public void Do3WayMerge(MergeOrder mergeOrder)
        {
            if (mergeOrder == null)
            {
                throw new ArgumentNullException("mergeOrder");
            }

            bool addedCollationAttr;

            PreMergeFile(mergeOrder, out addedCollationAttr);

            var merger = new XmlMerger(mergeOrder.MergeSituation);

            SetupElementStrategies(merger);

            merger.EventListener = mergeOrder.EventListener;
            XmlMergeService.RemoveAmbiguousChildNodes = true;
            var result = merger.MergeFiles(mergeOrder.pathToOurs, mergeOrder.pathToTheirs, mergeOrder.pathToCommonAncestor);

            using (var writer = XmlWriter.Create(mergeOrder.pathToOurs, CanonicalXmlSettings.CreateXmlWriterSettings()))
            {
                var readerSettings = CanonicalXmlSettings.CreateXmlReaderSettings(ConformanceLevel.Auto);
                readerSettings.XmlResolver = null;
                readerSettings.ProhibitDtd = false;
                using (var nodeReader = XmlReader.Create(new MemoryStream(Encoding.UTF8.GetBytes(result.MergedNode.OuterXml)), readerSettings))
                {
                    writer.WriteNode(nodeReader, false);
                }
            }
        }
Exemple #5
0
        public void Merge_EditAndDeleteEntry_GeneratesConflictWithContext()
        {
            const string pattern = @"<?xml version='1.0' encoding='utf-8'?>
				<lift version='0.10' producer='WeSay 1.0.0.0'>
					<entry
						dateCreated='2011-03-09T17:08:44Z'
						dateModified='2012-05-18T08:31:54Z'
						id='00853b73-fda2-4b12-8a89-6957cc7e7e79'
						guid='00853b73-fda2-4b12-8a89-6957cc7e7e79'>
						<lexical-unit>
							<form
								lang='ldb-fonipa-x-emic'>
								<text>{0}</text>
							</form>
						</lexical-unit>

					</entry>
				</lift>"                ;
            // We edited the text of the form slightly.
            string ours     = string.Format(pattern, "asaten");
            string ancestor = string.Format(pattern, "asat");

            // they deleted the whole entry
            const string theirs = @"<?xml version='1.0' encoding='utf-8'?>
				<lift version='0.10' producer='WeSay 1.0.0.0'>
				</lift>"                ;

            using (var oursTemp = new TempFile(ours))
                using (var theirsTemp = new TempFile(theirs))
                    using (var ancestorTemp = new TempFile(ancestor))
                    {
                        var listener   = new ListenerForUnitTests();
                        var situation  = new NullMergeSituation();
                        var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation)
                        {
                            EventListener = listener
                        };
                        var mergeStrategy = new LiftEntryMergingStrategy(mergeOrder);
                        var strategies    = mergeStrategy.GetStrategies();
                        var entryStrategy = strategies.ElementStrategies["entry"];
                        entryStrategy.ContextDescriptorGenerator = new EnhancedEntrycontextGenerator();
                        XmlMergeService.Do3WayMerge(mergeOrder, mergeStrategy,
                                                    false,
                                                    "header",
                                                    "entry", "guid");
                        var result   = File.ReadAllText(mergeOrder.pathToOurs);
                        var conflict = listener.Conflicts[0];
                        Assert.That(conflict, Is.InstanceOf <EditedVsRemovedElementConflict>());
                        Assert.That(conflict.HtmlDetails, Is.StringContaining("my silly context"), "merger should have used the context generator to make the html details");
                        Assert.That(conflict.HtmlDetails.IndexOf("my silly context"),
                                    Is.EqualTo(conflict.HtmlDetails.LastIndexOf("my silly context")),
                                    "since one change is a delete, the details should only be present once");
                        var context = conflict.Context;

                        Assert.That(context, Is.Not.Null, "the merge should supply a context for the conflict");
                        Assert.That(context.PathToUserUnderstandableElement, Is.Not.Null);
                        XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry/lexical-unit/form[@lang='ldb-fonipa-x-emic']/text[text()='asaten']");
                    }
        }
Exemple #6
0
 public void Do3WayMerge(MergeOrder order)
 {
     XmlMergeService.Do3WayMerge(order,
                                 new ChorusNotesAnnotationMergingStrategy(order),
                                 false,
                                 null,
                                 "annotation", "guid");
 }
Exemple #7
0
 public void Update(MergeOrder pEvent)
 {
     prompt = PosContext.Instance.PosPrompt;
     if (prompt != null)
     {
         prompt.PromptText = pEvent.PromptText;
     }
 }
        /// <summary>
        /// Produce a string that represents the 3-way merger of the given three elements.
        /// </summary>
        public ChorusNotesAnnotationMergingStrategy(MergeOrder order)
        {
            _annotationMerger = new XmlMerger(order.MergeSituation)
            {
                EventListener = order.EventListener
            };

            SetupElementStrategies();
        }
Exemple #9
0
        [Test]         // See http://jira.palaso.org/issues/browse/CHR-18
        public void Merge_DuplicateGuidsInEntry_ResultHasWarningReport()
        {
            const string ours = @"<?xml version='1.0' encoding='utf-8'?>
				<lift version='0.10' producer='WeSay 1.0.0.0'>
					<entry
						id='00853b73-fda2-4b12-8a89-6957cc7e7e79'
						guid='00853b73-fda2-4b12-8a89-6957cc7e7e79'>
					</entry>
				</lift>"                ;

            const string theirs = @"<?xml version='1.0' encoding='utf-8'?>
				<lift version='0.10' producer='WeSay 1.0.0.0'>
					<entry
						id='00853b73-fda2-4b12-8a89-6957cc7e7e79'
						guid='00853b73-fda2-4b12-8a89-6957cc7e7e79'>
					</entry>
				</lift>"                ;

            const string ancestor = @"<?xml version='1.0' encoding='utf-8'?>
				<lift version='0.10' producer='WeSay 1.0.0.0'>
					<entry
						id='00853b73-fda2-4b12-8a89-6957cc7e7e79'
						guid='00853b73-fda2-4b12-8a89-6957cc7e7e79'>
					</entry>
					<entry
						id='00853b73-fda2-4b12-8a89-6957cc7e7e79'
						guid='00853b73-fda2-4b12-8a89-6957cc7e7e79'>
						<lexical-unit>
							<form
								lang='en'>
								<text>goner form</text>
							</form>
						</lexical-unit>
					</entry>
				</lift>"                ;

            using (var oursTemp = new TempFile(ours))
                using (var theirsTemp = new TempFile(theirs))
                    using (var ancestorTemp = new TempFile(ancestor))
                    {
                        var listener   = new ListenerForUnitTests();
                        var situation  = new NullMergeSituation();
                        var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation)
                        {
                            EventListener = listener
                        };
                        XmlMergeService.Do3WayMerge(mergeOrder, new LiftEntryMergingStrategy(mergeOrder),
                                                    false,
                                                    "header",
                                                    "entry", "guid");
                        var result = File.ReadAllText(mergeOrder.pathToOurs);
                        // Check that there is only one entry in the merged file.
                        XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@guid='00853b73-fda2-4b12-8a89-6957cc7e7e79']");
                        XmlTestHelper.AssertXPathIsNull(result, "lift/entry[@guid='00853b73-fda2-4b12-8a89-6957cc7e7e79']/lexical-unit");
                        Assert.AreEqual(typeof(MergeWarning), listener.Warnings[0].GetType());
                    }
        }
Exemple #10
0
        public static int Main(string[] args)
        {
            try
            {
                string ourFilePath;
                string commonFilePath;
                string theirFilePath;

                if (Platform.IsMono)
                {
                    ourFilePath    = args[0];
                    commonFilePath = args[1];
                    theirFilePath  = args[2];
                }
                else
                {
                    // Convert the input arguments from cp1252 -> utf8 -> ucs2
                    // It always seems to be 1252, even when the input code page is actually something else. CP 2012-03
                    // var inputEncoding = Console.InputEncoding;
                    var inputEncoding = Encoding.GetEncoding(1252);
                    ourFilePath    = Encoding.UTF8.GetString(inputEncoding.GetBytes(args[0]));
                    commonFilePath = Encoding.UTF8.GetString(inputEncoding.GetBytes(args[1]));
                    theirFilePath  = Encoding.UTF8.GetString(inputEncoding.GetBytes(args[2]));
                    Console.WriteLine("ChorusMerge: Input encoding {0}",
                                      inputEncoding.EncodingName);
                }

                //this was originally put here to test if console writes were making it out to the linux log or not
                Console.WriteLine("ChorusMerge: {0}, {1}, {2}", ourFilePath, commonFilePath, theirFilePath);

#if RUNINDEBUGGER
                var order = new MergeOrder(ourFilePath, commonFilePath, theirFilePath, new MergeSituation(ourFilePath, "Me", "CHANGETHIS", "YOU", "CHANGETHIS", MergeOrder.ConflictHandlingModeChoices.WeWin));
#else
                MergeOrder order = MergeOrder.CreateUsingEnvironmentVariables(ourFilePath, commonFilePath, theirFilePath);
#endif
                var handlers = ChorusFileTypeHandlerCollection.CreateWithInstalledHandlers();
                var handler  = handlers.GetHandlerForMerging(order.pathToOurs);

                //DispatchingMergeEventListener listenerDispatcher = new DispatchingMergeEventListener();
                //using (HumanLogMergeEventListener humanListener = new HumanLogMergeEventListener(order.pathToOurs + ".ChorusNotes.txt"))
                using (var xmlListener = new ChorusNotesMergeEventListener(order.pathToOurs + ".NewChorusNotes"))
                {
//                    listenerDispatcher.AddEventListener(humanListener);
//                    listenerDispatcher.AddEventListener(xmlListener);
                    order.EventListener = xmlListener;

                    handler.Do3WayMerge(order);
                }
            }
            catch (Exception e)
            {
                ErrorWriter.WriteLine("ChorusMerge Error: " + e.Message);
                ErrorWriter.WriteLine(e.StackTrace);
                return(1);
            }
            return(0);           //no error
        }
Exemple #11
0
        public void Do3WayMerge(MetadataCache mdc, MergeOrder mergeOrder)
        {
            var merger = new XmlMerger(mergeOrder.MergeSituation)
            {
                EventListener = mergeOrder.EventListener
            };

            CustomLayoutMergeStrategiesMethod.AddElementStrategies(merger.MergeStrategies);
            CustomLayoutMergeService.DoMerge(mergeOrder, merger);
        }
Exemple #12
0
        /// <summary>
        /// Constructor
        /// </summary>
        public LiftRangesMergingStrategy(MergeOrder mergeOrder)
        {
            _merger = new XmlMerger(mergeOrder.MergeSituation)
            {
                EventListener = mergeOrder.EventListener
            };

            LiftBasicElementStrategiesMethod.AddLiftBasicElementStrategies(_merger.MergeStrategies);
            LiftRangesElementStrategiesMethod.AddLiftRangeElementStrategies(_merger.MergeStrategies);
        }
Exemple #13
0
        internal static XmlMerger CreateXmlMergerForFieldWorksData(MergeOrder mergeOrder, MetadataCache mdc)
        {
            var merger = new XmlMerger(mergeOrder.MergeSituation)
            {
                EventListener = mergeOrder.EventListener
            };

            BootstrapSystem(mdc, merger);
            return(merger);
        }
        public void FixtureSetup()
        {
            _mdc = MetadataCache.TestOnlyNewCache;
            var mergeOrder = new MergeOrder(null, null, null, new NullMergeSituation())
            {
                EventListener = new ListenerForUnitTests()
            };

            _merger = FieldWorksMergeServices.CreateXmlMergerForFieldWorksData(mergeOrder, _mdc);
        }
        /// <summary>
        /// Produce a string that represents the 3-way merger of the given three elements.
        /// </summary>
        public LiftEntryMergingStrategy(MergeOrder mergeOrder)
        {
            _entryMerger = new XmlMerger(mergeOrder.MergeSituation)
            {
                MergeStrategies = { ElementToMergeStrategyKeyMapper = new LiftElementToMergeStrategyKeyMapper() },
                EventListener   = mergeOrder.EventListener
            };

            LiftElementStrategiesMethod.AddLiftElementStrategies(_entryMerger.MergeStrategies);
        }
Exemple #16
0
        public void GetMergedLift_ConflictingGlosses_ListenerIsNotifiedOfBothEditedConflict()
        {
            const string ours = @"<?xml version='1.0' encoding='utf-8'?>
					<lift version='0.10' producer='WeSay 1.0.0.0'>
						<entry id='test'  guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6'>
							<sense id='123'>
								 <gloss lang='a'>
									<text>ourSense</text>
								 </gloss>
							 </sense>
						</entry>
					</lift>"                    ;

            const string theirs   = @"<?xml version='1.0' encoding='utf-8'?>
					<lift version='0.10' producer='WeSay 1.0.0.0'>
						<entry id='test'  guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6'>
							<sense id='123'>
								 <gloss lang='a'>
									<text>theirSense</text>
								 </gloss>
							 </sense>
						</entry>
					</lift>"                    ;
            const string ancestor = @"<?xml version='1.0' encoding='utf-8'?>
					<lift version='0.10' producer='WeSay 1.0.0.0'>
						<entry id='test'  guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6'>
							<sense id='123'>
								 <gloss lang='a'>
									<text>original</text>
								 </gloss>
							 </sense>
						</entry>
					</lift>"                    ;

            using (var oursTemp = new TempFile(ours))
                using (var theirsTemp = new TempFile(theirs))
                    using (var ancestorTemp = new TempFile(ancestor))
                    {
                        var listener   = new ListenerForUnitTests();
                        var situation  = new NullMergeSituation();
                        var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation)
                        {
                            EventListener = listener
                        };
                        XmlMergeService.Do3WayMerge(mergeOrder, new LiftEntryMergingStrategy(mergeOrder),
                                                    false,
                                                    "header",
                                                    "entry", "guid");
                        var conflict = listener.Conflicts[0];
                        AssertConflictType <XmlTextBothEditedTextConflict>(conflict);
                        const string expectedContext = "lift://unknown?type=entry&id=F169EB3D-16F2-4eb0-91AA-FDB91636F8F6";
                        Assert.AreEqual(expectedContext, listener.Contexts[0].PathToUserUnderstandableElement,
                                        "the listener wasn't give the expected context");
                    }
        }
Exemple #17
0
        internal static string DoMerge(
            IChorusFileTypeHandler chorusFileHandler,
            TempFile ourFile, string ourContent,
            TempFile commonFile, string commonAncestor,
            TempFile theirFile, string theirContent,
            IEnumerable <string> matchesExactlyOne, IEnumerable <string> isNull,
            int expectedConflictCount, List <Type> conflictTypes,
            int expectedChangesCount, List <Type> changeTypes, out List <IConflict> resultingConflicts)
        {
            File.WriteAllText(ourFile.Path, ourContent);
            if (commonFile != null)
            {
                File.WriteAllText(commonFile.Path, commonAncestor);
            }
            File.WriteAllText(theirFile.Path, theirContent);

            var situation     = new NullMergeSituation();
            var mergeOrder    = new MergeOrder(ourFile.Path, (commonFile == null ? null : commonFile.Path), theirFile.Path, situation);
            var eventListener = new ListenerForUnitTests();

            mergeOrder.EventListener = eventListener;

            chorusFileHandler.Do3WayMerge(mergeOrder);
            var result = File.ReadAllText(ourFile.Path);

            if (matchesExactlyOne != null)
            {
                foreach (var query in matchesExactlyOne)
                {
                    XmlTestHelper.AssertXPathMatchesExactlyOne(result, query);
                }
            }
            if (isNull != null)
            {
                foreach (var query in isNull)
                {
                    XmlTestHelper.AssertXPathIsNull(result, query);
                }
            }
            eventListener.AssertExpectedConflictCount(expectedConflictCount);
            Assert.AreEqual(conflictTypes.Count, eventListener.Conflicts.Count);
            for (var idx = 0; idx < conflictTypes.Count; ++idx)
            {
                Assert.AreSame(conflictTypes[idx], eventListener.Conflicts[idx].GetType());
            }
            eventListener.AssertExpectedChangesCount(expectedChangesCount);
            Assert.AreEqual(changeTypes.Count, eventListener.Changes.Count);
            for (var idx = 0; idx < changeTypes.Count; ++idx)
            {
                Assert.AreSame(changeTypes[idx], eventListener.Changes[idx].GetType());
            }
            resultingConflicts = eventListener.Conflicts;
            return(result);
        }
        public override void TestSetup()
        {
            base.TestSetup();
            Mdc.UpgradeToVersion(MetadataCache.MaximumModelVersion);
            var mergeOrder = new MergeOrder(null, null, null, new NullMergeSituation())
            {
                EventListener = new ListenerForUnitTests()
            };

            _merger = FieldWorksMergeServices.CreateXmlMergerForFieldWorksData(mergeOrder, Mdc);
        }
        internal static void DoMerge(MergeOrder mergeOrder, XmlMerger merger)
        {
            XmlNode ours;
            XmlNode theirs;
            XmlNode common;

            DoPreMerge(mergeOrder, out ours, out theirs, out common);
            var results = merger.Merge(ours, theirs, common);

            DoPostMerge(mergeOrder.pathToOurs, results.MergedNode);
        }
Exemple #20
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);
        }
Exemple #21
0
        public void Do3WayMerge(MergeOrder mergeOrder)
        {
            if (!OurWordAssemblyIsAvailable)
            {
                throw new ApplicationException("OurWord Dll is not available to do the merge (so this should not have been called).");
            }


            var method = RetrieveRemoteMethod("Do3WayMerge");

            method.Invoke(null, new object[] { mergeOrder });
        }
Exemple #22
0
        internal static void DoMerge(MergeOrder mergeOrder, XmlMerger merger)
        {
            XmlNode ours;
            XmlNode theirs;
            XmlNode common;

            DoPreMerge(mergeOrder, out ours, out theirs, out common);
            // The document element is being returned here, so our parent isn't relevant and won't be used by the merge
            var results = merger.Merge(null, ours, theirs, common);

            DoPostMerge(mergeOrder.pathToOurs, results.MergedNode);
        }
Exemple #23
0
 public void Do3WayMerge(MergeOrder mergeOrder)
 {
     // <mergenotice>
     // When the WeSay1.3 branch gets merged, do this:
     // 1. Keep this code and reject the WeSay1.3 changes. They were done as a partial port of some other code changes.
     // 2. Remove this <mergenotice> comment and its 'end tag' comment.
     // 3. The parm change from 'false' to 'true' is to be kept.
     XmlMergeService.Do3WayMerge(mergeOrder,
                                 new LiftEntryMergingStrategy(mergeOrder),
                                 true,
                                 "header",
                                 "entry", "guid");
     // </mergenotice>
 }
		/// <summary>
		/// handles that date business, so it doesn't overwhelm the poor user with conflict reports
		/// </summary>
		/// <param name="mergeOrder"></param>
		/// <param name="addedCollationAttr"></param>
		private static void PreMergeFile(MergeOrder mergeOrder, out bool addedCollationAttr)
		{
			addedCollationAttr = false;
			XDocument ourDoc = File.Exists(mergeOrder.pathToOurs) && File.ReadAllText(mergeOrder.pathToOurs).Contains("<UserLexiconSettings>") ? XDocument.Load(mergeOrder.pathToOurs) : null;
			XDocument theirDoc = File.Exists(mergeOrder.pathToTheirs) && File.ReadAllText(mergeOrder.pathToTheirs).Contains("<UserLexiconSettings>") ? XDocument.Load(mergeOrder.pathToTheirs) : null;

			if (ourDoc == null || theirDoc == null)
				return;

			var ourData = File.ReadAllText(mergeOrder.pathToOurs);
			File.WriteAllText(mergeOrder.pathToOurs, ourData);
			var theirData = File.ReadAllText(mergeOrder.pathToTheirs);
			File.WriteAllText(mergeOrder.pathToTheirs, theirData);
		}
Exemple #25
0
        private string DoMerge(string commonAncestor, string ourContent, string theirContent,
                               Dictionary <string, string> namespaces,
                               IEnumerable <string> matchesExactlyOne, IEnumerable <string> isNull,
                               int expectedConflictCount, List <Type> expectedConflictTypes,
                               int expectedChangesCount, List <Type> expectedChangeTypes)
        {
            string result;

            using (var ours = new TempFile(ourContent))
                using (var theirs = new TempFile(theirContent))
                    using (var ancestor = new TempFile(commonAncestor))
                    {
                        var situation  = new NullMergeSituation();
                        var mergeOrder = new MergeOrder(ours.Path, ancestor.Path, theirs.Path, situation);
                        _eventListener           = new ListenerForUnitTests();
                        mergeOrder.EventListener = _eventListener;

                        _ldmlFileHandler.Do3WayMerge(mergeOrder);
                        result = File.ReadAllText(ours.Path);
                        foreach (var query in matchesExactlyOne)
                        {
                            XmlTestHelper.AssertXPathMatchesExactlyOne(result, query, namespaces);
                        }
                        if (isNull != null)
                        {
                            foreach (var query in isNull)
                            {
                                XmlTestHelper.AssertXPathIsNull(result, query, namespaces);
                            }
                        }
                        _eventListener.AssertExpectedConflictCount(expectedConflictCount);
                        expectedConflictTypes = expectedConflictTypes ?? new List <Type>();
                        Assert.AreEqual(expectedConflictTypes.Count, _eventListener.Conflicts.Count,
                                        "Expected conflict count and actual number found differ.");
                        for (var idx = 0; idx < expectedConflictTypes.Count; ++idx)
                        {
                            Assert.AreSame(expectedConflictTypes[idx], _eventListener.Conflicts[idx].GetType());
                        }

                        _eventListener.AssertExpectedChangesCount(expectedChangesCount);
                        expectedChangeTypes = expectedChangeTypes ?? new List <Type>();
                        Assert.AreEqual(expectedChangeTypes.Count, _eventListener.Changes.Count,
                                        "Expected change count and actual number found differ.");
                        for (var idx = 0; idx < expectedChangeTypes.Count; ++idx)
                        {
                            Assert.AreSame(expectedChangeTypes[idx], _eventListener.Changes[idx].GetType());
                        }
                    }
            return(result);
        }
Exemple #26
0
        public void Merge_DuplicateKeyInGloss_NoThrow()
        {
            var ancestor =
                @"<?xml version='1.0' encoding='utf-8'?>
				<lift version='0.13' producer='FLEx 7.2.4'><entry id='lovely_f1c5a4c8-a24f-4351-8551-2b70d53a9256' guid='f1c5a4c8-a24f-4351-8551-2b70d53a9256'>
				<lexical-unit>
				<form lang='fr'><text>lovely</text></form>
				</lexical-unit>
				<trait name='morph-type' value='stem'/>
				<sense id='fist_0e0fc867-e56a-4df5-861a-1cb24d861037'>
				<grammatical-info
					value='Noun' />
				<gloss
					lang='en'>
					<text>base</text>
				</gloss>
				<gloss
					lang='swh'>
					<text>ngumi / mangumi</text>
				</gloss>
				<gloss
					lang='swh'>
					<text>konde / makonde</text>
				</gloss>
				</sense>
				</entry></lift>"                ;
            var ours   = ancestor.Replace("base", "ours");
            var theirs = ancestor.Replace("base", "theirs");

            Assert.DoesNotThrow(() =>
            {
                using (var oursTemp = new TempFile(ours))
                    using (var theirsTemp = new TempFile(theirs))
                        using (var ancestorTemp = new TempFile(ancestor))
                        {
                            var listener   = new ListenerForUnitTests();
                            var situation  = new NullMergeSituation();
                            var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation)
                            {
                                EventListener = listener
                            };
                            XmlMergeService.Do3WayMerge(mergeOrder, new LiftEntryMergingStrategy(mergeOrder),
                                                        false,
                                                        "header",
                                                        "entry", "guid");
                            //var result = File.ReadAllText(mergeOrder.pathToOurs);
                            //AssertThatXmlIn.String(result).HasSpecifiedNumberOfMatchesForXpath(@"/lift/entry/relation", 2);
                        }
            });
        }
Exemple #27
0
        public void EachHasNewSense_BothSensesCoveyed()
        {
            const string ours = @"<?xml version='1.0' encoding='utf-8'?>
					<lift version='0.10' producer='WeSay 1.0.0.0'>
						<entry id='test'  guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6'>
							<sense id='123'>
								 <gloss lang='a'>
									<text>ourSense</text>
								 </gloss>
							 </sense>
						</entry>
					</lift>"                    ;

            const string theirs   = @"<?xml version='1.0' encoding='utf-8'?>
					<lift version='0.10' producer='WeSay 1.0.0.0'>
						<entry id='test'  guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6'>
							<sense id='456'>
								 <gloss lang='a'>
									<text>theirSense</text>
								 </gloss>
							 </sense>
						</entry>
					</lift>"                    ;
            const string ancestor = @"<?xml version='1.0' encoding='utf-8'?>
					<lift version='0.10' producer='WeSay 1.0.0.0'>
						<entry id='test'  guid='F169EB3D-16F2-4eb0-91AA-FDB91636F8F6' />
					</lift>"                    ;

            using (var oursTemp = new TempFile(ours))
                using (var theirsTemp = new TempFile(theirs))
                    using (var ancestorTemp = new TempFile(ancestor))
                    {
                        var listener   = new ListenerForUnitTests();
                        var situation  = new NullMergeSituation();
                        var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation)
                        {
                            EventListener = listener
                        };
                        XmlMergeService.Do3WayMerge(mergeOrder, new LiftEntryMergingStrategy(mergeOrder),
                                                    false,
                                                    "header",
                                                    "entry", "guid");
                        //this doesn't seem particular relevant, but senses are, in fact, ordered, so there is some ambiguity here
                        Assert.AreEqual(typeof(AmbiguousInsertConflict), listener.Conflicts[0].GetType());
                        var result = File.ReadAllText(mergeOrder.pathToOurs);
                        XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='test']");
                        XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='test' and sense[@id='123']/gloss/text='ourSense']");
                        XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='test' and sense[@id='456']/gloss/text='theirSense']");
                    }
        }
        public void Conflict_TheirsAppearsInCollisionNote()
        {
            const string ours = @"<?xml version='1.0' encoding='utf-8'?>
					<lift version='0.10' producer='WeSay 1.0.0.0'>
						<entry id='lexicalformcollission' guid='c1ed1fa7-e382-11de-8a39-0800200c9a66' >
							<lexical-unit>
								<form lang='x'>
									<text>ours</text>
								</form>
							</lexical-unit>
						</entry>
					</lift>"                    ;

            const string theirs   = @"<?xml version='1.0' encoding='utf-8'?>
					<lift version='0.10' producer='WeSay 1.0.0.0'>
						<entry id='lexicalformcollission' guid='c1ed1fa7-e382-11de-8a39-0800200c9a66' >
							<lexical-unit>
								<form lang='x'>
									<text>theirs</text>
								</form>
							</lexical-unit>
						</entry>
					</lift>"                    ;
            const string ancestor = @"<?xml version='1.0' encoding='utf-8'?>
					<lift version='0.10' producer='WeSay 1.0.0.0'>
						<entry id='lexicalformcollission' guid='c1ed1fa7-e382-11de-8a39-0800200c9a66' />
					</lift>"                    ;

            using (var oursTemp = new TempFile(ours))
                using (var theirsTemp = new TempFile(theirs))
                    using (var ancestorTemp = new TempFile(ancestor))
                    {
                        var listener   = new ListenerForUnitTests();
                        var situation  = new NullMergeSituation();
                        var mergeOrder = new MergeOrder(oursTemp.Path, ancestorTemp.Path, theirsTemp.Path, situation)
                        {
                            EventListener = listener
                        };
                        XmlMergeService.Do3WayMerge(mergeOrder, new PoorMansMergeStrategy(),
                                                    false,
                                                    "header",
                                                    "entry", "guid");
                        var result = File.ReadAllText(mergeOrder.pathToOurs);
                        XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry[@id='lexicalformcollission']");
                        XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry");        //just one
                        XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry/field[@type='mergeConflict']/trait[@name = 'looserData']");
                        XmlTestHelper.AssertXPathMatchesExactlyOne(result, "lift/entry/field[@type='mergeConflict' and @dateCreated]");
                    }
        }
Exemple #29
0
        public void Do3WayMerge(MergeOrder order)
        {
            // Debug.Fail("hello");
            // FailureSimulator is only used by tests to force a failure.
            FailureSimulator.IfTestRequestsItThrowNow("TextMerger");

            //trigger on a particular file name
            // FailureSimulator is only used by tests to force a failure.
            FailureSimulator.IfTestRequestsItThrowNow("TextMerger-" + Path.GetFileName(order.pathToOurs));

            //Throws on conflict
            var contents = GetRawMerge(order.pathToOurs, order.pathToCommonAncestor, order.pathToTheirs);

            File.WriteAllText(order.pathToOurs, contents);
        }
Exemple #30
0
 private int DoMerge(GroupOfConflictingLiftFiles group)
 {
     MergeSituation.PushRevisionsToEnvironmentVariables("bob", "-123", "sally", "-456");
     MergeOrder.PushToEnvironmentVariables(group.Folder.Path);
     // Change error logging to standard out so that tests which simulate errors don't fail the build
     Program.ErrorWriter = Console.Out;
     try
     {
         return(Program.Main(new[] { group.BobFile.Path, group.AncestorFile.Path, group.SallyFile.Path }));
     }
     finally
     {
         Program.ErrorWriter = Console.Error;
     }
 }
Exemple #31
0
        private static HashSet<string> CollectDataAndReportNormalEditConflicts(MergeOrder mergeOrder,
																			   IMergeStrategy mergeStrategy,
																			   IDictionary<string, XmlNode>
																				   fluffedUpLoserNodes,
																			   IDictionary<string, string>
																				   allCommonAncestorData,
																			   IDictionary<string, XmlNode>
																				   fluffedUpAncestorNodes,
																			   IDictionary<string, XmlNode>
																				   fluffedUpWinnerNodes,
																			   IDictionary<string, string> allLoserData,
																			   IDictionary<string, string> allWinnerData,
																			   IEnumerable<string> allWinnerIds,
																			   IEnumerable<string> allLoserIds,
																			   HashSet<string> allCommonAncestorIds,
																			   out HashSet<string> allIdsForUniqueLoserChanges,
																			   out HashSet<string> allIdsWinnerModified)
        {
            HashSet<string> allIdsLoserModified;
            HashSet<string> allIdsWhereUsersMadeDifferentChanges;
            CollectModifiedIdsFromWinnerAndLoser(allWinnerData, allLoserData, allWinnerIds, allCommonAncestorIds, allLoserIds,
                                                 allCommonAncestorData, out allIdsWhereUsersMadeDifferentChanges,
                                                 out allIdsLoserModified, out allIdsWinnerModified,
                                                 out allIdsForUniqueLoserChanges);
            ReportNormalEditConflicts(mergeOrder, mergeStrategy, // current
                                      allLoserData, fluffedUpAncestorNodes, allCommonAncestorData,
                                      allIdsWhereUsersMadeDifferentChanges,
                                      fluffedUpWinnerNodes, fluffedUpLoserNodes, allWinnerData);
            return allIdsLoserModified;
        }
Exemple #32
0
        private static IDictionary<string, string> DoMerge(MergeOrder mergeOrder, IMergeStrategy mergeStrategy,
														   bool sortRepeatingRecordOutputByKeyIdentifier,
														   string optionalFirstElementMarker,
														   string repeatingRecordElementName,
														   string repeatingRecordKeyIdentifier,
														   string pathToLoser, string winnerId, string pathToWinner,
														   string loserId,
														   string commonAncestorPathname)
        {
            // Step 1. Load each of the three files.
            HashSet<string> allCommonAncestorIds;
            HashSet<string> allWinnerIds;
            HashSet<string> allLoserIds;
            Dictionary<string, string> allLoserData;
            Dictionary<string, string> allWinnerData;
            Dictionary<string, string> allCommonAncestorData;
            LoadDataFiles(mergeOrder, mergeStrategy,
                          optionalFirstElementMarker, repeatingRecordElementName, repeatingRecordKeyIdentifier,
                          commonAncestorPathname, pathToWinner, pathToLoser,
                          out allCommonAncestorData, out allCommonAncestorIds,
                          out allWinnerData, out allWinnerIds,
                          out allLoserData, out allLoserIds);

            var originalValue = RemoveAmbiguousChildNodes;
            RemoveAmbiguousChildNodes = false;

            // Step 2. Collect up new items from winner and loser and report relevant conflicts.
            var fluffedUpAncestorNodes = new Dictionary<string, XmlNode>();
            var fluffedUpLoserNodes = new Dictionary<string, XmlNode>();
            var fluffedUpWinnerNodes = new Dictionary<string, XmlNode>();
            var allNewIdsFromBoth = CollectDataAndReportEditConflictsForBothAddedNewObjectsWithDifferentContent(mergeOrder,
                                                                                                                mergeStrategy,
                                                                                                                pathToWinner,
                                                                                                                fluffedUpWinnerNodes,
                                                                                                                fluffedUpLoserNodes,
                                                                                                                allCommonAncestorIds,
                                                                                                                allWinnerIds,
                                                                                                                allWinnerData,
                                                                                                                allLoserData,
                                                                                                                allLoserIds);

            // Step 3. Collect up deleted items from winner and loser.
            HashSet<string> allIdsRemovedByWinner;
            HashSet<string> allIdsRemovedByLoser;
            HashSet<string> allIdsRemovedByBoth;
            CollectDeletedIdsFromWinnerAndLoser(allLoserIds, allCommonAncestorIds, allWinnerIds,
                                                out allIdsRemovedByWinner, out allIdsRemovedByLoser, out allIdsRemovedByBoth);

            // Step 4. Collect up modified items from winner and loser and report all other conflicts.
            HashSet<string> allDeletedByLoserButEditedByWinnerIds;
            HashSet<string> allDeletedByWinnerButEditedByLoserIds;
            var allIdsForUniqueLoserChanges = CollectDataAndReportAllConflicts(mergeOrder, mergeStrategy, winnerId, loserId,
                                                                               allLoserIds, allWinnerData,
                                                                               allIdsRemovedByWinner, allIdsRemovedByLoser,
                                                                               allCommonAncestorIds, allCommonAncestorData,
                                                                               fluffedUpLoserNodes, allWinnerIds, allLoserData,
                                                                               fluffedUpWinnerNodes, fluffedUpAncestorNodes,
                                                                               pathToWinner,
                                                                               pathToLoser,
                                                                               out allDeletedByLoserButEditedByWinnerIds,
                                                                               out allDeletedByWinnerButEditedByLoserIds);

            // Step 5. Collect all ids that are to be written out.
            var allWritableIds = new HashSet<string>(allCommonAncestorIds, StringComparer.InvariantCultureIgnoreCase);
            allWritableIds.UnionWith(allWinnerIds);
            allWritableIds.UnionWith(allLoserIds);
            allWritableIds.UnionWith(allNewIdsFromBoth); // Adds new ones from winner & loser
            allWritableIds.ExceptWith(allIdsRemovedByWinner); // Removes deletions by winner.
            allWritableIds.ExceptWith(allIdsRemovedByLoser); // Removes deletions by loser.
            allWritableIds.ExceptWith(allIdsRemovedByBoth); // Removes deletions by both.
            allWritableIds.UnionWith(allDeletedByWinnerButEditedByLoserIds); // Puts back the loser edited vs winner deleted ids.
            allWritableIds.UnionWith(allDeletedByLoserButEditedByWinnerIds); // Puts back the winner edited vs loser deleted ids.
            // Write out data in sorted identifier order or 'ot luck' order.
            var allWritableData = sortRepeatingRecordOutputByKeyIdentifier
                                      ? new SortedDictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
                                      : new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) as
                                        IDictionary<string, string>;
            foreach (var identifier in allWritableIds)
            {
                string updatedData;
                if (allIdsForUniqueLoserChanges.Contains(identifier))
                {
                    // Loser made change. Winner did nothing.
                    updatedData = allLoserData[identifier];
                }
                else
                {
                    allWinnerData.TryGetValue(identifier, out updatedData);
                    if (updatedData == null)
                        updatedData = allLoserData[identifier];
                }
                allWinnerData.Remove(identifier);
                allLoserData.Remove(identifier);
                allWritableData.Add(identifier, updatedData);
            }

            RemoveAmbiguousChildNodes = originalValue;

            return allWritableData;
        }
Exemple #33
0
        private static void LoadDataFiles(MergeOrder mergeOrder, IMergeStrategy mergeStrategy,
										  string optionalFirstElementMarker, string repeatingRecordElementName,
										  string repeatingRecordKeyIdentifier,
										  string commonAncestorPathname, string pathToWinner, string pathToLoser,
										  out Dictionary<string, string> allCommonAncestorData,
										  out HashSet<string> allCommonAncestorIds,
										  out Dictionary<string, string> allWinnerData, out HashSet<string> allWinnerIds,
										  out Dictionary<string, string> allLoserData, out HashSet<string> allLoserIds)
        {
            allCommonAncestorData = MakeRecordDictionary(mergeOrder.EventListener, mergeStrategy,
                                                         commonAncestorPathname, optionalFirstElementMarker,
                                                         repeatingRecordElementName, repeatingRecordKeyIdentifier);
            allCommonAncestorIds = new HashSet<string>(allCommonAncestorData.Keys, StringComparer.InvariantCultureIgnoreCase);
            allWinnerData = MakeRecordDictionary(mergeOrder.EventListener, mergeStrategy,
                                                 pathToWinner, optionalFirstElementMarker,
                                                 repeatingRecordElementName, repeatingRecordKeyIdentifier);
            allWinnerIds = new HashSet<string>(allWinnerData.Keys, StringComparer.InvariantCultureIgnoreCase);
            allLoserData = MakeRecordDictionary(mergeOrder.EventListener, mergeStrategy,
                                                pathToLoser, optionalFirstElementMarker, repeatingRecordElementName,
                                                repeatingRecordKeyIdentifier);
            allLoserIds = new HashSet<string>(allLoserData.Keys, StringComparer.InvariantCultureIgnoreCase);
        }
Exemple #34
0
        private static void ReportEditConflictsForBothAddedNewObjectsWithDifferentContent(
			MergeOrder mergeOrder, IMergeStrategy mergeStrategy,
			string pathToWinner,
			IDictionary<string, string> allLoserData, IDictionary<string, XmlNode> fluffedUpLoserNodes,
			IEnumerable<string> allNewIdsFromBothWithSameData, IEnumerable<string> allNewIdsFromBoth,
			IDictionary<string, string> allWinnerData, IDictionary<string, XmlNode> fluffedUpWinnerNodes)
        {
            foreach (var identifier in allNewIdsFromBoth.Except(allNewIdsFromBothWithSameData))
            {
                //// These were added by both, but they do not have the same content.
                XmlNode winnerNode;
                if (!fluffedUpWinnerNodes.TryGetValue(identifier, out winnerNode))
                {
                    winnerNode = XmlUtilities.GetDocumentNodeFromRawXml(allWinnerData[identifier], new XmlDocument());
                    fluffedUpWinnerNodes.Add(identifier, winnerNode);
                }
                XmlNode loserNode;
                if (!fluffedUpLoserNodes.TryGetValue(identifier, out loserNode))
                {
                    loserNode = XmlUtilities.GetDocumentNodeFromRawXml(allLoserData[identifier], new XmlDocument());
                    fluffedUpLoserNodes.Add(identifier, loserNode);
                }

                var elementStrategy = mergeStrategy.GetElementStrategy(winnerNode);
                var generator = elementStrategy.ContextDescriptorGenerator;
                if (generator != null)
                {
                    mergeOrder.EventListener.EnteringContext(generator.GenerateContextDescriptor(allWinnerData[identifier],
                                                                                                 pathToWinner));
                }
                var mergedResult = mergeStrategy.MakeMergedEntry(
                    mergeOrder.EventListener,
                    mergeOrder.MergeSituation.ConflictHandlingMode == MergeOrder.ConflictHandlingModeChoices.WeWin
                        ? winnerNode
                        : loserNode,
                    mergeOrder.MergeSituation.ConflictHandlingMode == MergeOrder.ConflictHandlingModeChoices.WeWin
                        ? loserNode
                        : winnerNode,
                    null);
                allWinnerData[identifier] = mergedResult;
                fluffedUpWinnerNodes.Remove(identifier);
                allLoserData[identifier] = mergedResult;
                    // They really are the same now, but is it a good idea to make them the same?
                fluffedUpLoserNodes.Remove(identifier);
            }
        }
Exemple #35
0
        private static void ReportEditVsDeleteConflicts(MergeOrder mergeOrder, IMergeStrategy mergeStrategy,
														IDictionary<string, XmlNode> fluffedUpWinnerNodes,
														IDictionary<string, string> allWinnerData,
														string winnerId,
														IEnumerable<string> allDeletedByLoserButEditedByWinnerIds,
														IDictionary<string, string> allCommonAncestorData,
														IDictionary<string, XmlNode> fluffedUpAncestorNodes,
														string pathToWinner)
        {
            foreach (var allDeletedByLoserButEditedByWinnerId in allDeletedByLoserButEditedByWinnerIds)
            {
                // Report winner edited vs loser deleted
                XmlNode commonNode;
                if (!fluffedUpAncestorNodes.TryGetValue(allDeletedByLoserButEditedByWinnerId, out commonNode))
                {
                    commonNode = XmlUtilities.GetDocumentNodeFromRawXml(allCommonAncestorData[allDeletedByLoserButEditedByWinnerId],
                                                                        new XmlDocument());
                    fluffedUpAncestorNodes.Add(allDeletedByLoserButEditedByWinnerId, commonNode);
                }
                XmlNode winnerNode;
                if (!fluffedUpWinnerNodes.TryGetValue(allDeletedByLoserButEditedByWinnerId, out winnerNode))
                {
                    winnerNode = XmlUtilities.GetDocumentNodeFromRawXml(allWinnerData[allDeletedByLoserButEditedByWinnerId],
                                                                        new XmlDocument());
                    fluffedUpWinnerNodes.Add(allDeletedByLoserButEditedByWinnerId, winnerNode);
                }
                var elementStrategy = mergeStrategy.GetElementStrategy(winnerNode);
                var generator = elementStrategy.ContextDescriptorGenerator;
                if (generator != null)
                {
                    mergeOrder.EventListener.EnteringContext(generator.GenerateContextDescriptor(allWinnerData[allDeletedByLoserButEditedByWinnerId],
                                                                                                 pathToWinner));
                }
                AddConflictToListener(
                    mergeOrder.EventListener,
                    new EditedVsRemovedElementConflict(commonNode.Name, winnerNode, null, commonNode, mergeOrder.MergeSituation,
                                                       mergeStrategy.GetElementStrategy(commonNode), winnerId),
                    winnerNode, null, commonNode, generator as IGenerateHtmlContext ?? new SimpleHtmlGenerator());
            }
        }
Exemple #36
0
        private static IEnumerable<string> CollectDataAndReportEditConflictsForBothAddedNewObjectsWithDifferentContent(
			MergeOrder mergeOrder, IMergeStrategy mergeStrategy, string pathToWinner,
			IDictionary<string, XmlNode> fluffedUpWinnerNodes,
			IDictionary<string, XmlNode> fluffedUpLoserNodes, HashSet<string> allCommonAncestorIds,
			IEnumerable<string> allWinnerIds, IDictionary<string, string> allWinnerData,
			IDictionary<string, string> allLoserData, IEnumerable<string> allLoserIds)
        {
            HashSet<string> allNewIdsFromBoth;
            HashSet<string> allNewIdsFromBothWithSameData;
            CollectNewItemsFromWinnerAndLoser(allWinnerData, allWinnerIds, allLoserIds, allLoserData, allCommonAncestorIds,
                                              out allNewIdsFromBoth, out allNewIdsFromBothWithSameData, fluffedUpLoserNodes,
                                              fluffedUpWinnerNodes);
            ReportEditConflictsForBothAddedNewObjectsWithDifferentContent(mergeOrder, mergeStrategy, pathToWinner,
                                                                          allLoserData, fluffedUpLoserNodes,
                                                                          allNewIdsFromBothWithSameData, allNewIdsFromBoth,
                                                                          allWinnerData, fluffedUpWinnerNodes);
            return allNewIdsFromBoth;
        }
Exemple #37
0
        /// <summary>
        /// Perform the 3-way merge.
        /// </summary>
        public static void Do3WayMerge(MergeOrder mergeOrder, IMergeStrategy mergeStrategy,
									   // Get from mergeOrder: IMergeEventListener listener,
									   bool sortRepeatingRecordOutputByKeyIdentifier,
									   string optionalFirstElementMarker,
									   string repeatingRecordElementName, string repeatingRecordKeyIdentifier)
        {
            // NB: The FailureSimulator is *only* used in tests.
            FailureSimulator.IfTestRequestsItThrowNow("LiftMerger.FindEntryById");

            Guard.AgainstNull(mergeStrategy, string.Format("'{0}' is null.", mergeStrategy));
            Guard.AgainstNull(mergeOrder, string.Format("'{0}' is null.", mergeOrder));
            Guard.AgainstNull(mergeOrder.EventListener, string.Format("'{0}' is null.", "mergeOrder.EventListener"));
            Guard.AgainstNullOrEmptyString(repeatingRecordElementName, "No primary record element name.");
            Guard.AgainstNullOrEmptyString(repeatingRecordKeyIdentifier, "No identifier attribute for primary record element.");

            var commonAncestorPathname = mergeOrder.pathToCommonAncestor;
            Require.That(File.Exists(commonAncestorPathname), string.Format("'{0}' does not exist.", commonAncestorPathname));

            string pathToWinner;
            string pathToLoser;
            string winnerId;
            string loserId;
            switch (mergeOrder.MergeSituation.ConflictHandlingMode)
            {
                case MergeOrder.ConflictHandlingModeChoices.WeWin:
                    pathToWinner = mergeOrder.pathToOurs;
                    pathToLoser = mergeOrder.pathToTheirs;
                    winnerId = mergeOrder.MergeSituation.AlphaUserId;
                    loserId = mergeOrder.MergeSituation.BetaUserId;
                    break;
                default: //case MergeOrder.ConflictHandlingModeChoices.TheyWin:
                    pathToWinner = mergeOrder.pathToTheirs;
                    pathToLoser = mergeOrder.pathToOurs;
                    winnerId = mergeOrder.MergeSituation.BetaUserId;
                    loserId = mergeOrder.MergeSituation.AlphaUserId;
                    break;
            }
            Require.That(File.Exists(pathToWinner), string.Format("'{0}' does not exist.", pathToWinner));
            Require.That(File.Exists(pathToLoser), string.Format("'{0}' does not exist.", pathToLoser));
            SortedDictionary<string, string> sortedAttributes;
            var rootElementName = GetRootElementData(mergeOrder.pathToOurs, mergeOrder.pathToTheirs,
                                                     mergeOrder.pathToCommonAncestor, out sortedAttributes);
            EnsureCommonAncestorFileHasMinimalXmlContent(commonAncestorPathname, rootElementName, sortedAttributes);

            // Do main merge work.
            var allWritableData = DoMerge(mergeOrder, mergeStrategy,
                                          sortRepeatingRecordOutputByKeyIdentifier, optionalFirstElementMarker,
                                          repeatingRecordElementName, repeatingRecordKeyIdentifier,
                                          pathToLoser, winnerId, pathToWinner, loserId, commonAncestorPathname);

            GC.Collect(2, GCCollectionMode.Forced); // Not nice, but required for the 164Meg ChorusNotes file.

            // Write all objects.
            WriteMainOutputData(allWritableData,
                                mergeOrder.pathToOurs,
                                // Do not change to another output file, or be ready to fix SyncScenarioTests.CanCollaborateOnLift()!
                                optionalFirstElementMarker, rootElementName, sortedAttributes, mergeStrategy.SuppressIndentingChildren());
        }
Exemple #38
0
        private static void ReportNormalEditConflicts(MergeOrder mergeOrder, IMergeStrategy mergeStrategy,
													  IDictionary<string, string> allLoserData,
													  IDictionary<string, XmlNode> fluffedUpAncestorNodes,
													  IDictionary<string, string> allCommonAncestorData,
													  IEnumerable<string> allIdsWhereUsersMadeDifferentChanges,
													  IDictionary<string, XmlNode> fluffedUpWinnerNodes,
													  IDictionary<string, XmlNode> fluffedUpLoserNodes,
													  IDictionary<string, string> allWinnerData)
        {
            foreach (var identifier in allIdsWhereUsersMadeDifferentChanges)
            {
                // Report normal edit conflicts for 'allIdsWhereUsersMadeDifferentChanges'
                XmlNode winnerNode;
                if (!fluffedUpWinnerNodes.TryGetValue(identifier, out winnerNode))
                {
                    winnerNode = XmlUtilities.GetDocumentNodeFromRawXml(allWinnerData[identifier], new XmlDocument());
                    fluffedUpWinnerNodes.Add(identifier, winnerNode);
                }
                XmlNode loserNode;
                if (!fluffedUpLoserNodes.TryGetValue(identifier, out loserNode))
                {
                    loserNode = XmlUtilities.GetDocumentNodeFromRawXml(allLoserData[identifier], new XmlDocument());
                    fluffedUpLoserNodes.Add(identifier, loserNode);
                }
                XmlNode commonNode;
                if (!fluffedUpAncestorNodes.TryGetValue(identifier, out commonNode))
                {
                    commonNode = XmlUtilities.GetDocumentNodeFromRawXml(allCommonAncestorData[identifier], new XmlDocument());
                    fluffedUpAncestorNodes.Add(identifier, commonNode);
                }
                var mergedResult = mergeStrategy.MakeMergedEntry(
                    mergeOrder.EventListener,
                    mergeOrder.MergeSituation.ConflictHandlingMode == MergeOrder.ConflictHandlingModeChoices.WeWin
                        ? winnerNode
                        : loserNode,
                    mergeOrder.MergeSituation.ConflictHandlingMode == MergeOrder.ConflictHandlingModeChoices.WeWin
                        ? loserNode
                        : winnerNode,
                    commonNode);
                allWinnerData[identifier] = mergedResult;
                fluffedUpWinnerNodes.Remove(identifier);
                allLoserData[identifier] = mergedResult;
                    // They really are the same now, but is it a good idea to make them the same?
                fluffedUpLoserNodes.Remove(identifier);
                allCommonAncestorData[identifier] = mergedResult;
                // They really are the same now, but is it a good idea to make them the same?
                fluffedUpAncestorNodes.Remove(identifier);
            }
        }
Exemple #39
0
        private static HashSet<string> CollectDataAndReportAllConflicts(MergeOrder mergeOrder, IMergeStrategy mergeStrategy,
																		string winnerId, string loserId,
																		IEnumerable<string> allLoserIds,
																		IDictionary<string, string> allWinnerData,
																		IEnumerable<string> allIdsRemovedByWinner,
																		IEnumerable<string> allIdsRemovedByLoser,
																		HashSet<string> allCommonAncestorIds,
																		IDictionary<string, string> allCommonAncestorData,
																		IDictionary<string, XmlNode> fluffedUpLoserNodes,
																		IEnumerable<string> allWinnerIds,
																		IDictionary<string, string> allLoserData,
																		IDictionary<string, XmlNode> fluffedUpWinnerNodes,
																		IDictionary<string, XmlNode> fluffedUpAncestorNodes,
																		string pathToWinner,
																		string pathToLoser,
																		out HashSet<string>
																			allDeletedByLoserButEditedByWinnerIds,
																		out HashSet<string>
																			allDeletedByWinnerButEditedByLoserIds)
        {
            HashSet<string> allIdsForUniqueLoserChanges;
            HashSet<string> allIdsWinnerModified;
            var allIdsLoserModified = CollectDataAndReportNormalEditConflicts(mergeOrder, mergeStrategy, fluffedUpLoserNodes,
                                                                              allCommonAncestorData,
                                                                              fluffedUpAncestorNodes, fluffedUpWinnerNodes,
                                                                              allLoserData, allWinnerData, allWinnerIds,
                                                                              allLoserIds, allCommonAncestorIds,
                                                                              out allIdsForUniqueLoserChanges,
                                                                              out allIdsWinnerModified);

            // Step 5. Collect up items modified by one user, but deleted by the other.
            CollectIdsOfEditVsDelete(allIdsRemovedByLoser, allIdsWinnerModified, allIdsLoserModified, allIdsRemovedByWinner,
                                     out allDeletedByWinnerButEditedByLoserIds, out allDeletedByLoserButEditedByWinnerIds);
            allIdsWinnerModified.Clear();
            allIdsLoserModified.Clear();

            // Step 6. Do merging and report conflicts.
            ReportDeleteVsEditConflicts(mergeOrder, mergeStrategy,
                                        fluffedUpLoserNodes, allLoserData, loserId, allDeletedByWinnerButEditedByLoserIds,
                                        allCommonAncestorData, fluffedUpAncestorNodes, pathToLoser);
            ReportEditVsDeleteConflicts(mergeOrder, mergeStrategy,
                                        fluffedUpWinnerNodes, allWinnerData, winnerId, allDeletedByLoserButEditedByWinnerIds,
                                        allCommonAncestorData, fluffedUpAncestorNodes, pathToWinner);

            return allIdsForUniqueLoserChanges;
        }