From 0cf410fbea413d0f0267ef52920b39204a062d9f Mon Sep 17 00:00:00 2001 From: Kevin Jump Date: Mon, 29 Apr 2019 14:10:01 +0100 Subject: [PATCH] Dev flags (#17) * Save Flags - Gives us options to not save on deserialize Adding flags that can be sent to the serializer, mainly 'DoNotSave' this gives us the option not to save as part of the deserialization - this is mainly to allow for some optimisations where we can batch save a load of changes, - which will trigger less cache rebuilds, and more importantly less ModelsBuilder rebuilds. * Add BatchSave to the config (so we can turn it on at some point) * Add batch save to config. * Flag Messages - so we know what the wait is for. --- .../App_Plugins/uSync8/dashboard.html | 2 +- .../App_Plugins/uSync8/usync.css | 6 ++- uSync8.BackOffice/Config/uSync8.config | 1 + .../Configuration/BackOfficeConfig.cs | 12 ++++- .../Configuration/uSyncHandlerSettings.cs | 2 + .../Configuration/uSyncSettings.cs | 3 ++ uSync8.BackOffice/Services/uSyncService.cs | 16 ++++++- .../SyncHandlers/Handlers/DataTypeHandler.cs | 2 +- .../SyncHandlers/SyncHandlerBase.cs | 18 ++++++-- .../SyncHandlers/SyncHandlerLevelBase.cs | 13 +++++- .../Serializers/ContentSerializer.cs | 7 ++- .../Serializers/ContentSerializerBase.cs | 31 +++++++------ .../Serializers/ContentTemplateSerializer.cs | 6 ++- .../Serializers/DictionaryItemSerializer.cs | 5 ++- .../Serializers/DomainSerializer.cs | 5 ++- .../Serializers/MediaSerializer.cs | 9 +++- uSync8.Core/Serialization/ISyncSerializer.cs | 9 +++- uSync8.Core/Serialization/SerializerFlags.cs | 10 +++++ .../Serializers/ContentTypeBaseSerializer.cs | 6 +++ .../Serializers/ContentTypeSerializer.cs | 5 ++- .../Serializers/DataTypeSerializer.cs | 12 +++-- .../Serializers/LanguageSerializer.cs | 7 ++- .../Serializers/MacroSerializer.cs | 4 +- .../Serializers/MediaTypeSerializer.cs | 5 ++- .../Serializers/MemberTypeSerializer.cs | 2 +- .../Serializers/TemplateSerializer.cs | 8 +++- .../Serialization/SyncSerializerBase.cs | 45 ++++++++++++++++--- uSync8.Core/Tracking/SyncBaseTracker.cs | 5 ++- uSync8.Core/uSync8.Core.csproj | 1 + uSync8.Site/App_Plugins/uSync8/dashboard.html | 2 +- uSync8.Site/App_Plugins/uSync8/usync.css | 6 ++- uSync8.Site/Web.config | 2 +- uSync8.Site/config/uSync8.config | 2 + 33 files changed, 215 insertions(+), 54 deletions(-) create mode 100644 uSync8.Core/Serialization/SerializerFlags.cs diff --git a/uSync8.BackOffice/App_Plugins/uSync8/dashboard.html b/uSync8.BackOffice/App_Plugins/uSync8/dashboard.html index 6f8a2800..99dcd2ae 100644 --- a/uSync8.BackOffice/App_Plugins/uSync8/dashboard.html +++ b/uSync8.BackOffice/App_Plugins/uSync8/dashboard.html @@ -69,7 +69,7 @@

uSync 8

{{vm.status.Message}}

{{vm.update.Message}} -
+
diff --git a/uSync8.BackOffice/App_Plugins/uSync8/usync.css b/uSync8.BackOffice/App_Plugins/uSync8/usync.css index e7f7a8a4..dd7333fe 100644 --- a/uSync8.BackOffice/App_Plugins/uSync8/usync.css +++ b/uSync8.BackOffice/App_Plugins/uSync8/usync.css @@ -118,4 +118,8 @@ .usync-root-folder input { width: 100%; - } \ No newline at end of file + } + +.usync-not-animated .bar { + transition: none; +} \ No newline at end of file diff --git a/uSync8.BackOffice/Config/uSync8.config b/uSync8.BackOffice/Config/uSync8.config index a5e5c16c..21da4993 100644 --- a/uSync8.BackOffice/Config/uSync8.config +++ b/uSync8.BackOffice/Config/uSync8.config @@ -7,6 +7,7 @@ False True False + False diff --git a/uSync8.BackOffice/Configuration/BackOfficeConfig.cs b/uSync8.BackOffice/Configuration/BackOfficeConfig.cs index 2ec25bcc..13796df4 100644 --- a/uSync8.BackOffice/Configuration/BackOfficeConfig.cs +++ b/uSync8.BackOffice/Configuration/BackOfficeConfig.cs @@ -34,6 +34,8 @@ public uSyncSettings LoadSettings() settings.ExportAtStartup = node.Element("ExportAtStartup").ValueOrDefault(false); settings.ExportOnSave = node.Element("ExportOnSave").ValueOrDefault(true); settings.UseGuidNames = node.Element("UseGuidFilenames").ValueOrDefault(false); + settings.BatchSave = node.Element("BatchSave").ValueOrDefault(false); + settings.ReportDebug = node.Element("ReportDebug").ValueOrDefault(false); var handlerConfig = node.Element("Handlers"); @@ -64,6 +66,8 @@ public uSyncSettings SaveSettings(uSyncSettings settings, bool fireReload = fals node.CreateOrSetElement("ExportAtStartup", settings.ExportAtStartup); node.CreateOrSetElement("ExportOnSave", settings.ExportOnSave); node.CreateOrSetElement("UseGuidFilenames", settings.UseGuidNames); + node.CreateOrSetElement("BatchSave", settings.BatchSave); + node.CreateOrSetElement("ReportDebug", settings.ReportDebug); if (settings.Handlers != null && settings.Handlers.Any()) { @@ -84,6 +88,9 @@ public uSyncSettings SaveSettings(uSyncSettings settings, bool fireReload = fals if (!handler.UseFlatStructure.IsOverridden) handler.UseFlatStructure.SetDefaultValue(settings.UseFlatStructure); + if (!handler.BatchSave.IsOverridden) + handler.BatchSave.SetDefaultValue(settings.BatchSave); + var handlerNode = handlerConfig.Elements("Handler").FirstOrDefault(x => x.Attribute("Alias").Value == handler.Alias); if (handlerNode == null) { @@ -128,7 +135,7 @@ public HandlerSettings LoadHandlerConfig(XElement node, uSyncSettings defaultSet // we get them from the global setting. settings.GuidNames = GetLocalValue(node.Attribute("GuidNames"), defaultSettings.UseGuidNames); settings.UseFlatStructure = GetLocalValue(node.Attribute("UseFlatStructure"), defaultSettings.UseFlatStructure); - + settings.BatchSave = GetLocalValue(node.Attribute("BatchSave"), defaultSettings.BatchSave); settings.Actions = node.Attribute("Actions").ValueOrDefault("All").ToDelimitedList().ToArray(); var settingNode = node.Element("Settings"); @@ -174,6 +181,9 @@ public void SaveHandlerConfig(XElement node, HandlerSettings config, uSyncSettin if (config.UseFlatStructure.IsOverridden) node.SetAttributeValue("UseFlatStructure", config.UseFlatStructure); + if (config.BatchSave.IsOverridden) + node.SetAttributeValue("BatchSave", config.BatchSave); + if (config.Actions.Length > 0 && !(config.Actions.Length == 1 && config.Actions[0].InvariantEquals("all"))) node.SetAttributeValue("Actions", string.Join(",", config.Actions)); diff --git a/uSync8.BackOffice/Configuration/uSyncHandlerSettings.cs b/uSync8.BackOffice/Configuration/uSyncHandlerSettings.cs index 75124aeb..9dff4cf4 100644 --- a/uSync8.BackOffice/Configuration/uSyncHandlerSettings.cs +++ b/uSync8.BackOffice/Configuration/uSyncHandlerSettings.cs @@ -12,6 +12,8 @@ public class HandlerSettings public OverriddenValue UseFlatStructure { get; set; } = new OverriddenValue(); public OverriddenValue GuidNames { get; set; } = new OverriddenValue(); + public OverriddenValue BatchSave { get; set; } = new OverriddenValue(); + public Dictionary Settings { get; set; } = new Dictionary(); public HandlerSettings(string alias, bool enabled) diff --git a/uSync8.BackOffice/Configuration/uSyncSettings.cs b/uSync8.BackOffice/Configuration/uSyncSettings.cs index a5a199a0..b5ba8088 100644 --- a/uSync8.BackOffice/Configuration/uSyncSettings.cs +++ b/uSync8.BackOffice/Configuration/uSyncSettings.cs @@ -14,6 +14,7 @@ public class uSyncSettings public bool UseFlatStructure { get; set; } = true; public bool UseGuidNames { get; set; } = false; + public bool BatchSave { get; set; } = false; public bool ImportAtStartup { get; set; } = false; public bool ExportAtStartup { get; set; } = false; @@ -21,6 +22,8 @@ public class uSyncSettings public bool EnableMissingHandlers { get; set; } = true; public List Handlers { get; set; } = new List(); + + public bool ReportDebug { get; set; } = false; } } diff --git a/uSync8.BackOffice/Services/uSyncService.cs b/uSync8.BackOffice/Services/uSyncService.cs index 307dcb26..1a5f7a28 100644 --- a/uSync8.BackOffice/Services/uSyncService.cs +++ b/uSync8.BackOffice/Services/uSyncService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -46,6 +47,16 @@ public IEnumerable Report(string folder, SyncEventCallback callback var summary = new SyncProgressSummary(configuredHandlers.Select(x => x.Handler), "Reporting", configuredHandlers.Count); + if (settings.ReportDebug) + { + // debug - full export into a dated folder. + summary.Message = "Debug: Creating Extract in Tracker folder"; + callback?.Invoke(summary); + } + + this.Export($"~/uSync/Tracker/{DateTime.Now.ToString("yyyyMMdd_HHmmss")}/", null, null); + + foreach (var configuredHandler in configuredHandlers) { var handler = configuredHandler.Handler; @@ -74,6 +85,8 @@ public IEnumerable Import(string folder, bool force, SyncEventCallb { lock (_importLock) { + var sw = Stopwatch.StartNew(); + try { uSync8BackOffice.eventsPaused = true; @@ -137,7 +150,8 @@ public IEnumerable Import(string folder, bool force, SyncEventCallb } } - summary.UpdateHandler("Post Import", HandlerStatus.Complete, "Import Completed"); + sw.Stop(); + summary.UpdateHandler("Post Import", HandlerStatus.Complete, $"Import Completed ({sw.ElapsedMilliseconds}ms)"); callback?.Invoke(summary); return actions; diff --git a/uSync8.BackOffice/SyncHandlers/Handlers/DataTypeHandler.cs b/uSync8.BackOffice/SyncHandlers/Handlers/DataTypeHandler.cs index 8db004e2..9c92201d 100644 --- a/uSync8.BackOffice/SyncHandlers/Handlers/DataTypeHandler.cs +++ b/uSync8.BackOffice/SyncHandlers/Handlers/DataTypeHandler.cs @@ -62,7 +62,7 @@ public override IEnumerable ProcessPostImport(string folder, IEnume foreach (var action in actions) { - var attempt = Import(action.FileName, config); + var attempt = Import(action.FileName, config, SerializerFlags.None); if (attempt.Success) { ImportSecondPass(action.FileName, attempt.Item, config, null); diff --git a/uSync8.BackOffice/SyncHandlers/SyncHandlerBase.cs b/uSync8.BackOffice/SyncHandlers/SyncHandlerBase.cs index 475c6441..7727e77c 100644 --- a/uSync8.BackOffice/SyncHandlers/SyncHandlerBase.cs +++ b/uSync8.BackOffice/SyncHandlers/SyncHandlerBase.cs @@ -144,9 +144,12 @@ public IEnumerable ImportAll(string folder, HandlerSettings config, protected virtual IEnumerable ImportFolder(string folder, HandlerSettings config, Dictionary updates, bool force, SyncUpdateCallback callback) { List actions = new List(); - var files = syncFileService.GetFiles(folder, "*.config"); + var flags = SerializerFlags.None; + if (force) flags |= SerializerFlags.Force; + if (config.BatchSave) flags |= SerializerFlags.DoNotSave; + int count = 0; int total = files.Count(); foreach (string file in files) @@ -155,7 +158,7 @@ protected virtual IEnumerable ImportFolder(string folder, HandlerSe callback?.Invoke($"Importing {Path.GetFileName(file)}", count, total); - var attempt = Import(file, config, force); + var attempt = Import(file, config, flags); if (attempt.Success && attempt.Item != null) { updates.Add(file, attempt.Item); @@ -168,6 +171,13 @@ protected virtual IEnumerable ImportFolder(string folder, HandlerSe actions.Add(action); } + // bulk save .. + if (flags.HasFlag(SerializerFlags.DoNotSave) && updates.Any()) + { + callback?.Invoke($"Saving {updates.Count()} changes", 1, 1); + serializer.Save(updates.Select(x => x.Value)); + } + var folders = syncFileService.GetDirectories(folder); foreach (var children in folders) { @@ -179,7 +189,7 @@ protected virtual IEnumerable ImportFolder(string folder, HandlerSe return actions; } - virtual public SyncAttempt Import(string filePath, HandlerSettings config, bool force = false) + virtual public SyncAttempt Import(string filePath, HandlerSettings config, SerializerFlags flags) { try { @@ -188,7 +198,7 @@ virtual public SyncAttempt Import(string filePath, HandlerSettings conf using (var stream = syncFileService.OpenRead(filePath)) { var node = XElement.Load(stream); - var attempt = serializer.Deserialize(node, force, false); + var attempt = serializer.Deserialize(node, flags); return attempt; } } diff --git a/uSync8.BackOffice/SyncHandlers/SyncHandlerLevelBase.cs b/uSync8.BackOffice/SyncHandlers/SyncHandlerLevelBase.cs index 1367377f..780c6fa5 100644 --- a/uSync8.BackOffice/SyncHandlers/SyncHandlerLevelBase.cs +++ b/uSync8.BackOffice/SyncHandlers/SyncHandlerLevelBase.cs @@ -53,6 +53,7 @@ protected SyncHandlerLevelBase( /// protected override IEnumerable ImportFolder(string folder, HandlerSettings config, Dictionary updates, bool force, SyncUpdateCallback callback) { + // if not using flat, then directory structure is doing // this for us. if (config.UseFlatStructure == false) @@ -90,6 +91,9 @@ protected override IEnumerable ImportFolder(string folder, HandlerS } // loaded - now process. + var flags = SerializerFlags.None; + if (force) flags |= SerializerFlags.Force; + if (config.BatchSave) flags |= SerializerFlags.DoNotSave; var count = 0; foreach (var node in nodes.OrderBy(x => x.Level)) @@ -97,7 +101,7 @@ protected override IEnumerable ImportFolder(string folder, HandlerS count++; callback?.Invoke($"{Path.GetFileName(node.File)}", count, nodes.Count); - var attempt = Import(node.File, config, force); + var attempt = Import(node.File, config, flags); if (attempt.Success && attempt.Item != null) { updates.Add(node.File, attempt.Item); @@ -106,6 +110,13 @@ protected override IEnumerable ImportFolder(string folder, HandlerS actions.Add(uSyncActionHelper.SetAction(attempt, node.File, IsTwoPass)); } + if (flags.HasFlag(SerializerFlags.DoNotSave) && updates.Any()) + { + // bulk save - should be the fastest way to do this + callback?.Invoke($"Saving {updates.Count()} changes", 1, 1); + serializer.Save(updates.Select(x => x.Value)); + } + var folders = syncFileService.GetDirectories(folder); foreach (var children in folders) { diff --git a/uSync8.ContentEdition/Serializers/ContentSerializer.cs b/uSync8.ContentEdition/Serializers/ContentSerializer.cs index 2d9f2af5..08adee3e 100644 --- a/uSync8.ContentEdition/Serializers/ContentSerializer.cs +++ b/uSync8.ContentEdition/Serializers/ContentSerializer.cs @@ -103,7 +103,7 @@ protected override SyncAttempt DeserializeCore(XElement node) DeserializeBase(item, node); - contentService.Save(item); + // contentService.Save(item); return SyncAttempt.Succeed( item.Name, @@ -198,6 +198,11 @@ protected override IContent FindAtRoot(string alias) #endregion + public override void Save(IEnumerable items) + => contentService.Save(items); + + protected override void SaveItem(IContent item) + => contentService.Save(item); } } diff --git a/uSync8.ContentEdition/Serializers/ContentSerializerBase.cs b/uSync8.ContentEdition/Serializers/ContentSerializerBase.cs index 785ec73a..9d1cfcc8 100644 --- a/uSync8.ContentEdition/Serializers/ContentSerializerBase.cs +++ b/uSync8.ContentEdition/Serializers/ContentSerializerBase.cs @@ -22,7 +22,7 @@ public abstract class ContentSerializerBase : SyncTreeSerializerBase x.Alias)) + foreach (var property in item.Properties.OrderBy(x => x.Alias)) { var propertyNode = new XElement(property.Alias); - foreach(var value in property.Values) + // this can cause us false change readings + // but we need to preserve the values if they are blank + // because we have to be able to set them to blank on deserialization + foreach (var value in property.Values) { var valueNode = new XElement("Value"); - - if (!string.IsNullOrWhiteSpace(value.Culture)) { + if (!string.IsNullOrWhiteSpace(value.Culture)) + { valueNode.Add(new XAttribute("Culture", value.Culture ?? string.Empty)); } - if (!string.IsNullOrWhiteSpace(value.Segment)) { - valueNode.Add(new XAttribute("Segment", value.Segment ?? string.Empty)); + if (!string.IsNullOrWhiteSpace(value.Segment)) + { + valueNode.Add(new XAttribute("Segment", value.Segment ?? string.Empty)); } valueNode.Value = value.EditedValue?.ToString() ?? string.Empty; - propertyNode.Add(valueNode); } - node.Add(propertyNode); } @@ -147,7 +149,7 @@ protected Attempt DeserializeName(TObject item, XElement node) if (name != string.Empty) item.Name = name; - foreach(var cultureNode in nameNode.Elements("Name")) + foreach (var cultureNode in nameNode.Elements("Name")) { var culture = cultureNode.Attribute("Culture").ValueOrDefault(string.Empty); if (culture == string.Empty) continue; @@ -168,7 +170,7 @@ protected Attempt DeserializeProperties(TObject item, XElement node) if (properties == null || !properties.HasElements) return Attempt.Fail(item, new Exception("No Properties in the content node")); - foreach(var property in properties.Elements()) + foreach (var property in properties.Elements()) { var alias = property.Name.LocalName; if (item.HasProperty(alias)) @@ -204,7 +206,7 @@ protected string GetImportValue(PropertyType propertyType, string value, string } public override bool IsValid(XElement node) - => node != null + => node != null && node.GetKey() != null && node.GetAlias() != null && node.Element("Info") != null; @@ -229,7 +231,8 @@ protected override TObject FindOrCreate(XElement node) // create var parent = default(TObject); - if (parentKey != Guid.Empty) { + if (parentKey != Guid.Empty) + { parent = FindItem(parentKey); } diff --git a/uSync8.ContentEdition/Serializers/ContentTemplateSerializer.cs b/uSync8.ContentEdition/Serializers/ContentTemplateSerializer.cs index 47e1015a..ae9c4799 100644 --- a/uSync8.ContentEdition/Serializers/ContentTemplateSerializer.cs +++ b/uSync8.ContentEdition/Serializers/ContentTemplateSerializer.cs @@ -53,7 +53,7 @@ protected override SyncAttempt DeserializeCore(XElement node) DeserializeBase(item, node); - contentService.SaveBlueprint(item); + // contentService.SaveBlueprint(item); return SyncAttempt.Succeed( item.Name, @@ -108,5 +108,9 @@ protected override Attempt DoSaveOrPublish(IContent item, XElement node) contentService.SaveBlueprint(item); return Attempt.Succeed("blueprint saved"); } + + protected override void SaveItem(IContent item) + => contentService.SaveBlueprint(item); } + } diff --git a/uSync8.ContentEdition/Serializers/DictionaryItemSerializer.cs b/uSync8.ContentEdition/Serializers/DictionaryItemSerializer.cs index 635df769..283e97ab 100644 --- a/uSync8.ContentEdition/Serializers/DictionaryItemSerializer.cs +++ b/uSync8.ContentEdition/Serializers/DictionaryItemSerializer.cs @@ -87,7 +87,7 @@ private void DeserializeTranslations(IDictionaryItem item, XElement node) item.Translations = currentTranslations; - localizationService.Save(item); + // localizationService.Save(item); } protected override SyncAttempt SerializeCore(IDictionaryItem item) @@ -138,5 +138,8 @@ private int GetLevel(IDictionaryItem item, int level = 0) return level; } + protected override void SaveItem(IDictionaryItem item) + => localizationService.Save(item); + } } diff --git a/uSync8.ContentEdition/Serializers/DomainSerializer.cs b/uSync8.ContentEdition/Serializers/DomainSerializer.cs index 78efeebf..537c3527 100644 --- a/uSync8.ContentEdition/Serializers/DomainSerializer.cs +++ b/uSync8.ContentEdition/Serializers/DomainSerializer.cs @@ -76,7 +76,7 @@ protected override SyncAttempt DeserializeCore(XElement node) } - domainService.Save(item); + // domainService.Save(item); return SyncAttempt.Succeed(item.DomainName, item, ChangeType.Import); @@ -179,5 +179,8 @@ private IContent FindContentItem(string alias, IContent parent) return default(IContent); } + + protected override void SaveItem(IDomain item) + => domainService.Save(item); } } diff --git a/uSync8.ContentEdition/Serializers/MediaSerializer.cs b/uSync8.ContentEdition/Serializers/MediaSerializer.cs index 6fab5deb..a8fea3d0 100644 --- a/uSync8.ContentEdition/Serializers/MediaSerializer.cs +++ b/uSync8.ContentEdition/Serializers/MediaSerializer.cs @@ -39,7 +39,7 @@ protected override SyncAttempt DeserializeCore(XElement node) DeserializeBase(item, node); - mediaService.Save(item); + // mediaService.Save(item); return SyncAttempt.Succeed( item.Name, item, ChangeType.Import, ""); @@ -103,5 +103,12 @@ protected override IMedia FindAtRoot(string alias) return null; } + + public override void Save(IEnumerable items) + => mediaService.Save(items); + + protected override void SaveItem(IMedia item) + => mediaService.Save(item); } + } diff --git a/uSync8.Core/Serialization/ISyncSerializer.cs b/uSync8.Core/Serialization/ISyncSerializer.cs index df8fd447..0a8f5b3c 100644 --- a/uSync8.Core/Serialization/ISyncSerializer.cs +++ b/uSync8.Core/Serialization/ISyncSerializer.cs @@ -1,11 +1,14 @@ using System; +using System.Collections.Generic; using System.Xml.Linq; + using Umbraco.Core.Models.Entities; + using uSync8.Core.Models; namespace uSync8.Core.Serialization { - + public interface ISyncSerializerBase { Type objectType { get; } @@ -25,7 +28,7 @@ public interface ISyncSerializer : ISyncSerializerBase SyncAttempt SerializeEmpty(TObject item, string alias); - SyncAttempt Deserialize(XElement node, bool force, bool onePass); + SyncAttempt Deserialize(XElement node, SerializerFlags flags); SyncAttempt DeserializeSecondPass(TObject item, XElement node); /// @@ -37,5 +40,7 @@ public interface ISyncSerializer : ISyncSerializerBase bool IsTwoPass { get; } string ItemType { get; } + + void Save(IEnumerable items); } } diff --git a/uSync8.Core/Serialization/SerializerFlags.cs b/uSync8.Core/Serialization/SerializerFlags.cs new file mode 100644 index 00000000..00df8a91 --- /dev/null +++ b/uSync8.Core/Serialization/SerializerFlags.cs @@ -0,0 +1,10 @@ +namespace uSync8.Core.Serialization +{ + public enum SerializerFlags + { + None = 0, + Force = 1, // force the change (even if there isn't one) + OnePass = 2, // do this in one pass + DoNotSave = 4 // don't save + } +} diff --git a/uSync8.Core/Serialization/Serializers/ContentTypeBaseSerializer.cs b/uSync8.Core/Serialization/Serializers/ContentTypeBaseSerializer.cs index 9b1fab03..05107272 100644 --- a/uSync8.Core/Serialization/Serializers/ContentTypeBaseSerializer.cs +++ b/uSync8.Core/Serialization/Serializers/ContentTypeBaseSerializer.cs @@ -9,6 +9,7 @@ using Umbraco.Core.Models.Entities; using Umbraco.Core.Services; using uSync8.Core.Extensions; +using uSync8.Core.Models; namespace uSync8.Core.Serialization.Serializers { @@ -638,6 +639,11 @@ override protected IEnumerable FindContainers(string folder, in override protected Attempt> FindContainers(int parentId, string name) => baseService.CreateContainer(parentId, name); + protected override void SaveItem(TObject item) + => baseService.Save(item); + + public override void Save(IEnumerable items) + => baseService.Save(items); protected override void SaveContainer(EntityContainer container) { diff --git a/uSync8.Core/Serialization/Serializers/ContentTypeSerializer.cs b/uSync8.Core/Serialization/Serializers/ContentTypeSerializer.cs index 97928b38..d6a2136a 100644 --- a/uSync8.Core/Serialization/Serializers/ContentTypeSerializer.cs +++ b/uSync8.Core/Serialization/Serializers/ContentTypeSerializer.cs @@ -107,7 +107,7 @@ protected override SyncAttempt DeserializeCore(XElement node) // templates DeserializeTemplates(item, node); - contentTypeService.Save(item); + // contentTypeService.Save(item); return SyncAttempt.Succeed( item.Name, @@ -125,7 +125,8 @@ public override SyncAttempt DeserializeSecondPass(IContentType ite { DeserializeCompositions(item, node); DeserializeStructure(item, node); - contentTypeService.Save(item); + + // contentTypeService.Save(item); CleanFolder(item, node); diff --git a/uSync8.Core/Serialization/Serializers/DataTypeSerializer.cs b/uSync8.Core/Serialization/Serializers/DataTypeSerializer.cs index f3f52095..7db0e5cf 100644 --- a/uSync8.Core/Serialization/Serializers/DataTypeSerializer.cs +++ b/uSync8.Core/Serialization/Serializers/DataTypeSerializer.cs @@ -23,14 +23,12 @@ namespace uSync8.Core.Serialization.Serializers public class DataTypeSerializer : SyncContainerSerializerBase, ISyncSerializer { private readonly IDataTypeService dataTypeService; - private IContentSection contentSection; public DataTypeSerializer(IEntityService entityService, ILogger logger, - IDataTypeService dataTypeService, IContentSection contentSection) + IDataTypeService dataTypeService) : base(entityService, logger, UmbracoObjectTypes.DataTypeContainer) { this.dataTypeService = dataTypeService; - this.contentSection = contentSection; } protected override SyncAttempt DeserializeCore(XElement node) @@ -66,7 +64,7 @@ protected override SyncAttempt DeserializeCore(XElement node) SetFolderFromElement(item, info.Element("Folder")); - dataTypeService.Save(item); + // dataTypeService.Save(item); return SyncAttempt.Succeed(item.Name, item, ChangeType.Import); @@ -180,6 +178,12 @@ protected override IEnumerable FindContainers(string folder, in protected override Attempt> FindContainers(int parentId, string name) => dataTypeService.CreateContainer(parentId, name); + protected override void SaveItem(IDataType item) + => dataTypeService.Save(item); + + public override void Save(IEnumerable items) + => dataTypeService.Save(items); + protected override void SaveContainer(EntityContainer container) => dataTypeService.SaveContainer(container); } diff --git a/uSync8.Core/Serialization/Serializers/LanguageSerializer.cs b/uSync8.Core/Serialization/Serializers/LanguageSerializer.cs index 66b08c23..533795a3 100644 --- a/uSync8.Core/Serialization/Serializers/LanguageSerializer.cs +++ b/uSync8.Core/Serialization/Serializers/LanguageSerializer.cs @@ -52,8 +52,8 @@ protected override SyncAttempt DeserializeCore(XElement node) if (fallback > 0) item.FallbackLanguageId = fallback; - logger.Debug("Saving Language"); - localizationService.Save(item); + // logger.Debug("Saving Language"); + //localizationService.Save(item); return SyncAttempt.Succeed(item.CultureName, item, ChangeType.Import); } @@ -88,6 +88,9 @@ protected override ILanguage FindItem(string alias) => protected override ILanguage FindItem(Guid key) => default(ILanguage); + protected override void SaveItem(ILanguage item) + => localizationService.Save(item); + protected override XElement CleanseNode(XElement node) { node.Attribute("Key").Value = ""; diff --git a/uSync8.Core/Serialization/Serializers/MacroSerializer.cs b/uSync8.Core/Serialization/Serializers/MacroSerializer.cs index a0e1d698..cf0fc87a 100644 --- a/uSync8.Core/Serialization/Serializers/MacroSerializer.cs +++ b/uSync8.Core/Serialization/Serializers/MacroSerializer.cs @@ -97,7 +97,7 @@ protected override SyncAttempt DeserializeCore(XElement node) RemoveOrphanProperties(item, properties); - macroService.Save(item); + // macroService.Save(item); var attempt = SyncAttempt.Succeed(item.Name, item, ChangeType.Import); if (changes.Any()) @@ -171,5 +171,7 @@ protected override IMacro FindItem(Guid key) protected override IMacro FindItem(string alias) => macroService.GetByAlias(alias); + protected override void SaveItem(IMacro item) + => macroService.Save(item); } } diff --git a/uSync8.Core/Serialization/Serializers/MediaTypeSerializer.cs b/uSync8.Core/Serialization/Serializers/MediaTypeSerializer.cs index b96ade5e..3066112d 100644 --- a/uSync8.Core/Serialization/Serializers/MediaTypeSerializer.cs +++ b/uSync8.Core/Serialization/Serializers/MediaTypeSerializer.cs @@ -69,7 +69,7 @@ protected override SyncAttempt DeserializeCore(XElement node) CleanTabs(item, node); - mediaTypeService.Save(item); + // mediaTypeService.Save(item); return SyncAttempt.Succeed( item.Name, @@ -82,7 +82,8 @@ public override SyncAttempt DeserializeSecondPass(IMediaType item, X { DeserializeCompositions(item, node); DeserializeStructure(item, node); - mediaTypeService.Save(item); + + // mediaTypeService.Save(item); return SyncAttempt.Succeed(item.Name, item, ChangeType.Import); } diff --git a/uSync8.Core/Serialization/Serializers/MemberTypeSerializer.cs b/uSync8.Core/Serialization/Serializers/MemberTypeSerializer.cs index 9023074e..ea95c193 100644 --- a/uSync8.Core/Serialization/Serializers/MemberTypeSerializer.cs +++ b/uSync8.Core/Serialization/Serializers/MemberTypeSerializer.cs @@ -72,7 +72,7 @@ protected override SyncAttempt DeserializeCore(XElement node) CleanTabs(item, node); - memberTypeService.Save(item); + // memberTypeService.Save(item); return SyncAttempt.Succeed( item.Name, diff --git a/uSync8.Core/Serialization/Serializers/TemplateSerializer.cs b/uSync8.Core/Serialization/Serializers/TemplateSerializer.cs index b2d179c3..e23594da 100644 --- a/uSync8.Core/Serialization/Serializers/TemplateSerializer.cs +++ b/uSync8.Core/Serialization/Serializers/TemplateSerializer.cs @@ -82,7 +82,8 @@ protected override SyncAttempt DeserializeCore(XElement node) item.SetMasterTemplate(masterItem); } - fileService.SaveTemplate(item); + // Deserialize now takes care of the save. + // fileService.SaveTemplate(item); return SyncAttempt.Succeed(item.Name, item, ChangeType.Import); } @@ -123,7 +124,10 @@ protected override ITemplate FindItem(string alias) protected override ITemplate FindItem(Guid key) => fileService.GetTemplate(key); + protected override void SaveItem(ITemplate item) + => fileService.SaveTemplate(item); - + public override void Save(IEnumerable items) + => fileService.SaveTemplate(items); } } diff --git a/uSync8.Core/Serialization/SyncSerializerBase.cs b/uSync8.Core/Serialization/SyncSerializerBase.cs index c559842d..2e10039b 100644 --- a/uSync8.Core/Serialization/SyncSerializerBase.cs +++ b/uSync8.Core/Serialization/SyncSerializerBase.cs @@ -14,6 +14,7 @@ namespace uSync8.Core.Serialization { + public abstract class SyncSerializerBase : IDiscoverable where TObject : IEntity { @@ -56,8 +57,9 @@ public SyncAttempt Serialize(TObject item) { return SerializeCore(item); } + - public SyncAttempt Deserialize(XElement node, bool force, bool OnePass) + public SyncAttempt Deserialize(XElement node, SerializerFlags flags) { if (IsEmpty(node)) { @@ -70,14 +72,33 @@ public SyncAttempt Deserialize(XElement node, bool force, bool OnePass) throw new FormatException($"XML Not valid for type {ItemType}"); - if (force || IsCurrent(node) > ChangeType.NoChange) + if ( flags.HasFlag(SerializerFlags.Force) || IsCurrent(node) > ChangeType.NoChange) { logger.Debug("Base: Deserializing"); var result = DeserializeCore(node); - if (OnePass && result.Success) + + if (result.Success) { - logger.Debug("Base: Second Pass"); - DeserializeSecondPass(result.Item, node); + if (!flags.HasFlag(SerializerFlags.DoNotSave)) + { + // save + SaveItem(result.Item); + } + + if (flags.HasFlag(SerializerFlags.OnePass)) + { + logger.Debug("Base: Second Pass"); + var secondAttempt = DeserializeSecondPass(result.Item, node); + if (secondAttempt.Success) + { + + if (!flags.HasFlag(SerializerFlags.DoNotSave)) + { + // save (again) + SaveItem(secondAttempt.Item); + } + } + } } return result; @@ -193,6 +214,20 @@ private string MakeHash(XElement node) protected abstract TObject FindItem(Guid key); protected abstract TObject FindItem(string alias); + protected abstract void SaveItem(TObject item); + + /// + /// for bulk saving, some services do this, it causes less cache hits and + /// so should be faster. + /// + public virtual void Save(IEnumerable items) + { + foreach(var item in items) + { + this.SaveItem(item); + } + } + public virtual TObject FindItem(XElement node) { var (key, alias) = FindKeyAndAlias(node); diff --git a/uSync8.Core/Tracking/SyncBaseTracker.cs b/uSync8.Core/Tracking/SyncBaseTracker.cs index fc91ee0d..a68956b6 100644 --- a/uSync8.Core/Tracking/SyncBaseTracker.cs +++ b/uSync8.Core/Tracking/SyncBaseTracker.cs @@ -1,8 +1,11 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.IO; using System.Linq; using System.Xml.Linq; using System.Xml.XPath; using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.Models.Entities; using uSync8.Core.Extensions; using uSync8.Core.Models; diff --git a/uSync8.Core/uSync8.Core.csproj b/uSync8.Core/uSync8.Core.csproj index 275f7bed..f4840752 100644 --- a/uSync8.Core/uSync8.Core.csproj +++ b/uSync8.Core/uSync8.Core.csproj @@ -152,6 +152,7 @@ + diff --git a/uSync8.Site/App_Plugins/uSync8/dashboard.html b/uSync8.Site/App_Plugins/uSync8/dashboard.html index 111d4f4c..349ae353 100644 --- a/uSync8.Site/App_Plugins/uSync8/dashboard.html +++ b/uSync8.Site/App_Plugins/uSync8/dashboard.html @@ -69,7 +69,7 @@

uSync 8

{{vm.status.Message}}

{{vm.update.Message}} -
+
diff --git a/uSync8.Site/App_Plugins/uSync8/usync.css b/uSync8.Site/App_Plugins/uSync8/usync.css index 0ed39205..afce1e98 100644 --- a/uSync8.Site/App_Plugins/uSync8/usync.css +++ b/uSync8.Site/App_Plugins/uSync8/usync.css @@ -118,4 +118,8 @@ .usync-root-folder input { width: 100%; - } \ No newline at end of file + } + +.usync-not-animated .bar { + transition: none; +} \ No newline at end of file diff --git a/uSync8.Site/Web.config b/uSync8.Site/Web.config index 360595fd..4d0cc2d0 100644 --- a/uSync8.Site/Web.config +++ b/uSync8.Site/Web.config @@ -1,5 +1,5 @@  - +