private PatchingUI(SqlConnectionStringBuilder builder, ITableRepository repository, Version databaseVersion, IPatcher patcher, Patch[] patchesInDatabase, SortedDictionary<string, Patch> allPatchesInAssembly) { _builder = builder; _repository = repository; _databaseVersion = databaseVersion; _patcher = patcher; InitializeComponent(); if (_patcher == null) return; _hostAssemblyVersion = new Version(FileVersionInfo.GetVersionInfo(_patcher.GetDbAssembly().Location).FileVersion); _patchesInDatabase = patchesInDatabase; _allPatchesInAssembly = allPatchesInAssembly; lblPatchingAssembly.Text = patcher.GetDbAssembly().FullName; if (builder == null || string.IsNullOrWhiteSpace(builder.InitialCatalog)) { lblDatabaseVersion.Text = "Form loaded without a specific database to target!"; lblDatabaseVersion.ForeColor = Color.Red; } else { lblDatabaseVersion.Text = string.Format("{0}, Version:{1}", builder.InitialCatalog,repository.GetVersion()); } }
private PatchingUI(DiscoveredDatabase database, ITableRepository repository, Version databaseVersion, IPatcher patcher, Patch[] patchesInDatabase, SortedDictionary <string, Patch> allPatchesInAssembly) { _database = database; _repository = repository; _databaseVersion = databaseVersion; _patcher = patcher; InitializeComponent(); if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) { return; } _hostAssemblyVersion = new Version(FileVersionInfo.GetVersionInfo(_patcher.GetDbAssembly().Location).FileVersion); _patchesInDatabase = patchesInDatabase; _allPatchesInAssembly = allPatchesInAssembly; string name = patcher.Name + " v" + patcher.GetDbAssembly().GetName().Version.ToString(3); int numberOfPatchesToApply = _allPatchesInAssembly.Values.Except(_patchesInDatabase).Count(); tbPatch.Text = $"{name} ({numberOfPatchesToApply} Patch{(numberOfPatchesToApply > 1 ? "es":"")})"; if (_database == null) { tbDatabase.Text = "Form loaded without a specific database to target!"; tbDatabase.ForeColor = Color.Red; } else { tbDatabase.Text = string.Format("{0}, Version:{1}", _database.GetRuntimeName(), repository.GetVersion()); } }
private PatchingUI(DiscoveredDatabase database, ITableRepository repository, IPatcher patcher) { _database = database; _repository = repository; _patcher = patcher; InitializeComponent(); if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) { return; } string name = patcher.Name + " v" + patcher.GetDbAssembly().GetName().Version.ToString(3); tbPatch.Text = $"{name}"; if (_database == null) { tbDatabase.Text = "Form loaded without a specific database to target!"; tbDatabase.ForeColor = Color.Red; } else { tbDatabase.Text = string.Format("{0}, Version:{1}", _database.GetRuntimeName(), repository.GetVersion()); } }
public static string GetInitialCreateScriptContents(IPatcher patcher) { var assembly = patcher.GetDbAssembly(); var subdirectory = patcher.ResourceSubdirectory; Regex initialCreationRegex; if (string.IsNullOrWhiteSpace(subdirectory)) { initialCreationRegex = new Regex(@".*\.runAfterCreateDatabase\..*\.sql"); } else { initialCreationRegex = new Regex(@".*\." + Regex.Escape(subdirectory) + @"\.runAfterCreateDatabase\..*\.sql"); } var candidates = assembly.GetManifestResourceNames().Where(r => initialCreationRegex.IsMatch(r)).ToArray(); if (candidates.Length == 1) { var sr = new StreamReader(assembly.GetManifestResourceStream(candidates[0])); return(sr.ReadToEnd()); } if (candidates.Length == 0) { throw new FileNotFoundException("Could not find an initial create database script in dll " + assembly.FullName + ". Make sure it is marked as an Embedded Resource and that it is in a folder called 'runAfterCreateDatabase' (and matches regex " + initialCreationRegex + "). And make sure that it is marked as 'Embedded Resource' in the .csproj build action"); } throw new Exception("There are too many create scripts in the assembly " + assembly.FullName + " only 1 create database script is allowed, all other scripts must go into the up folder"); }
public static SortedDictionary <string, Patch> GetAllPatchesInAssembly(IPatcher patcher) { var assembly = patcher.GetDbAssembly(); var subdirectory = patcher.ResourceSubdirectory; Regex upgradePatchesRegexPattern; if (string.IsNullOrWhiteSpace(subdirectory)) { upgradePatchesRegexPattern = new Regex(@".*\.up\.(.*\.sql)"); } else { upgradePatchesRegexPattern = new Regex(@".*\." + Regex.Escape(subdirectory) + @"\.up\.(.*\.sql)"); } var files = new SortedDictionary <string, Patch>(); //get all resources out of foreach (string manifestResourceName in assembly.GetManifestResourceNames()) { var match = upgradePatchesRegexPattern.Match(manifestResourceName); if (match.Success) { string fileContents = new StreamReader(assembly.GetManifestResourceStream(manifestResourceName)).ReadToEnd(); files.Add(match.Groups[1].Value, new Patch(match.Groups[1].Value, fileContents)); } } return(files); }
public override Image GetImage(IIconProvider iconProvider) { if (_patcher != null) { var basicIcon = _databaseIconProvider.GetIconForAssembly(_patcher.GetDbAssembly()); return(_overlayProvider.GetOverlay(basicIcon, OverlayKind.Add)); } return(iconProvider.GetImage(RDMPConcept.ExternalDatabaseServer, OverlayKind.Add)); }
public static PatchingState IsPatchingRequired(DiscoveredDatabase database, IPatcher patcher, out Version databaseVersion, out Patch[] patchesInDatabase, out SortedDictionary <string, Patch> allPatchesInAssembly) { databaseVersion = DatabaseVersionProvider.GetVersionFromDatabase(database); MasterDatabaseScriptExecutor scriptExecutor = new MasterDatabaseScriptExecutor(database); patchesInDatabase = scriptExecutor.GetPatchesRun(); allPatchesInAssembly = patcher.GetAllPatchesInAssembly(database); AssemblyName databaseAssemblyName = patcher.GetDbAssembly().GetName(); if (databaseAssemblyName.Version < databaseVersion) { return(PatchingState.SoftwareBehindDatabase); } //if there are patches that have not been applied return (allPatchesInAssembly.Values .Except(patchesInDatabase) .Any() ? PatchingState.Required:PatchingState.NotRequired); }
public static PatchingState IsPatchingRequired(SqlConnectionStringBuilder builder, IPatcher patcher, out Version databaseVersion, out Patch[] patchesInDatabase, out SortedDictionary <string, Patch> allPatchesInAssembly) { databaseVersion = DatabaseVersionProvider.GetVersionFromDatabase(builder); MasterDatabaseScriptExecutor scriptExecutor = new MasterDatabaseScriptExecutor(builder.DataSource, builder.InitialCatalog, builder.UserID, builder.Password); patchesInDatabase = scriptExecutor.GetPatchesRun(); allPatchesInAssembly = GetAllPatchesInAssembly(patcher); AssemblyName databaseAssemblyName = patcher.GetDbAssembly().GetName(); if (databaseAssemblyName.Version < databaseVersion) { return(PatchingState.SoftwareBehindDatabase); } //if there are patches that have not been applied return (allPatchesInAssembly.Values .Except(patchesInDatabase) .Any() ? PatchingState.Required:PatchingState.NotRequired); }
private void btnAttemptPatching_Click(object sender, EventArgs e) { bool stop = false; //start with the assumption that we will apply all patches SortedDictionary <string, Patch> toApply = new SortedDictionary <string, Patch>(); foreach (Patch potentialInstallable in _allPatchesInAssembly.Values.Except(_patchesInDatabase)) { toApply.Add(potentialInstallable.locationInAssembly, potentialInstallable); } var listener = new ToMemoryCheckNotifier(checksUI1); checksUI1.BeginUpdate(); try { //make sure the existing patches in the live database are not freaky phantom patches foreach (Patch patch in _patchesInDatabase) { //if patch is not in database assembly if (!_allPatchesInAssembly.Any(a => a.Value.Equals(patch))) { listener.OnCheckPerformed(new CheckEventArgs( "The database contains an unexplained patch called " + patch.locationInAssembly + " (it is not in " + _patcher.GetDbAssembly().FullName + " ) so how did it get there?", CheckResult.Warning, null)); } else if (!_allPatchesInAssembly[patch.locationInAssembly].GetScriptBody().Equals(patch.GetScriptBody())) { listener.OnCheckPerformed(new CheckEventArgs( "The contents of patch " + patch.locationInAssembly + " are different between live database and the database patching assembly", CheckResult.Warning, null)); //do not apply this patch toApply.Remove(patch.locationInAssembly); } else { //we found it and it was intact listener.OnCheckPerformed(new CheckEventArgs("Patch " + patch.locationInAssembly + " was previously installed successfully so no need to touch it", CheckResult.Success, null)); //do not apply this patch toApply.Remove(patch.locationInAssembly); } } } catch (Exception exception) { listener.OnCheckPerformed(new CheckEventArgs("Patch evaluation failed", CheckResult.Fail, exception)); stop = true; } finally { checksUI1.EndUpdate(); } //if any of the patches we are trying to apply are earlier than the latest in the database IEnumerable <Patch> missedOppertunities = toApply.Values.Where(p => p.DatabaseVersionNumber < _patchesInDatabase.Max(p2 => p2.DatabaseVersionNumber)); foreach (Patch missedOppertunity in missedOppertunities) { stop = true; listener.OnCheckPerformed(new CheckEventArgs( "Patch " + missedOppertunity.locationInAssembly + " cannot be applied because it's version number is " + missedOppertunity.DatabaseVersionNumber + " but the current database is at version " + _databaseVersion + Environment.NewLine + " Contents of patch was:" + Environment.NewLine + missedOppertunity.EntireScript , CheckResult.Fail, null)); } //if the patches to be applied would bring the version number above that of the host Library foreach (Patch futurePatch in toApply.Values.Where(patch => patch.DatabaseVersionNumber > _hostAssemblyVersion)) { listener.OnCheckPerformed(new CheckEventArgs( "Cannot apply patch " + futurePatch.locationInAssembly + " because it's database version number is " + futurePatch.DatabaseVersionNumber + " which is higher than the currently loaded host assembly (" + _patcher.GetDbAssembly().FullName + "). ", CheckResult.Fail, null)); stop = true; } if (stop) { listener.OnCheckPerformed(new CheckEventArgs("Abandonning patching process (no patches have been applied) because of one or more previous errors", CheckResult.Fail, null)); return; } try { MasterDatabaseScriptExecutor executor = new MasterDatabaseScriptExecutor(_database); //todo: Only ms has a backup implementation in FAnsi currently bool backupDatabase = _database.Server.DatabaseType == DatabaseType.MicrosoftSQLServer && MessageBox.Show("Backup Database First", "Backup", MessageBoxButtons.YesNo) == DialogResult.Yes; executor.PatchDatabase(toApply, listener, PreviewPatch, backupDatabase); //if it crashed during patching if (listener.GetWorst() == CheckResult.Fail) { btnAttemptPatching.Enabled = true; return; } listener.OnCheckPerformed(new CheckEventArgs("Patching completed without exception, disabling the patching button", CheckResult.Success, null)); //patching worked so prevent them doing it again! btnAttemptPatching.Enabled = false; if (_repository != null) { _repository.ClearUpdateCommandCache(); checksUI1.OnCheckPerformed(new CheckEventArgs("Cleared UPDATE commands cache", CheckResult.Success, null)); } checksUI1.OnCheckPerformed(new CheckEventArgs("Patching Succesful", CheckResult.Success, null)); if (MessageBox.Show("Application will now restart", "Close?", MessageBoxButtons.YesNo) == DialogResult.Yes) { Application.Restart(); } } catch (Exception exception) { checksUI1.OnCheckPerformed(new CheckEventArgs("Patching failed", CheckResult.Fail, exception)); } }