Example #1
0
        /// <summary>
        /// The merge policy is expecting <c>asset2</c> to be the new base of <c>asset1</c>, and <c>base</c> the current base of <c>asset1</c>. 
        /// In case of conflicts:
        /// <ul>
        /// <li>If there is a type conflict, leave as-is</li>
        /// <li>If there is a <see cref="Diff3ChangeType.Conflict"/>:
        ///     <ul>
        ///      <li>If it is on a member, and both <c>asset1</c> and <c>asset2</c> are not null and changes were done 
        ///      in <c>asset2</c> but not in <c>asset1</c>, select <c>asset2</c> else select <c>asset1</c></li>
        ///      <li>If it is on a list item, we can't resolve it and leave the conflict as-is</li>
        ///      <li>If it is on a array item, we select <c>asset2</c></li>
        ///     </ul>
        /// </li>
        /// </ul>
        /// </summary>
        /// <param name="diff3Node">The diff3 node.</param>
        /// <returns>.</returns>
        public static Diff3ChangeType MergePolicyAsset2AsNewBaseOfAsset1(Diff3Node diff3Node)
        {
            var hasConflicts = diff3Node.ChangeType > Diff3ChangeType.Conflict;
            if (hasConflicts)
            {
                return diff3Node.ChangeType;
            }

            switch (diff3Node.ChangeType)
            {
                case Diff3ChangeType.Conflict:
                case Diff3ChangeType.MergeFromAsset2:

                    var dataNode = diff3Node.Asset2Node ?? diff3Node.Asset1Node ?? diff3Node.BaseNode;

                    if (dataNode is DataVisitMember)
                    {
                        if (diff3Node.Asset1Node != null && diff3Node.Asset2Node != null && diff3Node.ChangeType == Diff3ChangeType.MergeFromAsset2)
                        {
                            return Diff3ChangeType.MergeFromAsset2;
                        }

                        return Diff3ChangeType.MergeFromAsset1;
                    }

                    if (dataNode is DataVisitListItem)
                    {
                        // If we have a conflict in a list, we can't really resolve it here, so we are breaking out of the loop
                        if (diff3Node.ChangeType == Diff3ChangeType.Conflict)
                        {
                            return Diff3ChangeType.Conflict;
                        }
                        return Diff3ChangeType.MergeFromAsset2;
                    }

                    if (dataNode is DataVisitDictionaryItem)
                    {
                        return Diff3ChangeType.MergeFromAsset2;
                    }

                    if (dataNode is DataVisitArrayItem)
                    {
                        if (diff3Node.Asset1Node != null && ((DataVisitArrayItem)diff3Node.Asset1Node).Index == ((DataVisitArrayItem)dataNode).Index)
                        {
                            return Diff3ChangeType.MergeFromAsset2;
                        }
                    }
                    break;
            }

            return diff3Node.ChangeType;
        }
Example #2
0
        private static void MergeContainer(Diff3Node diff3Node, out object dataInstanceOut)
        {
            dataInstanceOut = null;

            // We don't have a valid parent (probably removed), so skip this node
            if (diff3Node.Parent != null && diff3Node.Parent.Asset1Node.Instance == null)
                return;

            if (diff3Node.Asset1Node == null)
            {
                diff3Node.Asset1Node = (diff3Node.Asset2Node ?? diff3Node.BaseNode).CreateWithEmptyInstance();
                if (diff3Node.Parent != null)
                    diff3Node.Asset1Node.Parent = diff3Node.Parent.Asset1Node;
            }

            object dataInstance = diff3Node.Asset1Node.Instance;

            // If a node has children, since DiffCollection/DiffDictionary takes null as empty arrays,
            // we should now create this array for it to be properly merged
            if (dataInstance == null)
                dataInstanceOut = dataInstance = Activator.CreateInstance(diff3Node.InstanceType);

            // If it's a collection, clear it and reconstruct it from DiffCollection result (stored in Diff3Node.Items)
            // TODO: Various optimizations to avoid removing and reinserting items that were already here before (would need to diff Asset1 and Diff3Node...)
            var collectionDescriptor = diff3Node.Asset1Node.InstanceDescriptor as CollectionDescriptor;
            if (collectionDescriptor != null && diff3Node.Type == Diff3NodeType.Collection)
            {
                collectionDescriptor.Clear(dataInstance);
                if (diff3Node.Items != null)
                {
                    foreach (var item in diff3Node.Items)
                    {
                        object itemInstance;
                        switch (item.ChangeType)
                        {
                            case Diff3ChangeType.Children:
                            case Diff3ChangeType.Conflict:
                            case Diff3ChangeType.ConflictType:
                                // Use any valid object, it will be replaced later
                                itemInstance = SafeNodeInstance(item.Asset1Node) ?? SafeNodeInstance(item.Asset2Node) ?? SafeNodeInstance(item.BaseNode);
                                break;
                            case Diff3ChangeType.None:
                            case Diff3ChangeType.MergeFromAsset1:
                            case Diff3ChangeType.MergeFromAsset1And2:
                                itemInstance = item.Asset1Node.Instance;
                                break;
                            case Diff3ChangeType.MergeFromAsset2:
                                itemInstance = item.Asset2Node.Instance;
                                break;
                            default:
                                throw new InvalidOperationException();
                        }
                        collectionDescriptor.Add(dataInstance, itemInstance);
                    }
                }
            }
        }