/// <inheritdoc/> /// <exception cref="ArgumentOutOfRangeException"><c>hints.SourceModel</c> or <c>hints.TargetModel</c> /// is out of range.</exception> /// <exception cref="InvalidOperationException">Upgrade sequence validation has failed.</exception> public ReadOnlyList <NodeAction> GetUpgradeSequence(Difference difference, HintSet hints, IComparer comparer) { ArgumentValidator.EnsureArgumentNotNull(hints, nameof(hints)); ArgumentValidator.EnsureArgumentNotNull(comparer, nameof(comparer)); if (difference == null) { return(new ReadOnlyList <NodeAction>(Enumerable.Empty <NodeAction>().ToList())); } TemporaryRenames = new Dictionary <string, Node>(StringComparer.OrdinalIgnoreCase); SourceModel = (IModel)difference.Source; TargetModel = (IModel)difference.Target; Hints = hints ?? new HintSet(SourceModel, TargetModel); Comparer = comparer; if (Hints.SourceModel != SourceModel) { throw new ArgumentOutOfRangeException("hints.SourceModel"); } if (Hints.TargetModel != TargetModel) { throw new ArgumentOutOfRangeException("hints.TargetModel"); } CurrentModel = (IModel)SourceModel.Clone(null, SourceModel.Name); Difference = difference; var previous = currentAsync.Value; currentAsync.Value = this; using (NullActionHandler.Instance.Activate()) { try { var actions = new GroupingNodeAction(); ProcessStage(UpgradeStage.CleanupData, actions); ProcessStage(UpgradeStage.Prepare, actions); ProcessStage(UpgradeStage.TemporaryRename, actions); ProcessStage(UpgradeStage.Upgrade, actions); ProcessStage(UpgradeStage.CopyData, actions); ProcessStage(UpgradeStage.PostCopyData, actions); ProcessStage(UpgradeStage.Cleanup, actions); var validationHints = new HintSet(CurrentModel, TargetModel); Hints.OfType <IgnoreHint>() .Where(h => CurrentModel.Resolve(h.Path, false) != null && SourceModel.Resolve(h.Path, false) != null) .ForEach(validationHints.Add); var diff = comparer.Compare(CurrentModel, TargetModel, validationHints); if (diff != null) { CoreLog.InfoRegion(Strings.LogAutomaticUpgradeSequenceValidation); CoreLog.Info(Strings.LogValidationFailed); CoreLog.Info(Strings.LogItemFormat, Strings.Difference); CoreLog.Info("{0}", diff); CoreLog.Info(Strings.LogItemFormat + "\r\n{1}", Strings.UpgradeSequence, new ActionSequence() { actions }); CoreLog.Info(Strings.LogItemFormat, Strings.ExpectedTargetModel); TargetModel.Dump(); CoreLog.Info(Strings.LogItemFormat, Strings.ActualTargetModel); CurrentModel.Dump(); throw new InvalidOperationException(Strings.ExUpgradeSequenceValidationFailure); } return(new ReadOnlyList <NodeAction>(actions.Actions, true)); } finally { currentAsync.Value = previous; } } }