示例#1
0
        internal static bool RebuildBuildManagerFile(int defaultTimeout, string buildFileName, List <RebuilderData> rebuildData)
        {
            string tempPath = System.IO.Path.GetTempPath() + System.Guid.NewGuid();

            Directory.CreateDirectory(tempPath);
            try
            {
                string projFileName = Path.Combine(tempPath, SqlSync.SqlBuild.XmlFileNames.MainProjectFile);

                for (int i = 0; i < rebuildData.Count; i++)
                {
                    File.WriteAllText(Path.Combine(tempPath, rebuildData[i].ScriptFileName), rebuildData[i].ScriptText);
                }

                SqlSyncBuildData buildData = SqlBuildFileHelper.CreateShellSqlSyncBuildDataObject();
                buildData.AcceptChanges();

                if (!SqlBuildFileHelper.PackageProjectFileIntoZip(buildData, tempPath, buildFileName))
                {
                    return(false);
                }

                if (!ZipHelper.UnpackZipPackage(tempPath, buildFileName, false))
                {
                    return(false);
                }

                for (int i = 0; i < rebuildData.Count; i++)
                {
                    SqlBuildFileHelper.AddScriptFileToBuild(ref buildData,
                                                            projFileName,
                                                            rebuildData[i].ScriptFileName,
                                                            rebuildData[i].Sequence + 1,
                                                            string.Empty,
                                                            true,
                                                            true,
                                                            rebuildData[i].Database,
                                                            false,
                                                            buildFileName,
                                                            false,
                                                            false,
                                                            System.Environment.UserName,
                                                            defaultTimeout,
                                                            rebuildData[i].ScriptId,
                                                            rebuildData[i].Tag);
                }

                SqlBuildFileHelper.SaveSqlBuildProjectFile(ref buildData, projFileName, buildFileName);

                return(true);
            }
            finally
            {
                if (Directory.Exists(tempPath))
                {
                    Directory.Delete(tempPath, true);
                }
            }
        }
        public void CleanProjectFileForRemoteExecutionTest_CleanOutUnitTest()
        {
            Initialization init = GetInitializationObject();

            //Create the build package...
            SqlSyncBuildData buildData = init.CreateSqlSyncSqlBuildDataObject();

            init.AddInsertScript(ref buildData, true);
            init.AddFailureScript(ref buildData, true, true);
            foreach (SqlSyncBuildData.ScriptRow row in buildData.Script)
            {
                row.FileName = Path.GetFileName(row.FileName);
            }

            //Add in code review rows
            buildData.CodeReview.AddCodeReviewRow(
                Guid.NewGuid(),
                buildData.Script[0],
                DateTime.Now,
                "Reviewer",
                1,
                "Comment",
                "12345",
                "AABBCCDD",
                "EEFFGGHHII");

            buildData.AcceptChanges();

            string zipFileName = init.GetTrulyUniqueFile();

            string path            = Path.GetDirectoryName(zipFileName);
            string projectFileName = Path.Combine(path, XmlFileNames.MainProjectFile);

            buildData.WriteXml(projectFileName);
            SqlBuildFileHelper.PackageProjectFileIntoZip(buildData, path, zipFileName, false);

            byte[] expected = File.ReadAllBytes(zipFileName);
            byte[] actual;

            SqlSyncBuildData cleanedBuildData;

            actual = SqlBuildFileHelper.CleanProjectFileForRemoteExecution(zipFileName, out cleanedBuildData);
            Assert.IsTrue(actual.Length >= 1200);  //can't get exact length due to variations in guids and dates.
            Assert.IsTrue(cleanedBuildData.GetXml().ToString().Length > 100);
            Assert.IsTrue(buildData.GetXml().ToString().Length > cleanedBuildData.GetXml().ToString().Length);

            Assert.IsTrue(cleanedBuildData.ScriptRun.Rows.Count == 0);
            Assert.IsTrue(cleanedBuildData.Build.Rows.Count == 0);
            Assert.IsTrue(cleanedBuildData.CodeReview.Rows.Count == 0);
            Assert.AreEqual(buildData.Script.Rows.Count, cleanedBuildData.Script.Rows.Count);
        }
        public void CleanProjectFileForRemoteExecutionTest_CleanOutScriptRunRowsTest()
        {
            Initialization init = GetInitializationObject();

            //Create the build package...
            SqlSyncBuildData buildData = init.CreateSqlSyncSqlBuildDataObject();

            init.AddInsertScript(ref buildData, true);
            init.AddInsertScript(ref buildData, true);
            init.AddInsertScript(ref buildData, true);
            init.AddFailureScript(ref buildData, true, true);
            foreach (SqlSyncBuildData.ScriptRow row in buildData.Script)
            {
                row.FileName = Path.GetFileName(row.FileName);
            }

            buildData.Builds.AddBuildsRow((SqlSyncBuildData.SqlSyncBuildProjectRow)buildData.SqlSyncBuildProject.Rows[0]);
            buildData.Build.AddBuildRow("Script", "Development", DateTime.Now, DateTime.Now, "Server", "Committed", Guid.NewGuid().ToString(), "user", buildData.Builds[0]);
            buildData.ScriptRun.AddScriptRunRow("HASH", "Committed", "FileName", 2.2, DateTime.Now, DateTime.Now, true, "Database", Guid.NewGuid().ToString(), (SqlSyncBuildData.BuildRow)buildData.Build[0]);


            buildData.AcceptChanges();

            string zipFileName = init.GetTrulyUniqueFile();

            string path            = Path.GetDirectoryName(zipFileName);
            string projectFileName = Path.Combine(path, XmlFileNames.MainProjectFile);

            buildData.WriteXml(projectFileName);
            SqlBuildFileHelper.PackageProjectFileIntoZip(buildData, path, zipFileName, false);

            byte[] expected = File.ReadAllBytes(zipFileName);
            byte[] actual;

            SqlSyncBuildData cleanedBuildData;

            actual = SqlBuildFileHelper.CleanProjectFileForRemoteExecution(zipFileName, out cleanedBuildData);
            Assert.IsTrue(2000 <= actual.Length);  //can't get exact length due to variations in guids and dates.
            Assert.IsTrue(cleanedBuildData.GetXml().ToString().Length > 100);
            Assert.IsTrue(buildData.GetXml().ToString().Length > cleanedBuildData.GetXml().ToString().Length);

            Assert.IsTrue(cleanedBuildData.ScriptRun.Rows.Count == 0);
            Assert.IsTrue(cleanedBuildData.Build.Rows.Count == 0);
            Assert.IsTrue(cleanedBuildData.CodeReview.Rows.Count == 0);
            Assert.AreEqual(buildData.Script.Rows.Count, cleanedBuildData.Script.Rows.Count);
        }
 public static void ValidateReviewCheckSum(SqlSyncBuildData sqlSyncBuildData, string baseDirectory)
 {
     foreach (SqlSyncBuildData.ScriptRow scriptRow in sqlSyncBuildData.Script)
     {
         var codeReview = from cr in sqlSyncBuildData.CodeReview
                          where cr.ScriptId == scriptRow.ScriptId
                          select cr;
         if (codeReview.Any())
         {
             string[] batch      = SqlBuildHelper.ReadBatchFromScriptFile(baseDirectory + scriptRow.FileName, false, true);
             string   scriptText = String.Join("", batch);
             foreach (var crRow in codeReview)
             {
                 if (!ValidateReviewCheckSum(crRow, scriptText))
                 {
                     crRow.ReviewStatus = (short)CodeReviewStatus.OutOfDate;
                 }
             }
         }
     }
     sqlSyncBuildData.AcceptChanges();
 }
        /// <summary>
        /// Used to infer script tags for an entire build package
        /// </summary>
        /// <param name="buildData" >The SqlSyncBuildData object for the current package</param>
        /// <param name="projectPath">The path that the SBM is unpacked to</param>
        /// <param name="regexFormats">The Regex formats that will be used to try to extract script tags</param>
        /// <param name="source">The enum designating where to get the tag from</param>
        /// <returns>Boolean as to whether the inference worked</returns>
        public static bool InferScriptTags(ref SqlSyncBuildData buildData, string projectPath, List <string> regexFormats, TagInferenceSource source)
        {
            bool   atLeastOneUpdated = false;
            string tmpTag            = string.Empty;

            foreach (SqlSyncBuildData.ScriptRow row in buildData.Script)
            {
                tmpTag = InferScriptTag(source, regexFormats, row.FileName, projectPath);
                if (tmpTag.Length > 0)
                {
                    row.Tag           = tmpTag;
                    atLeastOneUpdated = true;
                }
            }

            if (atLeastOneUpdated)
            {
                buildData.AcceptChanges();
            }

            return(atLeastOneUpdated);
        }
示例#6
0
        private void mnuImportScripts_Click(object sender, EventArgs e)
        {
            if (lstFiles.SelectedItems.Count == 0)
            {
                return;
            }

            List <string> files = new List <string>();

            for (int i = 0; i < lstFiles.SelectedItems.Count; i++)
            {
                if (lstFiles.SelectedItems[i].SubItems[3].Text.Length > 0)
                {
                    files.Add(lstFiles.SelectedItems[i].SubItems[3].Text);
                }
            }



            bool   isValid;
            string path = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);

            SqlSync.Validator.SchemaValidator validator = new SqlSync.Validator.SchemaValidator();
            string importFileXml = string.Empty;

            if (File.Exists(this.rightTempFilePath + XmlFileNames.MainProjectFile))
            {
                importFileXml = this.rightTempFilePath + XmlFileNames.MainProjectFile;
            }
            string valErrorMessage;

            isValid = SqlBuildFileHelper.ValidateAgainstSchema(importFileXml, out valErrorMessage);
            if (isValid == false)
            {
                MessageBox.Show("Unable to Import. Invalid Build File Schema?");
                return;
            }

            SqlSyncBuildData importData;

            if (File.Exists(importFileXml))
            {
                importData = new SqlSyncBuildData();
                importData.ReadXml(this.rightTempFilePath + XmlFileNames.MainProjectFile);
                importData.AcceptChanges();

                foreach (SqlSyncBuildData.ScriptRow row in importData.Script)
                {
                    if (files.Contains(row.FileName) == false)
                    {
                        row.Delete();
                    }
                }
                importData.Script.AcceptChanges();
                importData.AcceptChanges();
            }
            else
            {
                return;
            }

            string[] arrFiles = new string[files.Count];
            files.CopyTo(arrFiles);

            SqlBuild.ImportListForm frmImport = new SqlBuild.ImportListForm(importData, this.rightTempFilePath, this.buildData, arrFiles);
            if (DialogResult.OK != frmImport.ShowDialog())
            {
                return;
            }

            string[] addedFileNames;
            double   importStartNumber = SqlBuild.SqlBuildFileHelper.ImportSqlScriptFile(ref this.buildData,
                                                                                         importData, this.rightTempFilePath, lastBuildNumber, this.leftTempFilePath, this.leftTempFilePath + XmlFileNames.MainProjectFile, this.leftZipFilePath, false, out addedFileNames);


            if (importStartNumber > 0)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("Import Successful\r\n");
                sb.Append("New file indexes start at: " + importStartNumber.ToString() + "\r\n\r\n");
                MessageBox.Show(sb.ToString(), "Import Successful", MessageBoxButtons.OK, MessageBoxIcon.Information);
                this.refreshProjectList = true;
                this.lastBuildNumber    = this.lastBuildNumber + addedFileNames.Length;
            }
            else
            {
                if (importStartNumber == (double)ImportFileStatus.Canceled)
                {
                    MessageBox.Show("Import Canceled", "Import Canceled", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else if (importStartNumber == (double)ImportFileStatus.UnableToImport)
                {
                    MessageBox.Show("Unable to Import the requested file", "Import Failed", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else if (importStartNumber == (double)ImportFileStatus.NoRowsImported)
                {
                    MessageBox.Show("No rows were selected for import", "None selected", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }


            btnCompare_Click(null, EventArgs.Empty);
        }
        public void CalculateBuildPackageSHA1_CompareMethodologyTest_OrderCheckingWithTransactionsToRemove()
        {
            //Set up directory and files...
            string projectFileExtractionPath = Path.GetTempPath() + Guid.NewGuid().ToString() + "\\";

            if (!Directory.Exists(projectFileExtractionPath))
            {
                Directory.CreateDirectory(projectFileExtractionPath);
            }

            string file1 = "File1.sql";

            File.WriteAllText(projectFileExtractionPath + file1, @"This is My script
with my 
COMMIT TRANS
test");

            string file2 = "File2.sql";

            File.WriteAllText(projectFileExtractionPath + file2, Properties.Resources.CreateTestTablesScript);

            string file3 = "File3.sql";

            File.WriteAllText(projectFileExtractionPath + file3, @"This is another test that has
--ROLLBACK TRANSACTION
where the 
BEGIN TRAN
needs to be removed");


            SqlSyncBuildData buildData = SqlBuildFileHelper.CreateShellSqlSyncBuildDataObject();

            SqlSyncBuildData.ScriptRow row1 = buildData.Script.NewScriptRow();
            row1.BuildOrder           = 1;
            row1.FileName             = file1;
            row1.StripTransactionText = true;

            SqlSyncBuildData.ScriptRow row2 = buildData.Script.NewScriptRow();
            row2.BuildOrder           = 2;
            row2.FileName             = file2;
            row2.StripTransactionText = true;

            SqlSyncBuildData.ScriptRow row3 = buildData.Script.NewScriptRow();
            row3.BuildOrder           = 3;
            row3.FileName             = file3;
            row3.StripTransactionText = true;

            buildData.Script.Rows.Add(row1);
            buildData.Script.Rows.Add(row2);
            buildData.Script.Rows.Add(row3);


            string fromPath123 = SqlBuildFileHelper.CalculateBuildPackageSHA1SignatureFromPath(projectFileExtractionPath, buildData);

            ScriptBatchCollection batch = SqlBuildHelper.LoadAndBatchSqlScripts(buildData, projectFileExtractionPath);
            string fromBatch123         = SqlBuildFileHelper.CalculateBuildPackageSHA1SignatureFromBatchCollection(batch);

            buildData.Script[0].BuildOrder = 2;
            buildData.Script[1].BuildOrder = 1;
            buildData.Script[2].BuildOrder = 3;
            buildData.AcceptChanges();

            string fromPath213 = SqlBuildFileHelper.CalculateBuildPackageSHA1SignatureFromPath(projectFileExtractionPath, buildData);

            batch = SqlBuildHelper.LoadAndBatchSqlScripts(buildData, projectFileExtractionPath);
            string fromBatch213 = SqlBuildFileHelper.CalculateBuildPackageSHA1SignatureFromBatchCollection(batch);


            if (Directory.Exists(projectFileExtractionPath))
            {
                Directory.Delete(projectFileExtractionPath, true);
            }

            Assert.AreEqual(fromPath123, fromBatch123);
            Assert.AreEqual(fromPath213, fromBatch213);
            Assert.AreNotEqual(fromPath123, fromBatch213);
            Assert.AreNotEqual(fromPath213, fromBatch123);
        }
        public void CalculateBuildPackageSHA1SignatureFromPathTest_BuildOrderSwitch()
        {
            //Set up directory and files...
            string projectFileExtractionPath = Path.GetTempPath() + Guid.NewGuid().ToString() + "\\";

            if (!Directory.Exists(projectFileExtractionPath))
            {
                Directory.CreateDirectory(projectFileExtractionPath);
            }

            string file1 = "File1.sql";

            File.WriteAllText(projectFileExtractionPath + file1, Properties.Resources.CreateDatabaseScript);

            string file2 = "File2.sql";

            File.WriteAllText(projectFileExtractionPath + file2, Properties.Resources.CreateTestTablesScript);

            string file3 = "File3.sql";

            File.WriteAllText(projectFileExtractionPath + file3, Properties.Resources.LoggingTable);


            SqlSyncBuildData buildData = SqlBuildFileHelper.CreateShellSqlSyncBuildDataObject();

            SqlSyncBuildData.ScriptRow row1 = buildData.Script.NewScriptRow();
            row1.BuildOrder = 1;
            row1.FileName   = file1;

            SqlSyncBuildData.ScriptRow row2 = buildData.Script.NewScriptRow();
            row2.BuildOrder = 2;
            row2.FileName   = file2;

            SqlSyncBuildData.ScriptRow row3 = buildData.Script.NewScriptRow();
            row3.BuildOrder = 3;
            row3.FileName   = file3;

            buildData.Script.Rows.Add(row1);
            buildData.Script.Rows.Add(row2);
            buildData.Script.Rows.Add(row3);

            string order123 = SqlBuildFileHelper.CalculateBuildPackageSHA1SignatureFromPath(projectFileExtractionPath, buildData);

            buildData.Script[0].BuildOrder = 1;
            buildData.Script[1].BuildOrder = 3;
            buildData.Script[2].BuildOrder = 2;
            buildData.AcceptChanges();

            string order132 = SqlBuildFileHelper.CalculateBuildPackageSHA1SignatureFromPath(projectFileExtractionPath, buildData);

            buildData.Script[0].BuildOrder = 2;
            buildData.Script[1].BuildOrder = 1;
            buildData.Script[2].BuildOrder = 3;
            buildData.AcceptChanges();

            string order213 = SqlBuildFileHelper.CalculateBuildPackageSHA1SignatureFromPath(projectFileExtractionPath, buildData);

            buildData.Script[0].BuildOrder = 2;
            buildData.Script[1].BuildOrder = 3;
            buildData.Script[2].BuildOrder = 1;
            buildData.AcceptChanges();

            string order231 = SqlBuildFileHelper.CalculateBuildPackageSHA1SignatureFromPath(projectFileExtractionPath, buildData);

            buildData.Script[0].BuildOrder = 3;
            buildData.Script[1].BuildOrder = 1;
            buildData.Script[2].BuildOrder = 2;
            buildData.AcceptChanges();

            string order312 = SqlBuildFileHelper.CalculateBuildPackageSHA1SignatureFromPath(projectFileExtractionPath, buildData);

            buildData.Script[0].BuildOrder = 3;
            buildData.Script[1].BuildOrder = 2;
            buildData.Script[2].BuildOrder = 1;
            buildData.AcceptChanges();

            string order321 = SqlBuildFileHelper.CalculateBuildPackageSHA1SignatureFromPath(projectFileExtractionPath, buildData);

            if (Directory.Exists(projectFileExtractionPath))
            {
                Directory.Delete(projectFileExtractionPath, true);
            }

            Assert.AreNotEqual(order123, order132);
            Assert.AreNotEqual(order123, order213);
            Assert.AreNotEqual(order123, order231);
            Assert.AreNotEqual(order123, order312);
            Assert.AreNotEqual(order312, order321);

            Assert.AreNotEqual(order132, order213);
            Assert.AreNotEqual(order132, order231);
            Assert.AreNotEqual(order132, order312);
            Assert.AreNotEqual(order132, order321);

            Assert.AreNotEqual(order213, order231);
            Assert.AreNotEqual(order213, order312);
            Assert.AreNotEqual(order213, order321);

            Assert.AreNotEqual(order231, order312);
            Assert.AreNotEqual(order231, order321);

            Assert.AreNotEqual(order231, order321);
        }
        public static SqlSyncBuildData LoadCodeReviewData(SqlSyncBuildData buildData, out bool databaseSuccess)
        {
            //Make sure the table it empty...
            SqlSyncBuildData.CodeReviewDataTable crTable = buildData.CodeReview;

            //Get the list of script ids...
            var scriptIds = from s in buildData.Script
                            select s.ScriptId;
            List <string> lstScriptIds = scriptIds.ToList();

            try //sync the database and the local reviews if possible...
            {
                SqlCodeReviewEntities e = GetNewEntity();

                //Get all reviews from the database that match our scripts...
                var reviews = from crEntity in e.CodeReviews
                              where lstScriptIds.Contains(crEntity.ScriptId)
                              select crEntity;
                //string sql = ((System.Data.Objects.ObjectQuery)reviews).ToTraceString();
                List <CodeReview> lstDatabaseReviews = reviews.ToList();


                //find the matching EF CodeReview and CodeReview table entries and sync as appropriate
                var matches = from r in lstDatabaseReviews
                              join c in crTable on r.CodeReviewId equals c.CodeReviewId
                              select new { r, c };
                var matchList = matches.ToList();

                //Update the EF reviews where there is a matching, more current local version
                bool localChanges = false;
                foreach (var pair in matchList)
                {
                    //Only need to update if the XML review is more current...
                    if (pair.c.ReviewDate > pair.r.ReviewDate)
                    {
                        SyncXmlReviewDatatoEfReview(pair.c, pair.r);
                        localChanges = true;
                    }
                }


                //Add to the EF reviews if there are local ones that don't exist in the database...
                var         efReview    = from r in reviews select r.CodeReviewId;
                List <Guid> efReviewIds = efReview.ToList();
                var         localOnlyId = (from c in crTable
                                           select c.CodeReviewId).Except(efReviewIds);

                var localOnlyRow = from c in crTable
                                   where localOnlyId.Contains(c.CodeReviewId)
                                   select c;

                foreach (SqlSyncBuildData.CodeReviewRow row in localOnlyRow)
                {
                    CodeReview codeReview = new CodeReview();
                    SyncXmlReviewDatatoEfReview(row, codeReview);
                    lstDatabaseReviews.Add(codeReview);  //add to local collection
                    e.CodeReviews.AddObject(codeReview); //add to database collection
                    localChanges = true;
                }

                if (localChanges)
                {
                    e.SaveChanges();
                }


                //Now that the database can be considered the "master" set of data, load it up!
                try
                {
                    //Clear out the local rows and pull from database...
                    buildData.CodeReview.Rows.Clear();

                    List <SqlSyncBuildData.CodeReviewRow> newRows = new List <SqlSyncBuildData.CodeReviewRow>();
                    Parallel.ForEach(buildData.Script, row =>
                    {
                        string scriptId = row.ScriptId;

                        var match = from r in lstDatabaseReviews
                                    where r.ScriptId == scriptId
                                    select r;

                        foreach (CodeReview cr in match)
                        {
                            SqlSyncBuildData.CodeReviewRow newRow = buildData.CodeReview.NewCodeReviewRow();
                            newRow.ScriptId      = row.ScriptId;
                            newRow.CheckSum      = cr.CheckSum;
                            newRow.CodeReviewId  = cr.CodeReviewId;
                            newRow.Comment       = cr.Comment;
                            newRow.ReviewBy      = cr.ReviewBy;
                            newRow.ReviewDate    = (DateTime)cr.ReviewDate;
                            newRow.ReviewNumber  = cr.ReviewNumber;
                            newRow.ReviewStatus  = (short)cr.ReviewStatus;
                            newRow.ValidationKey = cr.ValidationKey;
                            newRow.ScriptRow     = row;

                            newRows.Add(newRow);
                        }
                    });

                    //Add them on the same thread...
                    foreach (SqlSyncBuildData.CodeReviewRow newRow in newRows)
                    {
                        buildData.CodeReview.AddCodeReviewRow(newRow);
                    }

                    buildData.AcceptChanges();
                    databaseSuccess = true;
                }
                catch (System.Data.Entity.Core.EntityException exe)
                {
                    log.Error(
                        "Unable to connect to SqlCodeReview database. Code Reviews will not be sync'd with the database",
                        exe);
                    databaseSuccess = false;
                }
                catch (Exception generalExe)
                {
                    log.Error("Unable to read SqlCodeReview", generalExe);
                    databaseSuccess = false;
                }
            }
            catch (System.Data.SqlClient.SqlException sqlExe)
            {
                log.Error(string.Format("Current user '{0}' errored at the database", System.Environment.UserName), sqlExe);
                databaseSuccess = false;
            }
            catch (Exception ex)
            {
                log.Error(
                    "Unable to sync local code reviews with SqlCodeReview database. Code Reviews will not be sync'd with the database",
                    ex);
                databaseSuccess = false;
            }
            return(buildData);
        }
示例#10
0
        private void saveBuildDetailsForSelectedRowsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.dgMaster.SelectedCells.Count == 0)
            {
                return;
            }

            List <SqlSyncBuildData.BuildRow> rows = new List <SqlSyncBuildData.BuildRow>();

            for (int i = 0; i < this.dgMaster.SelectedCells.Count; i++)
            {
                SqlSyncBuildData.BuildRow row = (SqlSyncBuildData.BuildRow)((System.Data.DataRowView) this.dgMaster.SelectedCells[i].OwningRow.DataBoundItem).Row;
                if (!rows.Contains(row))
                {
                    rows.Add(row);
                }
            }

            if (DialogResult.OK == saveFileDialog1.ShowDialog())
            {
                try
                {
                    //Perform a deep copy of the build data...
                    SqlSyncBuildData data = new SqlSyncBuildData();
                    using (StringReader sr = new StringReader("<?xml version=\"1.0\" standalone=\"yes\"?>" + this.sqlSyncBuildData1.GetXml()))
                    {
                        data.ReadXml(sr);
                    }

                    //Get ID's for selected rows...
                    StringBuilder sb = new StringBuilder("(");
                    foreach (SqlSyncBuildData.BuildRow row in rows)
                    {
                        sb.Append("'" + row.BuildId.ToString() + "',");
                    }
                    sb.Length = sb.Length - 1;
                    sb.Append(")");

                    //Filter out any rows that were not selected
                    System.Data.DataView view = data.Build.DefaultView;
                    view.RowFilter = data.Build.BuildIdColumn.ColumnName + " not in " + sb.ToString();

                    //Delete the non-selected rows from the build data copy object.
                    while (view.Count > 0)
                    {
                        DataRow[] kids = view[0].Row.GetChildRows("Builds_Build");
                        for (int j = 0; j < kids.Length; j++)
                        {
                            kids[j].Delete();
                        }

                        view[0].Row.Delete();
                    }

                    //Save the file...
                    string fileName = saveFileDialog1.FileName;
                    data.AcceptChanges();
                    data.WriteXml(fileName);

                    if (DialogResult.Yes == MessageBox.Show("Saved history to " + fileName + "\r\nOpen this file?", "Save Complete", MessageBoxButtons.YesNo, MessageBoxIcon.Question))
                    {
                        System.Diagnostics.Process.Start(fileName);
                    }
                }
                catch (Exception exe)
                {
                    MessageBox.Show("There was an error saving the history.\r\n" + exe.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }