public XmlNode Merge(IMergeEventListener eventListener, XmlNode ourParent, XmlNode ours, XmlNode theirs, XmlNode ancestor) { SendMergeHeartbeat(); EventListener = eventListener; MergeInner(ourParent, ref ours, theirs, ancestor); return(ours); }
/// <summary> /// Create instance of Xml2WayDiffer /// </summary> public static Xml2WayDiffer CreateFromMixed(Dictionary <string, byte[]> parentIndex, string childPathname, IMergeEventListener eventListener, string firstElementMarker, string startTag, string identfierAttribute) { return(new Xml2WayDiffer(eventListener, parentIndex, childPathname, firstElementMarker, startTag, identfierAttribute)); }
/// <summary> /// Create instance of Xml2WayDiffer /// </summary> public static Xml2WayDiffer CreateFromFileInRevision(FileInRevision parent, FileInRevision child, IMergeEventListener eventListener, HgRepository repository, string firstElementMarker, string startTag, string identfierAttribute) { return(new Xml2WayDiffer(repository, eventListener, parent, child, firstElementMarker, startTag, identfierAttribute)); }
internal static void PreMergeStTxtPara(IMergeEventListener listener, ref XmlNode ours, XmlNode theirs, XmlNode ancestor) { if (!AnyChanges(ours, theirs, ancestor)) return; MakeParseIsCurrentFalse(ours); MakeParseIsCurrentFalse(theirs); MakeParseIsCurrentFalse(ancestor); }
/// <summary> /// Create instance of Xml2WayDiffer /// </summary> public static Xml2WayDiffer CreateFromFiles(string parentPathname, string childPathname, IMergeEventListener eventListener, string firstElementMarker, string startTag, string identfierAttribute) { return(new Xml2WayDiffer(eventListener, parentPathname, childPathname, firstElementMarker, startTag, identfierAttribute)); }
public void Premerge(IMergeEventListener listener, ref XmlNode ours, XmlNode theirs, XmlNode ancestor) { var keyElt = ours ?? theirs ?? ancestor; if (keyElt == null) return; var className = XmlUtilities.GetStringAttribute(keyElt, "class"); if (className == "StTxtPara" || className == "ScrTxtPara") { StTxtParaPremerger.PreMergeStTxtPara(listener, ref ours, theirs, ancestor); } }
private Lift2WayDiffer(IMergeStrategy mergeStrategy, string parentXml, string childXml,IMergeEventListener eventListener) { _childDom = new XmlDocument(); _parentDom = new XmlDocument(); _childDom.LoadXml(childXml); _parentDom.LoadXml(parentXml); _parentIdToNodeIndex = new Dictionary<string, XmlNode>(); EventListener = eventListener; }
public MergeOrder(string pathToOurs, string pathToCommon, string pathToTheirs, MergeSituation situation) { this.pathToOurs = pathToOurs; this.pathToTheirs = pathToTheirs; MergeSituation = situation; pathToCommonAncestor = pathToCommon; // ConflictHandlingMode = mode; EventListener = new NullMergeEventListener(); //client can put something useful in if it needs one }
internal static void PreMergeStTxtPara(IMergeEventListener listener, ref XmlNode ours, XmlNode theirs, XmlNode ancestor) { if (!AnyChanges(ours, theirs, ancestor)) { return; } MakeParseIsCurrentFalse(ours); MakeParseIsCurrentFalse(theirs); MakeParseIsCurrentFalse(ancestor); }
public void Premerge(IMergeEventListener listener, ref XmlNode ourDateTimeNode, XmlNode theirDateTimeNode, XmlNode ancestorDateTimeNode) { RestoreOriginalIfTimestampIsTheOnlyChange(ancestorDateTimeNode, ourDateTimeNode); RestoreOriginalIfTimestampIsTheOnlyChange(ancestorDateTimeNode, theirDateTimeNode); var newest = DateTime.MinValue.ToString(CultureInfo.InvariantCulture); newest = GetMostRecentVal(newest, ourDateTimeNode); newest = GetMostRecentVal(newest, theirDateTimeNode); UpdateDateTimeVal(newest, ourDateTimeNode); UpdateDateTimeVal(newest, theirDateTimeNode); }
private Lift2WayDiffer(IMergeStrategy mergeStrategy, string parentXml, string childXml, IMergeEventListener eventListener) { _childDom = new XmlDocument(); _parentDom = new XmlDocument(); _childDom.LoadXml(childXml); _parentDom.LoadXml(parentXml); _parentIdToNodeIndex = new Dictionary <string, XmlNode>(); EventListener = eventListener; }
private static void ProcessEntries(XmlWriter writer, IMergeEventListener eventListener, IMergeStrategy mergingStrategy, XmlNode ancestorDom, HashSet <string> processedIds, XmlNode sourceDom, string sourceLabel, string sourcePath, IDictionary <string, XmlNode> otherIdNodeIndex, string otherLabel, string otherPath) { foreach (XmlNode sourceEntry in sourceDom.SafeSelectNodes("lift/entry")) { ProcessEntry(writer, eventListener, mergingStrategy, ancestorDom, processedIds, sourceEntry, sourceLabel, sourcePath, otherIdNodeIndex, otherLabel, otherPath); } }
private Xml2WayDiffer(IMergeEventListener eventListener, Dictionary<string, byte[]> parentIndex, string childPathname, string firstElementMarker, string startTag, string identfierAttribute) { _diffingMode = DiffingMode.FromMixed; _parentIndex = parentIndex; _childPathname = childPathname; if (!string.IsNullOrEmpty(firstElementMarker)) _firstElementTag = firstElementMarker.Trim(); _startTag = "<" + startTag.Trim(); _identfierAttribute = identfierAttribute; _eventListener = eventListener; }
private Xml2WayDiffer(IMergeEventListener eventListener, string parentPathname, string childPathname, string firstElementMarker, string startTag, string identfierAttribute) { _diffingMode = DiffingMode.FromPathnames; _parentPathname = parentPathname; _childPathname = childPathname; if (!string.IsNullOrEmpty(firstElementMarker)) _firstElementTag = firstElementMarker.Trim(); _startTag = "<" + startTag.Trim(); _identfierAttribute = identfierAttribute; _eventListener = eventListener; }
/// <summary> /// Produce a string that represents the 3-way merger of the given three elements. /// </summary> public string MakeMergedEntry(IMergeEventListener listener, XmlNode ourEntry, XmlNode theirEntry, XmlNode unusedCommonEntry) { XmlNode mergeNoteFieldNode = ourEntry.OwnerDocument.CreateElement("field"); XmlUtilities.AddAttribute(mergeNoteFieldNode, "type", Conflict.ConflictAnnotationClassName); XmlUtilities.AddDateCreatedAttribute(mergeNoteFieldNode); StringBuilder b = new StringBuilder(); b.Append("<trait name='looserData'>"); b.AppendFormat("<![CDATA[{0}]]>", theirEntry.OuterXml); b.Append("</trait>"); mergeNoteFieldNode.InnerXml = b.ToString(); ourEntry.AppendChild(mergeNoteFieldNode); return ourEntry.OuterXml; }
private Xml2WayDiffer(HgRepository repository, IMergeEventListener eventListener, FileInRevision parent, FileInRevision child, string firstElementMarker, string startTag, string identfierAttribute) { _diffingMode = DiffingMode.FromFileInRevisions; _repository = repository; _parentFileInRevision = parent; _childFileInRevision = child; if (!string.IsNullOrEmpty(firstElementMarker)) _firstElementTag = firstElementMarker.Trim(); _startTag = "<" + startTag.Trim(); _identfierAttribute = identfierAttribute; _eventListener = eventListener; }
private static XmlNode DoMerge( string ancestorXml, string ourXml, string theirXml, MergeSituation mergeSituation, IMergeEventListener listener, out XmlNode ours, out XmlNode theirs) { var merger = new XmlMerger(mergeSituation) { EventListener = listener }; XmlNode ancestor; XmlNode ourParent; XmlTestHelper.CreateThreeNodes(ourXml, theirXml, ancestorXml, out ours, out ourParent, out theirs, out ancestor); ImmutableElementMergeService.DoMerge(merger, ourParent, ref ours, theirs, ancestor); return(ours); }
public void Premerge(IMergeEventListener listener, ref XmlNode ours, XmlNode theirs, XmlNode ancestor) { var keyElt = ours ?? theirs ?? ancestor; if (keyElt == null) { return; } var className = XmlUtilities.GetStringAttribute(keyElt, "class"); if (className == "StTxtPara" || className == "ScrTxtPara") { StTxtParaPremerger.PreMergeStTxtPara(listener, ref ours, theirs, ancestor); } }
/// <summary> /// Add conflict. If RecordContextInConflict fails to set a context, and nodeToFindGeneratorFrom is non-null, /// attempt to add a context based on the argument. /// </summary> public static void AddConflictToListener(IMergeEventListener listener, IConflict conflict, XmlNode oursContext, XmlNode theirsContext, XmlNode ancestorContext, IGenerateHtmlContext htmlContextGenerator, XmlMerger merger, XmlNode nodeToFindGeneratorFrom) { // NB: All these steps are crucially ordered. listener.RecordContextInConflict(conflict); if ((conflict.Context == null || conflict.Context is NullContextDescriptor) && nodeToFindGeneratorFrom != null) { // We are too far up the stack for the listener to have been told a context. // Make one out of the current node. conflict.Context = merger.GetContext(nodeToFindGeneratorFrom); } conflict.MakeHtmlDetails(oursContext, theirsContext, ancestorContext, htmlContextGenerator); listener.ConflictOccurred(conflict); }
private Xml2WayDiffer(IMergeEventListener eventListener, string parentPathname, string childPathname, string firstElementMarker, string startTag, string identfierAttribute) { _diffingMode = DiffingMode.FromPathnames; _parentPathname = parentPathname; _childPathname = childPathname; if (!string.IsNullOrEmpty(firstElementMarker)) { _firstElementTag = firstElementMarker.Trim(); } _startTag = "<" + startTag.Trim(); _identfierAttribute = identfierAttribute; _eventListener = eventListener; }
/// <summary> /// Produce a string that represents the 3-way merger of the given three elements. /// </summary> public string MakeMergedEntry(IMergeEventListener listener, XmlNode ourEntry, XmlNode theirEntry, XmlNode unusedCommonEntry) { XmlNode mergeNoteFieldNode = ourEntry.OwnerDocument.CreateElement("field"); XmlUtilities.AddAttribute(mergeNoteFieldNode, "type", Conflict.ConflictAnnotationClassName); XmlUtilities.AddDateCreatedAttribute(mergeNoteFieldNode); StringBuilder b = new StringBuilder(); b.Append("<trait name='looserData'>"); b.AppendFormat("<![CDATA[{0}]]>", theirEntry.OuterXml); b.Append("</trait>"); mergeNoteFieldNode.InnerXml = b.ToString(); ourEntry.AppendChild(mergeNoteFieldNode); return(ourEntry.OuterXml); }
private static XmlNode DoMerge( string ancestorXml, string ourXml, string theirXml, MergeSituation mergeSituation, IMergeEventListener listener, out XmlNode ours, out XmlNode theirs) { var merger = new XmlMerger(mergeSituation) { EventListener = listener }; ours = CreateNode(ourXml); theirs = CreateNode(theirXml); var ancestorNode = CreateNode(ancestorXml); ImmutableElementMergeService.DoMerge(merger, ref ours, theirs, ancestorNode); return(ours); }
private Xml2WayDiffer(HgRepository repository, IMergeEventListener eventListener, FileInRevision parent, FileInRevision child, string firstElementMarker, string startTag, string identfierAttribute) { _diffingMode = DiffingMode.FromFileInRevisions; _repository = repository; _parentFileInRevision = parent; _childFileInRevision = child; if (!string.IsNullOrEmpty(firstElementMarker)) { _firstElementTag = firstElementMarker.Trim(); } _startTag = "<" + startTag.Trim(); _identfierAttribute = identfierAttribute; _eventListener = eventListener; }
/// <summary> /// Report the differences between two versions of files in the repository. /// </summary> /// <returns>Zero or more change reports.</returns> public static IEnumerable<IChangeReport> ReportDifferences( string parentPathname, string childPathname, IMergeEventListener listener, string firstElementMarker, string recordMarker, string identfierAttribute) { var changeAndConflictAccumulator = listener ?? new ChangeAndConflictAccumulator(); var differ = Xml2WayDiffer.CreateFromFiles( parentPathname, childPathname, changeAndConflictAccumulator, firstElementMarker, recordMarker, identfierAttribute); differ.ReportDifferencesToListener(); return changeAndConflictAccumulator is ChangeAndConflictAccumulator ? ((ChangeAndConflictAccumulator) changeAndConflictAccumulator).Changes : null; // unit tests use impl class that has no "Changes" property. }
/// <summary> /// Report the differences between two versions of files in the repository. /// </summary> /// <returns>Zero or more change reports.</returns> public static IEnumerable <IChangeReport> ReportDifferences( string parentPathname, string childPathname, IMergeEventListener listener, string firstElementMarker, string recordMarker, string identfierAttribute) { var changeAndConflictAccumulator = listener ?? new ChangeAndConflictAccumulator(); var differ = Xml2WayDiffer.CreateFromFiles( parentPathname, childPathname, changeAndConflictAccumulator, firstElementMarker, recordMarker, identfierAttribute); differ.ReportDifferencesToListener(); return(changeAndConflictAccumulator is ChangeAndConflictAccumulator ? ((ChangeAndConflictAccumulator)changeAndConflictAccumulator).Changes : null); // unit tests use impl class that has no "Changes" property. }
public void Premerge(IMergeEventListener listener, ref XmlNode ours, XmlNode theirs, XmlNode ancestor) { PreMergeStTxtPara(listener, ref ours, theirs, ancestor); }
/// <summary> /// Add conflict. /// </summary> public static void AddConflictToListener(IMergeEventListener listener, IConflict conflict, XmlNode oursContext, XmlNode theirsContext, XmlNode ancestorContext, IGenerateHtmlContext htmlContextGenerator) { AddConflictToListener(listener, conflict, oursContext, theirsContext, ancestorContext, htmlContextGenerator, null, null); }
public static Lift2WayDiffer CreateFromStrings(IMergeStrategy mergeStrategy, string parentXml, string childXml, IMergeEventListener eventListener) { return new Lift2WayDiffer(mergeStrategy, parentXml, childXml, eventListener); }
private Lift2WayDiffer(IMergeStrategy mergeStrategy, string parentXml, string childXml , IMergeEventListener listener, FileInRevision parentFileInRevision, FileInRevision childFileInRevision) : this(mergeStrategy,parentXml, childXml, listener) { _parentFileInRevision = parentFileInRevision; _childFileInRevision = childFileInRevision; }
/// <summary> /// Produce a string that represents the 3-way merger of the given three elements. /// </summary> public string MakeMergedEntry(IMergeEventListener eventListener, XmlNode ourEntry, XmlNode theirEntry, XmlNode commonEntry) { return(_returnOurs ? (ourEntry == null ? null : ourEntry.OuterXml) : (theirEntry == null ? null : theirEntry.OuterXml)); }
/// <summary> /// <para>Before we attempt to compare a node with a corresponding one from another revision, /// we want to make sure that it is in a good state for matching its children with the children of the corresponding node.</para> /// /// <para>To do this, for each child, we allow the Finder which will be used to find a corresponding child in /// another revision to provide a query, which can be used to check whether the parent node has 'ambiguous' children, /// that is, groups of children which the finder would consider indistinguisable.</para> /// </summary> /// <remarks> /// This is recursive, since it moves on down to all child nodes. /// </remarks> public static string RemoveAmbiguousChildren(IMergeEventListener eventListener, MergeStrategies mergeStrategies, string parent, string pathname) { if (!RemoveAmbiguousChildNodes) return parent; if (pathname.ToLowerInvariant().EndsWith("lift") || pathname.ToLowerInvariant().EndsWith("lift-ranges")) { parent = LiftSorter.FixBadTextElements(parent).ToString(); } var parentNode = XmlUtilities.GetDocumentNodeFromRawXml(parent, new XmlDocument()); RemoveAmbiguousChildren( eventListener, mergeStrategies, parentNode); return parentNode.OuterXml; }
public void Premerge(IMergeEventListener listener, ref XmlNode ours, XmlNode theirs, XmlNode ancestor) { /* Do nothing at all. */ }
/// <summary> /// Add warning. /// </summary> public static void AddWarningToListener(IMergeEventListener listener, IConflict warning, XmlNode oursContext, XmlNode theirsContext, XmlNode ancestorContext) { AddWarningToListener(listener, warning, oursContext, theirsContext, ancestorContext, new SimpleHtmlGenerator()); }
/// <summary> /// Add warning. /// </summary> public static void AddWarningToListener(IMergeEventListener listener, IConflict warning, XmlNode oursContext, XmlNode theirsContext, XmlNode ancestorContext, IGenerateHtmlContext htmlContextGenerator) { // NB: All three of these are crucially ordered. listener.RecordContextInConflict(warning); warning.MakeHtmlDetails(oursContext, theirsContext, ancestorContext, htmlContextGenerator); listener.WarningOccurred(warning); }
/// <summary> /// Add warning. /// </summary> public static void AddWarningToListener(IMergeEventListener listener, IConflict warning) { AddWarningToListener(listener, warning, null, null, null); }
public static Lift2WayDiffer CreateFromFileInRevision(IMergeStrategy mergeStrategy, FileInRevision parent, FileInRevision child, IMergeEventListener eventListener, HgRepository repository) { return(new Lift2WayDiffer(mergeStrategy, parent.GetFileContents(repository), child.GetFileContents(repository), eventListener, parent, child)); }
/// <summary> /// <para>Before we attempt to compare a node with a corresponding one from another revision, /// we want to make sure that it is in a good state for matching its children with the children of the corresponding node.</para> /// /// <para>To do this, for each child, we allow the Finder which will be used to find a corresponding child in /// another revision to provide a query, which can be used to check whether the parent node has 'ambiguous' children, /// that is, groups of children which the finder would consider indistinguisable.</para> /// </summary> /// <remarks> /// This is recursive, since it moves on down to all child nodes. /// </remarks> public static void RemoveAmbiguousChildren(IMergeEventListener eventListener, MergeStrategies mergeStrategies, XmlNode parent) { if (parent == null || !parent.HasChildNodes || !RemoveAmbiguousChildNodes) return; var elementStrat = mergeStrategies.GetElementStrategy(parent); if (elementStrat.IsImmutable) return; var ambiguousNodes = new List<XmlNode>(); var copyOfChildNodes = new List<XmlNode>(parent.ChildNodes.Count); copyOfChildNodes.AddRange(parent.ChildNodes.Cast<XmlNode>()); foreach (var childNode in copyOfChildNodes) { var childNodeAsVariable = childNode; if (ambiguousNodes.Contains(childNodeAsVariable)) continue; // Already found it, so don't bother processing it again. elementStrat = mergeStrategies.GetElementStrategy(childNodeAsVariable); if (elementStrat.IsImmutable) continue; var finder = elementStrat.MergePartnerFinder; if (!(finder is IFindMatchingNodesToMerge)) continue; var finderOfMultiples = (IFindMatchingNodesToMerge) finder; var matches = finderOfMultiples.GetMatchingNodes(childNodeAsVariable, parent).ToList(); if (matches.Count < 2) continue; // No duplicates were found, so keep going. // The following code implements the "DropAmbiguitiesAndAddErrorNote" option of a possible three in "AmbiguousSiblingPolicy" // TODO (maybe): If we ever implement the "ThrowException" option, then throw here instead of adding the warning and eating the ambiguities. // TODO (maybe): If we ever implement the "LiveWithIt" option, then just do a return at the start of this method, or don't bother calling the method at all. // Since they are ambiguities (at least as far as the finder is concerned), // we really only need one warning. Add the count, so the user knows how many there were, though. // Possible enhancement: Generate reports that go into the details of what might be different between the keeper and each ambiguous sibling. AddWarningToListener(eventListener, new MergeWarning(string.Format("Parent element '{0}' contains {1} ambiguous child elements. Only the first one is retained. Details: {2}.", parent.Name, matches.Count, finderOfMultiples.GetWarningMessageForAmbiguousNodes(matches[0])))); // Add all but the current one (the first one), so they can be removed in the next loop. ambiguousNodes.AddRange(matches.Where(match => match != childNodeAsVariable)); } foreach (var ambiguousNode in ambiguousNodes) { // Remove all but the first one from the parent. parent.RemoveChild(ambiguousNode); } foreach (XmlNode childNode in parent.ChildNodes) { // Drill on down the child nodes to see if there are any other ambiguities in lower-level nodes. // Since the ambiguous nodes have been removed from parent, they won't get processed again. RemoveAmbiguousChildren(eventListener, mergeStrategies, childNode); } }
public string MakeMergedEntry(IMergeEventListener listener, XmlNode ourEntry, XmlNode theirEntry, XmlNode commonEntry) { return _entryMerger.Merge(listener, ourEntry, theirEntry, commonEntry).OuterXml; }
/// <summary> /// Produce a string that represents the 3-way merger of the given three elements. /// </summary> public string MakeMergedEntry(IMergeEventListener eventListener, XmlNode ourEntry, XmlNode theirEntry, XmlNode commonEntry) { return _annotationMerger.Merge(eventListener, ourEntry, theirEntry, commonEntry).OuterXml; }
/// <summary> /// Produce a string that represents the 3-way merger of the given three elements. /// </summary> public string MakeMergedEntry(IMergeEventListener listener, XmlNode ourEntry, XmlNode theirEntry, XmlNode unusedCommonEntry) { return(ourEntry.OuterXml); }
public string MakeMergedEntry(IMergeEventListener listener, XmlNode ourEntry, XmlNode theirEntry, XmlNode commonEntry) { return(_entryMerger.Merge(listener, ourEntry.ParentNode, ourEntry, theirEntry, commonEntry).OuterXml); }
/// <summary> /// Produce a string that represents the 3-way merger of the given three elements. /// </summary> public string MakeMergedEntry(IMergeEventListener listener, XmlNode ourEntry, XmlNode theirEntry, XmlNode unusedCommonEntry) { return ourEntry.OuterXml; }
private static void ProcessEntry(XmlWriter writer, IMergeEventListener eventListener, IMergeStrategy mergingStrategy, XmlNode ancestorDom, HashSet <string> processedIds, XmlNode sourceEntry, string sourceLabel, string sourcePath, IDictionary <string, XmlNode> otherIdNodeIndex, string otherLabel, string otherPath) { var id = LiftUtils.GetId(sourceEntry); if (processedIds.Contains(id)) { return; // Already handled the id. } XmlNode otherEntry; var commonEntry = FindEntry(ancestorDom, id); if (!otherIdNodeIndex.TryGetValue(id, out otherEntry)) { // It is in source, but not in target, so it clearly has been deleted by target (new style deletion). if (LiftUtils.GetIsMarkedAsDeleted(sourceEntry)) { if (!LiftUtils.GetIsMarkedAsDeleted(commonEntry)) { // source and target both deleted but in different ways, so make deletion change report. // There is no need to write anything. eventListener.ChangeOccurred(new XmlDeletionChangeReport(sourcePath, commonEntry, sourceEntry)); } //else //{ // // Make it go away without fanfare by doing nothing to writer, since target actually removed the dead entry. //} processedIds.Add(id); return; } if (commonEntry == null) { // source added it eventListener.ChangeOccurred(new XmlAdditionChangeReport(sourcePath, sourceEntry)); writer.WriteNode(sourceEntry.CreateNavigator(), false); } else { if (AreTheSame(sourceEntry, commonEntry)) { // target's deletion wins with a plain vanilla deletion report. eventListener.ChangeOccurred(new XmlDeletionChangeReport(sourcePath, commonEntry, otherEntry)); } else { // source wins over target's new style deletion on the least loss priciple. // Add an edit vs remove conflict report. eventListener.ConflictOccurred(new RemovedVsEditedElementConflict("entry", sourceEntry, otherEntry, commonEntry, new MergeSituation(sourcePath, sourceLabel, "", otherLabel, "", MergeOrder.ConflictHandlingModeChoices.WeWin), null, sourceLabel)); writer.WriteNode(sourceEntry.CreateNavigator(), false); } processedIds.Add(id); return; } } else if (AreTheSame(sourceEntry, otherEntry)) { //unchanged or both made same change writer.WriteNode(sourceEntry.CreateNavigator(), false); } else if (LiftUtils.GetIsMarkedAsDeleted(otherEntry)) { // source edited, target deleted (old style deletion using dateDeleted attr). eventListener.ConflictOccurred(new RemovedVsEditedElementConflict("entry", sourceEntry, otherEntry, commonEntry, new MergeSituation(sourcePath, sourceLabel, "", otherLabel, "", MergeOrder.ConflictHandlingModeChoices.WeWin), null, sourceLabel)); } else if (LiftUtils.GetIsMarkedAsDeleted(sourceEntry)) { // source deleted (old style), but target edited. // target wins with the least loss principle. // But generate a conflict report. eventListener.ConflictOccurred(new RemovedVsEditedElementConflict("entry", otherEntry, sourceEntry, commonEntry, new MergeSituation(otherPath, otherLabel, "", sourceLabel, "", MergeOrder.ConflictHandlingModeChoices.TheyWin), null, sourceLabel)); writer.WriteNode(otherEntry.CreateNavigator(), false); } else { // One or both of them edited it, so merge the hard way. using (var reader = XmlReader.Create(new StringReader( mergingStrategy.MakeMergedEntry(eventListener, sourceEntry, otherEntry, commonEntry) ))) { writer.WriteNode(reader, false); } } processedIds.Add(id); }
/// <summary> /// Produce a string that represents the 3-way merger of the given three elements. /// </summary> public string MakeMergedEntry(IMergeEventListener eventListener, XmlNode ourEntry, XmlNode theirEntry, XmlNode commonEntry) { return(_merger.Merge(eventListener, ourEntry, theirEntry, commonEntry).OuterXml); }
public void AddEventListener(IMergeEventListener listener) { _listeners.Add(listener); }
public static Lift2WayDiffer CreateFromStrings(IMergeStrategy mergeStrategy, string parentXml, string childXml, IMergeEventListener eventListener) { return(new Lift2WayDiffer(mergeStrategy, parentXml, childXml, eventListener)); }
public static Lift2WayDiffer CreateFromFileInRevision(IMergeStrategy mergeStrategy, FileInRevision parent, FileInRevision child, IMergeEventListener eventListener, HgRepository repository) { return new Lift2WayDiffer(mergeStrategy, parent.GetFileContents(repository), child.GetFileContents(repository), eventListener, parent, child); }
private static XmlNode DoMerge( string ancestorXml, string ourXml, string theirXml, MergeSituation mergeSituation, IMergeEventListener listener, out XmlNode ours, out XmlNode theirs) { var merger = new XmlMerger(mergeSituation) { EventListener = listener }; ours = CreateNode(ourXml); theirs = CreateNode(theirXml); var ancestorNode = CreateNode(ancestorXml); ImmutableElementMergeService.DoMerge(merger, ref ours, theirs, ancestorNode); return ours; }
private static void ProcessEntries(XmlWriter writer, IMergeEventListener eventListener, IMergeStrategy mergingStrategy, XmlNode ancestorDom, HashSet<string> processedIds, XmlNode sourceDom, string sourceLabel, string sourcePath, IDictionary<string, XmlNode> otherIdNodeIndex, string otherLabel, string otherPath) { foreach (XmlNode sourceEntry in sourceDom.SafeSelectNodes("lift/entry")) { ProcessEntry(writer, eventListener, mergingStrategy, ancestorDom, processedIds, sourceEntry, sourceLabel, sourcePath, otherIdNodeIndex, otherLabel, otherPath); } }
/// <summary> /// Add conflict. /// </summary> public static void AddConflictToListener(IMergeEventListener listener, IConflict conflict) { AddConflictToListener(listener, conflict, null, null, null); }
public void Premerge(IMergeEventListener listener, ref XmlNode ours, XmlNode theirs, XmlNode ancestor) { ((XmlElement)ours).SetAttribute("silly", "nonsense"); ((XmlElement)theirs).SetAttribute("silly", "nonsense"); ((XmlElement)ancestor).SetAttribute("silly", "nonsense"); }
private static void ProcessEntry(XmlWriter writer, IMergeEventListener eventListener, IMergeStrategy mergingStrategy, XmlNode ancestorDom, HashSet<string> processedIds, XmlNode sourceEntry, string sourceLabel, string sourcePath, IDictionary<string, XmlNode> otherIdNodeIndex, string otherLabel, string otherPath) { var id = LiftUtils.GetId(sourceEntry); if (processedIds.Contains(id)) return; // Already handled the id. XmlNode otherEntry; var commonEntry = FindEntry(ancestorDom, id); if (!otherIdNodeIndex.TryGetValue(id, out otherEntry)) { // It is in source, but not in target, so it clearly has been deleted by target (new style deletion). if (LiftUtils.GetIsMarkedAsDeleted(sourceEntry)) { if (!LiftUtils.GetIsMarkedAsDeleted(commonEntry)) { // source and target both deleted but in different ways, so make deletion change report. // There is no need to write anything. eventListener.ChangeOccurred(new XmlDeletionChangeReport(sourcePath, commonEntry, sourceEntry)); } //else //{ // // Make it go away without fanfare by doing nothing to writer, since target actually removed the dead entry. //} processedIds.Add(id); return; } if (commonEntry == null) { // source added it eventListener.ChangeOccurred(new XmlAdditionChangeReport(sourcePath, sourceEntry)); writer.WriteNode(sourceEntry.CreateNavigator(), false); } else { if (AreTheSame(sourceEntry, commonEntry)) { // target's deletion wins with a plain vanilla deletion report. eventListener.ChangeOccurred(new XmlDeletionChangeReport(sourcePath, commonEntry, otherEntry)); } else { // source wins over target's new style deletion on the least loss priciple. // Add an edit vs remove conflict report. eventListener.ConflictOccurred(new RemovedVsEditedElementConflict("entry", sourceEntry, otherEntry, commonEntry, new MergeSituation(sourcePath, sourceLabel, "", otherLabel, "", MergeOrder.ConflictHandlingModeChoices.WeWin), null, sourceLabel)); writer.WriteNode(sourceEntry.CreateNavigator(), false); } processedIds.Add(id); return; } } else if (AreTheSame(sourceEntry, otherEntry)) { //unchanged or both made same change writer.WriteNode(sourceEntry.CreateNavigator(), false); } else if (LiftUtils.GetIsMarkedAsDeleted(otherEntry)) { // source edited, target deleted (old style deletion using dateDeleted attr). eventListener.ConflictOccurred(new RemovedVsEditedElementConflict("entry", sourceEntry, otherEntry, commonEntry, new MergeSituation(sourcePath, sourceLabel, "", otherLabel, "", MergeOrder.ConflictHandlingModeChoices.WeWin), null, sourceLabel)); } else if (LiftUtils.GetIsMarkedAsDeleted(sourceEntry)) { // source deleted (old style), but target edited. // target wins with the least loss principle. // But generate a conflict report. eventListener.ConflictOccurred(new RemovedVsEditedElementConflict("entry", otherEntry, sourceEntry, commonEntry, new MergeSituation(otherPath, otherLabel, "", sourceLabel, "", MergeOrder.ConflictHandlingModeChoices.TheyWin), null, sourceLabel)); writer.WriteNode(otherEntry.CreateNavigator(), false); } else { // One or both of them edited it, so merge the hard way. using (var reader = XmlReader.Create(new StringReader( mergingStrategy.MakeMergedEntry(eventListener, sourceEntry, otherEntry, commonEntry) ))) { writer.WriteNode(reader, false); } } processedIds.Add(id); }
private static Dictionary<string, string> MakeRecordDictionary(IMergeEventListener mainMergeEventListener, IMergeStrategy mergeStrategy, string pathname, string firstElementMarker, string recordStartingTag, string identifierAttribute) { var records = new Dictionary<string, string>(EstimatedObjectCount(pathname), StringComparer.InvariantCultureIgnoreCase); using (var fastSplitter = new FastXmlElementSplitter(pathname)) { bool foundOptionalFirstElement; foreach (var record in fastSplitter.GetSecondLevelElementStrings(firstElementMarker, recordStartingTag, out foundOptionalFirstElement)) { if (foundOptionalFirstElement) { var key = firstElementMarker.ToLowerInvariant(); if (records.ContainsKey(key)) { mainMergeEventListener.WarningOccurred( new MergeWarning(string.Format("{0}: There is more than one optional first element '{1}'", pathname, key))); } else { if (RemoveAmbiguousChildNodes) { var possiblyRevisedRecord = RemoveAmbiguousChildren(mainMergeEventListener, mergeStrategy.GetStrategies(), record, pathname); records.Add(key, possiblyRevisedRecord); } else { records.Add(key, record); } } foundOptionalFirstElement = false; } else { var attrValues = XmlUtils.GetAttributes(record, new HashSet<string> {"dateDeleted", identifierAttribute}); // Eat tombstones. if (attrValues["dateDeleted"] != null) continue; var identifier = attrValues[identifierAttribute]; if (string.IsNullOrEmpty(identifierAttribute)) { mainMergeEventListener.WarningOccurred( new MergeWarning(string.Format("{0}: There was no identifier for the record", pathname))); continue; } if (records.ContainsKey(identifier)) { mainMergeEventListener.WarningOccurred( new MergeWarning(string.Format("{0}: There is more than one element with the identifier '{1}'", pathname, identifier))); } else { if (RemoveAmbiguousChildNodes) { var possiblyRevisedRecord = RemoveAmbiguousChildren(mainMergeEventListener, mergeStrategy.GetStrategies(), record, pathname); records.Add(identifier, possiblyRevisedRecord); } else { records.Add(identifier, record); } } } } } return records; }
private Lift2WayDiffer(IMergeStrategy mergeStrategy, string parentXml, string childXml, IMergeEventListener listener, FileInRevision parentFileInRevision, FileInRevision childFileInRevision) : this(mergeStrategy, parentXml, childXml, listener) { _parentFileInRevision = parentFileInRevision; _childFileInRevision = childFileInRevision; }