public Synchronizer(ILogger logger, ISourceRepository sourceRepository, ITargetRepository targetRepository, IMergeStrategy mergeStrategy) { _logger = logger; _sourceRepository = sourceRepository; _targetRepository = targetRepository; _mergeStrategy = mergeStrategy; }
public void GetItemsDelegatesToTheStrategy() { MergedDataSet dataSet = new MergedDataSet(); IDataSet provider = Mocks.Stub <IDataSet>(); dataSet.AddDataSet(provider); IMergeStrategy strategy = Mocks.StrictMock <IMergeStrategy>(); dataSet.Strategy = strategy; IEnumerable <IDataItem> results = Mocks.Stub <IEnumerable <IDataItem> >(); DataBinding[] bindings = new DataBinding[0]; using (Mocks.Record()) { Expect.Call(strategy.Merge(null, null, false)).IgnoreArguments().Do((MergeDelegate) delegate(IList <IDataProvider> mergeProviders, ICollection <DataBinding> mergeBindings, bool includeDynamicItems) { Assert.IsTrue(includeDynamicItems); Assert.AreElementsEqual(new IDataProvider[] { provider }, mergeProviders); Assert.AreSame(bindings, mergeBindings); return(results); }); } using (Mocks.Playback()) { Assert.AreSame(results, dataSet.GetItems(bindings, true)); } }
/// <summary> /// Merges a collection of view models with a list of models /// </summary> public static void MergeCollection <TViewModel, TModel>( this ICollection <TViewModel> collection, IReadOnlyList <TModel> updated, IMergeStrategy <TModel, TViewModel> strategy) where TViewModel : IIdentifiableObject where TModel : IIdentifiableObject { // Remove those without id or not existing in the updated collection var removed = collection.Where(r => r.Id == 0 || updated.All(u => u.Id != r.Id)).ToList(); foreach (var obj in removed) { collection.Remove(obj); } foreach (var updatedModel in updated) { var match = collection.FirstOrDefault(r => r.Id == updatedModel.Id); if (match != null) { strategy.UpdateModel(match, updatedModel); } else { var vm = strategy.FromModel(updatedModel); collection.Add(vm); } } }
/// <summary> /// Used by tests (and public constructor), which prefer to give us raw contents rather than paths /// </summary> internal LiftMerger(string alphaLiftContents, string betaLiftContents, string ancestorLiftContents, IMergeStrategy mergeStrategy) { _alphaLift = alphaLiftContents; _betaLift = betaLiftContents; _ancestorLift = ancestorLiftContents; _mergingStrategy = mergeStrategy; }
public void RenderToFileHelper <T>(string filePath, IMergeStrategy strategy) where T : EntityCodeTemplate, new() { var template = this.Create <T>(); CopyPropertiesTo(template, true, PropertyIgnoreList); template.RenderToFile(filePath, strategy); }
public MergeActivity(string name, IMergeStrategy strategy) : base(name) { if (strategy == null) { throw new ArgumentNullException(nameof(strategy)); } Strategy = strategy; }
public GitignoreGetCommandHandler(IGitignoreService gitignoreService, IConcatedNamesProcessor concatedNamesProcessor, IMergeStrategy mergeStrategy, IGitignoreFileWriter gitignoreFileWriter) { _gitignoreService = gitignoreService ?? throw new ArgumentNullException(nameof(gitignoreService)); _concatedNamesProcessor = concatedNamesProcessor ?? throw new ArgumentNullException(nameof(concatedNamesProcessor)); _mergeStrategy = mergeStrategy ?? throw new ArgumentNullException(nameof(mergeStrategy)); _gitignoreFileWriter = gitignoreFileWriter ?? throw new ArgumentNullException(nameof(gitignoreFileWriter)); }
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 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; }
/// <summary> /// Merge a recursive model structure into an existing observable view model structure /// </summary> public static void MergeTree <TModel>( this Collection <TreeItemViewModel> current, IReadOnlyList <TModel> updated, IMergeStrategy <TModel, TreeItemViewModel> strategy) where TModel : class, ITreeItemModel <TModel> { // Use 'for'-loop, because it is modification tolerant int currentIndex = 0, updatedIndex = 0; while (currentIndex < current.Count || updatedIndex < updated.Count) { var currentItem = GetItem(current, currentIndex); var updatedItem = GetItem(updated, updatedIndex); // Default: Update the model if it matches if (currentItem != null && currentItem.Id == updatedItem?.Id) { strategy.UpdateModel(currentItem, updatedItem); currentIndex++; updatedIndex++; MergeTree(currentItem.Children, updatedItem.Children, strategy); } // Item was appended or inserted else if (currentItem == null || HasId(updated, currentItem.Id, updatedIndex)) { currentItem = strategy.FromModel(updatedItem); current.Insert(currentIndex, currentItem); currentIndex++; updatedIndex++; MergeTree(currentItem.Children, updatedItem.Children, strategy); } // In any other case: Remove else { current.RemoveAt(currentIndex); updatedIndex++; } } }
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 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 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); }
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; }
public static IWorkflowBuilder Merge(this IWorkflowBuilder builder, string name, IMergeStrategy strategy) { return(builder.Activity(activity => activity.Merge(name, strategy))); }
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); }
public object Merge(IMergeStrategy strategy) { return(strategy.Merge(Value)); }
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 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 Lift2WayDiffer(IMergeStrategy mergeStrategy, string parentXml, string childXml, IMergeEventListener listener, FileInRevision parentFileInRevision, FileInRevision childFileInRevision) : this(mergeStrategy, parentXml, childXml, listener) { _parentFileInRevision = parentFileInRevision; _childFileInRevision = childFileInRevision; }
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)); }
public static void BuildSubTemplate(CodeTemplate parent, CodeTemplate template, IMergeStrategy strategy, string pathAndFile, string outputDir) { // instantiate the sub-template parent.Response.WriteLine(string.Format("Begin Build SubTemplate for file {0}...",Path.GetFileName(pathAndFile))); // Set up the DL project parent.CopyPropertiesTo(template); //Render the file if(strategy == null) template.RenderToFile(Path.Combine(outputDir,pathAndFile), true); else template.RenderToFile(Path.Combine(outputDir,pathAndFile), strategy); parent.Response.WriteLine(string.Format("Build of {0} Complete.",Path.GetFileName(pathAndFile))); }
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); } }
/// <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 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); } }
public async Task MergeFromMetaDataAsync(IFullAlbumDescriptor iad, IMergeStrategy Strategy) { await Task.Run( () => MergeFromMetaData(iad, Strategy)); }
/// <summary> /// Here, "alpha" is the guy who wins when there's no better way to decide, and "beta" is the loser. /// </summary> public LiftMerger(IMergeStrategy mergeStrategy, string alphaLiftPath, string betaLiftPath, string ancestorLiftPath) : this(File.ReadAllText(alphaLiftPath), File.ReadAllText(betaLiftPath), File.ReadAllText(ancestorLiftPath), mergeStrategy) { }
public static IActivityFactorableBuilder Merge(this IActivityBuilder builder, string name, IMergeStrategy strategy) { return(builder.Proxy(new MergeActivity(name, strategy))); }
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; }
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 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 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; }
public void MergeFromMetaData(IFullAlbumDescriptor iad, IMergeStrategy Strategy) { if (Strategy.AlbumMetaData != IndividualMergeStategy.Never) { if ((Year == 0) || Strategy.AlbumMetaData == IndividualMergeStategy.Always) Year = iad.Year; if (string.IsNullOrEmpty(Name) || Strategy.AlbumMetaData == IndividualMergeStategy.Always) Name = iad.Name; if ((_Artists.MofifiableCollection.Count == 0) || (Strategy.AlbumMetaData == IndividualMergeStategy.Always)) { _Artists.MofifiableCollection.Clear(); _Artists.MofifiableCollection.AddCollection(this._IT.GetArtistFromName(iad.Artist)); } if ((string.IsNullOrEmpty(Genre)) || (Strategy.AlbumMetaData == IndividualMergeStategy.Always)) Genre = iad.Genre; } if ((Strategy.InjectAlbumImage == IndividualMergeStategy.Always) || ((Strategy.InjectAlbumImage == IndividualMergeStategy.IfDummyValue) && Images.Count == 0)) { int i = 0; if (iad.Images != null) { foreach (IIMageInfo Im in iad.Images) { if (AddImage(AlbumImage.GetFromBuffer(_AM, Im.ImageBuffer), i) != null) i++; } } } if (Strategy.TrackMetaData == IndividualMergeStategy.Never) return; //var OrderedTracksInput = (from r in iad.TrackDescriptors orderby r.Duration.TotalMilliseconds ascending select r).ToList(); //var OrderedTracks = (from r in Tracks orderby r.Duration.TotalMilliseconds ascending select r).ToList(); var OrderedTracksInput = iad.TrackDescriptors.OrderBy(r => r.DiscNumber).ThenBy(r=>r.TrackNumber).ToList(); var OrderedTracks = Tracks.OrderBy(r => r.DiscNumber).ThenBy(r=>r.TrackNumber).ToList(); if (OrderedTracksInput.Count != OrderedTracks.Count) return; int j = 0; foreach (IModifiableTrack INT in OrderedTracks) { ITrackMetaDataDescriptor Tr = OrderedTracksInput[j++]; if ((Strategy.TrackMetaData == IndividualMergeStategy.Always) || (new StringTrackParser(INT.Name, false).IsDummy)) INT.Name = Tr.Name; if ((Strategy.TrackMetaData == IndividualMergeStategy.Always) || string.IsNullOrEmpty(INT.Artist)) INT.Artist = Tr.Artist; if ((Strategy.TrackMetaData == IndividualMergeStategy.Always) || (INT.TrackNumber == 0)) INT.TrackNumber = Tr.TrackNumber; TimeSpan delta = (Tr.Duration - INT.Duration); Trace.WriteLine(delta); } }
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; }