/// <summary> /// Saves an output to a <c>WixOutput</c> container. /// </summary> /// <param name="wixout">Container to save to.</param> public void Save(WixOutput wixout) { using (var writer = XmlWriter.Create(wixout.CreateDataStream(WixOutputStreamName), WriterSettings)) { this.Save(writer); } }
private WixOutput CreateWixout(List <ITrackedFile> trackedFiles, Intermediate intermediate, string manifestPath, string baDataPath, string bextDataPath) { WixOutput wixout; if (String.IsNullOrEmpty(this.OutputPdbPath)) { wixout = WixOutput.Create(); } else { var trackPdb = this.BackendHelper.TrackFile(this.OutputPdbPath, TrackedFileType.Final); trackedFiles.Add(trackPdb); wixout = WixOutput.Create(trackPdb.Path); } intermediate.Save(wixout); wixout.ImportDataStream(BurnConstants.BurnManifestWixOutputStreamName, manifestPath); wixout.ImportDataStream(BurnConstants.BootstrapperApplicationDataWixOutputStreamName, baDataPath); wixout.ImportDataStream(BurnConstants.BundleExtensionDataWixOutputStreamName, bextDataPath); wixout.Reopen(); return(wixout); }
public void CanBuildBundleWithSlipstreamPatch() { var folder = TestData.Get(@"TestData\PatchSingle"); using (var fs = new DisposableFileSystem()) { var tempFolder = fs.GetFolder(); var baselinePdb = BuildMsi("Baseline.msi", folder, tempFolder, "1.0.0", "1.0.0", "1.0.0"); var update1Pdb = BuildMsi("Update.msi", folder, tempFolder, "1.0.1", "1.0.1", "1.0.1"); var patchPdb = BuildMsp("Patch1.msp", folder, tempFolder, "1.0.1"); var bundleAPdb = BuildBundle("BundleA.exe", Path.Combine(folder, "BundleA"), tempFolder); using (var wixOutput = WixOutput.Read(bundleAPdb)) { var manifestData = wixOutput.GetData(BurnConstants.BurnManifestWixOutputStreamName); var doc = new XmlDocument(); doc.LoadXml(manifestData); var nsmgr = BundleExtractor.GetBurnNamespaceManager(doc, "w"); var slipstreamMspNodes = doc.SelectNodes("/w:BurnManifest/w:Chain/w:MsiPackage/w:SlipstreamMsp", nsmgr); Assert.Equal(1, slipstreamMspNodes.Count); Assert.Equal("<SlipstreamMsp Id='PatchA' />", slipstreamMspNodes[0].GetTestXml()); } } }
public void Execute() { var trackedFiles = new List <ITrackedFile>(); var group = this.FilesWithEmbeddedFiles.GroupBy(e => e.Uri); foreach (var expectedEmbeddedFileByUri in group) { var baseUri = expectedEmbeddedFileByUri.Key; using (var wixout = WixOutput.Read(baseUri)) { var uniqueIds = new SortedSet <string>(StringComparer.OrdinalIgnoreCase); foreach (var embeddedFile in expectedEmbeddedFileByUri) { if (uniqueIds.Add(embeddedFile.EmbeddedFileId)) { wixout.ExtractEmbeddedFile(embeddedFile.EmbeddedFileId, embeddedFile.OutputPath); trackedFiles.Add(this.BackendHelper.TrackFile(embeddedFile.OutputPath, TrackedFileType.Temporary)); } } } } this.TrackedFiles = trackedFiles; }
/// <summary> /// Loads an output from a path on disk. /// </summary> /// <param name="path">Path to output file saved on disk.</param> /// <param name="tableDefinitions">Table definitions to use for creating strongly-typed rows.</param> /// <param name="suppressVersionCheck">Suppresses wix.dll version mismatch check.</param> /// <returns>Output object.</returns> public static WindowsInstallerData Load(string path, TableDefinitionCollection tableDefinitions, bool suppressVersionCheck = false) { using (var wixOutput = WixOutput.Read(path)) { return(WindowsInstallerData.Load(wixOutput, tableDefinitions, suppressVersionCheck)); } }
public void CanLoadPdbGeneratedByBuildViaWixOutput() { var folder = TestData.Get(@"TestData\MultiFileCompressed"); using (var fs = new DisposableFileSystem()) { var intermediateFolder = fs.GetFolder(); var result = WixRunner.Execute(new[] { "build", Path.Combine(folder, "Package.wxs"), Path.Combine(folder, "PackageComponents.wxs"), "-d", "MediaTemplateCompressionLevel", "-loc", Path.Combine(folder, "Package.en-us.wxl"), "-bindpath", Path.Combine(folder, "data"), "-intermediateFolder", intermediateFolder, "-o", Path.Combine(intermediateFolder, @"bin\test.msi") }); result.AssertSuccess(); Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\test.msi"))); Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\cab1.cab"))); var pdbPath = Path.Combine(intermediateFolder, @"bin\test.wixpdb"); Assert.True(File.Exists(pdbPath)); var wixOutput = WixOutput.Read(pdbPath); var output = WindowsInstallerData.Load(wixOutput, suppressVersionCheck: true); Assert.NotNull(output); } }
public void CanBuildBinaryWixlib() { var folder = TestData.Get(@"TestData\SingleFile"); using (var fs = new DisposableFileSystem()) { var baseFolder = fs.GetFolder(); var intermediateFolder = Path.Combine(baseFolder, "obj"); var result = WixRunner.Execute( "build", Path.Combine(folder, "Package.wxs"), Path.Combine(folder, "PackageComponents.wxs"), "-loc", Path.Combine(folder, "Package.en-us.wxl"), "-bindpath", Path.Combine(folder, "data"), "-intermediateFolder", intermediateFolder, "-bindfiles", "-o", Path.Combine(baseFolder, @"bin\test.wixlib")); result.AssertSuccess(); using (var wixout = WixOutput.Read(Path.Combine(baseFolder, @"bin\test.wixlib"))) { Assert.NotNull(wixout.GetDataStream("wix-ir.json")); var text = wixout.GetData("wix-ir/test.txt"); Assert.Equal("This is test.txt.", text); } } }
public void CanBuildBinaryWixlibWithCollidingFilenames() { var folder = TestData.Get(@"TestData\SameFileFolders"); using (var fs = new DisposableFileSystem()) { var baseFolder = fs.GetFolder(); var intermediateFolder = Path.Combine(baseFolder, "obj"); var result = WixRunner.Execute( "build", Path.Combine(folder, "TestComponents.wxs"), "-bindpath", Path.Combine(folder, "data"), "-intermediateFolder", intermediateFolder, "-bindfiles", "-o", Path.Combine(baseFolder, @"bin\test.wixlib")); result.AssertSuccess(); using (var wixout = WixOutput.Read(Path.Combine(baseFolder, @"bin\test.wixlib"))) { Assert.NotNull(wixout.GetDataStream("wix-ir.json")); var text = wixout.GetData("wix-ir/test.txt"); Assert.Equal(@"This is a\test.txt.", text); var text2 = wixout.GetData("wix-ir/test.txt-1"); Assert.Equal(@"This is b\test.txt.", text2); var text3 = wixout.GetData("wix-ir/test.txt-2"); Assert.Equal(@"This is c\test.txt.", text3); } } }
private WindowsInstallerData GetWindowsInstallerData() { if (this.WiData == null) { using var wixOutput = WixOutput.Read(this.PackagePdb); this.WiData = WindowsInstallerData.Load(wixOutput); } return(this.WiData); }
public void VerifyPackageIsCached(string packageId) { using var wixOutput = WixOutput.Read(this.BundlePdb); var intermediate = Intermediate.Load(wixOutput); var section = intermediate.Sections.Single(); var packageSymbol = section.Symbols.OfType <WixBundlePackageSymbol>().Single(p => p.Id.Id == packageId); var cachePath = this.GetPackageCachePathForCacheId(packageSymbol.CacheId, packageSymbol.PerMachine == YesNoDefaultType.Yes); Assert.True(Directory.Exists(cachePath)); }
public void CanBuildBundleWithTag() { var testDataFolder = TestData.Get(@"TestData"); using (var fs = new DisposableFileSystem()) { var baseFolder = fs.GetFolder(); var intermediateFolder = Path.Combine(baseFolder, "obj"); var result = WixRunner.Execute(new[] { "build", Path.Combine(testDataFolder, "ProductTag", "PackageWithTag.wxs"), Path.Combine(testDataFolder, "ProductTag", "PackageComponents.wxs"), "-loc", Path.Combine(testDataFolder, "ProductTag", "Package.en-us.wxl"), "-bindpath", Path.Combine(testDataFolder, "ProductTag"), "-intermediateFolder", Path.Combine(intermediateFolder, "package"), "-o", Path.Combine(baseFolder, "package", @"test.msi") }); result.AssertSuccess(); result = WixRunner.Execute(new[] { "build", Path.Combine(testDataFolder, "BundleTag", "BundleWithTag.wxs"), "-bindpath", Path.Combine(testDataFolder, "BundleTag"), "-bindpath", Path.Combine(baseFolder, "package"), "-intermediateFolder", intermediateFolder, "-o", Path.Combine(baseFolder, @"bin\test.exe") }); result.AssertSuccess(); Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.exe"))); Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); using (var ouput = WixOutput.Read(Path.Combine(baseFolder, @"bin\test.wixpdb"))) { var badata = ouput.GetDataStream("wix-burndata.xml"); var doc = XDocument.Load(badata); var swidTag = doc.Root.Element(BurnManifestNamespace + "Registration").Element(BurnManifestNamespace + "SoftwareTag").Value; var swidTagPath = Path.Combine(baseFolder, "test.swidtag"); File.WriteAllText(swidTagPath, swidTag); var docTag = XDocument.Load(swidTagPath); var title = docTag.Root.Attribute("name").Value; var version = docTag.Root.Attribute("version").Value; Assert.Equal("~TagTestBundle", title); Assert.Equal("4.3.2.1", version); } } }
public void CanBuildBundleWithTag() { var testDataFolder = TestData.Get(@"TestData"); using (var fs = new DisposableFileSystem()) { var baseFolder = fs.GetFolder(); var intermediateFolder = Path.Combine(baseFolder, "obj"); var extPath = Path.GetFullPath(new Uri(typeof(TagExtensionFactory).Assembly.CodeBase).LocalPath); var result = WixRunner.Execute(new[] { "build", Path.Combine(testDataFolder, "ProductTag", "PackageWithTag.wxs"), Path.Combine(testDataFolder, "ProductTag", "PackageComponents.wxs"), "-loc", Path.Combine(testDataFolder, "ProductTag", "Package.en-us.wxl"), "-bindpath", Path.Combine(testDataFolder, "ProductTag"), "-ext", extPath, "-intermediateFolder", Path.Combine(intermediateFolder, "package"), "-o", Path.Combine(baseFolder, "package", @"test.msi") }); result.AssertSuccess(); result = WixRunner.Execute(new[] { "build", Path.Combine(testDataFolder, "BundleTag", "BundleWithTag.wxs"), "-ext", extPath, "-bindpath", Path.Combine(testDataFolder, "BundleTag"), "-bindpath", Path.Combine(baseFolder, "package"), "-intermediateFolder", intermediateFolder, "-o", Path.Combine(baseFolder, @"bin\test.exe") }); result.AssertSuccess(); Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.exe"))); Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); using var ouput = WixOutput.Read(Path.Combine(baseFolder, @"bin\test.wixpdb")); var badata = ouput.GetDataStream("wix-badata.xml"); var doc = XDocument.Load(badata); var swidTag = doc.Root.Element("WixSoftwareTag").Value; var docTag = XDocument.Parse(swidTag); var title = docTag.Root.Element(SwidTagNamespace + "product_title").Value; var version = docTag.Root.Element(SwidTagNamespace + "product_version").Element(SwidTagNamespace + "name").Value; Assert.Equal("~TagTestBundle", title); Assert.Equal("4.3.2.1", version); } }
public void CanUpdateIntermediate() { var sln = new SourceLineNumber("test.wxs", 1); var section = new IntermediateSection("test", SectionType.Product, 65001); section.Symbols.Add(new ComponentSymbol(sln, new Identifier(AccessModifier.Public, "TestComponent")) { ComponentId = new Guid(1, 0, 0, new byte[8]).ToString("B"), DirectoryRef = "TestFolder", Location = ComponentLocation.Either, }); var intermediate = new Intermediate("TestIntermediate", IntermediateLevels.Compiled, new[] { section }, null); var path = Path.GetTempFileName(); try { intermediate.Save(path); var uri = new Uri(Path.GetFullPath(path)); var stream = File.Open(path, FileMode.Open, FileAccess.ReadWrite); using (var wixout = WixOutput.Read(uri, stream)) { var loaded = Intermediate.Load(wixout); var symbol = (ComponentSymbol)loaded.Sections.Single().Symbols.Single(); Assert.Equal("TestComponent", symbol.Id.Id); Assert.Equal(AccessModifier.Public, symbol.Id.Access); wixout.Reopen(writable: true); section.Symbols.Add(new ComponentSymbol(sln, new Identifier(AccessModifier.Public, "NewComponent")) { ComponentId = new Guid(1, 0, 0, new byte[8]).ToString("B"), }); intermediate.Save(wixout); loaded = Intermediate.Load(wixout); var newSymbol = loaded.Sections.Single().Symbols.Where(t => t.Id.Id == "NewComponent"); Assert.Single(newSymbol); } var loadedAfterDispose = Intermediate.Load(path); var newSymbolStillThere = loadedAfterDispose.Sections.Single().Symbols.Where(t => t.Id.Id == "NewComponent"); Assert.Single(newSymbolStillThere); } finally { File.Delete(path); } }
private WixBundleSymbol GetBundleSymbol() { if (this.BundleSymbol == null) { using var wixOutput = WixOutput.Read(this.BundlePdb); var intermediate = Intermediate.Load(wixOutput); var section = intermediate.Sections.Single(); this.BundleSymbol = section.Symbols.OfType <WixBundleSymbol>().Single(); } return(this.BundleSymbol); }
public void RemovePackageFromCache(string packageId) { using var wixOutput = WixOutput.Read(this.BundlePdb); var intermediate = Intermediate.Load(wixOutput); var section = intermediate.Sections.Single(); var packageSymbol = section.Symbols.OfType <WixBundlePackageSymbol>().Single(p => p.Id.Id == packageId); var cachePath = this.GetPackageCachePathForCacheId(packageSymbol.CacheId, packageSymbol.PerMachine == YesNoDefaultType.Yes); if (Directory.Exists(cachePath)) { Directory.Delete(cachePath, true); } }
public void CanBuildBundleWithLargePayload() { var folder = TestData.Get(@"TestData\LargePayload"); // Overwrite the payload with a 2.5 GiB file. We do this dynamically to avoid committing such // a large file to source control. var largeFile = Path.Combine(folder, "data", "large_file.dat"); const long TwoAndAHalfGigabytes = 2_684_354_560; using (var stream = File.Create(largeFile)) { stream.Seek(TwoAndAHalfGigabytes - 1, SeekOrigin.Begin); stream.WriteByte(1); } using (var fs = new DisposableFileSystem()) { var baseFolder = fs.GetFolder(); var intermediateFolder = Path.Combine(baseFolder, "obj"); var exePath = Path.Combine(baseFolder, @"bin\test.exe"); var pdbPath = Path.Combine(baseFolder, @"bin\test.wixpdb"); var result = WixRunner.Execute(new[] { "build", Path.Combine(folder, "Bundle.wxs"), "-loc", Path.Combine(folder, "Bundle.en-us.wxl"), "-bindpath", Path.Combine(folder, "data"), "-intermediateFolder", intermediateFolder, "-o", exePath, }); result.AssertSuccess(); Assert.Empty(result.Messages.Where(m => m.Level == MessageLevel.Warning)); Assert.True(File.Exists(exePath)); Assert.True(File.Exists(pdbPath)); Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\large_file.dat"))); using (var wixOutput = WixOutput.Read(pdbPath)) { var intermediate = Intermediate.Load(wixOutput); var section = intermediate.Sections.Single(); var payloadSymbol = section.Symbols.OfType <WixBundlePayloadSymbol>().Where(x => x.Name == "large_file.dat").Single(); Assert.Equal(TwoAndAHalfGigabytes, payloadSymbol.FileSize); } } File.Delete(largeFile); }
/// <summary> /// Loads an output from a WixOutput object. /// </summary> /// <param name="wixOutput">WixOutput object.</param> /// <param name="tableDefinitions">Table definitions to use for creating strongly-typed rows.</param> /// <param name="suppressVersionCheck">Suppresses wix.dll version mismatch check.</param> /// <returns>Output object.</returns> public static WindowsInstallerData Load(WixOutput wixOutput, TableDefinitionCollection tableDefinitions, bool suppressVersionCheck = false) { using (var stream = wixOutput.GetDataStream(WixOutputStreamName)) using (var reader = XmlReader.Create(stream, null, wixOutput.Uri.AbsoluteUri)) { try { reader.MoveToContent(); return(WindowsInstallerData.Read(reader, tableDefinitions, suppressVersionCheck)); } catch (XmlException xe) { throw new WixCorruptFileException(wixOutput.Uri.AbsoluteUri, "wixout", xe); } } }
public PackageInstaller(WixTestContext testContext, string filename) { this.Package = Path.Combine(testContext.TestDataFolder, $"{filename}.msi"); this.PackagePdb = Path.Combine(testContext.TestDataFolder, $"{filename}.wixpdb"); this.TestContext = testContext; using var wixOutput = WixOutput.Read(this.PackagePdb); var intermediate = Intermediate.Load(wixOutput); var section = intermediate.Sections.Single(); var platformSummary = section.Symbols.OfType <SummaryInformationSymbol>().Single(s => s.PropertyId == SummaryInformationType.PlatformAndLanguage); var platformString = platformSummary.Value.Split(new char[] { ';' }, 2)[0]; this.IsX64 = platformString != "Intel"; this.WiData = WindowsInstallerData.Load(wixOutput); }
private static void VerifyPatchTargetCodes(string pdbPath, string[] expected) { using (var wixOutput = WixOutput.Read(pdbPath)) { var manifestData = wixOutput.GetData(BurnConstants.BurnManifestWixOutputStreamName); var doc = new XmlDocument(); doc.LoadXml(manifestData); var nsmgr = BundleExtractor.GetBurnNamespaceManager(doc, "w"); var patchTargetCodes = doc.SelectNodes("/w:BurnManifest/w:PatchTargetCode", nsmgr); var actual = new List <string>(); foreach (XmlNode patchTargetCodeNode in patchTargetCodes) { actual.Add(patchTargetCodeNode.GetTestXml()); } WixAssert.CompareLineByLine(expected, actual.ToArray()); } }
public void IncludeSourceLineNumbersPreserved() { var folder = TestData.Get(@"TestData\IncludePath"); using (var fs = new DisposableFileSystem()) { var baseFolder = fs.GetFolder(); var intermediateFolder = Path.Combine(baseFolder, "obj"); var result = WixRunner.Execute(warningsAsErrors: false, new[] { "build", Path.Combine(folder, "Package.wxs"), Path.Combine(folder, "PackageComponents.wxs"), "-loc", Path.Combine(folder, "Package.en-us.wxl"), "-includepath", Path.Combine(folder, "data"), "-bindpath", Path.Combine(folder, "data"), "-intermediateFolder", intermediateFolder, "-o", Path.Combine(baseFolder, @"bin\test.msi") }); result.AssertSuccess(); using (var output = WixOutput.Read(Path.Combine(baseFolder, @"bin\test.wixpdb"))) { var intermediate = Intermediate.Load(output); var component = intermediate.Sections.Single().Symbols.OfType <ComponentSymbol>().Single(); Assert.Equal(3, component.SourceLineNumbers.LineNumber); Assert.Equal(5, component.SourceLineNumbers.Parent.LineNumber); var encoded = component.SourceLineNumbers.GetEncoded(); var decoded = SourceLineNumber.CreateFromEncoded(encoded); Assert.Equal(3, decoded.LineNumber); Assert.Equal(5, decoded.Parent.LineNumber); } } }
public void CanSaveAndLoadWindowsInstallerData() { var sln = new SourceLineNumber("test.wxs", 1); var windowsInstallerData = new Wid.WindowsInstallerData(sln) { Type = OutputType.Product, }; var fileTable = windowsInstallerData.EnsureTable(Wid.WindowsInstallerTableDefinitions.File); var fileRow = (FileRow)fileTable.CreateRow(sln); fileRow.File = "TestFile"; var path = Path.GetTempFileName(); try { using (var wixout = WixOutput.Create(path)) { windowsInstallerData.Save(wixout); } var loaded = Wid.WindowsInstallerData.Load(path); var loadedTable = Assert.Single(loaded.Tables); Assert.Equal(Wid.WindowsInstallerTableDefinitions.File.Name, loadedTable.Name); var loadedRow = Assert.Single(loadedTable.Rows); var loadedFileRow = Assert.IsType <FileRow>(loadedRow); Assert.Equal("TestFile", loadedFileRow.File); } finally { File.Delete(path); } }
public void CanBuildSingleExeRemotePayloadBundle() { var folder = TestData.Get(@"TestData"); using (var fs = new DisposableFileSystem()) { var baseFolder = fs.GetFolder(); var intermediateFolder = Path.Combine(baseFolder, "obj"); var exePath = Path.Combine(baseFolder, @"bin\test.exe"); var pdbPath = Path.Combine(baseFolder, @"bin\test.wixpdb"); var result = WixRunner.Execute(new[] { "build", Path.Combine(folder, "SingleExeBundle", "SingleExeRemotePayload.wxs"), Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"), "-bindpath", Path.Combine(folder, "SimpleBundle", "data"), "-intermediateFolder", intermediateFolder, "-o", exePath, }); result.AssertSuccess(); Assert.True(File.Exists(exePath)); Assert.True(File.Exists(pdbPath)); using (var wixOutput = WixOutput.Read(pdbPath)) { var intermediate = Intermediate.Load(wixOutput); var section = intermediate.Sections.Single(); var payloadSymbol = section.Symbols.OfType <WixBundlePayloadSymbol>().Where(x => x.Id.Id == "NetFx462Web").Single(); Assert.Equal(Int64.MaxValue, payloadSymbol.FileSize); } } }
private WixOutput CreateWixout(List <ITrackedFile> trackedFiles, Intermediate intermediate, WindowsInstallerData output) { WixOutput wixout; if (String.IsNullOrEmpty(this.OutputPdbPath)) { wixout = WixOutput.Create(); } else { var trackPdb = this.BackendHelper.TrackFile(this.OutputPdbPath, TrackedFileType.Final); trackedFiles.Add(trackPdb); wixout = WixOutput.Create(trackPdb.Path); } intermediate.Save(wixout); output.Save(wixout); wixout.Reopen(); return(wixout); }
public void CanBuildSimpleBundle() { var folder = TestData.Get(@"TestData\SimpleBundle"); using (var fs = new DisposableFileSystem()) { var baseFolder = fs.GetFolder(); var intermediateFolder = Path.Combine(baseFolder, "obj"); var exePath = Path.Combine(baseFolder, @"bin\test.exe"); var pdbPath = Path.Combine(baseFolder, @"bin\test.wixpdb"); var baFolderPath = Path.Combine(baseFolder, "ba"); var extractFolderPath = Path.Combine(baseFolder, "extract"); var result = WixRunner.Execute(new[] { "build", Path.Combine(folder, "Bundle.wxs"), "-loc", Path.Combine(folder, "Bundle.en-us.wxl"), "-bindpath", Path.Combine(folder, "data"), "-intermediateFolder", intermediateFolder, "-o", exePath, }); result.AssertSuccess(); Assert.Empty(result.Messages.Where(m => m.Level == MessageLevel.Warning)); Assert.True(File.Exists(exePath)); Assert.True(File.Exists(pdbPath)); using (var wixOutput = WixOutput.Read(pdbPath)) { var intermediate = Intermediate.Load(wixOutput); var section = intermediate.Sections.Single(); var bundleSymbol = section.Symbols.OfType <WixBundleSymbol>().Single(); Assert.Equal("1.0.0.0", bundleSymbol.Version); var previousVersion = bundleSymbol.Fields[(int)WixBundleSymbolFields.Version].PreviousValue; Assert.Equal("!(bind.packageVersion.test.msi)", previousVersion.AsString()); var msiSymbol = section.Symbols.OfType <WixBundlePackageSymbol>().Single(); Assert.Equal("test.msi", msiSymbol.Id.Id); var extractResult = BundleExtractor.ExtractBAContainer(null, exePath, baFolderPath, extractFolderPath); extractResult.AssertSuccess(); var burnManifestData = wixOutput.GetData(BurnConstants.BurnManifestWixOutputStreamName); var extractedBurnManifestData = File.ReadAllText(Path.Combine(baFolderPath, "manifest.xml"), Encoding.UTF8); Assert.Equal(extractedBurnManifestData, burnManifestData); var baManifestData = wixOutput.GetData(BurnConstants.BootstrapperApplicationDataWixOutputStreamName); var extractedBaManifestData = File.ReadAllText(Path.Combine(baFolderPath, "BootstrapperApplicationData.xml"), Encoding.UTF8); Assert.Equal(extractedBaManifestData, baManifestData); var bextManifestData = wixOutput.GetData(BurnConstants.BundleExtensionDataWixOutputStreamName); var extractedBextManifestData = File.ReadAllText(Path.Combine(baFolderPath, "BundleExtensionData.xml"), Encoding.UTF8); Assert.Equal(extractedBextManifestData, bextManifestData); var logElements = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Log"); var logElement = (XmlNode)Assert.Single(logElements); Assert.Equal("<Log PathVariable='WixBundleLog' Prefix='~TestBundle' Extension='log' />", logElement.GetTestXml()); var registrationElements = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Registration"); var registrationElement = (XmlNode)Assert.Single(registrationElements); Assert.Equal($"<Registration Id='{bundleSymbol.BundleId}' ExecutableName='test.exe' PerMachine='yes' Tag='' Version='1.0.0.0' ProviderKey='{bundleSymbol.BundleId}'>" + "<Arp Register='yes' DisplayName='~TestBundle' DisplayVersion='1.0.0.0' Publisher='Example Corporation' />" + "</Registration>", registrationElement.GetTestXml()); var msiPayloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload[@Id='test.msi']"); var msiPayload = (XmlNode)Assert.Single(msiPayloads); Assert.Equal("<Payload Id='test.msi' FilePath='test.msi' FileSize='*' Hash='*' Packaging='embedded' SourcePath='a0' Container='WixAttachedContainer' />", msiPayload.GetTestXml(new Dictionary <string, List <string> >() { { "Payload", new List <string> { "FileSize", "Hash" } } })); } var manifestResource = new Resource(ResourceType.Manifest, "#1", 1033); manifestResource.Load(exePath); var actualManifestData = Encoding.UTF8.GetString(manifestResource.Data); Assert.Equal("<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<assembly manifestVersion=\"1.0\" xmlns=\"urn:schemas-microsoft-com:asm.v1\">" + "<assemblyIdentity name=\"test.exe\" version=\"1.0.0.0\" processorArchitecture=\"x86\" type=\"win32\" />" + "<description>~TestBundle</description>" + "<dependency><dependentAssembly><assemblyIdentity name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"x86\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\" type=\"win32\" /></dependentAssembly></dependency>" + "<compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\"><application><supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\" /><supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\" /><supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\" /><supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\" /><supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\" /></application></compatibility>" + "<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\"><security><requestedPrivileges><requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\" /></requestedPrivileges></security></trustInfo>" + "<application xmlns=\"urn:schemas-microsoft-com:asm.v3\"><windowsSettings><dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">true/pm</dpiAware><dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness></windowsSettings></application>" + "</assembly>", actualManifestData); } }
public void CanBuildSimpleBundle() { var folder = TestData.Get(@"TestData\SimpleBundle"); using (var fs = new DisposableFileSystem()) { var baseFolder = fs.GetFolder(); var intermediateFolder = Path.Combine(baseFolder, "obj"); var exePath = Path.Combine(baseFolder, @"bin\test.exe"); var pdbPath = Path.Combine(baseFolder, @"bin\test.wixpdb"); var baFolderPath = Path.Combine(baseFolder, "ba"); var extractFolderPath = Path.Combine(baseFolder, "extract"); var result = WixRunner.Execute(new[] { "build", Path.Combine(folder, "Bundle.wxs"), "-loc", Path.Combine(folder, "Bundle.en-us.wxl"), "-bindpath", Path.Combine(folder, "data"), "-intermediateFolder", intermediateFolder, "-o", exePath, }); result.AssertSuccess(); Assert.Empty(result.Messages.Where(m => m.Level == MessageLevel.Warning)); Assert.True(File.Exists(exePath)); Assert.True(File.Exists(pdbPath)); using (var wixOutput = WixOutput.Read(pdbPath)) { var intermediate = Intermediate.Load(wixOutput); var section = intermediate.Sections.Single(); var bundleSymbol = section.Symbols.OfType <WixBundleSymbol>().Single(); Assert.Equal("1.0.0.0", bundleSymbol.Version); var previousVersion = bundleSymbol.Fields[(int)WixBundleSymbolFields.Version].PreviousValue; Assert.Equal("!(bind.packageVersion.test.msi)", previousVersion.AsString()); var msiSymbol = section.Symbols.OfType <WixBundlePackageSymbol>().Single(); Assert.Equal("test.msi", msiSymbol.Id.Id); var extractResult = BundleExtractor.ExtractBAContainer(null, exePath, baFolderPath, extractFolderPath); extractResult.AssertSuccess(); var burnManifestData = wixOutput.GetData(BurnConstants.BurnManifestWixOutputStreamName); var extractedBurnManifestData = File.ReadAllText(Path.Combine(baFolderPath, "manifest.xml"), Encoding.UTF8); Assert.Equal(extractedBurnManifestData, burnManifestData); var baManifestData = wixOutput.GetData(BurnConstants.BootstrapperApplicationDataWixOutputStreamName); var extractedBaManifestData = File.ReadAllText(Path.Combine(baFolderPath, "BootstrapperApplicationData.xml"), Encoding.UTF8); Assert.Equal(extractedBaManifestData, baManifestData); var bextManifestData = wixOutput.GetData(BurnConstants.BundleExtensionDataWixOutputStreamName); var extractedBextManifestData = File.ReadAllText(Path.Combine(baFolderPath, "BundleExtensionData.xml"), Encoding.UTF8); Assert.Equal(extractedBextManifestData, bextManifestData); var logElements = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Log"); var logElement = (XmlNode)Assert.Single(logElements); Assert.Equal("<Log PathVariable='WixBundleLog' Prefix='~TestBundle' Extension='log' />", logElement.GetTestXml()); var registrationElements = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Registration"); var registrationElement = (XmlNode)Assert.Single(registrationElements); Assert.Equal($"<Registration Id='{bundleSymbol.BundleId}' ExecutableName='test.exe' PerMachine='yes' Tag='' Version='1.0.0.0' ProviderKey='{bundleSymbol.BundleId}'>" + "<Arp Register='yes' DisplayName='~TestBundle' DisplayVersion='1.0.0.0' Publisher='Example Corporation' />" + "</Registration>", registrationElement.GetTestXml()); } } }
/// <summary> /// Loads an output from a WixOutput object. /// </summary> /// <param name="wixOutput">WixOutput object.</param> /// <param name="suppressVersionCheck">Suppresses wix.dll version mismatch check.</param> /// <returns>Output object.</returns> public static WindowsInstallerData Load(WixOutput wixOutput, bool suppressVersionCheck = false) { var tableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All); return(WindowsInstallerData.Load(wixOutput, tableDefinitions, suppressVersionCheck)); }
public void Execute() { var section = this.Output.Sections.Single(); var fileTransfers = new List <IFileTransfer>(); var trackedFiles = new List <ITrackedFile>(); // First look for data we expect to find... Chain, WixGroups, etc. // We shouldn't really get past the linker phase if there are // no group items... that means that there's no UX, no Chain, // *and* no Containers! var chainPackageSymbols = this.GetRequiredSymbols <WixBundlePackageSymbol>(); var wixGroupSymbols = this.GetRequiredSymbols <WixGroupSymbol>(); // Ensure there is one and only one WixBundleSymbol. // The compiler and linker behavior should have colluded to get // this behavior. var bundleSymbol = this.GetSingleSymbol <WixBundleSymbol>(); bundleSymbol.ProviderKey = bundleSymbol.BundleId = Guid.NewGuid().ToString("B").ToUpperInvariant(); bundleSymbol.Attributes |= WixBundleAttributes.PerMachine; // default to per-machine but the first-per user package wil flip the bundle per-user. // Ensure there is one and only one WixBootstrapperApplicationDllSymbol. // The compiler and linker behavior should have colluded to get // this behavior. var bundleApplicationDllSymbol = this.GetSingleSymbol <WixBootstrapperApplicationDllSymbol>(); // Ensure there is one and only one WixChainSymbol. // The compiler and linker behavior should have colluded to get // this behavior. var chainSymbol = this.GetSingleSymbol <WixChainSymbol>(); if (this.Messaging.EncounteredError) { return; } // If there are any fields to resolve later, create the cache to populate during bind. var variableCache = this.DelayedFields.Any() ? new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase) : null; IEnumerable <ISearchFacade> orderedSearches; IDictionary <string, IEnumerable <IntermediateSymbol> > extensionSearchSymbolsById; { var orderSearchesCommand = new OrderSearchesCommand(this.Messaging, section); orderSearchesCommand.Execute(); orderedSearches = orderSearchesCommand.OrderedSearchFacades; extensionSearchSymbolsById = orderSearchesCommand.ExtensionSearchSymbolsByExtensionId; } // Extract files that come from binary .wixlibs and WixExtensions (this does not extract files from merge modules). { var extractedFiles = this.BackendHelper.ExtractEmbeddedFiles(this.ExpectedEmbeddedFiles); trackedFiles.AddRange(extractedFiles); } // Get the explicit payloads. var payloadSymbols = section.Symbols.OfType <WixBundlePayloadSymbol>().ToDictionary(t => t.Id.Id); var packagesPayloads = RecalculatePackagesPayloads(payloadSymbols, wixGroupSymbols); // Update explicitly authored payloads with their parent container // to make it easier to gather the payloads later. foreach (var groupSymbol in wixGroupSymbols) { if (ComplexReferenceChildType.Payload == groupSymbol.ChildType) { var payloadSymbol = payloadSymbols[groupSymbol.ChildId]; if (ComplexReferenceParentType.Container == groupSymbol.ParentType) { // TODO: v3 didn't warn if we overwrote the payload's container. // Should we warn now? payloadSymbol.ContainerRef = groupSymbol.ParentId; } else if (ComplexReferenceParentType.Layout == groupSymbol.ParentType) { payloadSymbol.LayoutOnly = true; } } } var layoutDirectory = Path.GetDirectoryName(this.OutputPath); // Process the explicitly authored payloads. ISet <string> processedPayloads; { var command = new ProcessPayloadsCommand(this.BackendHelper, this.PayloadHarvester, payloadSymbols.Values, bundleSymbol.DefaultPackagingType, layoutDirectory); command.Execute(); fileTransfers.AddRange(command.FileTransfers); trackedFiles.AddRange(command.TrackedFiles); processedPayloads = new HashSet <string>(payloadSymbols.Keys); } IDictionary <string, PackageFacade> facades; { var command = new GetPackageFacadesCommand(this.Messaging, chainPackageSymbols, section); command.Execute(); facades = command.PackageFacades; } if (this.Messaging.EncounteredError) { return; } // Process each package facade. Note this is likely to add payloads and other symbols so // note that any indexes created above may be out of date now. foreach (var facade in facades.Values) { switch (facade.PackageSymbol.Type) { case WixBundlePackageType.Exe: { var command = new ProcessExePackageCommand(facade, payloadSymbols); command.Execute(); } break; case WixBundlePackageType.Msi: { var command = new ProcessMsiPackageCommand(this.ServiceProvider, this.BackendExtensions, section, facade, packagesPayloads[facade.PackageId]); command.Execute(); } break; case WixBundlePackageType.Msp: { var command = new ProcessMspPackageCommand(this.Messaging, section, facade, payloadSymbols); command.Execute(); } break; case WixBundlePackageType.Msu: { var command = new ProcessMsuPackageCommand(facade, payloadSymbols); command.Execute(); } break; } if (null != variableCache) { BindBundleCommand.PopulatePackageVariableCache(facade, variableCache); } } if (this.Messaging.EncounteredError) { return; } // Reindex the payloads now that all the payloads (minus the manifest payloads that will be created later) // are present. payloadSymbols = section.Symbols.OfType <WixBundlePayloadSymbol>().ToDictionary(t => t.Id.Id); wixGroupSymbols = this.GetRequiredSymbols <WixGroupSymbol>(); packagesPayloads = RecalculatePackagesPayloads(payloadSymbols, wixGroupSymbols); // Process the payloads that were added by processing the packages. { var toProcess = payloadSymbols.Values.Where(r => !processedPayloads.Contains(r.Id.Id)).ToList(); var command = new ProcessPayloadsCommand(this.BackendHelper, this.PayloadHarvester, toProcess, bundleSymbol.DefaultPackagingType, layoutDirectory); command.Execute(); fileTransfers.AddRange(command.FileTransfers); trackedFiles.AddRange(command.TrackedFiles); processedPayloads = null; } // Set the package metadata from the payloads now that we have the complete payload information. { foreach (var facade in facades.Values) { facade.PackageSymbol.Size = 0; var packagePayloads = packagesPayloads[facade.PackageId]; foreach (var payload in packagePayloads.Values) { facade.PackageSymbol.Size += payload.FileSize.Value; } if (!facade.PackageSymbol.InstallSize.HasValue) { facade.PackageSymbol.InstallSize = facade.PackageSymbol.Size; } var packagePayload = payloadSymbols[facade.PackageSymbol.PayloadRef]; if (String.IsNullOrEmpty(facade.PackageSymbol.Description)) { facade.PackageSymbol.Description = packagePayload.Description; } if (String.IsNullOrEmpty(facade.PackageSymbol.DisplayName)) { facade.PackageSymbol.DisplayName = packagePayload.DisplayName; } } } // Give the UX payloads their embedded IDs... var uxPayloadIndex = 0; { foreach (var payload in payloadSymbols.Values.Where(p => BurnConstants.BurnUXContainerName == p.ContainerRef)) { // In theory, UX payloads could be embedded in the UX CAB, external to the bundle EXE, or even // downloaded. The current engine requires the UX to be fully present before any downloading starts, // so that rules out downloading. Also, the burn engine does not currently copy external UX payloads // into the temporary UX directory correctly, so we don't allow external either. if (PackagingType.Embedded != payload.Packaging) { this.Messaging.Write(WarningMessages.UxPayloadsOnlySupportEmbedding(payload.SourceLineNumbers, payload.SourceFile.Path)); payload.Packaging = PackagingType.Embedded; } payload.EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnUXContainerEmbeddedIdFormat, uxPayloadIndex); ++uxPayloadIndex; } if (0 == uxPayloadIndex) { // If we didn't get any UX payloads, it's an error! throw new WixException(ErrorMessages.MissingBundleInformation("BootstrapperApplication")); } // Give the embedded payloads without an embedded id yet an embedded id. var payloadIndex = 0; foreach (var payload in payloadSymbols.Values) { Debug.Assert(PackagingType.Unknown != payload.Packaging); if (PackagingType.Embedded == payload.Packaging && String.IsNullOrEmpty(payload.EmbeddedId)) { payload.EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnAttachedContainerEmbeddedIdFormat, payloadIndex); ++payloadIndex; } } } if (this.Messaging.EncounteredError) { return; } // Determine patches to automatically slipstream. { var command = new AutomaticallySlipstreamPatchesCommand(section, facades.Values); command.Execute(); } if (this.Messaging.EncounteredError) { return; } IEnumerable <PackageFacade> orderedFacades; IEnumerable <WixBundleRollbackBoundarySymbol> boundaries; { var command = new OrderPackagesAndRollbackBoundariesCommand(this.Messaging, section, facades); command.Execute(); orderedFacades = command.OrderedPackageFacades; boundaries = command.UsedRollbackBoundaries; } // Resolve any delayed fields before generating the manifest. if (this.DelayedFields.Any()) { this.BackendHelper.ResolveDelayedFields(this.DelayedFields, variableCache); } { var command = new ProcessDependencyProvidersCommand(this.Messaging, section, facades); command.Execute(); if (!String.IsNullOrEmpty(command.BundleProviderKey)) { bundleSymbol.ProviderKey = command.BundleProviderKey; // set the overridable bundle provider key. } } // Update the bundle per-machine/per-user scope based on the chained packages. this.ResolveBundleInstallScope(section, bundleSymbol, orderedFacades); var softwareTags = section.Symbols.OfType <WixBundleTagSymbol>().ToList(); if (softwareTags.Any()) { var command = new ProcessBundleSoftwareTagsCommand(section, softwareTags); command.Execute(); } this.DetectDuplicateCacheIds(facades); if (this.Messaging.EncounteredError) { return; } // Give the extension one last hook before generating the output files. foreach (var extension in this.BackendExtensions) { extension.SymbolsFinalized(section); } if (this.Messaging.EncounteredError) { return; } // Generate data for all manifests. { var command = new GenerateManifestDataFromIRCommand(this.Messaging, section, this.BackendExtensions, this.InternalBurnBackendHelper, extensionSearchSymbolsById); command.Execute(); } if (this.Messaging.EncounteredError) { return; } // Generate the core-defined BA manifest tables... string baManifestPath; { var command = new CreateBootstrapperApplicationManifestCommand(section, bundleSymbol, orderedFacades, uxPayloadIndex, packagesPayloads, this.IntermediateFolder, this.InternalBurnBackendHelper); command.Execute(); var baManifestPayload = command.BootstrapperApplicationManifestPayloadRow; baManifestPath = command.OutputPath; payloadSymbols.Add(baManifestPayload.Id.Id, baManifestPayload); ++uxPayloadIndex; trackedFiles.Add(this.BackendHelper.TrackFile(baManifestPath, TrackedFileType.Temporary)); } // Generate the bundle extension manifest... string bextManifestPath; { var command = new CreateBundleExtensionManifestCommand(section, bundleSymbol, uxPayloadIndex, this.IntermediateFolder, this.InternalBurnBackendHelper); command.Execute(); var bextManifestPayload = command.BundleExtensionManifestPayloadRow; bextManifestPath = command.OutputPath; payloadSymbols.Add(bextManifestPayload.Id.Id, bextManifestPayload); ++uxPayloadIndex; trackedFiles.Add(this.BackendHelper.TrackFile(bextManifestPath, TrackedFileType.Temporary)); } var containers = section.Symbols.OfType <WixBundleContainerSymbol>().ToDictionary(t => t.Id.Id); { var command = new DetectPayloadCollisionsCommand(this.Messaging, containers, facades.Values, payloadSymbols, packagesPayloads); command.Execute(); } if (this.Messaging.EncounteredError) { return; } // Create all the containers except the UX container first so the manifest (that goes in the UX container) // can contain all size and hash information about the non-UX containers. WixBundleContainerSymbol uxContainer; IEnumerable <WixBundlePayloadSymbol> uxPayloads; { var command = new CreateNonUXContainers(this.BackendHelper, section, bundleApplicationDllSymbol, containers.Values, payloadSymbols, this.IntermediateFolder, layoutDirectory, this.DefaultCompressionLevel); command.Execute(); fileTransfers.AddRange(command.FileTransfers); trackedFiles.AddRange(command.TrackedFiles); uxContainer = command.UXContainer; uxPayloads = command.UXContainerPayloads; } // Resolve the download URLs now that we have all of the containers and payloads calculated. { var command = new ResolveDownloadUrlsCommand(this.Messaging, this.BackendExtensions, containers.Values, payloadSymbols); command.Execute(); } // Create the bundle manifest. string manifestPath; { var executableName = Path.GetFileName(this.OutputPath); var command = new CreateBurnManifestCommand(executableName, section, bundleSymbol, containers.Values, chainSymbol, orderedFacades, boundaries, uxPayloads, payloadSymbols, packagesPayloads, orderedSearches, this.IntermediateFolder); command.Execute(); manifestPath = command.OutputPath; trackedFiles.Add(this.BackendHelper.TrackFile(manifestPath, TrackedFileType.Temporary)); } // Create the UX container. { var command = new CreateContainerCommand(manifestPath, uxPayloads, uxContainer.WorkingPath, this.DefaultCompressionLevel); command.Execute(); uxContainer.Hash = command.Hash; uxContainer.Size = command.Size; trackedFiles.Add(this.BackendHelper.TrackFile(uxContainer.WorkingPath, TrackedFileType.Temporary)); } { var command = new CreateBundleExeCommand(this.Messaging, this.BackendHelper, this.IntermediateFolder, this.OutputPath, bundleApplicationDllSymbol, bundleSymbol, uxContainer, containers.Values); command.Execute(); fileTransfers.Add(command.Transfer); trackedFiles.Add(this.BackendHelper.TrackFile(this.OutputPath, TrackedFileType.Final)); } #if TODO // does this need to come back, or do they only need to be in TrackedFiles? this.ContentFilePaths = payloadSymbols.Values.Where(p => p.ContentFile).Select(p => p.FullFileName).ToList(); #endif this.FileTransfers = fileTransfers; this.TrackedFiles = trackedFiles; this.Wixout = this.CreateWixout(trackedFiles, this.Output, manifestPath, baManifestPath, bextManifestPath); }