private IList<FieldDesynchronization> GetFieldSyncStatus(SitecoreSourceItem item, ISerializedItem serializedItem, IFieldPredicate fieldPredicate) { var desyncs = new List<FieldDesynchronization>(); var serializedVersion = serializedItem.Versions.FirstOrDefault(x => x.VersionNumber == item.InnerItem.Version.Number && x.Language == item.InnerItem.Language.Name); if (serializedVersion == null) { desyncs.Add(new FieldDesynchronization("Version")); return desyncs; } item.InnerItem.Fields.ReadAll(); foreach (Field field in item.InnerItem.Fields) { if (field.ID == FieldIDs.Revision || field.ID == FieldIDs.Updated || field.ID == FieldIDs.Created || field.ID == FieldIDs.CreatedBy || field.ID == FieldIDs.UpdatedBy || field.Type.Equals("attachment", StringComparison.OrdinalIgnoreCase) || !fieldPredicate.Includes(field.ID).IsIncluded) continue; // we're doing a data comparison here - revision, created (by), updated (by) don't matter // skipping these fields allows us to ignore spurious saves the template builder makes to unchanged items being conflicts // find the field in the serialized item in either versioned or shared fields string serializedField; if(!serializedVersion.Fields.TryGetValue(field.ID.ToString(), out serializedField)) serializedItem.SharedFields.TryGetValue(field.ID.ToString(), out serializedField); // we ignore if the field doesn't exist in the serialized item. This is because if you added a field to a template, // that does not immediately re-serialize all items based on that template so it's likely innocuous - we're not overwriting anything. if (serializedField == null) continue; if (!serializedField.Equals(field.Value, StringComparison.Ordinal)) { desyncs.Add(new FieldDesynchronization(field.Name)); } } return desyncs; }
private string GetErrorValue(SaveArgs args) { var results = new Dictionary<Item, IList<FieldDesynchronization>>(); try { foreach (var item in args.Items) { Item existingItem = Client.ContentDatabase.GetItem(item.ID, item.Language, item.Version); Assert.IsNotNull(existingItem, "Existing item {0} did not exist! This should never occur.", item.ID); var existingSitecoreItem = new SitecoreSourceItem(existingItem); foreach (var configuration in _configurations) { // ignore conflicts on items that Unicorn is not managing if (!configuration.Resolve<IPredicate>().Includes(existingSitecoreItem).IsIncluded) continue; ISerializedReference serializedReference = configuration.Resolve<ISerializationProvider>().GetReference(existingSitecoreItem); if(serializedReference == null) continue; // not having an existing serialized version means no possibility of conflict here ISerializedItem serializedItem = serializedReference.GetItem(); if (serializedItem == null) continue; var fieldPredicate = configuration.Resolve<IFieldPredicate>(); var fieldIssues = GetFieldSyncStatus(existingSitecoreItem, serializedItem, fieldPredicate); if (fieldIssues.Count == 0) continue; results.Add(existingItem, fieldIssues); } } // no problems if (results.Count == 0) return null; var sb = new StringBuilder(); sb.Append("CRITICAL MESSAGE FROM UNICORN:\n"); sb.Append("You need to run a Unicorn sync. The following fields did not match the serialized version:\n"); foreach (var item in results) { if(results.Count > 1) sb.AppendFormat("\n{0}: {1}", item.Key.DisplayName, string.Join(", ", item.Value.Select(x => x.FieldName))); else sb.AppendFormat("\n{0}", string.Join(", ", item.Value.Select(x => x.FieldName))); } sb.Append("\n\nDo you want to overwrite anyway?\nTHIS MAY CAUSE LOST WORK."); return sb.ToString(); } catch (Exception ex) { Log.Error("Exception occurred while performing serialization conflict check!", ex, this); return "Exception occurred: " + ex.Message; // this will cause a few retries } }
public void CopyItem(ItemDefinition source, ItemDefinition destination, string copyName, ID copyId, CallContext context) { if (DisableSerialization) return; // copying is easy - all we have to do is serialize the copyID. Copied children will all result in multiple calls to CopyItem so we don't even need to worry about them. var copiedItem = new SitecoreSourceItem(Database.GetItem(copyId)); if (!_predicate.Includes(copiedItem).IsIncluded) return; // destination parent is not in a path that we are serializing, so skip out _serializationProvider.SerializeItem(copiedItem); _logger.CopiedItem(_serializationProvider.LogName, () => GetSourceFromDefinition(source), copiedItem); }