public static int Main(string[] args) { try { #if MONO var ourFilePath = args[0]; var commonFilePath = args[1]; var 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); var ourFilePath = Encoding.UTF8.GetString(inputEncoding.GetBytes(args[0])); var commonFilePath = Encoding.UTF8.GetString(inputEncoding.GetBytes(args[1])); var theirFilePath = Encoding.UTF8.GetString(inputEncoding.GetBytes(args[2])); Console.WriteLine("ChorusMerge: Input encoding {0}", inputEncoding.EncodingName); #endif //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 (ChorusNotesMergeEventListener xmlListener = new ChorusNotesMergeEventListener(order.pathToOurs + ".NewChorusNotes")) { // listenerDispatcher.AddEventListener(humanListener); // listenerDispatcher.AddEventListener(xmlListener); order.EventListener = xmlListener; handler.Do3WayMerge(order); } } catch (Exception e) { Console.Error.WriteLine("ChorusMerge Error: " + e.Message); Console.Error.WriteLine(e.StackTrace); return 1; } return 0;//no error }
/// <summary> /// The only entry point in the class. This method (plus its private methods) does the work of the class. /// </summary> /// <param name="pathname">Pathname of the split up file that contains <paramref name="element"/>.</param> /// <param name="sortedData">All of the data being collected that will end up as CmObject elments in the rebuilt fwdata file. These are sorted by guid order.</param> /// <param name="element">The xml element to check for a duplicate guid.</param> /// <param name="isOwnSeqNode">Out paramenter that is used by caller.</param> /// <param name="className">The class of <paramref name="element"/>.</param> /// <returns></returns> internal static string CheckForDuplicateGuid(string pathname, SortedDictionary<string, XElement> sortedData, XElement element, out bool isOwnSeqNode, out string className) { var mdc = MetadataCache.MdCache; FdoClassInfo classInfo; isOwnSeqNode = GetClassInfoFromElement(mdc, element, out classInfo, out className); var elementGuid = element.Attribute(SharedConstants.GuidStr).Value.ToLowerInvariant(); if (!sortedData.ContainsKey(elementGuid)) return elementGuid; // Does LT-12524 "Handle merge in case of conflicting move object to different destination". // This need will manifest itself in the guid already being in 'sortedData' and an exception being thrown. // At this point element has not been flattened, so stuff it owns will still be in it. // That is good, if we go with JohnT's idea of using a new guid for guids that are already in 'sortedData'. // By changing it before flattening, then the owned stuff will get the new one for their ownerguid attrs. // The owned stuff will also be dup, so the idea is to also change their guids right now. [ChangeGuids is recursive down the owning tree.] // Just be sure to change 'elementGuid' to the new one. :-) // The first item added to sortedData has been flattened by this point, but not any following ones. var oldGuid = elementGuid; elementGuid = ChangeGuids(mdc, classInfo, element); using (var listener = new ChorusNotesMergeEventListener(ChorusNotesMergeEventListener.GetChorusNotesFilePath(pathname))) { // Don't try to use something like this: // var contextGenerator = new FieldWorkObjectContextGenerator(); // contextGenerator.GenerateContextDescriptor(element.ToString(), pathname) // it will fail for elements in an owning sequence because in the unflattened form // the object representing a sequence item has element name <ownseq> which won't generate a useful label. var context = FieldWorksMergeServices.GenerateContextDescriptor(pathname, elementGuid, className); listener.EnteringContext(context); // Adding the conflict to the listener, will result in the ChorusNotes file being updated (created if need be.) var conflict = new IncompatibleMoveConflict(className, CmObjectFlatteningService.GetXmlNode(element)) { Situation = new NullMergeSituation() }; // The order of the next three lines is critical. Each prepares state that the following lines use. listener.RecordContextInConflict(conflict); conflict.HtmlDetails = MakeHtmlForIncompatibleMove(conflict, oldGuid, elementGuid, element); listener.ConflictOccurred(conflict); File.WriteAllText(pathname + "." + SharedConstants.dupid, ""); } return elementGuid; }
public void EnsureMergedCData_IsRetained() { using (var common = TempFile.WithFilename("common.ChorusNotes")) using (var ours = TempFile.WithFilename("ours.ChorusNotes")) using (var theirs = TempFile.WithFilename("theirs.ChorusNotes")) { const string commonData = @"<?xml version='1.0' encoding='utf-8'?> <notes version='0'> <annotation class='mergeConflict' ref='silfw://localhost/link?app=flex&database=current&server=&tool=default&guid=bab7776e-531b-4ce1-997f-fa638c09e381&tag=&label=Entry "pintu"' guid='1cb66d60-90d5-4367-95b1-b7b41eb8986d'> <message author='merger' status='open' guid='ef89b532-5441-48a8-aea9-065b6ab5cfbd' date='2012-07-20T14:18:35Z'>Entry 'pintu': user57@tpad2 deleted this element, while user57 edited it. The automated merger kept the change made by user57.<![CDATA[<conflict typeGuid='3d9ba4ac-4a25-11df-9879-0800200c9a66' class='Chorus.merge.xml.generic.EditedVsRemovedElementConflict' relativeFilePath='Linguistics\Lexicon\Lexicon.lexdb' type='Removed Vs Edited Element Conflict' guid='ef89b532-5441-48a8-aea9-065b6ab5cfbd' date='2012-07-20T14:18:35Z' whoWon='user57' htmlDetails='<head><style type='text/css'></style></head><body><div class='description'>Entry "pintu": user57@tpad2 deleted this element, while user57 edited it. The automated merger kept the change made by user57.</div><div class='alternative'>user57's changes: &lt;LexEntry guid="bab7776e-531b-4ce1-997f-fa638c09e381"><br/>&nbsp;&nbsp;&lt;DateCreated val="2012-7-20 13:46:3.625" /><br/>&nbsp;&nbsp;&lt;DateModified val="2012-7-20 <span style="text-decoration: line-through; color: red">13:46:3.625</span><span style="background: Yellow">14:14:20.218</span>" /><br/>&nbsp;&nbsp;&lt;DoNotUseForParsing val="False" /><br/>&nbsp;&nbsp;&lt;HomographNumber val="0" /><br/>&nbsp;&nbsp;&lt;LexemeForm><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;MoStemAllomorph guid="556f6e08-0fb2-4171-82e0-6dcdddf9490b"><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Form><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;AUni ws="id">pintu&lt;/AUni><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Form><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;IsAbstract val="False" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MorphType><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;objsur guid="d7f713e8-e8cf-11d3-9764-00c04f186933" t="r" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MorphType><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MoStemAllomorph><br/>&nbsp;&nbsp;&lt;/LexemeForm><br/>&nbsp;&nbsp;&lt;MorphoSyntaxAnalyses><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;MoStemMsa guid="f63e03f0-ac9d-4b1b-980f-316bbb741f70" /><br/>&nbsp;&nbsp;&lt;/MorphoSyntaxAnalyses><br/>&nbsp;&nbsp;&lt;Senses><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;ownseq class="LexSense" guid="dad069de-dfad-45f6-a5d2-449265adbc3a"><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;Definition></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;AStr</span> <span style="background: Yellow">ws="en"></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;Run</span> <span style="background: Yellow">ws="en">a</span> <span style="background: Yellow">door</span><span style="background: Yellow">&lt;/Run></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;/AStr></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;/Definition></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Gloss><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;AUni ws="en">door&lt;/AUni><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Gloss><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MorphoSyntaxAnalysis><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;objsur guid="f63e03f0-ac9d-4b1b-980f-316bbb741f70" t="r" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MorphoSyntaxAnalysis><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ownseq><br/>&nbsp;&nbsp;&lt;/Senses><br/>&lt;/LexEntry></div><div class='alternative'>user57@tpad2's changes: &lt;LexEntry guid="bab7776e-531b-4ce1-997f-fa638c09e381"><br/>&nbsp;&nbsp;&lt;DateCreated val="2012-7-20 13:46:3.625" /><br/>&nbsp;&nbsp;&lt;DateModified val="2012-7-20 13:46:3.625" /><br/>&nbsp;&nbsp;&lt;DoNotUseForParsing val="False" /><br/>&nbsp;&nbsp;&lt;HomographNumber val="0" /><br/>&nbsp;&nbsp;&lt;LexemeForm><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;MoStemAllomorph guid="556f6e08-0fb2-4171-82e0-6dcdddf9490b"><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Form><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;AUni ws="id">pintu&lt;/AUni><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Form><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;IsAbstract val="False" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MorphType><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;objsur guid="d7f713e8-e8cf-11d3-9764-00c04f186933" t="r" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MorphType><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MoStemAllomorph><br/>&nbsp;&nbsp;&lt;/LexemeForm><br/>&nbsp;&nbsp;&lt;MorphoSyntaxAnalyses><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;MoStemMsa guid="f63e03f0-ac9d-4b1b-980f-316bbb741f70" /><br/>&nbsp;&nbsp;&lt;/MorphoSyntaxAnalyses><br/>&nbsp;&nbsp;&lt;Senses><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;ownseq class="LexSense" guid="dad069de-dfad-45f6-a5d2-449265adbc3a"><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Gloss><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;AUni ws="en">door&lt;/AUni><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Gloss><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MorphoSyntaxAnalysis><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;objsur guid="f63e03f0-ac9d-4b1b-980f-316bbb741f70" t="r" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MorphoSyntaxAnalysis><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ownseq><br/>&nbsp;&nbsp;&lt;/Senses><br/>&lt;/LexEntry></div><div class='mergechoice'>The merger kept the change made by user57</div></body>' contextPath='silfw://localhost/link?app=flex&database=current&server=&tool=default&guid=bab7776e-531b-4ce1-997f-fa638c09e381&tag=&label=Entry "pintu"' contextDataLabel='Entry "pintu"'> <MergeSituation alphaUserId='user57' betaUserId='user57@tpad2' alphaUserRevision='306520fcc148' betaUserRevision='5aa248710fbc' path='Linguistics\Lexicon\Lexicon.lexdb' conflictHandlingMode='WeWin' /> </conflict>]]></message> <message author='user57' status='closed' date='2012-07-20T22:49:03Z' guid='bf43783e-eca1-4b0f-bacd-6fe168d7d616'></message> </annotation> </notes>"; File.WriteAllText(common.Path, commonData); const string ourData = @"<?xml version='1.0' encoding='utf-8'?> <notes version='0'> <annotation class='mergeConflict' ref='silfw://localhost/link?app=flex&database=current&server=&tool=default&guid=bab7776e-531b-4ce1-997f-fa638c09e381&tag=&label=Entry "pintu"' guid='1cb66d60-90d5-4367-95b1-b7b41eb8986d'> <message author='merger' status='open' guid='ef89b532-5441-48a8-aea9-065b6ab5cfbd' date='2012-07-20T14:18:35Z'>Entry 'pintu': user57@tpad2 deleted this element, while user57 edited it. The automated merger kept the change made by user57.<![CDATA[<conflict typeGuid='3d9ba4ac-4a25-11df-9879-0800200c9a66' class='Chorus.merge.xml.generic.EditedVsRemovedElementConflict' relativeFilePath='Linguistics\Lexicon\Lexicon.lexdb' type='Removed Vs Edited Element Conflict' guid='ef89b532-5441-48a8-aea9-065b6ab5cfbd' date='2012-07-20T14:18:35Z' whoWon='user57' htmlDetails='<head><style type='text/css'></style></head><body><div class='description'>Entry "pintu": user57@tpad2 deleted this element, while user57 edited it. The automated merger kept the change made by user57.</div><div class='alternative'>user57's changes: &lt;LexEntry guid="bab7776e-531b-4ce1-997f-fa638c09e381"><br/>&nbsp;&nbsp;&lt;DateCreated val="2012-7-20 13:46:3.625" /><br/>&nbsp;&nbsp;&lt;DateModified val="2012-7-20 <span style="text-decoration: line-through; color: red">13:46:3.625</span><span style="background: Yellow">14:14:20.218</span>" /><br/>&nbsp;&nbsp;&lt;DoNotUseForParsing val="False" /><br/>&nbsp;&nbsp;&lt;HomographNumber val="0" /><br/>&nbsp;&nbsp;&lt;LexemeForm><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;MoStemAllomorph guid="556f6e08-0fb2-4171-82e0-6dcdddf9490b"><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Form><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;AUni ws="id">pintu&lt;/AUni><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Form><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;IsAbstract val="False" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MorphType><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;objsur guid="d7f713e8-e8cf-11d3-9764-00c04f186933" t="r" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MorphType><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MoStemAllomorph><br/>&nbsp;&nbsp;&lt;/LexemeForm><br/>&nbsp;&nbsp;&lt;MorphoSyntaxAnalyses><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;MoStemMsa guid="f63e03f0-ac9d-4b1b-980f-316bbb741f70" /><br/>&nbsp;&nbsp;&lt;/MorphoSyntaxAnalyses><br/>&nbsp;&nbsp;&lt;Senses><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;ownseq class="LexSense" guid="dad069de-dfad-45f6-a5d2-449265adbc3a"><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;Definition></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;AStr</span> <span style="background: Yellow">ws="en"></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;Run</span> <span style="background: Yellow">ws="en">a</span> <span style="background: Yellow">door</span><span style="background: Yellow">&lt;/Run></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;/AStr></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;/Definition></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Gloss><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;AUni ws="en">door&lt;/AUni><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Gloss><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MorphoSyntaxAnalysis><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;objsur guid="f63e03f0-ac9d-4b1b-980f-316bbb741f70" t="r" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MorphoSyntaxAnalysis><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ownseq><br/>&nbsp;&nbsp;&lt;/Senses><br/>&lt;/LexEntry></div><div class='alternative'>user57@tpad2's changes: &lt;LexEntry guid="bab7776e-531b-4ce1-997f-fa638c09e381"><br/>&nbsp;&nbsp;&lt;DateCreated val="2012-7-20 13:46:3.625" /><br/>&nbsp;&nbsp;&lt;DateModified val="2012-7-20 13:46:3.625" /><br/>&nbsp;&nbsp;&lt;DoNotUseForParsing val="False" /><br/>&nbsp;&nbsp;&lt;HomographNumber val="0" /><br/>&nbsp;&nbsp;&lt;LexemeForm><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;MoStemAllomorph guid="556f6e08-0fb2-4171-82e0-6dcdddf9490b"><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Form><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;AUni ws="id">pintu&lt;/AUni><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Form><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;IsAbstract val="False" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MorphType><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;objsur guid="d7f713e8-e8cf-11d3-9764-00c04f186933" t="r" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MorphType><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MoStemAllomorph><br/>&nbsp;&nbsp;&lt;/LexemeForm><br/>&nbsp;&nbsp;&lt;MorphoSyntaxAnalyses><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;MoStemMsa guid="f63e03f0-ac9d-4b1b-980f-316bbb741f70" /><br/>&nbsp;&nbsp;&lt;/MorphoSyntaxAnalyses><br/>&nbsp;&nbsp;&lt;Senses><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;ownseq class="LexSense" guid="dad069de-dfad-45f6-a5d2-449265adbc3a"><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Gloss><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;AUni ws="en">door&lt;/AUni><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Gloss><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MorphoSyntaxAnalysis><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;objsur guid="f63e03f0-ac9d-4b1b-980f-316bbb741f70" t="r" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MorphoSyntaxAnalysis><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ownseq><br/>&nbsp;&nbsp;&lt;/Senses><br/>&lt;/LexEntry></div><div class='mergechoice'>The merger kept the change made by user57</div></body>' contextPath='silfw://localhost/link?app=flex&database=current&server=&tool=default&guid=bab7776e-531b-4ce1-997f-fa638c09e381&tag=&label=Entry "pintu"' contextDataLabel='Entry "pintu"'> <MergeSituation alphaUserId='user57' betaUserId='user57@tpad2' alphaUserRevision='306520fcc148' betaUserRevision='5aa248710fbc' path='Linguistics\Lexicon\Lexicon.lexdb' conflictHandlingMode='WeWin' /> </conflict>]]></message> <message author='user57' status='closed' date='2012-07-20T22:49:03Z' guid='bf43783e-eca1-4b0f-bacd-6fe168d7d616'></message> <message author='user57' status='open' date='2012-07-20T23:11:24Z' guid='524786f4-8e27-4ebf-b7ea-02846723c2d8'>Chorus seems to have chosen the better gloss anyway.</message> </annotation> </notes>"; File.WriteAllText(ours.Path, ourData); const string theirData = @"<?xml version='1.0' encoding='utf-8'?> <notes version='0'> <annotation class='mergeConflict' ref='silfw://localhost/link?app=flex&database=current&server=&tool=default&guid=bab7776e-531b-4ce1-997f-fa638c09e381&tag=&label=Entry "pintu"' guid='1cb66d60-90d5-4367-95b1-b7b41eb8986d'> <message author='merger' status='open' guid='ef89b532-5441-48a8-aea9-065b6ab5cfbd' date='2012-07-20T14:18:35Z'>Entry 'pintu': user57@tpad2 deleted this element, while user57 edited it. The automated merger kept the change made by user57.<![CDATA[<conflict typeGuid='3d9ba4ac-4a25-11df-9879-0800200c9a66' class='Chorus.merge.xml.generic.EditedVsRemovedElementConflict' relativeFilePath='Linguistics\Lexicon\Lexicon.lexdb' type='Removed Vs Edited Element Conflict' guid='ef89b532-5441-48a8-aea9-065b6ab5cfbd' date='2012-07-20T14:18:35Z' whoWon='user57' htmlDetails='<head><style type='text/css'></style></head><body><div class='description'>Entry "pintu": user57@tpad2 deleted this element, while user57 edited it. The automated merger kept the change made by user57.</div><div class='alternative'>user57's changes: &lt;LexEntry guid="bab7776e-531b-4ce1-997f-fa638c09e381"><br/>&nbsp;&nbsp;&lt;DateCreated val="2012-7-20 13:46:3.625" /><br/>&nbsp;&nbsp;&lt;DateModified val="2012-7-20 <span style="text-decoration: line-through; color: red">13:46:3.625</span><span style="background: Yellow">14:14:20.218</span>" /><br/>&nbsp;&nbsp;&lt;DoNotUseForParsing val="False" /><br/>&nbsp;&nbsp;&lt;HomographNumber val="0" /><br/>&nbsp;&nbsp;&lt;LexemeForm><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;MoStemAllomorph guid="556f6e08-0fb2-4171-82e0-6dcdddf9490b"><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Form><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;AUni ws="id">pintu&lt;/AUni><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Form><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;IsAbstract val="False" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MorphType><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;objsur guid="d7f713e8-e8cf-11d3-9764-00c04f186933" t="r" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MorphType><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MoStemAllomorph><br/>&nbsp;&nbsp;&lt;/LexemeForm><br/>&nbsp;&nbsp;&lt;MorphoSyntaxAnalyses><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;MoStemMsa guid="f63e03f0-ac9d-4b1b-980f-316bbb741f70" /><br/>&nbsp;&nbsp;&lt;/MorphoSyntaxAnalyses><br/>&nbsp;&nbsp;&lt;Senses><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;ownseq class="LexSense" guid="dad069de-dfad-45f6-a5d2-449265adbc3a"><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;Definition></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;AStr</span> <span style="background: Yellow">ws="en"></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;Run</span> <span style="background: Yellow">ws="en">a</span> <span style="background: Yellow">door</span><span style="background: Yellow">&lt;/Run></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;/AStr></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: Yellow">&lt;/Definition></span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Gloss><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;AUni ws="en">door&lt;/AUni><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Gloss><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MorphoSyntaxAnalysis><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;objsur guid="f63e03f0-ac9d-4b1b-980f-316bbb741f70" t="r" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MorphoSyntaxAnalysis><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ownseq><br/>&nbsp;&nbsp;&lt;/Senses><br/>&lt;/LexEntry></div><div class='alternative'>user57@tpad2's changes: &lt;LexEntry guid="bab7776e-531b-4ce1-997f-fa638c09e381"><br/>&nbsp;&nbsp;&lt;DateCreated val="2012-7-20 13:46:3.625" /><br/>&nbsp;&nbsp;&lt;DateModified val="2012-7-20 13:46:3.625" /><br/>&nbsp;&nbsp;&lt;DoNotUseForParsing val="False" /><br/>&nbsp;&nbsp;&lt;HomographNumber val="0" /><br/>&nbsp;&nbsp;&lt;LexemeForm><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;MoStemAllomorph guid="556f6e08-0fb2-4171-82e0-6dcdddf9490b"><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Form><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;AUni ws="id">pintu&lt;/AUni><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Form><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;IsAbstract val="False" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MorphType><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;objsur guid="d7f713e8-e8cf-11d3-9764-00c04f186933" t="r" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MorphType><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MoStemAllomorph><br/>&nbsp;&nbsp;&lt;/LexemeForm><br/>&nbsp;&nbsp;&lt;MorphoSyntaxAnalyses><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;MoStemMsa guid="f63e03f0-ac9d-4b1b-980f-316bbb741f70" /><br/>&nbsp;&nbsp;&lt;/MorphoSyntaxAnalyses><br/>&nbsp;&nbsp;&lt;Senses><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;ownseq class="LexSense" guid="dad069de-dfad-45f6-a5d2-449265adbc3a"><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Gloss><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;AUni ws="en">door&lt;/AUni><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/Gloss><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MorphoSyntaxAnalysis><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;objsur guid="f63e03f0-ac9d-4b1b-980f-316bbb741f70" t="r" /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/MorphoSyntaxAnalysis><br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ownseq><br/>&nbsp;&nbsp;&lt;/Senses><br/>&lt;/LexEntry></div><div class='mergechoice'>The merger kept the change made by user57</div></body>' contextPath='silfw://localhost/link?app=flex&database=current&server=&tool=default&guid=bab7776e-531b-4ce1-997f-fa638c09e381&tag=&label=Entry "pintu"' contextDataLabel='Entry "pintu"'> <MergeSituation alphaUserId='user57' betaUserId='user57@tpad2' alphaUserRevision='306520fcc148' betaUserRevision='5aa248710fbc' path='Linguistics\Lexicon\Lexicon.lexdb' conflictHandlingMode='WeWin' /> </conflict>]]></message> <message author='user57' status='closed' date='2012-07-20T22:49:03Z' guid='bf43783e-eca1-4b0f-bacd-6fe168d7d616'></message> <message author='user57' status='closed' date='2012-07-20T23:11:27Z' guid='a0481907-3fff-45a2-bb1c-961c3198c86a'></message> </annotation> </notes>"; File.WriteAllText(theirs.Path, theirData); // Do it the new way. _chorusNotesFileHandler.Do3WayMerge(new MergeOrder(ours.Path, common.Path, theirs.Path, new NullMergeSituation())); var newWayResult = File.ReadAllText(ours.Path); CheckResults(false, ourData, newWayResult); // Do it the old way via XmlMerge. var mergeSit = new MergeSituation(ours.Path, "Me", "8", "You", "9", MergeOrder.ConflictHandlingModeChoices.WeWin); var merger = new XmlMerger(mergeSit); var listener = new ListenerForUnitTests(); merger.MergeStrategies.SetStrategy("annotation", ElementStrategy.CreateForKeyedElement("guid", false)); var messageStrategy = ElementStrategy.CreateForKeyedElement("guid", false); messageStrategy.IsImmutable = true; merger.MergeStrategies.SetStrategy("message", messageStrategy); merger.EventListener = listener; var mergeResult = merger.Merge( XmlUtilities.GetDocumentNodeFromRawXml(ourData.Replace("<?xml version='1.0' encoding='utf-8'?>", null).Trim(), new XmlDocument()), XmlUtilities.GetDocumentNodeFromRawXml(theirData.Replace("<?xml version='1.0' encoding='utf-8'?>", null).Trim(), new XmlDocument()), XmlUtilities.GetDocumentNodeFromRawXml(commonData.Replace("<?xml version='1.0' encoding='utf-8'?>", null).Trim(), new XmlDocument())); var oldWayResult = mergeResult.MergedNode.OuterXml; CheckResults(false, ourData, oldWayResult); // Compare old and new results. CheckResults(true, newWayResult, oldWayResult); using (var log = new ChorusNotesMergeEventListener(ours.Path)) { // The purpose here is to make sure that the listener works correctly regarding maintaining CData. // I (RandyR) saw a merged data set where the CData material was not maintained. } var result = File.ReadAllText(ours.Path); CheckResults(true, newWayResult, result); var doc = new XmlDocument(); doc.Load(ours.Path); // This is how the AnnotationRepository class writes out an updated ChorusNotes file. using (var writer = XmlWriter.Create(ours.Path, CanonicalXmlSettings.CreateXmlWriterSettings())) { doc.Save(writer); } CheckResults(true, result, File.ReadAllText(ours.Path)); } }
public void FileOutput_WithContent_UsesCanonicalXmlSettings() { string expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + "<notes\r\n" + "\tversion=\"0\">\r\n" + "\t<annotation>Dummy</annotation>\r\n" + "</notes>"; using (var logFile = TempFile.CreateAndGetPathButDontMakeTheFile()) { using (var log = new ChorusNotesMergeEventListener(logFile.Path)) { log.ConflictOccurred(new DummyConflict()); } string result = File.ReadAllText(logFile.Path); Assert.AreEqual(expected, result); } }
public void FileDidNotExist_NoConflicts_DoesNotCreatesEmptyNotesFile() { var tempFile = Path.GetTempFileName(); File.Delete(tempFile); using (ChorusNotesMergeEventListener log = new ChorusNotesMergeEventListener(tempFile)) { } Assert.IsFalse(File.Exists(tempFile)); }
public void FileDidNotExist_CreatesCorrectFile() { using (TempFile logFile = TempFile.CreateAndGetPathButDontMakeTheFile()) { using (ChorusNotesMergeEventListener log = new ChorusNotesMergeEventListener(logFile.Path)) { log.ConflictOccurred(new DummyConflict()); log.ConflictOccurred(new DummyConflict()); } XmlDocument doc = new XmlDocument(); doc.Load(logFile.Path); Assert.AreEqual(2, doc.SelectNodes("notes/annotation").Count); } }
/// <summary> /// This method will detect changed vs deleted file conflicts in the output coming from mercurial. /// It produces a conflict for that situation and tells mercurial to keep the changed file. /// <note>The default response for mercurial is to keep the changed, but on some user systems (Windows 8?) /// mercurial will pause waiting for input instead of using the default answer.</note> /// </summary> private bool HandleChangedVsDeletedFiles(string line, StreamWriter standardInput) { // The two situations we are dealing with are: // // local changed [filename] which remote deleted // use (c)hanged version or (d)elete? // and // remote changed [filename] which local deleted // use (c)hanged version or leave (d)eleted? string changedVsDeletedFile = null; var match = Regex.Match(line, @"local changed (.*) which remote deleted"); if(match.Captures.Count > 0) { changedVsDeletedFile = match.Groups[1].Value; } else { match = Regex.Match(line, @"remote changed (.*) which local deleted"); if(match.Captures.Count > 0) { changedVsDeletedFile = match.Groups[1].Value; } } if(changedVsDeletedFile != null) { var conflictPath = Path.Combine(_rootDirectory, changedVsDeletedFile); var conflictReport = new FileChangedVsFileDeletedConflict(conflictPath); using(var chorusNoteCreator = new ChorusNotesMergeEventListener(ChorusNotesMergeEventListener.GetChorusNotesFilePath(conflictPath))) { chorusNoteCreator.ConflictOccurred(conflictReport); } return true; } // Send hg the response it might be waiting for: if(line.Contains(@"(c)hanged") && line.Contains(@"(d)elete")) { standardInput.WriteLine('c'); return true; } // This input line was not related to a Changed vs Deleted File situation return false; }