<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Orchard.ContentManagement.MetaData;
using Orchard.Data.Migration.Interpreters;
using Orchard.Data.Migration.Records;
using Orchard.Data.Migration.Schema;
using Orchard.Environment.Extensions;
using Orchard.Localization;
using Orchard.Logging;

namespace Orchard.Data.Migration {
    /// <summary>
    /// Reponsible for maintaining the knowledge of data migration in a per tenant table
    /// </summary>
    public class DataMigrationManager : IDataMigrationManager {
        private readonly IEnumerable<IDataMigration> _dataMigrations;
        private readonly IRepository<DataMigrationRecord> _dataMigrationRepository;
        private readonly IExtensionManager _extensionManager;
        private readonly IDataMigrationInterpreter _interpreter;
        private readonly IContentDefinitionManager _contentDefinitionManager;
        private readonly ITransactionManager _transactionManager;

        private List<string> _processedFeatures;

        public DataMigrationManager(
            IEnumerable<IDataMigration> dataMigrations,
            IRepository<DataMigrationRecord> dataMigrationRepository,
            IExtensionManager extensionManager,
            IDataMigrationInterpreter interpreter,
            IContentDefinitionManager contentDefinitionManager,
            ITransactionManager transactionManager) {
            _dataMigrations = dataMigrations;
            _dataMigrationRepository = dataMigrationRepository;
            _extensionManager = extensionManager;
            _interpreter = interpreter;
            _contentDefinitionManager = contentDefinitionManager;
            _transactionManager = transactionManager;

            _processedFeatures = new List<string>();
            Logger = NullLogger.Instance;
        }
        public Localizer T { get; set; }
        public ILogger Logger { get; set; }

        public IEnumerable<string> GetFeaturesThatNeedUpdate() {
            var currentVersions = _dataMigrationRepository.Table.ToDictionary(r => r.DataMigrationClass);

            var outOfDateMigrations = _dataMigrations.Where(dataMigration => {
                DataMigrationRecord record;
                if (currentVersions.TryGetValue(dataMigration.GetType().FullName, out record))
                    return CreateUpgradeLookupTable(dataMigration).ContainsKey(record.Version.Value);

                return (GetCreateMethod(dataMigration) != null);
            });

            return outOfDateMigrations.Select(m => m.Feature.Descriptor.Id).ToList();
        }

        public void Update(IEnumerable<string> features) {
            foreach (var feature in features) {
                if (!_processedFeatures.Contains(feature)) {
                    Update(feature);
                }
            }
        }

        public void Update(string feature) {
            if (_processedFeatures.Contains(feature)) {
                return;
            }

            _processedFeatures.Add(feature);

            Logger.Information("Updating feature: {0}", feature);

            // proceed with dependent features first, whatever the module it's in
            var dependencies = _extensionManager.AvailableFeatures()
                .Where(f => String.Equals(f.Id, feature, StringComparison.OrdinalIgnoreCase))
                .Where(f => f.Dependencies != null)
                .SelectMany(f => f.Dependencies)
                .ToList();

            foreach (var dependency in dependencies) {
                Update(dependency);
            }

            var migrations = GetDataMigrations(feature);

            // apply update methods to each migration class for the module
            foreach (var migration in migrations) {
                // copy the object for the Linq query
                var tempMigration = migration;

                // get current version for this migration
                var dataMigrationRecord = GetDataMigrationRecord(tempMigration);

                var current = 0;
                if (dataMigrationRecord != null) {
                    current = dataMigrationRecord.Version.Value;
                }

                try {
                    _transactionManager.RequireNew();

                    // do we need to call Create() ?
                    if (current == 0) {
                        // try to resolve a Create method

                        var createMethod = GetCreateMethod(migration);
                        if (createMethod != null) {
                            current = (int)createMethod.Invoke(migration, new object[0]);
                        }
                    }

                    var lookupTable = CreateUpgradeLookupTable(migration);

                    while (lookupTable.ContainsKey(current)) {
                        try {
                            Logger.Information("Applying migration for {0} from version {1}", feature, current);
                            current = (int)lookupTable[current].Invoke(migration, new object[0]);
                        }
                        catch (Exception ex) {
                            Logger.Error(ex, "An unexpected error occurred while applying migration on {0} from version {1}", feature, current);
                            throw;
                        }
                    }

                    // if current is 0, it means no upgrade/create method was found or succeeded 
                    if (current == 0) {
                        continue;
                    }
                    if (dataMigrationRecord == null) {
                        _dataMigrationRepository.Create(new DataMigrationRecord { Version = current, DataMigrationClass = migration.GetType().FullName });
                    }
                    else {
                        dataMigrationRecord.Version = current;
                    }

                    _transactionManager.RequireNew();
                }
                catch (Exception e) {
                    Logger.Error(e, "Error while running migration version {0} for {1}", current, feature);
                    _transactionManager.Cancel();
                }

            }
        }

        public void Uninstall(string feature) {
            Logger.Information("Uninstalling feature: {0}", feature);

            var migrations = GetDataMigrations(feature);<commit_msg>Removing unnecessary transaction<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Orchard.ContentManagement.MetaData;
using Orchard.Data.Migration.Interpreters;
using Orchard.Data.Migration.Records;
using Orchard.Data.Migration.Schema;
using Orchard.Environment.Extensions;
using Orchard.Localization;
using Orchard.Logging;

namespace Orchard.Data.Migration {
    /// <summary>
    /// Reponsible for maintaining the knowledge of data migration in a per tenant table
    /// </summary>
    public class DataMigrationManager : IDataMigrationManager {
        private readonly IEnumerable<IDataMigration> _dataMigrations;
        private readonly IRepository<DataMigrationRecord> _dataMigrationRepository;
        private readonly IExtensionManager _extensionManager;
        private readonly IDataMigrationInterpreter _interpreter;
        private readonly IContentDefinitionManager _contentDefinitionManager;
        private readonly ITransactionManager _transactionManager;

        private List<string> _processedFeatures;

        public DataMigrationManager(
            IEnumerable<IDataMigration> dataMigrations,
            IRepository<DataMigrationRecord> dataMigrationRepository,
            IExtensionManager extensionManager,
            IDataMigrationInterpreter interpreter,
            IContentDefinitionManager contentDefinitionManager,
            ITransactionManager transactionManager) {
            _dataMigrations = dataMigrations;
            _dataMigrationRepository = dataMigrationRepository;
            _extensionManager = extensionManager;
            _interpreter = interpreter;
            _contentDefinitionManager = contentDefinitionManager;
            _transactionManager = transactionManager;

            _processedFeatures = new List<string>();
            Logger = NullLogger.Instance;
        }
        public Localizer T { get; set; }
        public ILogger Logger { get; set; }

        public IEnumerable<string> GetFeaturesThatNeedUpdate() {
            var currentVersions = _dataMigrationRepository.Table.ToDictionary(r => r.DataMigrationClass);

            var outOfDateMigrations = _dataMigrations.Where(dataMigration => {
                DataMigrationRecord record;
                if (currentVersions.TryGetValue(dataMigration.GetType().FullName, out record))
                    return CreateUpgradeLookupTable(dataMigration).ContainsKey(record.Version.Value);

                return (GetCreateMethod(dataMigration) != null);
            });

            return outOfDateMigrations.Select(m => m.Feature.Descriptor.Id).ToList();
        }

        public void Update(IEnumerable<string> features) {
            foreach (var feature in features) {
                if (!_processedFeatures.Contains(feature)) {
                    Update(feature);
                }
            }
        }

        public void Update(string feature) {
            if (_processedFeatures.Contains(feature)) {
                return;
            }

            _processedFeatures.Add(feature);

            Logger.Information("Updating feature: {0}", feature);

            // proceed with dependent features first, whatever the module it's in
            var dependencies = _extensionManager.AvailableFeatures()
                .Where(f => String.Equals(f.Id, feature, StringComparison.OrdinalIgnoreCase))
                .Where(f => f.Dependencies != null)
                .SelectMany(f => f.Dependencies)
                .ToList();

            foreach (var dependency in dependencies) {
                Update(dependency);
            }

            var migrations = GetDataMigrations(feature);

            // apply update methods to each migration class for the module
            foreach (var migration in migrations) {
                // copy the object for the Linq query
                var tempMigration = migration;

                // get current version for this migration
                var dataMigrationRecord = GetDataMigrationRecord(tempMigration);

                var current = 0;
                if (dataMigrationRecord != null) {
                    current = dataMigrationRecord.Version.Value;
                }

                try {
                    _transactionManager.RequireNew();

                    // do we need to call Create() ?
                    if (current == 0) {
                        // try to resolve a Create method

                        var createMethod = GetCreateMethod(migration);
                        if (createMethod != null) {
                            current = (int)createMethod.Invoke(migration, new object[0]);
                        }
                    }

                    var lookupTable = CreateUpgradeLookupTable(migration);

                    while (lookupTable.ContainsKey(current)) {
                        try {
                            Logger.Information("Applying migration for {0} from version {1}", feature, current);
                            current = (int)lookupTable[current].Invoke(migration, new object[0]);
                        }
                        catch (Exception ex) {
                            Logger.Error(ex, "An unexpected error occurred while applying migration on {0} from version {1}", feature, current);
                            throw;
                        }
                    }

                    // if current is 0, it means no upgrade/create method was found or succeeded 
                    if (current == 0) {
                        continue;
                    }
                    if (dataMigrationRecord == null) {
                        _dataMigrationRepository.Create(new DataMigrationRecord { Version = current, DataMigrationClass = migration.GetType().FullName });
                    }
                    else {
                        dataMigrationRecord.Version = current;
                    }
                }
                catch (Exception e) {
                    Logger.Error(e, "Error while running migration version {0} for {1}", current, feature);
                    _transactionManager.Cancel();
                }

            }
        }

        public void Uninstall(string feature) {
            Logger.Information("Uninstalling feature: {0}", feature);

            var migrations = GetDataMigrations(feature);
{'fraction_non_alphanumeric': 0.0724342928660826, 'fraction_numerical': 0.002190237797246558, 'mean_word_length': 1.7939248251748252, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5557448', 'n_tokens_mistral': 2849, 'n_tokens_neox': 2738, 'n_words': 708}