mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2025-09-27 04:21:27 +02:00
added better db migration support than what Subsonic provides out of the box.
This commit is contained in:
110
Migrator.net/Migrator/BaseMigrate.cs
Normal file
110
Migrator.net/Migrator/BaseMigrate.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using Migrator.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Migrator
|
||||
{
|
||||
public abstract class BaseMigrate
|
||||
{
|
||||
protected readonly ITransformationProvider _provider;
|
||||
protected ILogger _logger;
|
||||
protected List<long> _availableMigrations;
|
||||
protected List<long> _original;
|
||||
protected long _current;
|
||||
protected bool _dryrun;
|
||||
|
||||
protected BaseMigrate(List<long> availableMigrations, ITransformationProvider provider, ILogger logger)
|
||||
{
|
||||
_provider = provider;
|
||||
_availableMigrations = availableMigrations;
|
||||
_original = new List<long> (_provider.AppliedMigrations.ToArray()); //clone
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public static BaseMigrate GetInstance(List<long> availableMigrations, ITransformationProvider provider, ILogger logger)
|
||||
{
|
||||
return new MigrateAnywhere(availableMigrations, provider, logger);
|
||||
}
|
||||
|
||||
public List<long> AppliedVersions
|
||||
{
|
||||
get { return _original; }
|
||||
}
|
||||
|
||||
public virtual long Current
|
||||
{
|
||||
get { return _current; }
|
||||
protected set { _current = value; }
|
||||
}
|
||||
|
||||
public virtual bool DryRun
|
||||
{
|
||||
get { return _dryrun; }
|
||||
set { _dryrun = value; }
|
||||
}
|
||||
|
||||
public abstract long Previous { get; }
|
||||
public abstract long Next { get; }
|
||||
|
||||
public void Iterate()
|
||||
{
|
||||
Current = Next;
|
||||
}
|
||||
|
||||
public abstract bool Continue(long targetVersion);
|
||||
|
||||
public abstract void Migrate(IMigration migration);
|
||||
|
||||
/// <summary>
|
||||
/// Finds the next migration available to be applied. Only returns
|
||||
/// migrations that have NOT already been applied.
|
||||
/// </summary>
|
||||
/// <returns>The migration number of the next available Migration.</returns>
|
||||
protected long NextMigration()
|
||||
{
|
||||
// Start searching at the current index
|
||||
int migrationSearch = _availableMigrations.IndexOf(Current)+1;
|
||||
|
||||
// See if we can find a migration that matches the requirement
|
||||
while(migrationSearch < _availableMigrations.Count
|
||||
&& _provider.AppliedMigrations.Contains(_availableMigrations[migrationSearch]))
|
||||
{
|
||||
migrationSearch++;
|
||||
}
|
||||
|
||||
// did we exhaust the list?
|
||||
if(migrationSearch == _availableMigrations.Count){
|
||||
// we're at the last one. Done!
|
||||
return _availableMigrations[migrationSearch-1]+1;
|
||||
}
|
||||
// found one.
|
||||
return _availableMigrations[migrationSearch];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the previous migration that has been applied. Only returns
|
||||
/// migrations that HAVE already been applied.
|
||||
/// </summary>
|
||||
/// <returns>The most recently applied Migration.</returns>
|
||||
protected long PreviousMigration()
|
||||
{
|
||||
// Start searching at the current index
|
||||
int migrationSearch = _availableMigrations.IndexOf(Current)-1;
|
||||
|
||||
// See if we can find a migration that matches the requirement
|
||||
while(migrationSearch > -1
|
||||
&& !_provider.AppliedMigrations.Contains(_availableMigrations[migrationSearch]))
|
||||
{
|
||||
migrationSearch--;
|
||||
}
|
||||
|
||||
// did we exhaust the list?
|
||||
if(migrationSearch < 0){
|
||||
// we're at the first one. Done!
|
||||
return 0;
|
||||
}
|
||||
|
||||
// found one.
|
||||
return _availableMigrations[migrationSearch];
|
||||
}
|
||||
}
|
||||
}
|
118
Migrator.net/Migrator/Compile/ScriptEngine.cs
Normal file
118
Migrator.net/Migrator/Compile/ScriptEngine.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Migrator.Framework;
|
||||
|
||||
namespace Migrator.Compile
|
||||
{
|
||||
public class ScriptEngine
|
||||
{
|
||||
public readonly string[] extraReferencedAssemblies;
|
||||
|
||||
private readonly CodeDomProvider _provider;
|
||||
private string _codeType = "csharp";
|
||||
|
||||
public ScriptEngine() : this(null, null)
|
||||
{
|
||||
}
|
||||
|
||||
public ScriptEngine(string[] extraReferencedAssemblies)
|
||||
: this(null, extraReferencedAssemblies)
|
||||
{
|
||||
}
|
||||
|
||||
public ScriptEngine(string codeType, string[] extraReferencedAssemblies)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(codeType))
|
||||
_codeType = codeType;
|
||||
this.extraReferencedAssemblies = extraReferencedAssemblies;
|
||||
|
||||
// There is currently no way to generically create a CodeDomProvider and have it work with .NET 3.5
|
||||
_provider = CodeDomProvider.CreateProvider(_codeType);
|
||||
}
|
||||
|
||||
public Assembly Compile(string directory)
|
||||
{
|
||||
string[] files = GetFilesRecursive(directory);
|
||||
Console.Out.WriteLine("Compiling:");
|
||||
Array.ForEach(files, delegate(String file) { Console.Out.WriteLine(file); });
|
||||
|
||||
return Compile(files);
|
||||
}
|
||||
|
||||
private string[] GetFilesRecursive(string directory)
|
||||
{
|
||||
FileInfo[] files = GetFilesRecursive(new DirectoryInfo(directory));
|
||||
string[] fileNames = new string[files.Length];
|
||||
for (int i = 0; i < files.Length; i ++)
|
||||
{
|
||||
fileNames[i] = files[i].FullName;
|
||||
}
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
private FileInfo[] GetFilesRecursive(DirectoryInfo d)
|
||||
{
|
||||
List<FileInfo> files = new List<FileInfo>();
|
||||
files.AddRange(d.GetFiles(String.Format("*.{0}", _provider.FileExtension)));
|
||||
DirectoryInfo[] subDirs = d.GetDirectories();
|
||||
if (subDirs.Length > 0)
|
||||
{
|
||||
foreach (DirectoryInfo subDir in subDirs)
|
||||
{
|
||||
files.AddRange(GetFilesRecursive(subDir));
|
||||
}
|
||||
}
|
||||
|
||||
return files.ToArray();
|
||||
}
|
||||
|
||||
public Assembly Compile(params string[] files)
|
||||
{
|
||||
CompilerParameters parms = SetupCompilerParams();
|
||||
|
||||
CompilerResults compileResult = _provider.CompileAssemblyFromFile(parms, files);
|
||||
if (compileResult.Errors.Count != 0)
|
||||
{
|
||||
foreach (CompilerError err in compileResult.Errors)
|
||||
{
|
||||
Console.Error.WriteLine("{0} ({1}:{2}) {3}", err.FileName, err.Line, err.Column, err.ErrorText);
|
||||
}
|
||||
}
|
||||
return compileResult.CompiledAssembly;
|
||||
}
|
||||
|
||||
private CompilerParameters SetupCompilerParams()
|
||||
{
|
||||
string migrationFrameworkPath = FrameworkAssemblyPath();
|
||||
CompilerParameters parms = new CompilerParameters();
|
||||
parms.CompilerOptions = "/t:library";
|
||||
parms.GenerateInMemory = true;
|
||||
parms.IncludeDebugInformation = true;
|
||||
parms.OutputAssembly = Path.Combine(Path.GetDirectoryName(migrationFrameworkPath), "MyMigrations.dll");
|
||||
|
||||
Console.Out.WriteLine("Output assembly: " + parms.OutputAssembly);
|
||||
|
||||
// Add Default referenced assemblies
|
||||
parms.ReferencedAssemblies.Add("mscorlib.dll");
|
||||
parms.ReferencedAssemblies.Add("System.dll");
|
||||
parms.ReferencedAssemblies.Add("System.Data.dll");
|
||||
parms.ReferencedAssemblies.Add(FrameworkAssemblyPath());
|
||||
if (null != extraReferencedAssemblies && extraReferencedAssemblies.Length > 0)
|
||||
{
|
||||
Array.ForEach(extraReferencedAssemblies,
|
||||
delegate(String assemb) { parms.ReferencedAssemblies.Add(assemb); });
|
||||
}
|
||||
return parms;
|
||||
}
|
||||
|
||||
private static string FrameworkAssemblyPath()
|
||||
{
|
||||
string path = typeof (MigrationAttribute).Module.FullyQualifiedName;
|
||||
Console.Out.WriteLine("Framework DLL: " + path);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
26
Migrator.net/Migrator/DuplicatedVersionException.cs
Normal file
26
Migrator.net/Migrator/DuplicatedVersionException.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
#region License
|
||||
//The contents of this file are subject to the Mozilla Public License
|
||||
//Version 1.1 (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.mozilla.org/MPL/
|
||||
//Software distributed under the License is distributed on an "AS IS"
|
||||
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
//License for the specific language governing rights and limitations
|
||||
//under the License.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace Migrator
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception thrown when a migration number is not unique.
|
||||
/// </summary>
|
||||
public class DuplicatedVersionException : Exception
|
||||
{
|
||||
public DuplicatedVersionException(long version)
|
||||
: base(String.Format("Migration version #{0} is duplicated", version))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
26
Migrator.net/Migrator/IrreversibleMigrationException.cs
Normal file
26
Migrator.net/Migrator/IrreversibleMigrationException.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
#region License
|
||||
//The contents of this file are subject to the Mozilla Public License
|
||||
//Version 1.1 (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.mozilla.org/MPL/
|
||||
//Software distributed under the License is distributed on an "AS IS"
|
||||
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
//License for the specific language governing rights and limitations
|
||||
//under the License.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace Migrator
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception thrown in a migration <c>Down()</c> method
|
||||
/// when changes can't be undone.
|
||||
/// </summary>
|
||||
public class IrreversibleMigrationException : Exception
|
||||
{
|
||||
public IrreversibleMigrationException() : base("Irreversible migration")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
99
Migrator.net/Migrator/MigrateAnywhere.cs
Normal file
99
Migrator.net/Migrator/MigrateAnywhere.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Migrator.Framework;
|
||||
|
||||
namespace Migrator
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of MigrateAnywhere.
|
||||
/// </summary>
|
||||
public class MigrateAnywhere : BaseMigrate
|
||||
{
|
||||
private bool _goForward;
|
||||
|
||||
public MigrateAnywhere(List<long> availableMigrations, ITransformationProvider provider, ILogger logger)
|
||||
: base(availableMigrations, provider, logger)
|
||||
{
|
||||
_current = 0;
|
||||
if (provider.AppliedMigrations.Count > 0) {
|
||||
_current = provider.AppliedMigrations[provider.AppliedMigrations.Count - 1];
|
||||
}
|
||||
_goForward = false;
|
||||
}
|
||||
|
||||
public override long Next
|
||||
{
|
||||
get
|
||||
{
|
||||
return _goForward
|
||||
? NextMigration()
|
||||
: PreviousMigration();
|
||||
}
|
||||
}
|
||||
|
||||
public override long Previous
|
||||
{
|
||||
get
|
||||
{
|
||||
return _goForward
|
||||
? PreviousMigration()
|
||||
: NextMigration();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Continue(long version)
|
||||
{
|
||||
// If we're going backwards and our current is less than the target,
|
||||
// reverse direction. Also, start over at zero to make sure we catch
|
||||
// any merged migrations that are less than the current target.
|
||||
if (!_goForward && version >= Current)
|
||||
{
|
||||
_goForward = true;
|
||||
Current = 0;
|
||||
Iterate();
|
||||
}
|
||||
|
||||
// We always finish on going forward. So continue if we're still
|
||||
// going backwards, or if there are no migrations left in the forward direction.
|
||||
return !_goForward || Current <= version;
|
||||
}
|
||||
|
||||
public override void Migrate(IMigration migration)
|
||||
{
|
||||
_provider.BeginTransaction();
|
||||
MigrationAttribute attr = (MigrationAttribute)Attribute.GetCustomAttribute(migration.GetType(), typeof(MigrationAttribute));
|
||||
|
||||
if (_provider.AppliedMigrations.Contains(attr.Version)) {
|
||||
RemoveMigration(migration, attr);
|
||||
} else {
|
||||
ApplyMigration(migration, attr);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyMigration(IMigration migration, MigrationAttribute attr)
|
||||
{
|
||||
// we're adding this one
|
||||
_logger.MigrateUp(Current, migration.Name);
|
||||
if(! DryRun)
|
||||
{
|
||||
migration.Up();
|
||||
_provider.MigrationApplied(attr.Version);
|
||||
_provider.Commit();
|
||||
migration.AfterUp();
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveMigration(IMigration migration, MigrationAttribute attr)
|
||||
{
|
||||
// we're removing this one
|
||||
_logger.MigrateDown(Current, migration.Name);
|
||||
if (! DryRun)
|
||||
{
|
||||
migration.Down();
|
||||
_provider.MigrationUnApplied(attr.Version);
|
||||
_provider.Commit();
|
||||
migration.AfterDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
0
Migrator.net/Migrator/MigrateDown.cs
Normal file
0
Migrator.net/Migrator/MigrateDown.cs
Normal file
0
Migrator.net/Migrator/MigrateUp.cs
Normal file
0
Migrator.net/Migrator/MigrateUp.cs
Normal file
43
Migrator.net/Migrator/MigrationComparer.cs
Normal file
43
Migrator.net/Migrator/MigrationComparer.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
#region License
|
||||
//The contents of this file are subject to the Mozilla Public License
|
||||
//Version 1.1 (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.mozilla.org/MPL/
|
||||
//Software distributed under the License is distributed on an "AS IS"
|
||||
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
//License for the specific language governing rights and limitations
|
||||
//under the License.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Migrator.Framework;
|
||||
|
||||
namespace Migrator
|
||||
{
|
||||
/// <summary>
|
||||
/// Comparer of Migration by their version attribute.
|
||||
/// </summary>
|
||||
public class MigrationTypeComparer : IComparer<Type>
|
||||
{
|
||||
private readonly bool _ascending = true;
|
||||
|
||||
public MigrationTypeComparer(bool ascending)
|
||||
{
|
||||
_ascending = ascending;
|
||||
}
|
||||
|
||||
public int Compare(Type x, Type y)
|
||||
{
|
||||
MigrationAttribute attribOfX = (MigrationAttribute) Attribute.GetCustomAttribute(x, typeof(MigrationAttribute));
|
||||
MigrationAttribute attribOfY = (MigrationAttribute) Attribute.GetCustomAttribute(y, typeof(MigrationAttribute));
|
||||
|
||||
if (_ascending)
|
||||
return attribOfX.Version.CompareTo(attribOfY.Version);
|
||||
else
|
||||
return attribOfY.Version.CompareTo(attribOfX.Version);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
136
Migrator.net/Migrator/MigrationLoader.cs
Normal file
136
Migrator.net/Migrator/MigrationLoader.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Migrator.Framework;
|
||||
|
||||
namespace Migrator
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles inspecting code to find all of the Migrations in assemblies and reading
|
||||
/// other metadata such as the last revision, etc.
|
||||
/// </summary>
|
||||
public class MigrationLoader
|
||||
{
|
||||
private readonly ITransformationProvider _provider;
|
||||
private readonly List<Type> _migrationsTypes = new List<Type>();
|
||||
|
||||
public MigrationLoader(ITransformationProvider provider, Assembly migrationAssembly, bool trace)
|
||||
{
|
||||
_provider = provider;
|
||||
AddMigrations(migrationAssembly);
|
||||
|
||||
if (trace)
|
||||
{
|
||||
provider.Logger.Trace("Loaded migrations:");
|
||||
foreach (Type t in _migrationsTypes)
|
||||
{
|
||||
provider.Logger.Trace("{0} {1}", GetMigrationVersion(t).ToString().PadLeft(5), StringUtils.ToHumanName(t.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddMigrations(Assembly migrationAssembly)
|
||||
{
|
||||
if (migrationAssembly != null)
|
||||
_migrationsTypes.AddRange(GetMigrationTypes(migrationAssembly));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns registered migration <see cref="System.Type">types</see>.
|
||||
/// </summary>
|
||||
public List<Type> MigrationsTypes
|
||||
{
|
||||
get { return _migrationsTypes; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the last version of the migrations.
|
||||
/// </summary>
|
||||
public long LastVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_migrationsTypes.Count == 0)
|
||||
return 0;
|
||||
return GetMigrationVersion(_migrationsTypes[_migrationsTypes.Count - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check for duplicated version in migrations.
|
||||
/// </summary>
|
||||
/// <exception cref="CheckForDuplicatedVersion">CheckForDuplicatedVersion</exception>
|
||||
public void CheckForDuplicatedVersion()
|
||||
{
|
||||
List<long> versions = new List<long>();
|
||||
foreach (Type t in _migrationsTypes)
|
||||
{
|
||||
long version = GetMigrationVersion(t);
|
||||
|
||||
if (versions.Contains(version))
|
||||
throw new DuplicatedVersionException(version);
|
||||
|
||||
versions.Add(version);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collect migrations in one <c>Assembly</c>.
|
||||
/// </summary>
|
||||
/// <param name="asm">The <c>Assembly</c> to browse.</param>
|
||||
/// <returns>The migrations collection</returns>
|
||||
public static List<Type> GetMigrationTypes(Assembly asm)
|
||||
{
|
||||
List<Type> migrations = new List<Type>();
|
||||
foreach (Type t in asm.GetExportedTypes())
|
||||
{
|
||||
MigrationAttribute attrib =
|
||||
(MigrationAttribute) Attribute.GetCustomAttribute(t, typeof (MigrationAttribute));
|
||||
|
||||
if (attrib != null && typeof(IMigration).IsAssignableFrom(t) && !attrib.Ignore)
|
||||
{
|
||||
migrations.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
migrations.Sort(new MigrationTypeComparer(true));
|
||||
return migrations;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the version of the migration
|
||||
/// <see cref="MigrationAttribute">MigrationAttribute</see>.
|
||||
/// </summary>
|
||||
/// <param name="t">Migration type.</param>
|
||||
/// <returns>Version number sepcified in the attribute</returns>
|
||||
public static long GetMigrationVersion(Type t)
|
||||
{
|
||||
MigrationAttribute attrib = (MigrationAttribute)
|
||||
Attribute.GetCustomAttribute(t, typeof(MigrationAttribute));
|
||||
|
||||
return attrib.Version;
|
||||
}
|
||||
|
||||
public List<long> GetAvailableMigrations()
|
||||
{
|
||||
//List<int> availableMigrations = new List<int>();
|
||||
_migrationsTypes.Sort(new MigrationTypeComparer(true));
|
||||
return _migrationsTypes.ConvertAll(new Converter<Type, long>(GetMigrationVersion));
|
||||
}
|
||||
|
||||
public IMigration GetMigration(long version)
|
||||
{
|
||||
foreach (Type t in _migrationsTypes)
|
||||
{
|
||||
if (GetMigrationVersion(t) == version)
|
||||
{
|
||||
IMigration migration = (IMigration)Activator.CreateInstance(t);
|
||||
migration.Database = _provider;
|
||||
return migration;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
177
Migrator.net/Migrator/Migrator.cs
Normal file
177
Migrator.net/Migrator/Migrator.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
#region License
|
||||
|
||||
//The contents of this file are subject to the Mozilla Public License
|
||||
//Version 1.1 (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.mozilla.org/MPL/
|
||||
//Software distributed under the License is distributed on an "AS IS"
|
||||
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
//License for the specific language governing rights and limitations
|
||||
//under the License.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Migrator.Framework;
|
||||
using Migrator.Framework.Loggers;
|
||||
|
||||
namespace Migrator
|
||||
{
|
||||
/// <summary>
|
||||
/// Migrations mediator.
|
||||
/// </summary>
|
||||
public class Migrator
|
||||
{
|
||||
private readonly ITransformationProvider _provider;
|
||||
|
||||
private readonly MigrationLoader _migrationLoader;
|
||||
|
||||
private ILogger _logger = new Logger(false);
|
||||
protected bool _dryrun;
|
||||
private string[] _args;
|
||||
|
||||
public string[] args
|
||||
{
|
||||
get { return _args; }
|
||||
set { _args = value; }
|
||||
}
|
||||
|
||||
public Migrator(string provider, string connectionString, Assembly migrationAssembly)
|
||||
: this(provider, connectionString, migrationAssembly, false)
|
||||
{
|
||||
}
|
||||
|
||||
public Migrator(string provider, string connectionString, Assembly migrationAssembly, bool trace)
|
||||
: this(ProviderFactory.Create(provider, connectionString), migrationAssembly, trace)
|
||||
{
|
||||
}
|
||||
|
||||
public Migrator(string provider, string connectionString, Assembly migrationAssembly, bool trace, ILogger logger)
|
||||
: this(ProviderFactory.Create(provider, connectionString), migrationAssembly, trace, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace)
|
||||
: this(provider, migrationAssembly, trace, new Logger(trace, new ConsoleWriter()))
|
||||
{
|
||||
}
|
||||
|
||||
public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace, ILogger logger)
|
||||
{
|
||||
_provider = provider;
|
||||
Logger = logger;
|
||||
|
||||
_migrationLoader = new MigrationLoader(provider, migrationAssembly, trace);
|
||||
_migrationLoader.CheckForDuplicatedVersion();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns registered migration <see cref="System.Type">types</see>.
|
||||
/// </summary>
|
||||
public List<Type> MigrationsTypes
|
||||
{
|
||||
get { return _migrationLoader.MigrationsTypes; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run all migrations up to the latest. Make no changes to database if
|
||||
/// dryrun is true.
|
||||
/// </summary>
|
||||
public void MigrateToLastVersion()
|
||||
{
|
||||
MigrateTo(_migrationLoader.LastVersion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current migrations applied to the database.
|
||||
/// </summary>
|
||||
public List<long> AppliedMigrations
|
||||
{
|
||||
get { return _provider.AppliedMigrations; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the event logger.
|
||||
/// </summary>
|
||||
public ILogger Logger
|
||||
{
|
||||
get { return _logger; }
|
||||
set
|
||||
{
|
||||
_logger = value;
|
||||
_provider.Logger = value;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool DryRun
|
||||
{
|
||||
get { return _dryrun; }
|
||||
set { _dryrun = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Migrate the database to a specific version.
|
||||
/// Runs all migration between the actual version and the
|
||||
/// specified version.
|
||||
/// If <c>version</c> is greater then the current version,
|
||||
/// the <c>Up()</c> method will be invoked.
|
||||
/// If <c>version</c> lower then the current version,
|
||||
/// the <c>Down()</c> method of previous migration will be invoked.
|
||||
/// If <c>dryrun</c> is set, don't write any changes to the database.
|
||||
/// </summary>
|
||||
/// <param name="version">The version that must became the current one</param>
|
||||
public void MigrateTo(long version)
|
||||
{
|
||||
|
||||
if (_migrationLoader.MigrationsTypes.Count == 0)
|
||||
{
|
||||
_logger.Warn("No public classes with the Migration attribute were found.");
|
||||
return;
|
||||
}
|
||||
|
||||
bool firstRun = true;
|
||||
BaseMigrate migrate = BaseMigrate.GetInstance(_migrationLoader.GetAvailableMigrations(), _provider, _logger);
|
||||
migrate.DryRun = DryRun;
|
||||
Logger.Started(migrate.AppliedVersions, version);
|
||||
|
||||
while (migrate.Continue(version))
|
||||
{
|
||||
IMigration migration = _migrationLoader.GetMigration(migrate.Current);
|
||||
if (null == migration)
|
||||
{
|
||||
_logger.Skipping(migrate.Current);
|
||||
migrate.Iterate();
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (firstRun)
|
||||
{
|
||||
migration.InitializeOnce(_args);
|
||||
firstRun = false;
|
||||
}
|
||||
|
||||
migrate.Migrate(migration);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Exception(migrate.Current, migration.Name, ex);
|
||||
|
||||
// Oho! error! We rollback changes.
|
||||
Logger.RollingBack(migrate.Previous);
|
||||
_provider.Rollback();
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
migrate.Iterate();
|
||||
}
|
||||
|
||||
Logger.Finished(migrate.AppliedVersions, version);
|
||||
}
|
||||
}
|
||||
}
|
76
Migrator.net/Migrator/Migrator.csproj
Normal file
76
Migrator.net/Migrator/Migrator.csproj
Normal file
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Migrator</RootNamespace>
|
||||
<AssemblyName>Migrator</AssemblyName>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<UpgradeBackupLocation>
|
||||
</UpgradeBackupLocation>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>MigratorDotNet.snk</AssemblyOriginatorKeyFile>
|
||||
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Migrator\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Migrator\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\config\AssemblyInfo.cs">
|
||||
<Link>AssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="BaseMigrate.cs" />
|
||||
<Compile Include="Compile\ScriptEngine.cs" />
|
||||
<Compile Include="DuplicatedVersionException.cs" />
|
||||
<Compile Include="IrreversibleMigrationException.cs" />
|
||||
<Compile Include="MigrateAnywhere.cs" />
|
||||
<Compile Include="MigrationComparer.cs" />
|
||||
<Compile Include="MigrationLoader.cs" />
|
||||
<Compile Include="Migrator.cs" />
|
||||
<Compile Include="ProviderFactory.cs" />
|
||||
<Compile Include="Tools\SchemaDumper.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="MigratorDotNet.snk" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{B4F97281-0DBD-4835-9ED8-7DFB966E87FF}" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Migrator.Framework\Migrator.Framework.csproj">
|
||||
<Project>{5270F048-E580-486C-B14C-E5B9F6E539D4}</Project>
|
||||
<Name>Migrator.Framework</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Migrator.Providers\Migrator.Providers.csproj">
|
||||
<Project>{D58C68E4-D789-40F7-9078-C9F587D4363C}</Project>
|
||||
<Name>Migrator.Providers</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
BIN
Migrator.net/Migrator/MigratorDotNet.snk
Normal file
BIN
Migrator.net/Migrator/MigratorDotNet.snk
Normal file
Binary file not shown.
75
Migrator.net/Migrator/ProviderFactory.cs
Normal file
75
Migrator.net/Migrator/ProviderFactory.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
#region License
|
||||
|
||||
//The contents of this file are subject to the Mozilla Public License
|
||||
//Version 1.1 (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.mozilla.org/MPL/
|
||||
//Software distributed under the License is distributed on an "AS IS"
|
||||
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
//License for the specific language governing rights and limitations
|
||||
//under the License.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Migrator.Framework;
|
||||
using Migrator.Providers;
|
||||
|
||||
namespace Migrator
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles loading Provider implementations
|
||||
/// </summary>
|
||||
public class ProviderFactory
|
||||
{
|
||||
private static readonly Assembly providerAssembly;
|
||||
private static readonly Dictionary<String, object> dialects = new Dictionary<string, object>();
|
||||
static ProviderFactory()
|
||||
{
|
||||
|
||||
//string directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase);
|
||||
//string fullPath = Path.Combine(directory, "Migrator.Providers.dll");
|
||||
//if (fullPath.StartsWith("file:\\"))
|
||||
// fullPath = fullPath.Substring(6);
|
||||
//else if (fullPath.StartsWith("file:"))
|
||||
// fullPath = fullPath.Substring(5);
|
||||
providerAssembly = Assembly.GetAssembly(typeof(TransformationProvider));
|
||||
//providerAssembly = Assembly.LoadFrom("Migrator.Providers.dll");
|
||||
LoadDialects();
|
||||
}
|
||||
|
||||
public static ITransformationProvider Create(string providerName, string connectionString)
|
||||
{
|
||||
object dialectInstance = DialectForProvider(providerName);
|
||||
MethodInfo mi = dialectInstance.GetType().GetMethod("NewProviderForDialect", new Type[] {typeof (String)});
|
||||
return (ITransformationProvider)mi.Invoke(dialectInstance, new object[] { connectionString });
|
||||
}
|
||||
|
||||
public static object DialectForProvider(string providerName)
|
||||
{
|
||||
if (String.IsNullOrEmpty(providerName))
|
||||
return null;
|
||||
|
||||
foreach (string key in dialects.Keys)
|
||||
{
|
||||
if (0 < key.IndexOf(providerName, StringComparison.InvariantCultureIgnoreCase))
|
||||
return dialects[key];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void LoadDialects()
|
||||
{
|
||||
Type dialectType = providerAssembly.GetType("Migrator.Providers.Dialect");
|
||||
foreach (Type t in providerAssembly.GetTypes())
|
||||
{
|
||||
if (t.IsSubclassOf(dialectType))
|
||||
{
|
||||
dialects.Add(t.FullName, Activator.CreateInstance(t, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
70
Migrator.net/Migrator/Tools/SchemaDumper.cs
Normal file
70
Migrator.net/Migrator/Tools/SchemaDumper.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
#region License
|
||||
//The contents of this file are subject to the Mozilla Public License
|
||||
//Version 1.1 (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.mozilla.org/MPL/
|
||||
//Software distributed under the License is distributed on an "AS IS"
|
||||
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
//License for the specific language governing rights and limitations
|
||||
//under the License.
|
||||
#endregion
|
||||
|
||||
using System.IO;
|
||||
using Migrator.Framework;
|
||||
|
||||
namespace Migrator.Tools
|
||||
{
|
||||
public class SchemaDumper
|
||||
{
|
||||
private readonly ITransformationProvider _provider;
|
||||
|
||||
public SchemaDumper(string provider, string connectionString)
|
||||
{
|
||||
_provider = ProviderFactory.Create(provider, connectionString);
|
||||
}
|
||||
|
||||
public string Dump()
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
writer.WriteLine("using Migrator;\n");
|
||||
writer.WriteLine("[Migration(1)]");
|
||||
writer.WriteLine("public class SchemaDump : Migration");
|
||||
writer.WriteLine("{");
|
||||
writer.WriteLine("\tpublic override void Up()");
|
||||
writer.WriteLine("\t{");
|
||||
|
||||
foreach (string table in _provider.GetTables())
|
||||
{
|
||||
writer.WriteLine("\t\tDatabase.AddTable(\"{0}\",", table);
|
||||
foreach (Column column in _provider.GetColumns(table))
|
||||
{
|
||||
writer.WriteLine("\t\t\tnew Column(\"{0}\", typeof({1})),", column.Name, column.Type);
|
||||
}
|
||||
writer.WriteLine("\t\t);");
|
||||
}
|
||||
|
||||
writer.WriteLine("\t}\n");
|
||||
writer.WriteLine("\tpublic override void Down()");
|
||||
writer.WriteLine("\t{");
|
||||
|
||||
foreach (string table in _provider.GetTables())
|
||||
{
|
||||
writer.WriteLine("\t\tDatabase.RemoveTable(\"{0}\");", table);
|
||||
}
|
||||
|
||||
writer.WriteLine("\t}");
|
||||
writer.WriteLine("}");
|
||||
|
||||
return writer.ToString();
|
||||
}
|
||||
|
||||
public void DumpTo(string file)
|
||||
{
|
||||
using (StreamWriter writer = new StreamWriter(file))
|
||||
{
|
||||
writer.Write(Dump());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user