/// <summary> /// Warning! Will *really* flush the directory or throw exception. /// Can't just call the overload to Directory.Delete that is recursive because we need to call ClearAttributes on every file. /// </summary> /// <param name="dir">Directory to flush.</param> /// <param name="logger">Startup logger because we have no DI.</param> /// <param name="deleteDirAfterFlush">Whether to delete the actual directory after flushing it.</param> /// <returns>If failure, it probably can't flush an existing directory due to a locked file.</returns> public static bool FlushDirectory(string dir, IStartupLogger logger, bool deleteDirAfterFlush = false) { if (Directory.Exists(dir)) { FlushFilesFromDirectory(dir, logger); if (Directory.EnumerateFiles(dir, SEARCH_ALL_FILES).Any()) { return(false); // a file was locked } else { foreach (var d in Directory.EnumerateDirectories(dir)) { if (!FlushDirectory(d, logger, deleteDirAfterFlush)) { return(false); } } if (deleteDirAfterFlush) { DeleteDirectory(dir); } return(true); } } else { return(true); } }
private static void FlushFilesFromDirectory(string currentDir, IStartupLogger logger) { if (Directory.Exists(currentDir)) { foreach (var file in Directory.EnumerateFiles(currentDir)) { FileUtils.SafeDeleteFile(file, true, logger); } } }
internal JournalTable(string connectionString, IStartupLogger log, string journalTableCreationScript, Server serverConnection, Dictionary <int, string> failedScripts) : base(log) { _connectionString = connectionString; _journalTableCreationScript = journalTableCreationScript; _failedScripts = failedScripts; // share failed scripts with DatabaseMigrator _serverConnection = serverConnection; }
/// <summary> /// At time of writing, Smo has a bug with the utility command 'go'. It blows up on some proper queries containing go. /// Not sure what the heck, but in DatabaseMigrator.cs we call server.ConnectionContext.ExecuteNonQuery and go works. Here we call ExecuteReader and it doesn't. /// And this thread indicates it should never work. /// In any case, here we are splitting the scripts apart on go. /// https://github.com/microsoft/sqlmanagementobjects/issues/53 /// </summary> internal static bool SchemaChanged(Server server, string sql, IStartupLogger log) { SplitOnGo splitter = new(); foreach (var script in splitter.Split(sql)) { if (SchemaChanged_Inner(server, script, log)) { return(true); } } return(false); }
/// <summary>Safely deletes a file - no exception if operation fails</summary> /// <param name="path">File to delete</param> /// <param name="forceDelete">Try to alter flags (if necessary) to accomplish delete</param> /// <param name="logger">Startup logger because we have no DI.</param> public static void SafeDeleteFile(string path, bool forceDelete, IStartupLogger logger) { if (string.IsNullOrEmpty(path)) { return; } try { if (File.Exists(path)) { if (forceDelete) { // Not wrapping SetAttributes() with try/catch since Delete() will fail if SetAttributes() fails. if (File.GetAttributes(path) == FileAttributes.ReadOnly) { File.SetAttributes(path, FileAttributes.Normal); } } File.Delete(path); } } catch (UnauthorizedAccessException e) { logger?.LogException(e); } catch (ArgumentException e) { logger?.LogException(e); } catch (PathTooLongException e) { logger?.LogException(e); } catch (DirectoryNotFoundException e) { logger?.LogException(e); } catch (IOException e) { logger?.LogException(e); } catch (NotSupportedException e) { logger?.LogException(e); } }
/// <summary> /// xx /// </summary> /// <param name="s">Stream.</param> /// <param name="path">Path of file to create.</param> /// <returns>pass/fail</returns> /// <param name="logger">Startup logger because we have no DI.</param> public static bool StreamToFile(Stream s, string path, IStartupLogger logger) { if (s == null) { return(false); } try { using (var f = File.Create(path)) { s.Seek(0, SeekOrigin.Begin); s.CopyTo(f); } return(true); } catch (UnauthorizedAccessException e) { logger?.LogException(e); } catch (ArgumentException e) { logger?.LogException(e); } catch (PathTooLongException e) { logger?.LogException(e); } catch (DirectoryNotFoundException e) { logger?.LogException(e); } catch (IOException e) { logger?.LogException(e); } catch (NotSupportedException e) { logger?.LogException(e); } return(false); }
/// <summary> /// /// </summary> /// <param name="server"></param> /// <param name="script">A script that doesn't contain the go keyword.</param> /// <param name="log"></param> /// <returns></returns> private static bool SchemaChanged_Inner(Server server, string script, IStartupLogger log) { var result = false; server.ConnectionContext.ExecuteNonQuery(SQL_SERVER_SHOWPLAN); try { using SqlDataReader readerResult = server.ConnectionContext.ExecuteReader(script); var schema = readerResult.GetSchemaTable(); var statementTypeIndex = GetStatementTypeColIndex(schema); while (readerResult.Read()) { if (_ddlStatements.Any(s => readerResult[statementTypeIndex].ToString().ToLower().Contains(s))) { result = true; break; } } } catch (Exception ex) { log.LogInfo($"Error attempting to detect schema changing script: {ex.Message}"); var inner = ex.InnerException; while (inner != null) { log.LogInfo($"Schema changing error cont: {inner.Message}"); inner = inner.InnerException; } } finally { server.ConnectionContext.ExecuteNonQuery(SQL_SERVER_SHOWPLAN_OFF); } return(result); }
/// <summary> /// Sets the startup IStartupLogger /// </summary> /// <param name="logger"></param> /// <returns></returns> public DefaultsExpression UseLogger(IStartupLogger logger) { Logger = logger ?? throw new ArgumentNullException(nameof(logger)); return(this); }
public DirectDatabaseConnection(IStartupLogger log) => _log = log;