public void Run() { // check arguments if (string.IsNullOrEmpty(_args.InputFilename)) { throw new ApplicationException(DacChkSumResource.ErrorNoInputFile); } var inputFile = new FileInfo(_args.InputFilename); if (!inputFile.Exists) { throw new FileNotFoundException(_args.InputFilename); } if (!DacPackage.IsDacPac(inputFile)) { throw new FileFormatException(DacChkSumResource.ErrorNotValidDacPac); } if (_args.Verbose) { Console.Out.WriteLine("Starting: [{0}]", DateTime.Now); Console.Out.WriteLine("Input: [{0}]", inputFile.FullName); Console.Out.WriteLine("Update: [{0}]", this._args.Update.ToString(CultureInfo.InvariantCulture)); } using (var package = new DacPackage(inputFile)) { package.Open(); byte[] oldChkSum = package.ReadChecksum(); byte[] newChkSum = package.CalculateChecksum(); Console.Out.WriteLine("Model checksum"); Console.Out.WriteLine("Stored: :[{0}]", DacPackage.ByteArrayToString(oldChkSum)); Console.Out.WriteLine("Calculated:[{0}]", DacPackage.ByteArrayToString(newChkSum)); if ((_args.Update) && (!System.Linq.Enumerable.SequenceEqual(oldChkSum, newChkSum))) { Console.Out.WriteLine("Updating checksum"); package.UpdateChecksum(newChkSum); package.Save(); } package.Close(); } if (_args.Verbose) { Console.Out.WriteLine("Finished: [{0}]", DateTime.Now); } }
internal static bool Merge(FileInfo inputFile, FileInfo outputFile, DirectoryInfo referenceLoadPath) { bool singleFileMode = (outputFile == null); using (var inputPackage = new DacPackage(inputFile)) { inputPackage.Open(singleFileMode ? FileAccess.ReadWrite : FileAccess.Read); var inputModelDoc = inputPackage.Model; if (inputModelDoc.Root == null) { throw new NullReferenceException("inputModelDoc"); } LogWriter.WriteMessage(String.Format(DacMergeResource.LoadingFile, inputFile.Name)); // TODO:<GertD> check if this is needed // set to last model element in input document var inputModelElement = inputModelDoc.Root.Elements().LastOrDefault(e => e.Name.LocalName == Constants.ModelElement); if (inputModelElement == null) { throw new NullReferenceException(Constants.ModelElement); } // Event handder to record all the changes to the model inputModelElement.Changed += new EventHandler<XObjectChangeEventArgs> ((sender, e) => { var element = sender as XElement; if (element != null) { var elementType = Constants.Unknown; var attribute = element.Attribute(Constants.TypeAttribute); if (attribute != null) elementType = element.Attribute(Constants.TypeAttribute).Value; var elementName = Constants.Unnamed; attribute = element.Attribute(Constants.NameAttribute); if (attribute != null) elementName = element.Attribute(Constants.NameAttribute).Value; LogWriter.WriteMessage( String.Format("{0} - {1} - {2}", e.ObjectChange, elementType, elementName)); } } ); // get child packages, using the CustomData Category="Reference" and Type="SqlSchema" // // <CustomData Category="Reference" Type="SqlSchema"> // <Metadata Value="D:\USERS\GERTD\PROJECTS\DACMERGE\CHILDDB1\BIN\DEBUG\CHILDDB1.DACPAC" Name="FileName"/> // <Metadata Value="ChildDB1.dacpac" Name="LogicalName"/> // <Metadata Value="False" Name="SuppressMissingDependenciesErrors"/> // <Metadata Value="[$(OtherServer)].[$(ChildDB1)]" Name="ExternalParts"/> // </CustomData> var header = inputModelDoc.Root.Elements() .Where(e => e.Name.LocalName == Constants.HeaderElement); var customDataElements = header.Elements() .Where(e => e.Name.LocalName == Constants.CustomData) .Where(a => a.Attribute(Constants.CategoryAttribute).Value == Constants.Reference) .Where(a => a.Attribute(Constants.TypeAttribute).Value == Constants.SqlSchema); Int32 maxDisambiguator = 0; var x = inputModelElement.Descendants() .Where(e => e.Name.LocalName == Constants.AnnotationElement) .Where(a => { var attribute = a.Attribute(Constants.DisambiguatorAttribute); return attribute != null; }) .LastOrDefault().Attribute(Constants.DisambiguatorAttribute).Value; Int32.TryParse((String.IsNullOrEmpty(x) ? "3" : x), out maxDisambiguator); Int32 maxCummulativeDisambiguator = maxDisambiguator; foreach (var customDataElement in customDataElements.ToList()) { var inSameDb = String.IsNullOrEmpty(customDataElement.Elements() .Where(e => e.Name.LocalName == Constants.Metadata) .Where(a => a.Attribute(Constants.NameAttribute).Value == Constants.ExternalParts) .Select(a => a.Attribute(Constants.ValueAttribute).Value).FirstOrDefault()); if (inSameDb) { // get dacpac filename var childDacPac = customDataElement.Elements() .Where(e => e.Name.LocalName == Constants.Metadata) .Where(a => a.Attribute(Constants.NameAttribute).Value == Constants.FileName) .Select(a => a.Attribute(Constants.ValueAttribute).Value).FirstOrDefault(); if (childDacPac == null || String.IsNullOrEmpty(childDacPac)) { throw new ArgumentNullException("childDacPac"); } var childFile = ResolveFileName(childDacPac, inputFile, referenceLoadPath); if (childFile == null) { throw new ArgumentNullException("childFile"); } if (!childFile.Exists) { throw new FileNotFoundException(childDacPac); } LogWriter.WriteMessage(String.Format(DacMergeResource.MergeFile, childFile.Name)); // import child package using (var childPackage = new DacPackage(childFile)) { childPackage.Open(FileAccess.Read); // var childModelPart = childPackage.GetPart(modelPartUri); var childModelDoc = childPackage.Model; // XDocument.Load(XmlReader.Create(childModelPart.GetStream())); if (childModelDoc.Root == null) { throw new NullReferenceException("childModelDoc"); } var childModelElement = childModelDoc.Root.Elements().FirstOrDefault(e => e.Name.LocalName == Constants.ModelElement); if (childModelElement == null) { throw new NullReferenceException(Constants.ModelElement); } // remove DatabaseOptions from child model RemoveElements(childModelElement, Constants.TypeAttribute, SqlElementType.SqlDatabaseOptions); // update Disambiguator for Annotations var annotations = childModelElement.Descendants() .Where(e => e.Name.LocalName == Constants.AnnotationElement) .Where(a => { var attribute = a.Attribute(Constants.DisambiguatorAttribute); return attribute != null; }); foreach (var annotation in annotations) { Int32 disambiguator = 0; if (Int32.TryParse(annotation.Attribute(Constants.DisambiguatorAttribute).Value, out disambiguator)) { Int32 newdisambiguator = disambiguator + maxDisambiguator; annotation.Attribute(Constants.DisambiguatorAttribute).Value = newdisambiguator.ToString(CultureInfo.InvariantCulture); maxCummulativeDisambiguator = Math.Max(newdisambiguator, maxCummulativeDisambiguator); } else { System.Diagnostics.Debug.Assert(false); } } // update Disambiguator for AttachedAnnotations var attachedAnnotations = childModelElement.Descendants() .Where(e => e.Name.LocalName == Constants.AttachedAnnotationElement) .Where(a => { var attribute = a.Attribute(Constants.DisambiguatorAttribute); return attribute != null; }); foreach (var attachedAnnotation in attachedAnnotations) { Int32 disambiguator = 0; if (Int32.TryParse(attachedAnnotation.Attribute(Constants.DisambiguatorAttribute).Value, out disambiguator)) { Int32 newdisambiguator = disambiguator + maxDisambiguator; attachedAnnotation.Attribute(Constants.DisambiguatorAttribute).Value = newdisambiguator.ToString(CultureInfo.InvariantCulture); } else { System.Diagnostics.Debug.Assert(false); } } var childElements = childModelElement.Elements(); LogWriter.WriteMessage(String.Format(DacMergeResource.MergeModelElements, childElements.Count())); inputModelElement.Add(childElements); maxDisambiguator = maxCummulativeDisambiguator; customDataElement.Remove(); } } } DacPackage outputPackage = null; if (singleFileMode) { outputPackage = inputPackage; } else { outputPackage = new DacPackage(outputFile); outputPackage.Open(FileAccess.ReadWrite); } if (singleFileMode) { LogWriter.WriteMessage(String.Format(DacMergeResource.Stream, DacPackage.ModelUri)); inputModelDoc.Save(outputPackage.GetStream(DacPackage.ModelUri)); } else { LogWriter.WriteMessage(DacMergeResource.CopyingStreams); // copy all parts from input to output package, // except for the model.xml stream which will is replace with the merged XML document content foreach (var part in inputPackage.GetParts()) { LogWriter.WriteMessage(String.Format(DacMergeResource.Stream, part.Uri)); var outputPart = outputPackage.CreatePartAs(part); if (part.Uri == DacPackage.ModelUri) { inputModelDoc.Save(outputPart.GetStream()); } else { if (outputPart == null) throw new NullReferenceException("outputPart"); part.GetStream().CopyTo(outputPart.GetStream()); } } } var outputOriginDoc = XDocument.Load(XmlReader.Create(outputPackage.GetStream(DacPackage.OriginUri))); if (outputOriginDoc.Root == null) { throw new NullReferenceException("outputOriginDoc"); } LogWriter.WriteMessage(DacMergeResource.CalculatingChecksum); var newChecksum = outputPackage.CalculateChecksum(); LogWriter.WriteMessage(DacPackage.ByteArrayToString(newChecksum)); LogWriter.WriteMessage(DacMergeResource.UpdatingChecksum); outputPackage.UpdateChecksum(newChecksum); outputOriginDoc.Save(outputPackage.GetStream(DacPackage.OriginUri)); outputPackage.Close(); inputPackage.Close(); } return true; }