using Microsoft.Extensions.Logging; using System.Diagnostics; using System.Runtime.InteropServices; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; namespace CMS.Plugin.PipeLineLems.Domain.Data; /// /// 数据库迁移服务 /// public class CMSPluginDbMigrationService : ITransientDependency { private readonly IDataSeeder _dataSeeder; private readonly IEnumerable _dbSchemaMigrators; private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// /// The data seeder. /// The database schema migrators. /// The logger. public CMSPluginDbMigrationService(IDataSeeder dataSeeder, IEnumerable dbSchemaMigrators, ILogger logger) { _dataSeeder = dataSeeder; _dbSchemaMigrators = dbSchemaMigrators; _logger = logger; } /// /// Migrates the asynchronous. /// public async Task MigrateAsync() { var initialMigrationAdded = AddInitialMigrationIfNotExist(); if (initialMigrationAdded) { return; } _logger.LogDebug("Started database migrations..."); await MigrateDatabaseSchemaAsync(); await SeedDataAsync(); _logger.LogDebug($"Successfully completed host database migrations."); _logger.LogDebug("You can safely end this process..."); } /// /// Migrates the database schema asynchronous. /// private async Task MigrateDatabaseSchemaAsync() { _logger.LogDebug($"Migrating schema for database..."); foreach (var migrator in _dbSchemaMigrators) { await migrator.MigrateAsync(); } } /// /// Seeds the data asynchronous. /// private async Task SeedDataAsync() { _logger.LogDebug($"Executing database seed..."); await _dataSeeder.SeedAsync(new DataSeedContext().WithProperty(CMSPluginDbProperties.ConnectionStringName, CMSPluginDbProperties.ConnectionStringName)); } /// /// Adds the initial migration if not exist. /// /// private bool AddInitialMigrationIfNotExist() { try { if (!DbMigrationsProjectExists()) { return false; } } catch (Exception) { return false; } try { if (!MigrationsFolderExists()) { AddInitialMigration(); return true; } else { return false; } } catch (Exception e) { _logger.LogWarning("Couldn't determinate if any migrations exist : " + e.Message); return false; } } /// /// Databases the migrations project exists. /// /// private bool DbMigrationsProjectExists() { var dbMigrationsProjectFolder = GetEntityFrameworkCoreProjectFolderPath(); return dbMigrationsProjectFolder != null; } /// /// Migrationses the folder exists. /// /// private bool MigrationsFolderExists() { var dbMigrationsProjectFolder = GetEntityFrameworkCoreProjectFolderPath(); return Directory.Exists(Path.Combine(dbMigrationsProjectFolder, "Migrations")); } /// /// Adds the initial migration. /// /// Couldn't run ABP CLI... private void AddInitialMigration() { _logger.LogDebug("Creating initial migration..."); string argumentPrefix; string fileName; if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { argumentPrefix = "-c"; fileName = "/bin/bash"; } else { argumentPrefix = "/C"; fileName = "cmd.exe"; } var procStartInfo = new ProcessStartInfo(fileName, $"{argumentPrefix} \"abp create-migration-and-run-migrator \"{GetEntityFrameworkCoreProjectFolderPath()}\"\"" ); try { Process.Start(procStartInfo); } catch (Exception) { throw new Exception("Couldn't run ABP CLI..."); } } /// /// Gets the entity framework core project folder path. /// /// /// Solution folder not found! private string GetEntityFrameworkCoreProjectFolderPath() { var slnDirectoryPath = GetSolutionDirectoryPath(); if (slnDirectoryPath == null) { throw new Exception("Solution folder not found!"); } var srcDirectoryPath = Path.Combine(slnDirectoryPath, "src"); return Directory.GetDirectories(srcDirectoryPath) .FirstOrDefault(d => d.EndsWith(".EntityFrameworkCore")); } /// /// Gets the solution directory path. /// /// private string GetSolutionDirectoryPath() { var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory()); while (Directory.GetParent(currentDirectory.FullName) != null) { currentDirectory = Directory.GetParent(currentDirectory.FullName); if (Directory.GetFiles(currentDirectory.FullName).FirstOrDefault(f => f.EndsWith(".sln")) != null) { return currentDirectory.FullName; } } return null; } }