133 lines
5.3 KiB
C#
133 lines
5.3 KiB
C#
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
using NDB.Infrastructure.DatabaseMigration.Models;
|
|
using NDB.Infrastructure.DatabaseMigration.Repositories;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using System.Xml;
|
|
using System.Xml.Serialization;
|
|
|
|
namespace NDB.Infrastructure.DatabaseMigration.Services
|
|
{
|
|
internal class MigrationService : IMigrationService
|
|
{
|
|
private readonly string _migrationSignaturesFilePath;
|
|
private const string _migrationSignaturesFileName = "MigrationSignatures.xml";
|
|
private readonly ILogger<MigrationService> _logger;
|
|
private readonly IServiceProvider _serviceProvider;
|
|
private readonly ServiceConfiguration _configuration;
|
|
|
|
public MigrationService(ILogger<MigrationService> logger, IServiceProvider serviceProvider, ServiceConfiguration configuration)
|
|
{
|
|
_migrationSignaturesFilePath = Path.Combine(configuration.Workspace, _migrationSignaturesFileName);
|
|
_logger = logger;
|
|
_serviceProvider = serviceProvider;
|
|
_configuration = configuration;
|
|
}
|
|
|
|
private void CheckWorkspace()
|
|
{
|
|
if (string.IsNullOrEmpty(_configuration.Workspace))
|
|
throw new Exception($"Workspace path is empty! Check 'Workspace' parameter.");
|
|
|
|
if (!Directory.Exists(_configuration.Workspace))
|
|
Directory.CreateDirectory(_configuration.Workspace);
|
|
}
|
|
|
|
private MigrationSignature[] GetMigrationSignatures()
|
|
{
|
|
if (!File.Exists(_migrationSignaturesFilePath))
|
|
return null;
|
|
|
|
var serializer = new XmlSerializer(typeof(MigrationThumbprint));
|
|
using (var reader = XmlReader.Create(_migrationSignaturesFilePath))
|
|
{
|
|
var migrationSignatureRoot = (MigrationThumbprint)serializer.Deserialize(reader);
|
|
return migrationSignatureRoot.MigrationSignatures;
|
|
}
|
|
}
|
|
|
|
private void SaveMigrationSignatures(MigrationSignature[] migrationSignatures)
|
|
{
|
|
var root = new MigrationThumbprint() { MigrationSignatures = migrationSignatures };
|
|
var serializer = new XmlSerializer(root.GetType());
|
|
var settings = new XmlWriterSettings() { Indent = true };
|
|
using (var writer = XmlWriter.Create(_migrationSignaturesFilePath, settings))
|
|
{
|
|
serializer.Serialize(writer, root);
|
|
}
|
|
}
|
|
|
|
public void Execute()
|
|
{
|
|
_logger.LogInformation("Starting migration...");
|
|
|
|
CheckWorkspace();
|
|
|
|
var localSignatures = GetMigrationSignatures();
|
|
var lastInstalledVersion = localSignatures?.OrderByDescending(z => z.MigrationDate).FirstOrDefault()?.LastVersion ?? "0.0.0";
|
|
var targetVersion = new Version(lastInstalledVersion);
|
|
var scriptPacks = GetScriptPacks();
|
|
var packsToInstall = scriptPacks.Where(p => p.Version > targetVersion);
|
|
|
|
if (!packsToInstall.Any())
|
|
{
|
|
_logger.LogInformation("Nothing to migrate.");
|
|
return;
|
|
}
|
|
|
|
var signature = new MigrationSignature() { MachineName = System.Environment.MachineName, MigrationDate = DateTime.Now };
|
|
var migratedVersions = new List<MigratedVersion>();
|
|
|
|
foreach (var pack in packsToInstall.OrderBy(p => p.Version))
|
|
{
|
|
var scripts = Directory.GetFiles(pack.Path);
|
|
if (!scripts.Any())
|
|
continue;
|
|
|
|
_logger.LogInformation($"Running script pack: '{pack.Version}'");
|
|
|
|
Array.ForEach(scripts, s => RunScript(s));
|
|
var migratedVersion = new MigratedVersion() { Version = pack.Version.ToString(), Scripts = scripts.Select(z => Path.GetFileName(z)).ToArray() };
|
|
migratedVersions.Add(migratedVersion);
|
|
}
|
|
|
|
signature.MigratedVersions = migratedVersions.ToArray();
|
|
signature.LastVersion = packsToInstall.OrderByDescending(z => z.Version).First().Version.ToString();
|
|
|
|
var signatures = localSignatures != null ? new List<MigrationSignature>(localSignatures) : new List<MigrationSignature>();
|
|
signatures.Add(signature);
|
|
|
|
SaveMigrationSignatures(signatures.ToArray());
|
|
}
|
|
|
|
private ScriptPack[] GetScriptPacks()
|
|
{
|
|
var scripts = Directory.GetDirectories(_configuration.ScriptsDirectory);
|
|
var packs = scripts.Select(z => new ScriptPack() { Path = z, Version = new Version(new DirectoryInfo(z).Name) });
|
|
|
|
return packs.ToArray();
|
|
}
|
|
|
|
private void RunScript(string path)
|
|
=> RunScriptAsync(path).GetAwaiter().GetResult();
|
|
|
|
private async Task RunScriptAsync(string path)
|
|
{
|
|
_logger.LogInformation($"Running sql script: '{path}'");
|
|
var sqlContent = File.ReadAllText(path);
|
|
if (string.IsNullOrEmpty(sqlContent))
|
|
return;
|
|
|
|
using (var scope = _serviceProvider.CreateScope())
|
|
{
|
|
var _repository = scope.ServiceProvider.GetRequiredService<IMigrationRepository>();
|
|
await _repository.ExecuteSqlRaw(sqlContent);
|
|
}
|
|
}
|
|
}
|
|
}
|