Update FluentMigrator to v4

pull/1032/head
ta264 5 years ago
parent d8d7a2c28a
commit ebf4859167

@ -2,5 +2,6 @@
<configuration>
<packageSources>
<add key="MyFeed" value="https://pkgs.dev.azure.com/Lidarr/Lidarr/_packaging/SQLite/nuget/v3/index.json" />
<add key="FluentMigrator" value="https://www.myget.org/F/fluent-migrator/api/v3/index.json" />
</packageSources>
</configuration>

@ -14,7 +14,7 @@ namespace NzbDrone.Core.Test.Datastore.SqliteSchemaDumperTests
[SetUp]
public void Setup()
{
Subject = new SqliteSchemaDumper(null, null);
Subject = new SqliteSchemaDumper(null);
}
[TestCase(@"CREATE TABLE TestTable (MyId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT)", "TestTable", "MyId")]

@ -5,6 +5,8 @@ using System.IO;
using System.Linq;
using FluentMigrator.Runner;
using Marr.Data;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using NUnit.Framework;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Datastore.Migration.Framework;
@ -96,9 +98,15 @@ namespace NzbDrone.Core.Test.Framework
return testDb;
}
protected virtual void SetupLogging()
{
Mocker.SetConstant<ILoggerProvider>(NullLoggerProvider.Instance);
}
protected void SetupContainer()
{
WithTempAsAppPath();
SetupLogging();
Mocker.SetConstant<IConnectionStringFactory>(Mocker.Resolve<ConnectionStringFactory>());
Mocker.SetConstant<IMigrationController>(Mocker.Resolve<MigrationController>());

@ -1,6 +1,6 @@
using System;
using FluentMigrator;
using FluentMigrator.Runner;
using Microsoft.Extensions.Logging;
using NUnit.Framework;
using NzbDrone.Core.Datastore.Migration.Framework;
@ -36,10 +36,14 @@ namespace NzbDrone.Core.Test.Framework
return db.GetDirectDataMapper();
}
protected override void SetupLogging()
{
Mocker.SetConstant<ILoggerProvider>(Mocker.Resolve<MigrationLoggerProvider>());
}
[SetUp]
public override void SetupDb()
{
Mocker.SetConstant<IAnnouncer>(Mocker.Resolve<MigrationLogger>());
SetupContainer();
}
}

@ -4,9 +4,10 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
{
public class MigrationContext
{
public static MigrationContext Current { get; set; }
public MigrationType MigrationType { get; private set; }
public long? DesiredVersion { get; set; }
public Action<NzbDroneMigrationBase> BeforeMigration { get; set; }
public MigrationContext(MigrationType migrationType, long? desiredVersion = null)

@ -1,8 +1,12 @@
using System.Data.SQLite;
using System;
using System.Diagnostics;
using System.Reflection;
using FluentMigrator.Runner;
using FluentMigrator.Runner.Initialization;
using FluentMigrator.Runner.Processors;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NLog;
namespace NzbDrone.Core.Datastore.Migration.Framework
{
@ -13,56 +17,58 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
public class MigrationController : IMigrationController
{
private readonly IAnnouncer _announcer;
private readonly Logger _logger;
private readonly ILoggerProvider _migrationLoggerProvider;
public MigrationController(IAnnouncer announcer)
public MigrationController(Logger logger,
ILoggerProvider migrationLoggerProvider)
{
_announcer = announcer;
_logger = logger;
_migrationLoggerProvider = migrationLoggerProvider;
}
public void Migrate(string connectionString, MigrationContext migrationContext)
{
var sw = Stopwatch.StartNew();
_announcer.Heading("Migrating " + connectionString);
_logger.Info("*** Migrating {0} ***", connectionString);
var assembly = Assembly.GetExecutingAssembly();
var serviceProvider = new ServiceCollection()
.AddLogging(lb => lb.AddProvider(_migrationLoggerProvider))
.AddFluentMigratorCore()
.ConfigureRunner(
builder => builder
.AddNzbDroneSQLite()
.WithGlobalConnectionString(connectionString)
.WithMigrationsIn(Assembly.GetExecutingAssembly()))
.Configure<TypeFilterOptions>(opt => opt.Namespace = "NzbDrone.Core.Datastore.Migration")
.Configure<ProcessorOptions>(opt => {
opt.PreviewOnly = false;
opt.Timeout = TimeSpan.FromSeconds(60);
})
.BuildServiceProvider();
var runnerContext = new RunnerContext(_announcer)
using (var scope = serviceProvider.CreateScope())
{
Namespace = "NzbDrone.Core.Datastore.Migration",
ApplicationContext = migrationContext
};
var runner = scope.ServiceProvider.GetRequiredService<IMigrationRunner>();
var options = new MigrationOptions { PreviewOnly = false, Timeout = 60 };
var factory = new NzbDroneSqliteProcessorFactory();
var processor = factory.Create(connectionString, _announcer, options);
try
{
var runner = new MigrationRunner(assembly, runnerContext, processor);
MigrationContext.Current = migrationContext;
if (migrationContext.DesiredVersion.HasValue)
{
runner.MigrateUp(migrationContext.DesiredVersion.Value, true);
runner.MigrateUp(migrationContext.DesiredVersion.Value);
}
else
{
runner.MigrateUp(true);
}
}
catch (SQLiteException)
{
processor.Dispose();
SQLiteConnection.ClearAllPools();
throw;
runner.MigrateUp();
}
processor.Dispose();
MigrationContext.Current = null;
}
sw.Stop();
_announcer.ElapsedTime(sw.Elapsed);
_logger.Debug("Took: {0}", sw.Elapsed);
}
}
}

@ -1,14 +0,0 @@
using System.Data.Common;
using System.Data.SQLite;
using FluentMigrator.Runner.Processors;
namespace NzbDrone.Core.Datastore.Migration.Framework
{
public class MigrationDbFactory : DbFactoryBase
{
protected override DbProviderFactory CreateFactory()
{
return SQLiteFactory.Instance;
}
}
}

@ -1,5 +1,11 @@
using FluentMigrator.Builders.Create;
using FluentMigrator;
using FluentMigrator.Builders.Create;
using FluentMigrator.Builders.Create.Table;
using FluentMigrator.Runner;
using FluentMigrator.Runner.BatchParser;
using FluentMigrator.Runner.Generators.SQLite;
using FluentMigrator.Runner.Processors.SQLite;
using Microsoft.Extensions.DependencyInjection;
namespace NzbDrone.Core.Datastore.Migration.Framework
{
@ -16,5 +22,18 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
parameter.Value = value;
command.Parameters.Add(parameter);
}
public static IMigrationRunnerBuilder AddNzbDroneSQLite(this IMigrationRunnerBuilder builder)
{
builder.Services
.AddTransient<SQLiteBatchParser>()
.AddScoped<SQLiteDbFactory>()
.AddScoped<NzbDroneSQLiteProcessor>()
.AddScoped<IMigrationProcessor>(sp => sp.GetRequiredService<NzbDroneSQLiteProcessor>())
.AddScoped<SQLiteQuoter>()
.AddScoped<SQLiteGenerator>()
.AddScoped<IMigrationGenerator>(sp => sp.GetRequiredService<SQLiteGenerator>());
return builder;
}
}
}

@ -1,58 +1,59 @@
using System;
using FluentMigrator.Runner;
using FluentMigrator.Runner.Logging;
using NLog;
namespace NzbDrone.Core.Datastore.Migration.Framework
{
public class MigrationLogger : IAnnouncer
public class MigrationLogger : FluentMigratorLogger
{
private readonly Logger _logger;
public MigrationLogger(Logger logger)
public MigrationLogger(Logger logger,
FluentMigratorLoggerOptions options)
: base(options)
{
_logger = logger;
}
public void Heading(string message)
protected override void WriteHeading(string message)
{
_logger.Info("*** {0} ***", message);
}
public void Say(string message)
protected override void WriteSay(string message)
{
_logger.Debug(message);
}
public void Emphasize(string message)
protected override void WriteEmphasize(string message)
{
_logger.Warn(message);
}
public void Sql(string sql)
protected override void WriteSql(string sql)
{
_logger.Debug(sql);
}
public void ElapsedTime(TimeSpan timeSpan)
protected override void WriteEmptySql()
{
_logger.Debug("Took: {0}", timeSpan);
_logger.Debug(@"No SQL statement executed.");
}
public void Error(string message)
protected override void WriteElapsedTime(TimeSpan timeSpan)
{
_logger.Error(message);
_logger.Debug("Took: {0}", timeSpan);
}
public void Error(Exception exception)
protected override void WriteError(string message)
{
_logger.Error(exception);
_logger.Error(message);
}
public void Write(string message, bool escaped)
protected override void WriteError(Exception exception)
{
_logger.Info(message);
_logger.Error(exception);
}
}
}

@ -0,0 +1,34 @@
using System;
using FluentMigrator.Runner;
using Microsoft.Extensions.Logging;
using NLog;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace NzbDrone.Core.Datastore.Migration.Framework
{
public class MigrationLoggerProvider : ILoggerProvider
{
private readonly Logger _logger;
public MigrationLoggerProvider(Logger logger)
{
_logger = logger;
}
public ILogger CreateLogger(string categoryName)
{
return new MigrationLogger(_logger, new FluentMigratorLoggerOptions() { ShowElapsedTime = true, ShowSql = true });
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// Nothing to clean up
}
}
}

@ -1,11 +0,0 @@
using FluentMigrator;
namespace NzbDrone.Core.Datastore.Migration.Framework
{
public class MigrationOptions : IMigrationProcessorOptions
{
public bool PreviewOnly { get; set; }
public int Timeout { get; set; }
public string ProviderSwitches { get; private set; }
}
}

@ -8,7 +8,6 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
public abstract class NzbDroneMigrationBase : FluentMigrator.Migration
{
protected readonly Logger _logger;
private MigrationContext _migrationContext;
protected NzbDroneMigrationBase()
{
@ -32,26 +31,14 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
}
}
public MigrationContext Context
{
get
{
if (_migrationContext == null)
{
_migrationContext = (MigrationContext)ApplicationContext;
}
return _migrationContext;
}
}
public override void Up()
{
if (Context.BeforeMigration != null)
if (MigrationContext.Current.BeforeMigration != null)
{
Context.BeforeMigration(this);
MigrationContext.Current.BeforeMigration(this);
}
switch (Context.MigrationType)
switch (MigrationContext.Current.MigrationType)
{
case MigrationType.Main:
_logger.Info("Starting migration to " + Version);

@ -1,28 +1,30 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using FluentMigrator;
using System.Text.RegularExpressions;
using FluentMigrator.Expressions;
using FluentMigrator.Model;
using FluentMigrator.Runner;
using FluentMigrator.Runner.Announcers;
using FluentMigrator.Runner.Generators.SQLite;
using FluentMigrator.Runner.Initialization;
using FluentMigrator.Runner.Processors;
using FluentMigrator.Runner.Processors.SQLite;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace NzbDrone.Core.Datastore.Migration.Framework
{
public class NzbDroneSqliteProcessor : SQLiteProcessor
public class NzbDroneSQLiteProcessor : SQLiteProcessor
{
public NzbDroneSqliteProcessor(IDbConnection connection, IMigrationGenerator generator, IAnnouncer announcer, IMigrationProcessorOptions options, FluentMigrator.Runner.Processors.IDbFactory factory)
: base(connection, generator, announcer, options, factory)
public NzbDroneSQLiteProcessor(SQLiteDbFactory factory,
SQLiteGenerator generator,
ILogger<NzbDroneSQLiteProcessor> logger,
IOptionsSnapshot<ProcessorOptions> options,
IConnectionStringAccessor connectionStringAccessor,
IServiceProvider serviceProvider)
: base(factory, generator, logger, options, connectionStringAccessor, serviceProvider)
{
}
public override bool SupportsTransactions => true;
public override void Process(AlterColumnExpression expression)
{
var tableDefinition = GetTableSchema(expression.TableName);
@ -107,7 +109,7 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
protected virtual TableDefinition GetTableSchema(string tableName)
{
var schemaDumper = new SqliteSchemaDumper(this, Announcer);
var schemaDumper = new SqliteSchemaDumper(this);
var schema = schemaDumper.ReadDbSchema();
return schema.Single(v => v.Name == tableName);

@ -1,18 +0,0 @@
using FluentMigrator;
using FluentMigrator.Runner;
using FluentMigrator.Runner.Generators.SQLite;
using FluentMigrator.Runner.Processors.SQLite;
namespace NzbDrone.Core.Datastore.Migration.Framework
{
public class NzbDroneSqliteProcessorFactory : SQLiteProcessorFactory
{
public override IMigrationProcessor Create(string connectionString, IAnnouncer announcer, IMigrationProcessorOptions options)
{
var factory = new MigrationDbFactory();
var connection = factory.CreateConnection(connectionString);
var generator = new SQLiteGenerator { compatabilityMode = CompatabilityMode.STRICT };
return new NzbDroneSqliteProcessor(connection, generator, announcer, options, factory);
}
}
}

@ -1,7 +1,6 @@
using System.Collections.Generic;
using System.Data;
using FluentMigrator.Model;
using FluentMigrator.Runner;
using FluentMigrator.Runner.Processors.SQLite;
namespace NzbDrone.Core.Datastore.Migration.Framework
@ -10,13 +9,11 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
// The original implementation had bad support for escaped identifiers, amongst other things.
public class SqliteSchemaDumper
{
public SqliteSchemaDumper(SQLiteProcessor processor, IAnnouncer announcer)
public SqliteSchemaDumper(SQLiteProcessor processor)
{
Announcer = announcer;
Processor = processor;
}
public virtual IAnnouncer Announcer { get; set; }
public SQLiteProcessor Processor { get; set; }
protected internal virtual TableDefinition ReadTableSchema(string sqlSchema)

@ -0,0 +1,54 @@
#region License
//
// Copyright (c) 2007-2009, Sean Chambers <schambers80@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using FluentMigrator.Infrastructure.Extensions;
using FluentMigrator.Model;
namespace NzbDrone.Core.Datastore.Migration.Framework
{
public class TableDefinition : ICloneable
{
public TableDefinition()
{
Columns = new List<ColumnDefinition>();
ForeignKeys = new List<ForeignKeyDefinition>();
Indexes = new List<IndexDefinition>();
}
public virtual string Name { get; set; }
public virtual string SchemaName { get; set; }
public virtual ICollection<ColumnDefinition> Columns { get; set; }
public virtual ICollection<ForeignKeyDefinition> ForeignKeys { get; set; }
public virtual ICollection<IndexDefinition> Indexes { get; set; }
public object Clone()
{
return new TableDefinition
{
Name = Name,
SchemaName = SchemaName,
Columns = Columns.CloneAll().ToList(),
Indexes = Indexes.CloneAll().ToList()
};
}
}
}

@ -4,7 +4,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.3" />
<PackageReference Include="FluentMigrator.Runner" Version="1.6.2" />
<PackageReference Include="FluentMigrator.Runner" Version="4.0.0-alpha.268" />
<PackageReference Include="FluentMigrator.Runner.SQLite" Version="4.0.0-alpha.268" />
<PackageReference Include="FluentValidation" Version="8.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="NLog" Version="4.6.7" />

Loading…
Cancel
Save