diff --git a/uSync.BackOffice/Models/SyncMergeOptions.cs b/uSync.BackOffice/Models/SyncMergeOptions.cs
index a6159f878..bf1c762a9 100644
--- a/uSync.BackOffice/Models/SyncMergeOptions.cs
+++ b/uSync.BackOffice/Models/SyncMergeOptions.cs
@@ -1,4 +1,5 @@
using uSync.BackOffice.SyncHandlers.Interfaces;
+using uSync.Core.Roots.Models;
namespace uSync.BackOffice.Models;
@@ -28,4 +29,9 @@ public SyncMergeOptions(SyncUpdateCallback? callback)
/// Callback use to pass info to the UI.
///
public SyncUpdateCallback? UpdateCallback { get; set; }
-}
\ No newline at end of file
+
+ ///
+ /// what type of merging are we going to do.
+ ///
+ public SyncMergeStrategy MergeStrategy { get; set; } = SyncMergeStrategy.Magic;
+}
diff --git a/uSync.BackOffice/Services/ISyncFileService.cs b/uSync.BackOffice/Services/ISyncFileService.cs
index 839886777..475df0dd0 100644
--- a/uSync.BackOffice/Services/ISyncFileService.cs
+++ b/uSync.BackOffice/Services/ISyncFileService.cs
@@ -1,8 +1,10 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Xml.Linq;
-
+using uSync.BackOffice.Models;
+using uSync.Core.Roots.Models;
using uSync.Core.Tracking;
namespace uSync.BackOffice.Services;
@@ -91,10 +93,18 @@ public interface ISyncFileService
///
Task> GetAllNodesAsync(string[] filePaths);
+ ///
+ /// legacy merge (fancy) - will be removed in v19
+ ///
+ [Obsolete("Will be removed in v19 - pass the options for greater control")]
+ XElement? GetDifferences(List nodes, ISyncTrackerBase? trackerBase)
+ => GetDifferences(nodes, trackerBase, new SyncFileMergeOptions());
+
+
///
/// get a XML representation of the differences between two files
///
- XElement? GetDifferences(List nodes, ISyncTrackerBase? trackerBase);
+ XElement? GetDifferences(List nodes, ISyncTrackerBase? trackerBase, SyncFileMergeOptions options);
///
/// list the folders inside a folder
@@ -135,10 +145,24 @@ public interface ISyncFileService
///
Task LoadXElementAsync(string file);
+ ///
+ /// legacy merge (fancy) - will be removed in v19
+ ///
+ [Obsolete("Will be removed in v19 - pass the options for greater control")]
+ Task MakeSingleExportFromFolders(string[] folders, string itemType, ISyncTrackerBase? trackerBase, string fileName, string extension)
+ => MakeSingleExportFromFolders(folders, itemType, trackerBase, fileName, extension, new SyncFileMergeOptions());
+
///
/// merge all the files in the given folders into a single xml node, that can be bulk imported
///
- Task MakeSingleExportFromFolders(string[] folders, string itemType, ISyncTrackerBase? trackerBase, string fileName, string extension);
+ Task MakeSingleExportFromFolders(string[] folders, string itemType, ISyncTrackerBase? trackerBase, string fileName, string extension, SyncFileMergeOptions options);
+
+ ///
+ /// legacy merge (fancy) - will be removed in v19
+ ///
+ [Obsolete("Will be removed in v19 - pass the options for greater control")]
+ Task MergeFilesAsync(string[] filenames, ISyncTrackerBase? trackerBase)
+ => MergeFilesAsync(filenames, trackerBase, new SyncFileMergeOptions());
///
/// merge a list of files into a single XElement
@@ -146,7 +170,15 @@ public interface ISyncFileService
///
/// depending on the tracker this can do clever things like merge bits of doctypes together.
///
- Task MergeFilesAsync(string[] filenames, ISyncTrackerBase? trackerBase);
+ Task MergeFilesAsync(string[] filenames, ISyncTrackerBase? trackerBase, SyncFileMergeOptions options);
+
+ ///
+ /// legacy merge (fancy) - will be removed in v19
+ ///
+ [Obsolete("Will be removed in v19 - pass the options for greater control")]
+ Task> MergeFoldersAsync(string[] folders, string extension, ISyncTrackerBase? trackerBase)
+ => MergeFoldersAsync(folders, extension, trackerBase, new SyncFileMergeOptions());
+
///
/// Merge a number of uSync folders into a single 'usync source'
@@ -161,7 +193,8 @@ public interface ISyncFileService
/// the doctype tracker merges properties so you can have
/// property level root values for doctypes.
///
- Task> MergeFoldersAsync(string[] folders, string extension, ISyncTrackerBase? trackerBase);
+ Task> MergeFoldersAsync(string[] folders, string extension, ISyncTrackerBase? trackerBase,
+ SyncFileMergeOptions options);
///
diff --git a/uSync.BackOffice/Services/ISyncService.cs b/uSync.BackOffice/Services/ISyncService.cs
index 9ccce0492..64a5f2815 100644
--- a/uSync.BackOffice/Services/ISyncService.cs
+++ b/uSync.BackOffice/Services/ISyncService.cs
@@ -7,6 +7,7 @@
using uSync.BackOffice.Models;
using uSync.BackOffice.SyncHandlers.Interfaces;
using uSync.BackOffice.SyncHandlers.Models;
+using uSync.Core.Roots.Models;
namespace uSync.BackOffice;
@@ -158,7 +159,8 @@ public interface ISyncService
Task FinishBulkProcessAsync(HandlerActions action, IEnumerable actions);
///
- /// merge the given folders in single 'production' files for each handler.
+ /// Merge the given folders in single 'production' files for each handler.
+ /// [Obsolete: Use overload with SyncFileMergeOptions for greater control]
///
Task MergeExportFolder(string[] paths, IEnumerable handlers);
diff --git a/uSync.BackOffice/Services/SyncFileService.cs b/uSync.BackOffice/Services/SyncFileService.cs
index 9d79aa015..075357c72 100644
--- a/uSync.BackOffice/Services/SyncFileService.cs
+++ b/uSync.BackOffice/Services/SyncFileService.cs
@@ -12,8 +12,8 @@
using System.Xml.Linq;
using Umbraco.Cms.Core.Extensions;
-
using uSync.Core;
+using uSync.Core.Roots.Models;
using uSync.Core.Tracking;
namespace uSync.BackOffice.Services;
@@ -324,9 +324,9 @@ public void CopyFolder(string source, string target)
}
}
- public async Task MakeSingleExportFromFolders(string[] folders, string itemType, ISyncTrackerBase? trackerBase, string filename, string extension)
+ public async Task MakeSingleExportFromFolders(string[] folders, string itemType, ISyncTrackerBase? trackerBase, string filename, string extension, SyncFileMergeOptions options)
{
- var merged = await MergeFoldersAsync(folders, extension, trackerBase);
+ var merged = await MergeFoldersAsync(folders, extension, trackerBase, options);
var megaNode = new XElement(itemType + "s");
int count = 0;
@@ -407,7 +407,7 @@ static string GetShortFileName(string file)
#region roots
///
- public async Task> MergeFoldersAsync(string[] folders, string extension, ISyncTrackerBase? trackerBase)
+ public async Task> MergeFoldersAsync(string[] folders, string extension, ISyncTrackerBase? trackerBase, SyncFileMergeOptions options)
{
var elements = new Dictionary();
var cleanElements = new Dictionary();
@@ -436,7 +436,7 @@ public async Task> MergeFoldersAsync(string[] folde
if (elements.TryGetValue(item.Key, out var value))
{
// merge these files.
- item.Value.SetNode(MergeNodes(value.Node, item.Value.Node, trackerBase));
+ item.Value.SetNode(MergeNodes(value.Node, item.Value.Node, trackerBase, options));
item.Value.SetFileName($"{uSyncConstants.MergedFolderName}/{Path.GetFileName(item.Value.FileName)}");
}
}
@@ -468,7 +468,7 @@ public async Task> MergeFoldersAsync(string[] folde
}
///
- public async Task MergeFilesAsync(string[] filenames, ISyncTrackerBase? trackerBase)
+ public async Task MergeFilesAsync(string[] filenames, ISyncTrackerBase? trackerBase, SyncFileMergeOptions options)
{
if (filenames.Length == 0) return null;
var latest = await LoadXElementSafeAsync(filenames[0]);
@@ -478,13 +478,20 @@ public async Task> MergeFoldersAsync(string[] folde
{
var node = await LoadXElementSafeAsync(filenames[n]);
if (node is null) continue;
- latest = MergeNodes(latest, node, trackerBase);
+ latest = MergeNodes(latest, node, trackerBase, options);
}
return latest;
}
- private static XElement MergeNodes(XElement source, XElement target, ISyncTrackerBase? trackerBase)
- => trackerBase is null ? target : trackerBase.MergeFiles(source, target) ?? target;
+ private static XElement MergeNodes(XElement source, XElement target, ISyncTrackerBase? trackerBase, SyncFileMergeOptions options)
+ {
+ if (trackerBase is ISyncTrackerOptionsBase optionsBase)
+ {
+ return optionsBase.MergeFiles(source, target, options) ?? target;
+ }
+
+ return trackerBase is null ? target : trackerBase.MergeFiles(source, target) ?? target;
+ }
private async Task>> GetFolderItemsAsync(string folder, string extension)
{
@@ -525,7 +532,7 @@ private async Task>> GetFolder
}
///
- public XElement? GetDifferences(List nodes, ISyncTrackerBase? trackerBase)
+ public XElement? GetDifferences(List nodes, ISyncTrackerBase? trackerBase, SyncFileMergeOptions options)
{
try
{
@@ -534,6 +541,11 @@ private async Task>> GetFolder
if (trackerBase is null)
return SyncRootMergerHelper.GetDifferencesByFileContents(nodes);
+ if (trackerBase is ISyncTrackerOptionsBase optionsBase)
+ {
+ return optionsBase.GetDifferences(nodes, options);
+ }
+
return trackerBase?.GetDifferences(nodes);
}
catch (Exception ex)
diff --git a/uSync.BackOffice/Services/SyncService_Files.cs b/uSync.BackOffice/Services/SyncService_Files.cs
index 1d23577be..cbbabdd2c 100644
--- a/uSync.BackOffice/Services/SyncService_Files.cs
+++ b/uSync.BackOffice/Services/SyncService_Files.cs
@@ -6,8 +6,11 @@
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
-
+using uSync.BackOffice.Configuration;
using uSync.BackOffice.SyncHandlers.Models;
+using uSync.Core.Roots.Models;
+
+using CoreConstants = uSync.Core.uSyncConstants;
namespace uSync.BackOffice;
@@ -130,7 +133,14 @@ public async Task MergeExportFolder(string[] paths, IEnumerable(
+ CoreConstants.DefaultSettings.MergeStrategy,
+ CoreConstants.DefaultSettings.MergeStrategy_Default)
+ };
+
+ totalMerged += await _syncFileService.MakeSingleExportFromFolders(folders, serializerType, baseTracker, targetFileName, _uSyncConfig.Settings.DefaultExtension, handlerMergeOptions);
}
return totalMerged;
diff --git a/uSync.BackOffice/SyncHandlers/SyncHandlerRoot.cs b/uSync.BackOffice/SyncHandlers/SyncHandlerRoot.cs
index c32451040..418125cc3 100644
--- a/uSync.BackOffice/SyncHandlers/SyncHandlerRoot.cs
+++ b/uSync.BackOffice/SyncHandlers/SyncHandlerRoot.cs
@@ -26,9 +26,12 @@
using uSync.Core;
using uSync.Core.Dependency;
using uSync.Core.Models;
+using uSync.Core.Roots.Models;
using uSync.Core.Serialization;
using uSync.Core.Tracking;
+using CoreConstants = uSync.Core.uSyncConstants;
+
namespace uSync.BackOffice.SyncHandlers;
///
@@ -346,8 +349,13 @@ public async Task> FetchAllNodesAsync(string[] fo
///
protected virtual async Task> GetMergedItemsAsync(string[] folders, SyncMergeOptions options)
{
+ var fileMergeOptions = new SyncFileMergeOptions
+ {
+ MergeStrategy = options.MergeStrategy
+ };
+
var baseTracker = trackers.FirstOrDefault() as ISyncTrackerBase;
- return [.. (await syncFileService.MergeFoldersAsync(folders, uSyncConfig.Settings.DefaultExtension, baseTracker))];
+ return [.. (await syncFileService.MergeFoldersAsync(folders, uSyncConfig.Settings.DefaultExtension, baseTracker, fileMergeOptions))];
}
///
@@ -360,14 +368,14 @@ protected virtual async Task> GetMergedItemsAsync
///
/// given a file path, will give you the merged values across all folders.
///
- protected virtual async Task GetMergedNodeAsync(string filePath)
+ protected virtual async Task GetMergedNodeAsync(string filePath, SyncFileMergeOptions options)
{
var allFiles = uSyncConfig.GetFolders()
.Select(x => syncFileService.GetAbsPath($"{x}/{this.DefaultFolder}/{filePath}"))
.ToArray();
var baseTracker = trackers.FirstOrDefault() as ISyncTrackerBase;
- return await syncFileService.MergeFilesAsync(allFiles, baseTracker);
+ return await syncFileService.MergeFilesAsync(allFiles, baseTracker, options);
}
@@ -434,7 +442,7 @@ virtual public async Task> ImportAsync(string file, Han
if (file.InvariantStartsWith($"{uSyncConstants.MergedFolderName}/"))
{
- var node = await GetMergedNodeAsync(file.Substring(uSyncConstants.MergedFolderName.Length + 1));
+ var node = await GetMergedNodeAsync(file.Substring(uSyncConstants.MergedFolderName.Length + 1), new SyncFileMergeOptions());
if (node is not null)
return await ImportElementAsync(node, file, config, options);
else
@@ -859,7 +867,7 @@ public async Task> ExportAsync(Udi udi, string[] folder
return [uSyncAction.Fail(nameof(udi), this.handlerType, this.ItemType, ChangeType.Fail, $"Item not found {udi}",
new KeyNotFoundException(nameof(udi)))];
-
+
}
///
@@ -926,7 +934,15 @@ protected virtual async Task> Export_DoExportAsync(TObject
if (nodes.Count > 0)
{
nodes.Add(attempt.Item);
- var differences = syncFileService.GetDifferences(nodes, trackers.FirstOrDefault());
+
+ var mergeOptions = new SyncFileMergeOptions
+ {
+ MergeStrategy = config.GetSetting(
+ CoreConstants.DefaultSettings.MergeStrategy,
+ CoreConstants.DefaultSettings.MergeStrategy_Default)
+ };
+
+ var differences = syncFileService.GetDifferences(nodes, trackers.FirstOrDefault(), mergeOptions);
if (differences is not null && differences.HasElements)
{
if (config.FullFileOnDifference)
@@ -1309,7 +1325,7 @@ public virtual async Task> ReportElementSingleAsync(XEl
{
return [uSyncActionHelper
.ReportActionFail(Path.GetFileName(node.GetAlias()), $"format error {fex.Message}")];
-
+
}
}
diff --git a/uSync.Core/Roots/Configs/BlockGridConfigMerger.cs b/uSync.Core/Roots/Configs/BlockGridConfigMerger.cs
index 18d1c2ecb..e612ab20f 100644
--- a/uSync.Core/Roots/Configs/BlockGridConfigMerger.cs
+++ b/uSync.Core/Roots/Configs/BlockGridConfigMerger.cs
@@ -3,6 +3,7 @@
using Umbraco.Cms.Core;
using uSync.Core.Extensions;
+using uSync.Core.Roots.Models;
namespace uSync.Core.Roots.Configs;
@@ -30,7 +31,7 @@ public virtual object GetMergedConfig(string root, string target)
return MergeJsonProperties(rootConfig, targetConfig, "_");
}
- public virtual object GetDifferenceConfig(string root, string target)
+ public virtual object GetDifferenceConfig(string root, string target, SyncFileMergeOptions options)
{
var rootConfig = root.DeserializeJson();
var targetConfig = target.DeserializeJson();
@@ -38,6 +39,6 @@ public virtual object GetDifferenceConfig(string root, string target)
if (targetConfig is null) return target;
if (rootConfig is null) return target;
- return GetJsonPropertyDifferences(rootConfig, targetConfig, "_");
+ return GetJsonPropertyDifferences(rootConfig, targetConfig, "_", options);
}
}
diff --git a/uSync.Core/Roots/Configs/BlockListConfigMerger.cs b/uSync.Core/Roots/Configs/BlockListConfigMerger.cs
index 67a3871ee..b4c7c34c4 100644
--- a/uSync.Core/Roots/Configs/BlockListConfigMerger.cs
+++ b/uSync.Core/Roots/Configs/BlockListConfigMerger.cs
@@ -3,6 +3,7 @@
using Umbraco.Cms.Core;
using uSync.Core.Extensions;
+using uSync.Core.Roots.Models;
namespace uSync.Core.Roots.Configs;
@@ -30,7 +31,7 @@ public virtual object GetMergedConfig(string root, string target)
return MergeJsonProperties(rootConfig, targetConfig, "_");
}
- public virtual object GetDifferenceConfig(string root, string target)
+ public virtual object GetDifferenceConfig(string root, string target, SyncFileMergeOptions options)
{
var rootConfig = root.DeserializeJson();
var targetConfig = target.DeserializeJson();
@@ -38,7 +39,7 @@ public virtual object GetDifferenceConfig(string root, string target)
if (targetConfig is null) return target;
if (rootConfig is null) return target;
- return GetJsonPropertyDifferences(rootConfig, targetConfig, "_");
+ return GetJsonPropertyDifferences(rootConfig, targetConfig, "_", options);
}
}
\ No newline at end of file
diff --git a/uSync.Core/Roots/Configs/ISyncConfigMerger.cs b/uSync.Core/Roots/Configs/ISyncConfigMerger.cs
index b43da38e4..302da4f0d 100644
--- a/uSync.Core/Roots/Configs/ISyncConfigMerger.cs
+++ b/uSync.Core/Roots/Configs/ISyncConfigMerger.cs
@@ -1,9 +1,16 @@
-namespace uSync.Core.Roots.Configs;
+using uSync.Core.Roots.Models;
+
+namespace uSync.Core.Roots.Configs;
public interface ISyncConfigMerger
{
string[] Editors { get; }
object? GetMergedConfig(string root, string target);
- object? GetDifferenceConfig(string root, string target);
+
+ [Obsolete("Use GetDifferenceConfig(string root, string target, SyncFileMergeOptions options) instead. Will be removed in v19.")]
+ object? GetDifferenceConfig(string root, string target)
+ => GetDifferenceConfig(root, target, new SyncFileMergeOptions());
+
+ object? GetDifferenceConfig(string root, string target, SyncFileMergeOptions options);
}
diff --git a/uSync.Core/Roots/Configs/ImageCropperConfigMerger.cs b/uSync.Core/Roots/Configs/ImageCropperConfigMerger.cs
index b17489ed8..93b22a678 100644
--- a/uSync.Core/Roots/Configs/ImageCropperConfigMerger.cs
+++ b/uSync.Core/Roots/Configs/ImageCropperConfigMerger.cs
@@ -3,6 +3,7 @@
using Umbraco.Cms.Core;
using uSync.Core.Extensions;
+using uSync.Core.Roots.Models;
namespace uSync.Core.Roots.Configs;
internal class ImageCropperConfigMerger : SyncConfigMergerBase, ISyncConfigMerger
@@ -27,7 +28,7 @@ internal class ImageCropperConfigMerger : SyncConfigMergerBase, ISyncConfigMerge
return MergeJsonProperties(rootConfig, targetConfig, "_");
}
- public object? GetDifferenceConfig(string root, string target)
+ public object? GetDifferenceConfig(string root, string target, SyncFileMergeOptions options)
{
var rootConfig = root.DeserializeJson();
var targetConfig = target.DeserializeJson();
@@ -35,6 +36,6 @@ internal class ImageCropperConfigMerger : SyncConfigMergerBase, ISyncConfigMerge
if (targetConfig is null) return target;
if (rootConfig is null) return target;
- return GetJsonPropertyDifferences(rootConfig, targetConfig, "_");
+ return GetJsonPropertyDifferences(rootConfig, targetConfig, "_", options);
}
}
diff --git a/uSync.Core/Roots/Configs/SyncConfigMergerBase.cs b/uSync.Core/Roots/Configs/SyncConfigMergerBase.cs
index 0157708ed..334f53ccd 100644
--- a/uSync.Core/Roots/Configs/SyncConfigMergerBase.cs
+++ b/uSync.Core/Roots/Configs/SyncConfigMergerBase.cs
@@ -6,6 +6,7 @@
using Umbraco.Extensions;
using uSync.Core.Extensions;
+using uSync.Core.Roots.Models;
namespace uSync.Core.Roots.Configs;
@@ -72,7 +73,7 @@ protected static TObject[] GetObjectDifferences(TObject[]? rootOb
return [.. remaining];
}
- protected JsonArray? GetJsonArrayDifferences(JsonArray? sourceArray, JsonArray? targetArray, string key, string removeProperty)
+ protected JsonArray? GetJsonArrayDifferences(JsonArray? sourceArray, JsonArray? targetArray, string key, string removeProperty, SyncFileMergeOptions options)
{
// if target is blank the difference is nothing?
if (targetArray is null) return [];
@@ -98,7 +99,7 @@ protected static TObject[] GetObjectDifferences(TObject[]? rootOb
if (block.Value.IsJsonEqual(sourceItem) is false)
{
// the values are different, so we go property by property to see if we can merge them.
- var target = GetJsonPropertyDifferences(sourceItem, block.Value, key);
+ var target = GetJsonPropertyDifferences(sourceItem, block.Value, key, options);
targetOnly.Add(target);
}
}
@@ -113,7 +114,7 @@ protected static TObject[] GetObjectDifferences(TObject[]? rootOb
return targetOnly.ToJsonArray();
}
- public JsonObject GetJsonPropertyDifferences(JsonObject sourceObject, JsonObject targetObject, string propertyKey)
+ public JsonObject GetJsonPropertyDifferences(JsonObject sourceObject, JsonObject targetObject, string propertyKey, SyncFileMergeOptions options)
{
foreach (var property in sourceObject)
{
@@ -130,6 +131,9 @@ public JsonObject GetJsonPropertyDifferences(JsonObject sourceObject, JsonObject
if (property.Value.IsJsonEqual(targetValue) is false)
{
+ // we don't merge past the top level unless we are magic merging.
+ if (options.MergeStrategy < SyncMergeStrategy.Magic) continue;
+
// target is an update so we keep this value.
// unless its an array, and then we have to merge deeper.
switch (targetValue.GetValueKind())
@@ -141,7 +145,7 @@ public JsonObject GetJsonPropertyDifferences(JsonObject sourceObject, JsonObject
// this assumes we know what they key should be based on our array of well known array keys.
// if the array is new or generic we fall back to 'key';
var (arrayKey, arrayLabel) = _knownArrayKeys.GetValueOrDefault(property.Key, (key: "key", label: "label"));
- targetObject[property.Key] = GetJsonArrayDifferences(sourceArray, targetArray, arrayKey, arrayLabel);
+ targetObject[property.Key] = GetJsonArrayDifferences(sourceArray, targetArray, arrayKey, arrayLabel, options);
break;
case JsonValueKind.Object:
// i am not sure we ever hit this in the block config, but it's here should the block or json store
@@ -149,7 +153,7 @@ public JsonObject GetJsonPropertyDifferences(JsonObject sourceObject, JsonObject
// wouldn't have a key.
if (property.Value is JsonObject sourceObj && targetValue is JsonObject targetObj)
{
- targetObject[property.Key] = GetJsonPropertyDifferences(sourceObj, targetObj, string.Empty);
+ targetObject[property.Key] = GetJsonPropertyDifferences(sourceObj, targetObj, string.Empty, options);
}
break;
}
diff --git a/uSync.Core/Roots/Models/SyncMergeOptions.cs b/uSync.Core/Roots/Models/SyncMergeOptions.cs
new file mode 100644
index 000000000..859992403
--- /dev/null
+++ b/uSync.Core/Roots/Models/SyncMergeOptions.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace uSync.Core.Roots.Models;
+
+public enum SyncMergeStrategy
+{
+ ///
+ /// don't merge the value in the lowest folder wins.
+ ///
+ None,
+
+ ///
+ /// merge at a 'block' level, new properties merge, new blocks or values at the top level
+ ///
+ Fancy,
+
+ ///
+ /// merge down to the property level, so a property in a block will be merged individually.
+ ///
+ Magic,
+}
+
+public class SyncFileMergeOptions
+{
+ ///
+ /// what type of merging are we going to do.
+ ///
+ /// This determines how the merging process will handle conflicts and overlapping content.
+ ///
+ public SyncMergeStrategy MergeStrategy { get; set; } = SyncMergeStrategy.Magic;
+}
\ No newline at end of file
diff --git a/uSync.Core/Tracking/ISyncTracker.cs b/uSync.Core/Tracking/ISyncTracker.cs
index 7de703fb6..05e59d5d7 100644
--- a/uSync.Core/Tracking/ISyncTracker.cs
+++ b/uSync.Core/Tracking/ISyncTracker.cs
@@ -1,6 +1,7 @@
using System.Xml.Linq;
using uSync.Core.Models;
+using uSync.Core.Roots.Models;
using uSync.Core.Serialization;
namespace uSync.Core.Tracking;
@@ -13,10 +14,17 @@ public interface ISyncTrackerBase
XElement? GetDifferences(List nodes)
=> nodes.Count > 0 ? nodes[^1] : null;
+}
+
+public interface ISyncTrackerOptionsBase : ISyncTrackerBase
+{
+ XElement? MergeFiles(XElement a, XElement b, SyncFileMergeOptions options);
+ XElement? GetDifferences(List nodes, SyncFileMergeOptions options);
}
-public interface ISyncTracker : ISyncTrackerBase
+
+public interface ISyncTracker : ISyncTrackerOptionsBase
{
Task> GetChangesAsync(XElement target, XElement source, SyncSerializerOptions options);
Task> GetChangesAsync(XElement node, SyncSerializerOptions options);
diff --git a/uSync.Core/Tracking/Impliment/DataTypeTracker.cs b/uSync.Core/Tracking/Impliment/DataTypeTracker.cs
index 37c29878e..7af1a001a 100644
--- a/uSync.Core/Tracking/Impliment/DataTypeTracker.cs
+++ b/uSync.Core/Tracking/Impliment/DataTypeTracker.cs
@@ -4,6 +4,7 @@
using uSync.Core.Extensions;
using uSync.Core.Roots.Configs;
+using uSync.Core.Roots.Models;
using uSync.Core.Serialization;
namespace uSync.Core.Tracking.Impliment;
@@ -56,21 +57,21 @@ public DataTypeTracker(
return base.MergeFiles(a, b);
}
- public override XElement? GetDifferences(List nodes)
+ public override XElement? GetDifferences(List nodes, SyncFileMergeOptions options)
{
- if (nodes.Count <= 1) return base.GetDifferences(nodes);
+ if (nodes.Count <= 1) return base.GetDifferences(nodes, options);
var editorAlias = GetEditorAlias(nodes[0]);
var merger = GetConfigMerger(editorAlias);
if (!string.IsNullOrEmpty(editorAlias) && merger != null)
{
- return GetDifferences(nodes[0], nodes[1], merger);
+ return GetDifferences(nodes[0], nodes[1], merger, options);
}
- return SyncRootMergerHelper.GetDifferences(nodes, TrackingItems);
+ return SyncRootMergerHelper.GetDifferences(nodes, TrackingItems, options);
}
- public XElement? GetDifferences(XElement root, XElement target, ISyncConfigMerger merger)
+ protected XElement? GetDifferences(XElement root, XElement target, ISyncConfigMerger merger, SyncFileMergeOptions options)
{
var rootConfig = root.Element("Config").ValueOrDefault(string.Empty);
@@ -79,7 +80,7 @@ public DataTypeTracker(
if (!string.IsNullOrEmpty(rootConfig) && !string.IsNullOrEmpty(targetConfig))
{
// calculate config differences.
- var difference = merger.GetDifferenceConfig(rootConfig, targetConfig);
+ var difference = merger.GetDifferenceConfig(rootConfig, targetConfig, options);
if (difference != null)
{
root.Element("Config")?.ReplaceNodes(new XCData(SerializeConfig(difference)));
@@ -89,7 +90,7 @@ public DataTypeTracker(
}
- return SyncRootMergerHelper.GetDifferences([root, target], TrackingItems);
+ return SyncRootMergerHelper.GetDifferences([root, target], TrackingItems, options);
}
private string GetEditorAlias(XElement node)
diff --git a/uSync.Core/Tracking/SyncRootMergerHelper.cs b/uSync.Core/Tracking/SyncRootMergerHelper.cs
index de3de4934..c5a89f3f1 100644
--- a/uSync.Core/Tracking/SyncRootMergerHelper.cs
+++ b/uSync.Core/Tracking/SyncRootMergerHelper.cs
@@ -1,24 +1,27 @@
using System.Xml.Linq;
using System.Xml.XPath;
+using uSync.Core.Roots.Models;
namespace uSync.Core.Tracking;
public class SyncRootMergerHelper
{
- public static XElement GetDifferences(List nodes, IList trackedNodes)
+ public static XElement GetDifferences(List nodes, IList trackedNodes, SyncFileMergeOptions options)
{
- var (_, differences) = CompareNodes(nodes, trackedNodes);
+ var (_, differences) = CompareNodes(nodes, trackedNodes, options);
return differences;
}
- public static XElement GetCombined(List nodes, IList trackedNodes)
+ public static XElement GetCombined(List nodes, IList trackedNodes, SyncFileMergeOptions options)
{
- var (combined, _) = CompareNodes(nodes, trackedNodes);
+ var (combined, _) = CompareNodes(nodes, trackedNodes, options);
return combined;
}
public static XElement? GetDifferencesByFileContents(List nodes)
{
+ /// this is the fallback, and it basically does a 'none' merge where the latest difference is the one you get.
+
/// work out what is the 'latest' version of the node we are using for comparison.
///
// Node1, Node2, Node3
@@ -52,7 +55,7 @@ public static XElement GetCombined(List nodes, IList tra
return target;
}
- public static (XElement combined, XElement differences) CompareNodes(List nodes, IList trackedNodes)
+ public static (XElement combined, XElement differences) CompareNodes(List nodes, IList trackedNodes, SyncFileMergeOptions options)
{
var differences = XElement.Parse(nodes[^1].ToString());
var combined = XElement.Parse(nodes[^1].ToString());
diff --git a/uSync.Core/Tracking/SyncXmlTrackAndMerger.cs b/uSync.Core/Tracking/SyncXmlTrackAndMerger.cs
index fb442075a..f950ac2f5 100644
--- a/uSync.Core/Tracking/SyncXmlTrackAndMerger.cs
+++ b/uSync.Core/Tracking/SyncXmlTrackAndMerger.cs
@@ -1,5 +1,5 @@
using System.Xml.Linq;
-
+using uSync.Core.Roots.Models;
using uSync.Core.Serialization;
namespace uSync.Core.Tracking;
@@ -12,10 +12,20 @@ public SyncXmlTrackAndMerger(SyncSerializerCollection serializers)
{
}
- public override XElement? MergeFiles(XElement a, XElement b)
- => SyncRootMergerHelper.GetCombined([a, b], TrackingItems);
+ public virtual XElement? MergeFiles(XElement a, XElement b, SyncFileMergeOptions options)
+ {
+ if (options.MergeStrategy == SyncMergeStrategy.None)
+ return base.MergeFiles(a, b);
+
+ return SyncRootMergerHelper.GetCombined([a, b], TrackingItems, options);
+ }
- public override XElement? GetDifferences(List nodes)
- => SyncRootMergerHelper.GetDifferences(nodes, TrackingItems);
+ public virtual XElement? GetDifferences(List nodes, SyncFileMergeOptions options)
+ {
+ if (options.MergeStrategy == SyncMergeStrategy.None)
+ return base.GetDifferences(nodes);
+
+ return SyncRootMergerHelper.GetDifferences(nodes, TrackingItems, options);
+ }
}
diff --git a/uSync.Core/Tracking/SyncXmlTracker.cs b/uSync.Core/Tracking/SyncXmlTracker.cs
index 43a826a15..772ae9d36 100644
--- a/uSync.Core/Tracking/SyncXmlTracker.cs
+++ b/uSync.Core/Tracking/SyncXmlTracker.cs
@@ -6,6 +6,7 @@
using uSync.Core.Extensions;
using uSync.Core.Models;
+using uSync.Core.Roots.Models;
using uSync.Core.Serialization;
namespace uSync.Core.Tracking;
@@ -345,11 +346,11 @@ private static List CompareNode(XElement target, XElement source, s
};
}
- public virtual XElement? MergeFiles(XElement a, XElement b) => b;
+ public virtual XElement? MergeFiles(XElement a, XElement b)
+ => b;
public virtual XElement? GetDifferences(List nodes)
=> nodes?.Count > 0 ? nodes[^1] : null;
-
}
public class TrackingItem
diff --git a/uSync.Core/uSyncConstants.cs b/uSync.Core/uSyncConstants.cs
index 3057ba3d6..ea3a348db 100644
--- a/uSync.Core/uSyncConstants.cs
+++ b/uSync.Core/uSyncConstants.cs
@@ -1,4 +1,6 @@
-namespace uSync.Core;
+using uSync.Core.Roots.Models;
+
+namespace uSync.Core;
public static partial class uSyncConstants
{
@@ -143,6 +145,9 @@ public static class DefaultSettings
public const string UsingRazorViews = "UsingRazorViews";
public const bool UsingRazorViews_Default = false;
+ public const string MergeStrategy = "MergeStrategy";
+ public const SyncMergeStrategy MergeStrategy_Default = SyncMergeStrategy.Magic;
+
}
public const int DependencyCountMax = 204800;