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); }
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); } } }
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']"); } }
public void Do3WayMerge(MergeOrder order) { XmlMergeService.Do3WayMerge(order, new ChorusNotesAnnotationMergingStrategy(order), false, null, "annotation", "guid"); }
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(); }
[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()); } }
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 }
public void Do3WayMerge(MetadataCache mdc, MergeOrder mergeOrder) { var merger = new XmlMerger(mergeOrder.MergeSituation) { EventListener = mergeOrder.EventListener }; CustomLayoutMergeStrategiesMethod.AddElementStrategies(merger.MergeStrategies); CustomLayoutMergeService.DoMerge(mergeOrder, merger); }
/// <summary> /// Constructor /// </summary> public LiftRangesMergingStrategy(MergeOrder mergeOrder) { _merger = new XmlMerger(mergeOrder.MergeSituation) { EventListener = mergeOrder.EventListener }; LiftBasicElementStrategiesMethod.AddLiftBasicElementStrategies(_merger.MergeStrategies); LiftRangesElementStrategiesMethod.AddLiftRangeElementStrategies(_merger.MergeStrategies); }
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); }
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"); } }
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); }
/// <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); }
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 }); }
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); }
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); }
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); }
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); } }); }
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]"); } }
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); }
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; } }
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; }
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; }
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); }
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); } }
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()); } }
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; }
/// <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()); }
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); } }
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; }