private ActivityResult RunSqlScript( InstallData installData, string sqlScriptFile, int consoleMessageReportFrequency, int progressbarEventFrequency, int percentOfStep, int startPercent ) { ActivityResult result = new ActivityResult(); result.Success = true; SqlConnection conn = null; string currentScript = string.Empty; try { string sql = System.IO.File.ReadAllText( sqlScriptFile ); string connectionString = String.Format( "user id={0};password={1};server={2};Initial Catalog={3};connection timeout=10", installData.ConnectionString.Username, installData.ConnectionString.Password, installData.ConnectionString.Server, installData.ConnectionString.Database ); conn = new SqlConnection( connectionString ); conn.Open(); RockScriptParser scriptParser = new RockScriptParser(sql); int sqlScriptCount = scriptParser.ScriptCount; int scriptsRun = 0; int scriptNextConsolePercentile = consoleMessageReportFrequency; int scriptNextProgressbarPercentile = progressbarEventFrequency; if ( consoleMessageReportFrequency != 0 ) { this.SendConsoleMessage( String.Format("There are {0} scripts to run.", sqlScriptCount) ); } using ( SqlTransaction transaction = conn.BeginTransaction() ) { foreach ( var script in scriptParser.ScriptCollection ) { currentScript = script; if ( !string.IsNullOrWhiteSpace( script ) ) { SqlCommand command = new SqlCommand( script, conn, transaction ); command.ExecuteNonQuery(); } scriptsRun++; // calculate current percentile int currentPercentile = (int)(((double)scriptsRun / (double)sqlScriptCount) * 100); // update console messages if ( consoleMessageReportFrequency != 0 ) { if ( sqlScriptCount == scriptsRun ) { this.SendConsoleMessage( "100% of scripts run" ); } else if ( currentPercentile >= scriptNextConsolePercentile ) { this.SendConsoleMessage( currentPercentile + "% of scripts run" ); scriptNextConsolePercentile = currentPercentile + consoleMessageReportFrequency; } } // update progress bar if ( progressbarEventFrequency != 0 ) { if ( sqlScriptCount == scriptsRun ) { this.UpdateProgressBar( (int)(100 * (percentOfStep * .01)) + startPercent ); } else if ( currentPercentile >= scriptNextProgressbarPercentile ) { this.UpdateProgressBar( (int)(currentPercentile * (percentOfStep * .01)) + startPercent ); scriptNextProgressbarPercentile = currentPercentile + progressbarEventFrequency; } } } transaction.Commit(); } } catch ( Exception ex ) { result.Success = false; result.Message = ex.Message + " Current Script: " + currentScript; } finally { conn.Close(); conn.Dispose(); } return result; }
private ActivityResult UnzipFile( string sourceFile, string destPath, int consoleMessageReportFrequency, int progressbarEventFrequency, int percentOfStep, int startPercent ) { // consoleMessageReportFrequency - how often, in percents, should a console message be sent (0 = none) // progressbarEventFrequency - how often should a progress bar event be fired, in percents (0 = none) // percentOfStep - what percentage of this step is this unzip process // startPercent - what is the starting percentage to use for the progressbar ActivityResult result = new ActivityResult(); result.Success = true; int zipFileCount = 0; int unzippedFiles = 0; int unzipNextConsolePercentile = consoleMessageReportFrequency; int unzipNextProgressbarPercentile = progressbarEventFrequency; try { using ( ZipFile zip = ZipFile.Read( sourceFile ) ) { zipFileCount = zip.Count; // unzip each file updating console and progressbar foreach ( ZipEntry e in zip ) { e.Extract( destPath, ExtractExistingFileAction.OverwriteSilently ); unzippedFiles++; // calculate current percentile int currentPercentile = (int)(((double)unzippedFiles / (double)zipFileCount) * 100); // update console messages if ( consoleMessageReportFrequency != 0 ) { if ( zipFileCount == unzippedFiles ) { this.SendConsoleMessage( "100% unzipped" ); } else if ( currentPercentile >= unzipNextConsolePercentile ) { this.SendConsoleMessage( currentPercentile + "% unzipped" ); unzipNextConsolePercentile = currentPercentile + consoleMessageReportFrequency; } } // update progress bar if ( progressbarEventFrequency != 0 ) { if ( zipFileCount == unzippedFiles ) { this.UpdateProgressBar( (int)(100 * (percentOfStep * .01)) + startPercent ); } else if ( currentPercentile >= unzipNextProgressbarPercentile ) { int progressbarState = (int)(currentPercentile * (percentOfStep * .01)) + startPercent; this.UpdateProgressBar( progressbarState ); unzipNextProgressbarPercentile = currentPercentile + progressbarEventFrequency; } } } } } catch ( Exception ex ) { result.Success = false; result.Message = ex.Message; } return result; }
private ActivityResult InstallRockApp( InstallData installData ) { ActivityResult result = new ActivityResult(); result.Success = true; // if we're not in development unzip the file, otherwise we'll fake it... (for that full experience) if ( !installData.InstallerProperties.IsDebug ) { this.SendConsoleMessage( "Preparing to unzip the rock application file." ); // unzip the rock zip result = UnzipFile( serverPath + @"\" + rockSource, serverPath + @"\rock", 10, 1, 100, 0 ); this.SendConsoleMessage( "Unzip complete." ); } else { // fake it... for ( int i = 0; i <= 100; i++ ) { UpdateProgressBar( i ); Thread.Sleep( 100 ); // nap time... } } return result; }
private ActivityResult RunSql( InstallData installData, string sqlFile ) { ActivityResult result = new ActivityResult(); result.Success = true; SqlConnection conn = null; try { string sql = System.IO.File.ReadAllText( sqlFile ); string connectionString = String.Format( "user id={0};password={1};server={2};Initial Catalog={3};connection timeout=10", installData.ConnectionString.Username, installData.ConnectionString.Password, installData.ConnectionString.Server, installData.ConnectionString.Database ); conn = new SqlConnection( connectionString ); conn.Open(); SqlCommand command = new SqlCommand( sql, conn ); command.ExecuteNonQuery(); } catch ( Exception ex ) { result.Success = false; result.Message = ex.Message; } finally { conn.Close(); conn.Dispose(); } return result; }
private ActivityResult DownloadRockStep( InstallData installData ) { ActivityResult result = new ActivityResult(); this.SendConsoleMessage( new ConsoleMessage( "--= Download Rock Step =--", ConsoleMessageType.Highlight ) ); string rockURL = baseStorageUrl + installData.InstallerProperties.InstallVersion; this.SendConsoleMessage( "Downloading file: " + rockURL + "/Data/" + rockSource ); result = DownloadFile( rockURL + "/Data/" + rockSource, serverPath + @"\" + rockSource, 10, 1 ); if ( result.Success ) { this.SendConsoleMessage( "File Download Complete!" ); } return result; }
private ActivityResult DownloadSqlStep(InstallData installData) { ActivityResult result = new ActivityResult(); this.SendConsoleMessage( new ConsoleMessage( "--= Download SQL Step =--", ConsoleMessageType.Highlight ) ); string serverDir = baseStorageUrl + installData.InstallerProperties.InstallVersion; this.SendConsoleMessage( "Downloading file: " + serverDir + "/Data/" + sqlScripts ); result = DownloadFile( serverDir + "/Data/" + sqlScripts, serverPath + @"\" + sqlScripts, 10, 1 ); this.SendConsoleMessage( "File Download Complete!" ); return result; }
private ActivityResult DownloadFile( string remoteFile, string localFile, int consoleMessageReportFrequency, int progressbarEventFrequency ) { // solution from http://forums.xamarin.com/discussion/2022/threading-help // consoleMessageReportFrequency - how often, in percents, should a console message be sent (0 = none) // progressbarEventFrequency - how often should a progress bar event be fired, in percents (0 = none) ActivityResult result = new ActivityResult(); result.Success = true; try { Uri url = new Uri( remoteFile ); // Get the total size of the file System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create( url ); System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse(); response.Close(); double dTotal = (double)response.ContentLength; // keeps track of the total bytes downloaded so we can update the progress bar Int64 iRunningByteTotal = 0; int nextProgressbarPercentToNotify = progressbarEventFrequency; int nextConsolePercentToNotify = consoleMessageReportFrequency; // use the webclient object to download the file using ( System.Net.WebClient client = new System.Net.WebClient() ) { // open the file at the remote URL for reading using ( System.IO.Stream streamRemote = client.OpenRead( url ) ) { // using the FileStream object, we can write the downloaded bytes to the file system using ( Stream streamLocal = new FileStream( localFile, FileMode.Create, FileAccess.Write, FileShare.None ) ) { // loop the stream and get the file into the byte buffer int iByteSize = 0; int bufferSize = 65536; byte[] byteBuffer = new byte[bufferSize]; while ( (iByteSize = streamRemote.Read( byteBuffer, 0, byteBuffer.Length )) > 0 ) { // write the bytes to the file system at the file path specified streamLocal.Write( byteBuffer, 0, iByteSize ); iRunningByteTotal += iByteSize; // calculate the progress out of a base "100" double dIndex = (double)(iRunningByteTotal); double dProgressPercentage = (dIndex / dTotal); int iProgressPercentage = (int)(dProgressPercentage * 100); // send console notifications if ( consoleMessageReportFrequency != 0 ) { if ( iProgressPercentage == 100 ) { this.SendConsoleMessage( "100% downloaded" ); } else if ( iProgressPercentage >= nextConsolePercentToNotify ) { this.SendConsoleMessage( nextConsolePercentToNotify.ToString() + "% downloaded" ); nextConsolePercentToNotify += consoleMessageReportFrequency; } } // send progress bar notifications if ( progressbarEventFrequency != 0 ) { if ( iProgressPercentage == 100 ) { this.UpdateProgressBar( 100 ); } else if ( iProgressPercentage >= nextProgressbarPercentToNotify ) { this.UpdateProgressBar( iProgressPercentage ); nextProgressbarPercentToNotify += progressbarEventFrequency; } } } // while.. streamLocal.Close(); streamLocal.Dispose(); } streamRemote.Close(); streamRemote.Dispose(); } client.Dispose(); } } catch ( OutOfMemoryException mex ) { result.Success = false; result.Message = @"The server ran out of memory while downloading Rock. You may want to consider using a server with more available resources or try installing again."; } catch ( Exception ex ) { result.Success = false; result.Message = ex.Message; } return result; }
private ActivityResult CreateDatabase( InstallData installData ) { ActivityResult result = new ActivityResult(); result.Success = true; this.SendConsoleMessage( new ConsoleMessage( "--= Creating Database =--", ConsoleMessageType.Highlight ) ); // create database if needed if ( !RockEnvironmentChecks.CheckSqlDatabaseExists( installData.ConnectionString.Server, installData.ConnectionString.Username, installData.ConnectionString.Password, installData.ConnectionString.Database ) ) { this.SendConsoleMessage( String.Format("Database {0} does not exist creating it.", installData.ConnectionString.Database) ); string sql = String.Format("CREATE DATABASE [{0}]", installData.ConnectionString.Database); string connectionString = String.Format( "user id={0};password={1};server={2};connection timeout=10", installData.ConnectionString.Username, installData.ConnectionString.Password, installData.ConnectionString.Server ); SqlConnection conn = new SqlConnection( connectionString ); try { conn.Open(); SqlCommand command = new SqlCommand( sql, conn ); command.ExecuteNonQuery(); this.SendConsoleMessage( String.Format("Database {0} created successfully.", installData.ConnectionString.Database) ); } catch ( Exception ex ) { result.Success = false; result.Message = ex.Message; } finally { conn.Close(); conn.Dispose(); } } else { this.SendConsoleMessage( String.Format( "Database {0} exists, will attempt to install using it.", installData.ConnectionString.Database ) ); } // tease the user with a little progress this.UpdateProgressBar( 10 ); // unzip sql files if ( result.Success ) { this.SendConsoleMessage( "Unziping file: " + sqlScripts ); string sqlZipFile = serverPath + @"\" + sqlScripts; result = UnzipFile( sqlZipFile, serverPath, 10, 1, 30, 10 ); if ( result.Success ) { this.SendConsoleMessage( String.Format( "{0} sucessfully unzipped.", sqlScripts ) ); } } // run sql install if ( result.Success ) { this.SendConsoleMessage( "Preparing to run sql-install.sql" ); result = RunSqlScript( installData, serverPath + @"\sql-install.sql", 10, 1, 60, 40 ); if ( result.Success ) { this.SendConsoleMessage( String.Format( "Successfully ran sql-install.sql." ) ); } } return result; }
private ActivityResult ConfigureRock( InstallData installData ) { ActivityResult result = new ActivityResult(); result.Success = true; string tempWebConfig = serverPath + @"\webconfig.xml"; this.SendConsoleMessage( new ConsoleMessage( "--= Configuring Rock =--", ConsoleMessageType.Highlight ) ); string passwordKey = RockInstallUtilities.GeneratePasswordKey(); // write connection string file result = WriteConnectionStringFile( installData.ConnectionString.Server, installData.ConnectionString.Database, installData.ConnectionString.Username, installData.ConnectionString.Password ); if ( result.Success ) { this.UpdateProgressBar( 20 ); this.SendConsoleMessage( String.Format( "Successfully created web.ConnectionString.config." ) ); } // create and run custom sql config if ( result.Success ) { // download configure script string urlSqlConfigScript = baseStorageUrl + installData.InstallerProperties.InstallVersion + "/Data/" + sqlConfigureScript; string localSqlConfigScript = serverPath + @"\" + sqlConfigureScript; this.SendConsoleMessage( "Downloading SQL configuration script." ); result = this.DownloadFile( urlSqlConfigScript, localSqlConfigScript, 0, 0 ); if ( result.Success ) { this.SendConsoleMessage( "SQL configuration script downloaded." ); // merge settings this.SendConsoleMessage( "Merging values into SQL config script." ); string sqlScript = System.IO.File.ReadAllText( localSqlConfigScript ); sqlScript = sqlScript.Replace( "{AdminPassword}", RockInstallUtilities.EncodePassword( installData.AdminUser.Password, "7E10A764-EF6B-431F-87C7-861053C84131", passwordKey ) ); sqlScript = sqlScript.Replace( "{AdminUsername}", SqlClean(installData.AdminUser.Username) ); sqlScript = sqlScript.Replace( "{PublicAppRoot}", RockInstallUtilities.CleanBaseAddress( installData.HostingInfo.ExternalUrl ) ); sqlScript = sqlScript.Replace( "{PublicAppSite}", RockInstallUtilities.GetDomainFromString( installData.HostingInfo.ExternalUrl ) ); sqlScript = sqlScript.Replace( "{InternalAppRoot}", RockInstallUtilities.CleanBaseAddress( installData.HostingInfo.InternalUrl ) ); sqlScript = sqlScript.Replace( "{InternalAppSite}", RockInstallUtilities.GetDomainFromString( installData.HostingInfo.InternalUrl ) ); sqlScript = sqlScript.Replace( "{OrgName}", SqlClean(installData.Organization.Name )); sqlScript = sqlScript.Replace( "{OrgPhone}", SqlClean(installData.Organization.Phone )); sqlScript = sqlScript.Replace( "{OrgEmail}", SqlClean(installData.Organization.Email )); sqlScript = sqlScript.Replace( "{OrgWebsite}", SqlClean(installData.Organization.Website )); sqlScript = sqlScript.Replace( "{SafeSender}", RockInstallUtilities.GetDomainFromEmail( installData.Organization.Email ) ); sqlScript = sqlScript.Replace( "{EmailException}", SqlClean(installData.Organization.Email )); sqlScript = sqlScript.Replace( "{SmtpServer}", SqlClean(installData.EmailSettings.Server) ); sqlScript = sqlScript.Replace( "{SmtpPort}", installData.EmailSettings.Port ); sqlScript = sqlScript.Replace( "{SmtpUser}", SqlClean(installData.EmailSettings.RelayUsername )); sqlScript = sqlScript.Replace( "{SmtpPassword}", SqlClean( installData.EmailSettings.RelayPassword ) ); sqlScript = sqlScript.Replace( "{SmtpUseSsl}", installData.EmailSettings.UseSsl.ToString() ); System.IO.File.WriteAllText( localSqlConfigScript, sqlScript ); this.SendConsoleMessage( "Values merged into SQL config script." ); // run sql configure script this.SendConsoleMessage( "Running SQL config script." ); result = this.RunSql( installData, localSqlConfigScript ); if ( result.Success ) { this.SendConsoleMessage( "Successfully ran SQL config script." ); this.UpdateProgressBar( 40 ); } else { return result; } } } // extract web.config string rockZipFile = serverPath + @"\" + rockSource; if ( result.Success ) { this.SendConsoleMessage( "Extracting web.config file for edits." ); try { using ( FileStream fsZipFile = File.Create( tempWebConfig ) ) { using ( ZipFile zip = ZipFile.Read( rockZipFile ) ) { ZipEntry webConfigEntry = zip["web.config"]; webConfigEntry.Extract( fsZipFile ); // remove file from zip zip.RemoveEntry( "web.config" ); zip.Save(); } } this.SendConsoleMessage( "Extracted web.config to webconfig.xml." ); this.UpdateProgressBar( 60 ); } catch ( Exception ex ) { result.Success = false; result.Message = ex.Message; } } try { // edit web.config XDocument document = XDocument.Load( tempWebConfig ); // update timezone var node = document.Descendants( "appSettings" ).Elements( "add" ).Where( e => e.Attribute( "key" ).Value == "OrgTimeZone" ).FirstOrDefault(); node.SetAttributeValue( "value", installData.HostingInfo.Timezone ); // update password key node = document.Descendants( "appSettings" ).Elements( "add" ).Where( e => e.Attribute( "key" ).Value == "PasswordKey" ).FirstOrDefault(); node.SetAttributeValue( "value", passwordKey ); // update data encryption key string dataEncryptionKey = RockInstallUtilities.GeneratePasswordKey( 128 ); node = document.Descendants( "appSettings" ).Elements( "add" ).Where( e => e.Attribute( "key" ).Value == "DataEncryptionKey" ).FirstOrDefault(); node.SetAttributeValue( "value", dataEncryptionKey ); // update machine key string validationKey = RockInstallUtilities.GenerateMachineKey( 64 ); string decryptionKey = RockInstallUtilities.GenerateMachineKey( 32 ); node = document.Descendants( "system.web" ).Elements( "machineKey" ).FirstOrDefault(); node.SetAttributeValue( "validationKey", validationKey ); node.SetAttributeValue( "decryptionKey", decryptionKey ); document.Save( tempWebConfig ); } catch ( Exception ex ) { result.Success = false; result.Message = "An error occurred while customizing the web.config file for Rock. " + ex.Message; } this.UpdateProgressBar( 100 ); return result; }
private ActivityResult WriteConnectionStringFile( string server, string database, string username, string password ) { ActivityResult result = new ActivityResult(); result.Success = true; try { string configContents = String.Format( @"<add name=""RockContext"" connectionString=""Data Source={0};Initial Catalog={1}; User Id={2}; password={3};MultipleActiveResultSets=true"" providerName=""System.Data.SqlClient""/>", server, database, username, password ); StreamWriter configFile = new StreamWriter( serverPath + "/web.ConnectionStrings.config", false ); configFile.WriteLine( @"<?xml version=""1.0""?>" ); configFile.WriteLine( @"<connectionStrings>" ); configFile.WriteLine( "\t" + configContents ); configFile.WriteLine( "</connectionStrings>" ); configFile.Flush(); configFile.Close(); configFile.Dispose(); } catch ( Exception ex ) { result.Success = false; result.Message = ex.Message; } return result; }
private ActivityResult DeleteInstaller( InstallData installData ) { ActivityResult result = new ActivityResult(); result.Success = true; // let's not delete the installer if we're in development, source control is nice but no use pressing our luck... if ( !installData.InstallerProperties.IsDebug ) { try { File.Delete( serverPath + @"Start.aspx" ); File.Delete( serverPath + @"Install.aspx" ); File.Delete( serverPath + @"InstallController.cs" ); File.Delete( serverPath + @"Startup.cs" ); File.Delete( serverPath + @"bin\Microsoft.AspNet.SignalR.Core.dll" ); File.Delete( serverPath + @"bin\Microsoft.AspNet.SignalR.SystemWeb.dll" ); File.Delete( serverPath + @"bin\Microsoft.Owin.dll" ); File.Delete( serverPath + @"bin\Microsoft.Owin.Host.SystemWeb.dll" ); File.Delete( serverPath + @"bin\Microsoft.Owin.Security.dll" ); File.Delete( serverPath + @"bin\Owin.dll" ); File.Delete( serverPath + @"bin\Ionic.Zip.dll" ); File.Delete( serverPath + @"bin\Microsoft.ApplicationBlocks.Data.dll" ); File.Delete( serverPath + @"bin\RockInstaller.dll" ); File.Delete( serverPath + @"bin\RockInstallTools.dll" ); File.Delete( serverPath + @"bin\Subtext.Scripting.dll" ); } catch ( Exception ex ) { result.Success = false; result.Message = ex.Message; } } else { // if it is a debug session let's do delete the connection string file File.Delete( serverPath + @"web.ConnectionStrings.config" ); } // these files should be deleted even in the developer environment try { File.Delete( serverPath + @"\rock-install-latest.zip" ); File.Delete( serverPath + @"\sql-config.sql" ); File.Delete( serverPath + @"\sql-install.sql" ); File.Delete( serverPath + @"\sql-latest.zip" ); File.Delete( serverPath + @"\webconfig.xml" ); } catch ( Exception ex ) { result.Success = false; result.Message = ex.Message; } return result; }