This commit is contained in:
Rob Mensching 2019-10-07 11:18:13 -07:00
Родитель 3b98dac62b
Коммит 860676fa5b
62 изменённых файлов: 2300 добавлений и 2211 удалений

Просмотреть файл

@ -2,13 +2,13 @@
@pushd %~dp0
@set _P=%~dp0build\Release\publish
dotnet test -c Release src\test\WixToolsetTest.CoreIntegration
dotnet pack -c Release src\WixToolset.Core
dotnet pack -c Release src\WixToolset.Core.Burn
dotnet pack -c Release src\WixToolset.Core.WindowsInstaller
dotnet pack -c Release src\WixToolset.Core.TestPackage
dotnet build -c Release src\test\WixToolsetTest.CoreIntegration
@popd
@endlocal

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,166 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.Burn.Bind
{
using System;
using System.Collections.Generic;
using System.Linq;
using WixToolset.Data;
using WixToolset.Core.Burn.Bundles;
using WixToolset.Extensibility.Services;
using WixToolset.Data.Tuples;
internal class ProcessDependencyProvidersCommand
{
public ProcessDependencyProvidersCommand(IMessaging messaging, IntermediateSection section, IDictionary<string, PackageFacade> facades)
{
this.Messaging = messaging;
this.Section = section;
this.Facades = facades;
}
public string BundleProviderKey { get; private set; }
public Dictionary<string, ProvidesDependencyTuple> DependencyTuplesByKey { get; private set; }
private IMessaging Messaging { get; }
private IntermediateSection Section { get; }
private IDictionary<string, PackageFacade> Facades { get; }
/// <summary>
/// Sets the explicitly provided bundle provider key, if provided. And...
/// Imports authored dependency providers for each package in the manifest,
/// and generates dependency providers for certain package types that do not
/// have a provider defined.
/// </summary>
public void Execute()
{
var wixDependencyProviderTuples = this.Section.Tuples.OfType<WixDependencyProviderTuple>();
foreach (var wixDependencyProviderTuple in wixDependencyProviderTuples)
{
// Sets the provider key for the bundle, if it is not set already.
if (String.IsNullOrEmpty(this.BundleProviderKey))
{
if (wixDependencyProviderTuple.Bundle)
{
this.BundleProviderKey = wixDependencyProviderTuple.ProviderKey;
}
}
// Import any authored dependencies. These may merge with imported provides from MSI packages.
var packageId = wixDependencyProviderTuple.Id.Id;
if (this.Facades.TryGetValue(packageId, out var facade))
{
var dependency = new ProvidesDependencyTuple(wixDependencyProviderTuple.SourceLineNumbers, wixDependencyProviderTuple.Id)
{
PackageRef = packageId,
Key = wixDependencyProviderTuple.ProviderKey,
Version = wixDependencyProviderTuple.Version,
DisplayName = wixDependencyProviderTuple.DisplayName,
Attributes = (int)wixDependencyProviderTuple.Attributes
};
if (String.IsNullOrEmpty(dependency.Key))
{
switch (facade.SpecificPackageTuple)
{
// The WixDependencyExtension allows an empty Key for MSIs and MSPs.
case WixBundleMsiPackageTuple msiPackage:
dependency.Key = msiPackage.ProductCode;
break;
case WixBundleMspPackageTuple mspPackage:
dependency.Key = mspPackage.PatchCode;
break;
}
}
if (String.IsNullOrEmpty(dependency.Version))
{
dependency.Version = facade.PackageTuple.Version;
}
// If the version is still missing, a version could not be harvested from the package and was not authored.
if (String.IsNullOrEmpty(dependency.Version))
{
this.Messaging.Write(ErrorMessages.MissingDependencyVersion(facade.PackageId));
}
if (String.IsNullOrEmpty(dependency.DisplayName))
{
dependency.DisplayName = facade.PackageTuple.DisplayName;
}
this.Section.Tuples.Add(dependency);
}
}
this.DependencyTuplesByKey = this.GetDependencyTuplesByKey();
// Generate providers for MSI and MSP packages that still do not have providers.
foreach (var facade in this.Facades.Values)
{
string key = null;
//if (WixBundlePackageType.Msi == facade.PackageTuple.Type)
if (facade.SpecificPackageTuple is WixBundleMsiPackageTuple msiPackage)
{
//var msiPackage = (WixBundleMsiPackageTuple)facade.SpecificPackageTuple;
key = msiPackage.ProductCode;
}
//else if (WixBundlePackageType.Msp == facade.PackageTuple.Type)
else if (facade.SpecificPackageTuple is WixBundleMspPackageTuple mspPackage)
{
//var mspPackage = (WixBundleMspPackageTuple)facade.SpecificPackageTuple;
key = mspPackage.PatchCode;
}
if (!String.IsNullOrEmpty(key) && !this.DependencyTuplesByKey.ContainsKey(key))
{
var dependency = new ProvidesDependencyTuple(facade.PackageTuple.SourceLineNumbers, facade.PackageTuple.Id)
{
PackageRef = facade.PackageId,
Key = key,
Version = facade.PackageTuple.Version,
DisplayName = facade.PackageTuple.DisplayName
};
this.Section.Tuples.Add(dependency);
this.DependencyTuplesByKey.Add(dependency.Key, dependency);
}
}
}
private Dictionary<string, ProvidesDependencyTuple> GetDependencyTuplesByKey()
{
var dependencyTuplesByKey = new Dictionary<string, ProvidesDependencyTuple>();
var dependencyTuples = this.Section.Tuples.OfType<ProvidesDependencyTuple>();
foreach (var dependency in dependencyTuples)
{
if (dependencyTuplesByKey.TryGetValue(dependency.Key, out var collision))
{
// If not a perfect dependency collision, display an error.
if (dependency.Key != collision.Key ||
dependency.Version != collision.Version ||
dependency.DisplayName != collision.DisplayName)
{
this.Messaging.Write(ErrorMessages.DuplicateProviderDependencyKey(dependency.Key, dependency.PackageRef));
}
}
else
{
dependencyTuplesByKey.Add(dependency.Key, dependency);
}
}
return dependencyTuplesByKey;
}
}
}

Просмотреть файл

@ -1,110 +0,0 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.Burn
{
using System;
using System.Xml;
using WixToolset.Data;
/// <summary>
/// Represents an authored or imported dependency provider.
/// </summary>
internal sealed class ProvidesDependency
{
#if TODO
/// <summary>
/// Creates a new instance of the <see cref="ProviderDependency"/> class from a <see cref="Row"/>.
/// </summary>
/// <param name="row">The <see cref="Row"/> from which data is imported.</param>
internal ProvidesDependency(Row row)
: this((string)row[2], (string)row[3], (string)row[4], (int?)row[5])
{
}
#endif
/// <summary>
/// Creates a new instance of the <see cref="ProviderDependency"/> class.
/// </summary>
/// <param name="key">The unique key of the dependency.</param>
/// <param name="attributes">Additional attributes for the dependency.</param>
internal ProvidesDependency(string key, string version, string displayName, int? attributes)
{
this.Key = key;
this.Version = version;
this.DisplayName = displayName;
this.Attributes = attributes;
}
/// <summary>
/// Gets or sets the unique key of the package provider.
/// </summary>
internal string Key { get; set; }
/// <summary>
/// Gets or sets the version of the package provider.
/// </summary>
internal string Version { get; set; }
/// <summary>
/// Gets or sets the display name of the package provider.
/// </summary>
internal string DisplayName { get; set; }
/// <summary>
/// Gets or sets the attributes for the dependency.
/// </summary>
internal int? Attributes { get; set; }
/// <summary>
/// Gets or sets whether the dependency was imported from the package.
/// </summary>
internal bool Imported { get; set; }
/// <summary>
/// Gets whether certain properties are the same.
/// </summary>
/// <param name="other">Another <see cref="ProvidesDependency"/> to compare.</param>
/// <remarks>This is not the same as object equality, but only checks a subset of properties
/// to determine if the objects are similar and could be merged into a collection.</remarks>
/// <returns>True if certain properties are the same.</returns>
internal bool Equals(ProvidesDependency other)
{
if (null != other)
{
return this.Key == other.Key &&
this.Version == other.Version &&
this.DisplayName == other.DisplayName;
}
return false;
}
/// <summary>
/// Writes the dependency to the bundle XML manifest.
/// </summary>
/// <param name="writer">The <see cref="XmlTextWriter"/> for the bundle XML manifest.</param>
internal void WriteXml(XmlTextWriter writer)
{
writer.WriteStartElement("Provides");
writer.WriteAttributeString("Key", this.Key);
if (!String.IsNullOrEmpty(this.Version))
{
writer.WriteAttributeString("Version", this.Version);
}
if (!String.IsNullOrEmpty(this.DisplayName))
{
writer.WriteAttributeString("DisplayName", this.DisplayName);
}
if (this.Imported)
{
// The package dependency was explicitly authored into the manifest.
writer.WriteAttributeString("Imported", "yes");
}
writer.WriteEndElement();
}
}
}

Просмотреть файл

@ -1,64 +0,0 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.Burn
{
using System;
using System.Collections.ObjectModel;
/// <summary>
/// A case-insensitive collection of unique <see cref="ProvidesDependency"/> objects.
/// </summary>
internal sealed class ProvidesDependencyCollection : KeyedCollection<string, ProvidesDependency>
{
/// <summary>
/// Creates a case-insensitive collection of unique <see cref="ProvidesDependency"/> objects.
/// </summary>
internal ProvidesDependencyCollection()
: base(StringComparer.InvariantCultureIgnoreCase)
{
}
/// <summary>
/// Adds the <see cref="ProvidesDependency"/> to the collection if it doesn't already exist.
/// </summary>
/// <param name="dependency">The <see cref="ProvidesDependency"/> to add to the collection.</param>
/// <returns>True if the <see cref="ProvidesDependency"/> was added to the collection; otherwise, false.</returns>
/// <exception cref="ArgumentNullException">The <paramref name="dependency"/> parameter is null.</exception>
internal bool Merge(ProvidesDependency dependency)
{
if (null == dependency)
{
throw new ArgumentNullException("dependency");
}
// If the dependency key is already in the collection, verify equality for a subset of properties.
if (this.Contains(dependency.Key))
{
ProvidesDependency current = this[dependency.Key];
if (!current.Equals(dependency))
{
return false;
}
}
base.Add(dependency);
return true;
}
/// <summary>
/// Gets the <see cref="ProvidesDependency.Key"/> for the <paramref name="dependency"/>.
/// </summary>
/// <param name="dependency">The dependency to index.</param>
/// <exception cref="ArgumentNullException">The <paramref name="dependency"/> parameter is null.</exception>
/// <returns>The <see cref="ProvidesDependency.Key"/> for the <paramref name="dependency"/>.</returns>
protected override string GetKeyForItem(ProvidesDependency dependency)
{
if (null == dependency)
{
throw new ArgumentNullException("dependency");
}
return dependency.Key;
}
}
}

Просмотреть файл

@ -0,0 +1,197 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.Burn
{
using System;
using System.Xml;
using WixToolset.Data;
using WixToolset.Data.Tuples;
internal class SearchFacade
{
public SearchFacade(WixSearchTuple searchTuple, IntermediateTuple searchSpecificTuple)
{
this.SearchTuple = searchTuple;
this.SearchSpecificTuple = searchSpecificTuple;
}
public WixSearchTuple SearchTuple { get; }
public IntermediateTuple SearchSpecificTuple { get; }
/// <summary>
/// Generates Burn manifest and ParameterInfo-style markup a search.
/// </summary>
/// <param name="writer"></param>
public void WriteXml(XmlTextWriter writer)
{
switch (this.SearchSpecificTuple)
{
case WixComponentSearchTuple tuple:
this.WriteComponentSearchXml(writer, tuple);
break;
case WixFileSearchTuple tuple:
this.WriteFileSearchXml(writer, tuple);
break;
case WixProductSearchTuple tuple:
this.WriteProductSearchXml(writer, tuple);
break;
case WixRegistrySearchTuple tuple:
this.WriteRegistrySearchXml(writer, tuple);
break;
}
}
private void WriteCommonAttributes(XmlTextWriter writer)
{
writer.WriteAttributeString("Id", this.SearchTuple.Id.Id);
writer.WriteAttributeString("Variable", this.SearchTuple.Variable);
if (!String.IsNullOrEmpty(this.SearchTuple.Condition))
{
writer.WriteAttributeString("Condition", this.SearchTuple.Condition);
}
}
private void WriteComponentSearchXml(XmlTextWriter writer, WixComponentSearchTuple searchTuple)
{
writer.WriteStartElement("MsiComponentSearch");
this.WriteCommonAttributes(writer);
writer.WriteAttributeString("ComponentId", searchTuple.Guid);
if (!String.IsNullOrEmpty(searchTuple.ProductCode))
{
writer.WriteAttributeString("ProductCode", searchTuple.ProductCode);
}
if (0 != (searchTuple.Attributes & WixComponentSearchAttributes.KeyPath))
{
writer.WriteAttributeString("Type", "keyPath");
}
else if (0 != (searchTuple.Attributes & WixComponentSearchAttributes.State))
{
writer.WriteAttributeString("Type", "state");
}
else if (0 != (searchTuple.Attributes & WixComponentSearchAttributes.WantDirectory))
{
writer.WriteAttributeString("Type", "directory");
}
writer.WriteEndElement();
}
private void WriteFileSearchXml(XmlTextWriter writer, WixFileSearchTuple searchTuple)
{
writer.WriteStartElement((0 == (searchTuple.Attributes & WixFileSearchAttributes.IsDirectory)) ? "FileSearch" : "DirectorySearch");
this.WriteCommonAttributes(writer);
writer.WriteAttributeString("Path", searchTuple.Path);
if (WixFileSearchAttributes.WantExists == (searchTuple.Attributes & WixFileSearchAttributes.WantExists))
{
writer.WriteAttributeString("Type", "exists");
}
else if (WixFileSearchAttributes.WantVersion == (searchTuple.Attributes & WixFileSearchAttributes.WantVersion))
{
// Can never get here for DirectorySearch.
writer.WriteAttributeString("Type", "version");
}
else
{
writer.WriteAttributeString("Type", "path");
}
writer.WriteEndElement();
}
private void WriteProductSearchXml(XmlTextWriter writer, WixProductSearchTuple tuple)
{
writer.WriteStartElement("MsiProductSearch");
this.WriteCommonAttributes(writer);
if (0 != (tuple.Attributes & WixProductSearchAttributes.UpgradeCode))
{
writer.WriteAttributeString("UpgradeCode", tuple.Guid);
}
else
{
writer.WriteAttributeString("ProductCode", tuple.Guid);
}
if (0 != (tuple.Attributes & WixProductSearchAttributes.Version))
{
writer.WriteAttributeString("Type", "version");
}
else if (0 != (tuple.Attributes & WixProductSearchAttributes.Language))
{
writer.WriteAttributeString("Type", "language");
}
else if (0 != (tuple.Attributes & WixProductSearchAttributes.State))
{
writer.WriteAttributeString("Type", "state");
}
else if (0 != (tuple.Attributes & WixProductSearchAttributes.Assignment))
{
writer.WriteAttributeString("Type", "assignment");
}
writer.WriteEndElement();
}
private void WriteRegistrySearchXml(XmlTextWriter writer, WixRegistrySearchTuple tuple)
{
writer.WriteStartElement("RegistrySearch");
this.WriteCommonAttributes(writer);
switch (tuple.Root)
{
case RegistryRootType.ClassesRoot:
writer.WriteAttributeString("Root", "HKCR");
break;
case RegistryRootType.CurrentUser:
writer.WriteAttributeString("Root", "HKCU");
break;
case RegistryRootType.LocalMachine:
writer.WriteAttributeString("Root", "HKLM");
break;
case RegistryRootType.Users:
writer.WriteAttributeString("Root", "HKU");
break;
}
writer.WriteAttributeString("Key", tuple.Key);
if (!String.IsNullOrEmpty(tuple.Value))
{
writer.WriteAttributeString("Value", tuple.Value);
}
var existenceOnly = 0 != (tuple.Attributes & WixRegistrySearchAttributes.WantExists);
writer.WriteAttributeString("Type", existenceOnly ? "exists" : "value");
if (0 != (tuple.Attributes & WixRegistrySearchAttributes.Win64))
{
writer.WriteAttributeString("Win64", "yes");
}
if (!existenceOnly)
{
if (0 != (tuple.Attributes & WixRegistrySearchAttributes.ExpandEnvironmentVariables))
{
writer.WriteAttributeString("ExpandEnvironment", "yes");
}
// We *always* say this is VariableType="string". If we end up
// needing to be more specific, we will have to expand the "Format"
// attribute to allow "number" and "version".
writer.WriteAttributeString("VariableType", "string");
}
writer.WriteEndElement();
}
}
}

Просмотреть файл

@ -1,65 +0,0 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.Burn
{
using System;
using System.Xml;
using WixToolset.Data;
/// <summary>
/// Utility class for all WixComponentSearches.
/// </summary>
internal class WixComponentSearchInfo : WixSearchInfo
{
#if TODO
public WixComponentSearchInfo(Row row)
: this((string)row[0], (string)row[1], (string)row[2], (int)row[3])
{
}
#endif
public WixComponentSearchInfo(string id, string guid, string productCode, int attributes)
: base(id)
{
this.Guid = guid;
this.ProductCode = productCode;
this.Attributes = (WixComponentSearchAttributes)attributes;
}
public string Guid { get; private set; }
public string ProductCode { get; private set; }
public WixComponentSearchAttributes Attributes { get; private set; }
/// <summary>
/// Generates Burn manifest and ParameterInfo-style markup for a component search.
/// </summary>
/// <param name="writer"></param>
public override void WriteXml(XmlTextWriter writer)
{
writer.WriteStartElement("MsiComponentSearch");
this.WriteWixSearchAttributes(writer);
writer.WriteAttributeString("ComponentId", this.Guid);
if (!String.IsNullOrEmpty(this.ProductCode))
{
writer.WriteAttributeString("ProductCode", this.ProductCode);
}
if (0 != (this.Attributes & WixComponentSearchAttributes.KeyPath))
{
writer.WriteAttributeString("Type", "keyPath");
}
else if (0 != (this.Attributes & WixComponentSearchAttributes.State))
{
writer.WriteAttributeString("Type", "state");
}
else if (0 != (this.Attributes & WixComponentSearchAttributes.WantDirectory))
{
writer.WriteAttributeString("Type", "directory");
}
writer.WriteEndElement();
}
}
}

Просмотреть файл

@ -1,56 +0,0 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.Burn
{
using System;
using System.Xml;
using WixToolset.Data;
/// <summary>
/// Utility class for all WixFileSearches (file and directory searches).
/// </summary>
internal class WixFileSearchInfo : WixSearchInfo
{
#if TODO
public WixFileSearchInfo(Row row)
: this((string)row[0], (string)row[1], (int)row[9])
{
}
#endif
public WixFileSearchInfo(string id, string path, int attributes)
: base(id)
{
this.Path = path;
this.Attributes = (WixFileSearchAttributes)attributes;
}
public string Path { get; private set; }
public WixFileSearchAttributes Attributes { get; private set; }
/// <summary>
/// Generates Burn manifest and ParameterInfo-style markup for a file/directory search.
/// </summary>
/// <param name="writer"></param>
public override void WriteXml(XmlTextWriter writer)
{
writer.WriteStartElement((0 == (this.Attributes & WixFileSearchAttributes.IsDirectory)) ? "FileSearch" : "DirectorySearch");
this.WriteWixSearchAttributes(writer);
writer.WriteAttributeString("Path", this.Path);
if (WixFileSearchAttributes.WantExists == (this.Attributes & WixFileSearchAttributes.WantExists))
{
writer.WriteAttributeString("Type", "exists");
}
else if (WixFileSearchAttributes.WantVersion == (this.Attributes & WixFileSearchAttributes.WantVersion))
{
// Can never get here for DirectorySearch.
writer.WriteAttributeString("Type", "version");
}
else
{
writer.WriteAttributeString("Type", "path");
}
writer.WriteEndElement();
}
}
}

Просмотреть файл

@ -1,69 +0,0 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.Burn
{
using System;
using System.Xml;
using WixToolset.Data;
/// <summary>
/// Utility class for all WixProductSearches.
/// </summary>
internal class WixProductSearchInfo : WixSearchInfo
{
#if TODO
public WixProductSearchInfo(Row row)
: this((string)row[0], (string)row[1], (int)row[2])
{
}
#endif
public WixProductSearchInfo(string id, string guid, int attributes)
: base(id)
{
this.Guid = guid;
this.Attributes = (WixProductSearchAttributes)attributes;
}
public string Guid { get; private set; }
public WixProductSearchAttributes Attributes { get; private set; }
/// <summary>
/// Generates Burn manifest and ParameterInfo-style markup for a product search.
/// </summary>
/// <param name="writer"></param>
public override void WriteXml(XmlTextWriter writer)
{
writer.WriteStartElement("MsiProductSearch");
this.WriteWixSearchAttributes(writer);
if (0 != (this.Attributes & WixProductSearchAttributes.UpgradeCode))
{
writer.WriteAttributeString("UpgradeCode", this.Guid);
}
else
{
writer.WriteAttributeString("ProductCode", this.Guid);
}
if (0 != (this.Attributes & WixProductSearchAttributes.Version))
{
writer.WriteAttributeString("Type", "version");
}
else if (0 != (this.Attributes & WixProductSearchAttributes.Language))
{
writer.WriteAttributeString("Type", "language");
}
else if (0 != (this.Attributes & WixProductSearchAttributes.State))
{
writer.WriteAttributeString("Type", "state");
}
else if (0 != (this.Attributes & WixProductSearchAttributes.Assignment))
{
writer.WriteAttributeString("Type", "assignment");
}
writer.WriteEndElement();
}
}
}

Просмотреть файл

@ -1,93 +0,0 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.Burn
{
using System;
using System.Xml;
using WixToolset.Data.WindowsInstaller;
/// <summary>
/// Utility class for all WixRegistrySearches.
/// </summary>
internal class WixRegistrySearchInfo : WixSearchInfo
{
#if TODO
public WixRegistrySearchInfo(Row row)
: this((string)row[0], (int)row[1], (string)row[2], (string)row[3], (int)row[4])
{
}
#endif
public WixRegistrySearchInfo(string id, int root, string key, string value, int attributes)
: base(id)
{
this.Root = root;
this.Key = key;
this.Value = value;
this.Attributes = (WixRegistrySearchAttributes)attributes;
}
public int Root { get; private set; }
public string Key { get; private set; }
public string Value { get; private set; }
public WixRegistrySearchAttributes Attributes { get; private set; }
/// <summary>
/// Generates Burn manifest and ParameterInfo-style markup for a registry search.
/// </summary>
/// <param name="writer"></param>
public override void WriteXml(XmlTextWriter writer)
{
writer.WriteStartElement("RegistrySearch");
this.WriteWixSearchAttributes(writer);
switch (this.Root)
{
case WindowsInstallerConstants.MsidbRegistryRootClassesRoot:
writer.WriteAttributeString("Root", "HKCR");
break;
case WindowsInstallerConstants.MsidbRegistryRootCurrentUser:
writer.WriteAttributeString("Root", "HKCU");
break;
case WindowsInstallerConstants.MsidbRegistryRootLocalMachine:
writer.WriteAttributeString("Root", "HKLM");
break;
case WindowsInstallerConstants.MsidbRegistryRootUsers:
writer.WriteAttributeString("Root", "HKU");
break;
}
writer.WriteAttributeString("Key", this.Key);
if (!String.IsNullOrEmpty(this.Value))
{
writer.WriteAttributeString("Value", this.Value);
}
bool existenceOnly = 0 != (this.Attributes & WixRegistrySearchAttributes.WantExists);
writer.WriteAttributeString("Type", existenceOnly ? "exists" : "value");
if (0 != (this.Attributes & WixRegistrySearchAttributes.Win64))
{
writer.WriteAttributeString("Win64", "yes");
}
if (!existenceOnly)
{
if (0 != (this.Attributes & WixRegistrySearchAttributes.ExpandEnvironmentVariables))
{
writer.WriteAttributeString("ExpandEnvironment", "yes");
}
// We *always* say this is VariableType="string". If we end up
// needing to be more specific, we will have to expand the "Format"
// attribute to allow "number" and "version".
writer.WriteAttributeString("VariableType", "string");
}
writer.WriteEndElement();
}
}
}

Просмотреть файл

@ -1,55 +0,0 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.Burn
{
using System;
using System.Diagnostics;
using System.Xml;
using WixToolset.Data;
/// <summary>
/// Utility base class for all WixSearches.
/// </summary>
internal abstract class WixSearchInfo
{
public WixSearchInfo(string id)
{
this.Id = id;
}
#if TODO
public void AddWixSearchRowInfo(Row row)
{
Debug.Assert((string)row[0] == Id);
Variable = (string)row[1];
Condition = (string)row[2];
}
#endif
public string Id { get; private set; }
public string Variable { get; private set; }
public string Condition { get; private set; }
/// <summary>
/// Generates Burn manifest and ParameterInfo-style markup a search.
/// </summary>
/// <param name="writer"></param>
public virtual void WriteXml(XmlTextWriter writer)
{
}
/// <summary>
/// Writes attributes common to all WixSearch elements.
/// </summary>
/// <param name="writer"></param>
protected void WriteWixSearchAttributes(XmlTextWriter writer)
{
writer.WriteAttributeString("Id", this.Id);
writer.WriteAttributeString("Variable", this.Variable);
if (!String.IsNullOrEmpty(this.Condition))
{
writer.WriteAttributeString("Condition", this.Condition);
}
}
}
}

Просмотреть файл

@ -15,20 +15,26 @@ namespace WixToolset.Core.Burn
{
public IBindResult Bind(IBindContext context)
{
BindBundleCommand command = new BindBundleCommand(context);
//command.DefaultCompressionLevel = context.DefaultCompressionLevel;
//command.Extensions = context.Extensions;
//command.IntermediateFolder = context.IntermediateFolder;
//command.Output = context.IntermediateRepresentation;
//command.OutputPath = context.OutputPath;
//command.PdbFile = context.OutputPdbPath;
//command.WixVariableResolver = context.WixVariableResolver;
var extensionManager = context.ServiceProvider.GetService<IExtensionManager>();
var backendExtensions = extensionManager.GetServices<IBurnBackendExtension>();
foreach (var extension in backendExtensions)
{
extension.PreBackendBind(context);
}
var command = new BindBundleCommand(context, backendExtensions);
command.Execute();
var result = context.ServiceProvider.GetService<IBindResult>();
result.FileTransfers = command.FileTransfers;
result.TrackedFiles = command.TrackedFiles;
foreach (var extension in backendExtensions)
{
extension.PostBackendBind(result);
}
return result;
}
@ -53,10 +59,10 @@ namespace WixToolset.Core.Burn
public Intermediate Unbind(IUnbindContext context)
{
string uxExtractPath = Path.Combine(context.ExportBasePath, "UX");
string acExtractPath = Path.Combine(context.ExportBasePath, "AttachedContainer");
var uxExtractPath = Path.Combine(context.ExportBasePath, "UX");
var acExtractPath = Path.Combine(context.ExportBasePath, "AttachedContainer");
using (BurnReader reader = BurnReader.Open(context.InputFilePath))
using (var reader = BurnReader.Open(context.InputFilePath))
{
reader.ExtractUXContainer(uxExtractPath, context.IntermediateFolder);
reader.ExtractAttachedContainer(acExtractPath, context.IntermediateFolder);

Просмотреть файл

@ -7,107 +7,116 @@ namespace WixToolset.Core.Burn.Bundles
using System.Diagnostics;
using System.Linq;
using WixToolset.Data;
using WixToolset.Data.Tuples;
internal class AutomaticallySlipstreamPatchesCommand
{
#if TODO
public IEnumerable<PackageFacade> PackageFacades { private get; set; }
public AutomaticallySlipstreamPatchesCommand(IntermediateSection section, ICollection<PackageFacade> packageFacades)
{
this.Section = section;
this.PackageFacades = packageFacades;
}
public Table WixBundlePatchTargetCodeTable { private get; set; }
private IntermediateSection Section { get; }
public Table SlipstreamMspTable { private get; set; }
private IEnumerable<PackageFacade> PackageFacades { get; }
public void Execute()
{
List<WixBundleMsiPackageRow> msiPackages = new List<WixBundleMsiPackageRow>();
Dictionary<string, List<WixBundlePatchTargetCodeRow>> targetsProductCode = new Dictionary<string, List<WixBundlePatchTargetCodeRow>>();
Dictionary<string, List<WixBundlePatchTargetCodeRow>> targetsUpgradeCode = new Dictionary<string, List<WixBundlePatchTargetCodeRow>>();
var msiPackages = new List<WixBundleMsiPackageTuple>();
var targetsProductCode = new Dictionary<string, List<WixBundlePatchTargetCodeTuple>>();
var targetsUpgradeCode = new Dictionary<string, List<WixBundlePatchTargetCodeTuple>>();
foreach (PackageFacade facade in this.PackageFacades)
foreach (var facade in this.PackageFacades)
{
if (WixBundlePackageType.Msi == facade.Package.Type)
// Keep track of all MSI packages.
if (facade.SpecificPackageTuple is WixBundleMsiPackageTuple msiPackage)
{
// Keep track of all MSI packages.
msiPackages.Add(facade.MsiPackage);
msiPackages.Add(msiPackage);
}
else if (WixBundlePackageType.Msp == facade.Package.Type && facade.MspPackage.Slipstream)
else if (facade.SpecificPackageTuple is WixBundleMspPackageTuple mspPackage && mspPackage.Slipstream)
{
IEnumerable<WixBundlePatchTargetCodeRow> patchTargetCodeRows = this.WixBundlePatchTargetCodeTable.RowsAs<WixBundlePatchTargetCodeRow>().Where(r => r.MspPackageId == facade.Package.WixChainItemId);
var patchTargetCodeTuples = this.Section.Tuples
.OfType<WixBundlePatchTargetCodeTuple>()
.Where(r => r.PackageRef == facade.PackageId);
// Index target ProductCodes and UpgradeCodes for slipstreamed MSPs.
foreach (WixBundlePatchTargetCodeRow row in patchTargetCodeRows)
foreach (var tuple in patchTargetCodeTuples)
{
if (row.TargetsProductCode)
if (tuple.TargetsProductCode)
{
List<WixBundlePatchTargetCodeRow> rows;
if (!targetsProductCode.TryGetValue(row.TargetCode, out rows))
if (!targetsProductCode.TryGetValue(tuple.TargetCode, out var tuples))
{
rows = new List<WixBundlePatchTargetCodeRow>();
targetsProductCode.Add(row.TargetCode, rows);
tuples = new List<WixBundlePatchTargetCodeTuple>();
targetsProductCode.Add(tuple.TargetCode, tuples);
}
rows.Add(row);
tuples.Add(tuple);
}
else if (row.TargetsUpgradeCode)
else if (tuple.TargetsUpgradeCode)
{
List<WixBundlePatchTargetCodeRow> rows;
if (!targetsUpgradeCode.TryGetValue(row.TargetCode, out rows))
if (!targetsUpgradeCode.TryGetValue(tuple.TargetCode, out var tuples))
{
rows = new List<WixBundlePatchTargetCodeRow>();
targetsUpgradeCode.Add(row.TargetCode, rows);
tuples = new List<WixBundlePatchTargetCodeTuple>();
targetsUpgradeCode.Add(tuple.TargetCode, tuples);
}
}
}
}
}
RowIndexedList<Row> slipstreamMspRows = new RowIndexedList<Row>(SlipstreamMspTable);
var slipstreamMspIds = new HashSet<string>();
// Loop through the MSI and slipstream patches targeting it.
foreach (WixBundleMsiPackageRow msi in msiPackages)
foreach (var msi in msiPackages)
{
List<WixBundlePatchTargetCodeRow> rows;
if (targetsProductCode.TryGetValue(msi.ProductCode, out rows))
if (targetsProductCode.TryGetValue(msi.ProductCode, out var tuples))
{
foreach (WixBundlePatchTargetCodeRow row in rows)
foreach (var tuple in tuples)
{
Debug.Assert(row.TargetsProductCode);
Debug.Assert(!row.TargetsUpgradeCode);
Debug.Assert(tuple.TargetsProductCode);
Debug.Assert(!tuple.TargetsUpgradeCode);
Row slipstreamMspRow = SlipstreamMspTable.CreateRow(row.SourceLineNumbers, false);
slipstreamMspRow[0] = msi.ChainPackageId;
slipstreamMspRow[1] = row.MspPackageId;
if (slipstreamMspRows.TryAdd(slipstreamMspRow))
{
SlipstreamMspTable.Rows.Add(slipstreamMspRow);
}
this.TryAddSlipstreamTuple(slipstreamMspIds, msi, tuple);
}
rows = null;
}
if (!String.IsNullOrEmpty(msi.UpgradeCode) && targetsUpgradeCode.TryGetValue(msi.UpgradeCode, out rows))
if (!String.IsNullOrEmpty(msi.UpgradeCode) && targetsUpgradeCode.TryGetValue(msi.UpgradeCode, out tuples))
{
foreach (WixBundlePatchTargetCodeRow row in rows)
foreach (var tuple in tuples)
{
Debug.Assert(!row.TargetsProductCode);
Debug.Assert(row.TargetsUpgradeCode);
Debug.Assert(!tuple.TargetsProductCode);
Debug.Assert(tuple.TargetsUpgradeCode);
Row slipstreamMspRow = SlipstreamMspTable.CreateRow(row.SourceLineNumbers, false);
slipstreamMspRow[0] = msi.ChainPackageId;
slipstreamMspRow[1] = row.MspPackageId;
if (slipstreamMspRows.TryAdd(slipstreamMspRow))
{
SlipstreamMspTable.Rows.Add(slipstreamMspRow);
}
this.TryAddSlipstreamTuple(slipstreamMspIds, msi, tuple);
}
rows = null;
tuples = null;
}
}
}
#endif
private bool TryAddSlipstreamTuple(HashSet<string> slipstreamMspIds, WixBundleMsiPackageTuple msiPackage, WixBundlePatchTargetCodeTuple patchTargetCode)
{
var id = new Identifier(AccessModifier.Private, msiPackage.Id.Id, patchTargetCode.PackageRef);
if (slipstreamMspIds.Add(id.Id))
{
var slipstreamTuple = new WixBundleSlipstreamMspTuple(patchTargetCode.SourceLineNumbers)
{
TargetPackageRef = msiPackage.Id.Id,
MspPackageRef = patchTargetCode.PackageRef
};
//var slipstreamMspRow = SlipstreamMspTable.CreateRow(tuple.SourceLineNumbers, false);
//slipstreamMspRow[0] = msi.ChainPackageId;
//slipstreamMspRow[1] = tuple.MspPackageId;
this.Section.Tuples.Add(slipstreamTuple);
return true;
}
return false;
}
}
}

Просмотреть файл

@ -0,0 +1,30 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.Burn.Bundles
{
using System.IO;
using System.Security.Cryptography;
using System.Text;
internal static class BundleHashAlgorithm
{
public static string Hash(FileInfo fileInfo)
{
byte[] hashBytes;
using (var managed = new SHA1Managed())
using (var stream = fileInfo.OpenRead())
{
hashBytes = managed.ComputeHash(stream);
}
var sb = new StringBuilder(hashBytes.Length * 2);
for (var i = 0; i < hashBytes.Length; i++)
{
sb.AppendFormat("{0:X2}", hashBytes[i]);
}
return sb.ToString();
}
}
}

Просмотреть файл

@ -128,7 +128,7 @@ namespace WixToolset.Core.Burn.Bundles
public void Dispose()
{
Dispose(true);
this.Dispose(true);
GC.SuppressFinalize(this);
}
@ -238,7 +238,7 @@ namespace WixToolset.Core.Burn.Bundles
{
if (UInt32.MaxValue == this.wixburnDataOffset)
{
if (!EnsureNTHeader(reader))
if (!this.EnsureNTHeader(reader))
{
return false;
}
@ -286,7 +286,7 @@ namespace WixToolset.Core.Burn.Bundles
{
if (UInt32.MaxValue == this.firstSectionOffset)
{
if (!EnsureDosHeader(reader))
if (!this.EnsureDosHeader(reader))
{
return false;
}

Просмотреть файл

@ -67,19 +67,21 @@ namespace WixToolset.Core.Burn.Bundles
/// <param name="stubSize">Size of the stub engine "burn.exe".</param>
/// <param name="bundleId">Unique identifier for this bundle.</param>
/// <returns></returns>
public bool InitializeBundleSectionData(long stubSize, Guid bundleId)
public bool InitializeBundleSectionData(long stubSize, string bundleId)
{
if (this.invalidBundle)
{
return false;
}
var bundleGuid = Guid.Parse(bundleId);
this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_MAGIC, BURN_SECTION_MAGIC);
this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_VERSION, BURN_SECTION_VERSION);
this.messaging.Write(VerboseMessages.BundleGuid(bundleId.ToString("B")));
this.messaging.Write(VerboseMessages.BundleGuid(bundleId));
this.binaryWriter.BaseStream.Seek(this.wixburnDataOffset + BURN_SECTION_OFFSET_BUNDLEGUID, SeekOrigin.Begin);
this.binaryWriter.Write(bundleId.ToByteArray());
this.binaryWriter.Write(bundleGuid.ToByteArray());
this.StubSize = (uint)stubSize;
@ -146,7 +148,7 @@ namespace WixToolset.Core.Burn.Bundles
return false;
}
return AppendContainer(containerStream, (UInt32)containerSize, burnSectionOffsetSize, burnSectionCount);
return this.AppendContainer(containerStream, (UInt32)containerSize, burnSectionOffsetSize, burnSectionCount);
}
public void RememberThenResetSignature()

Просмотреть файл

@ -7,236 +7,268 @@ namespace WixToolset.Core.Burn.Bundles
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using WixToolset.Data;
using WixToolset.Data.Burn;
using WixToolset.Data.Tuples;
internal class CreateBootstrapperApplicationManifestCommand
{
#if TODO
public WixBundleRow BundleRow { private get; set; }
public CreateBootstrapperApplicationManifestCommand(IntermediateSection section, WixBundleTuple bundleTuple, IEnumerable<PackageFacade> chainPackages, int lastUXPayloadIndex, Dictionary<string, WixBundlePayloadTuple> payloadTuples, string intermediateFolder)
{
this.Section = section;
this.BundleTuple = bundleTuple;
this.ChainPackages = chainPackages;
this.LastUXPayloadIndex = lastUXPayloadIndex;
this.Payloads = payloadTuples;
this.IntermediateFolder = intermediateFolder;
}
public IEnumerable<PackageFacade> ChainPackages { private get; set; }
private IntermediateSection Section { get; }
public int LastUXPayloadIndex { private get; set; }
private WixBundleTuple BundleTuple { get; }
public IEnumerable<WixBundleMsiFeatureRow> MsiFeatures { private get; set; }
private IEnumerable<PackageFacade> ChainPackages { get; }
public Output Output { private get; set; }
private int LastUXPayloadIndex { get; }
public RowDictionary<WixBundlePayloadRow> Payloads { private get; set; }
private Dictionary<string, WixBundlePayloadTuple> Payloads { get; }
public TableDefinitionCollection TableDefinitions { private get; set; }
private string IntermediateFolder { get; }
public string TempFilesLocation { private get; set; }
public WixBundlePayloadRow BootstrapperApplicationManifestPayloadRow { get; private set; }
public WixBundlePayloadTuple BootstrapperApplicationManifestPayloadRow { get; private set; }
public void Execute()
{
this.GenerateBAManifestBundleTables();
this.GenerateBAManifestMsiFeatureTables();
this.GenerateBAManifestPackageTables();
this.GenerateBAManifestPayloadTables();
string baManifestPath = Path.Combine(this.TempFilesLocation, "wix-badata.xml");
this.CreateBootstrapperApplicationManifest(baManifestPath);
var baManifestPath = this.CreateBootstrapperApplicationManifest();
this.BootstrapperApplicationManifestPayloadRow = this.CreateBootstrapperApplicationManifestPayloadRow(baManifestPath);
}
private void GenerateBAManifestBundleTables()
private string CreateBootstrapperApplicationManifest()
{
Table wixBundlePropertiesTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleProperties"]);
var path = Path.Combine(this.IntermediateFolder, "wix-badata.xml");
Row row = wixBundlePropertiesTable.CreateRow(this.BundleRow.SourceLineNumbers);
row[0] = this.BundleRow.Name;
row[1] = this.BundleRow.LogPathVariable;
row[2] = (YesNoDefaultType.Yes == this.BundleRow.Compressed) ? "yes" : "no";
row[3] = this.BundleRow.BundleId.ToString("B");
row[4] = this.BundleRow.UpgradeCode;
row[5] = this.BundleRow.PerMachine ? "yes" : "no";
}
Directory.CreateDirectory(Path.GetDirectoryName(path));
private void GenerateBAManifestPackageTables()
{
Table wixPackagePropertiesTable = this.Output.EnsureTable(this.TableDefinitions["WixPackageProperties"]);
foreach (PackageFacade package in this.ChainPackages)
{
WixBundlePayloadRow packagePayload = this.Payloads[package.Package.PackagePayload];
Row row = wixPackagePropertiesTable.CreateRow(package.Package.SourceLineNumbers);
row[0] = package.Package.WixChainItemId;
row[1] = (YesNoType.Yes == package.Package.Vital) ? "yes" : "no";
row[2] = package.Package.DisplayName;
row[3] = package.Package.Description;
row[4] = package.Package.Size.ToString(CultureInfo.InvariantCulture); // TODO: DownloadSize (compressed) (what does this mean when it's embedded?)
row[5] = package.Package.Size.ToString(CultureInfo.InvariantCulture); // Package.Size (uncompressed)
row[6] = package.Package.InstallSize.Value.ToString(CultureInfo.InvariantCulture); // InstallSize (required disk space)
row[7] = package.Package.Type.ToString();
row[8] = package.Package.Permanent ? "yes" : "no";
row[9] = package.Package.LogPathVariable;
row[10] = package.Package.RollbackLogPathVariable;
row[11] = (PackagingType.Embedded == packagePayload.Packaging) ? "yes" : "no";
if (WixBundlePackageType.Msi == package.Package.Type)
{
row[12] = package.MsiPackage.DisplayInternalUI ? "yes" : "no";
if (!String.IsNullOrEmpty(package.MsiPackage.ProductCode))
{
row[13] = package.MsiPackage.ProductCode;
}
if (!String.IsNullOrEmpty(package.MsiPackage.UpgradeCode))
{
row[14] = package.MsiPackage.UpgradeCode;
}
}
else if (WixBundlePackageType.Msp == package.Package.Type)
{
row[12] = package.MspPackage.DisplayInternalUI ? "yes" : "no";
if (!String.IsNullOrEmpty(package.MspPackage.PatchCode))
{
row[13] = package.MspPackage.PatchCode;
}
}
if (!String.IsNullOrEmpty(package.Package.Version))
{
row[15] = package.Package.Version;
}
if (!String.IsNullOrEmpty(package.Package.InstallCondition))
{
row[16] = package.Package.InstallCondition;
}
switch (package.Package.Cache)
{
case YesNoAlwaysType.No:
row[17] = "no";
break;
case YesNoAlwaysType.Yes:
row[17] = "yes";
break;
case YesNoAlwaysType.Always:
row[17] = "always";
break;
}
}
}
private void GenerateBAManifestMsiFeatureTables()
{
Table wixPackageFeatureInfoTable = this.Output.EnsureTable(this.TableDefinitions["WixPackageFeatureInfo"]);
foreach (WixBundleMsiFeatureRow feature in this.MsiFeatures)
{
Row row = wixPackageFeatureInfoTable.CreateRow(feature.SourceLineNumbers);
row[0] = feature.ChainPackageId;
row[1] = feature.Name;
row[2] = Convert.ToString(feature.Size, CultureInfo.InvariantCulture);
row[3] = feature.Parent;
row[4] = feature.Title;
row[5] = feature.Description;
row[6] = Convert.ToString(feature.Display, CultureInfo.InvariantCulture);
row[7] = Convert.ToString(feature.Level, CultureInfo.InvariantCulture);
row[8] = feature.Directory;
row[9] = Convert.ToString(feature.Attributes, CultureInfo.InvariantCulture);
}
}
private void GenerateBAManifestPayloadTables()
{
Table wixPayloadPropertiesTable = this.Output.EnsureTable(this.TableDefinitions["WixPayloadProperties"]);
foreach (WixBundlePayloadRow payload in this.Payloads.Values)
{
WixPayloadPropertiesRow row = (WixPayloadPropertiesRow)wixPayloadPropertiesTable.CreateRow(payload.SourceLineNumbers);
row.Id = payload.Id;
row.Package = payload.Package;
row.Container = payload.Container;
row.Name = payload.Name;
row.Size = payload.FileSize.ToString();
row.DownloadUrl = payload.DownloadUrl;
row.LayoutOnly = payload.LayoutOnly ? "yes" : "no";
}
}
private void CreateBootstrapperApplicationManifest(string path)
{
using (XmlTextWriter writer = new XmlTextWriter(path, Encoding.Unicode))
using (var writer = new XmlTextWriter(path, Encoding.Unicode))
{
writer.Formatting = Formatting.Indented;
writer.WriteStartDocument();
writer.WriteStartElement("BootstrapperApplicationData", "http://wixtoolset.org/schemas/v4/2010/BootstrapperApplicationData");
writer.WriteStartElement("BootstrapperApplicationData", "http://wixtoolset.org/schemas/v4/BootstrapperApplicationData");
foreach (Table table in this.Output.Tables)
{
if (table.Definition.BootstrapperApplicationData)
{
// We simply assert that the table (and field) name is valid, because
// this is up to the extension developer to get right. An author will
// only affect the attribute value, and that will get properly escaped.
#if DEBUG
Debug.Assert(Common.IsIdentifier(table.Name));
foreach (ColumnDefinition column in table.Definition.Columns)
{
Debug.Assert(Common.IsIdentifier(column.Name));
}
#endif // DEBUG
this.WriteBundleInfo(writer);
foreach (Row row in table.Rows)
{
writer.WriteStartElement(table.Name);
this.WritePackageInfo(writer);
foreach (Field field in row.Fields)
{
if (null != field.Data)
{
writer.WriteAttributeString(field.Column.Name, field.Data.ToString());
}
}
this.WriteFeatureInfo(writer);
writer.WriteEndElement();
}
}
}
this.WritePayloadInfo(writer);
this.WriteCustomBootstrapperApplicationData(writer);
writer.WriteEndElement();
writer.WriteEndDocument();
}
return path;
}
private WixBundlePayloadRow CreateBootstrapperApplicationManifestPayloadRow(string baManifestPath)
private void WriteBundleInfo(XmlTextWriter writer)
{
Table payloadTable = this.Output.EnsureTable(this.TableDefinitions["WixBundlePayload"]);
WixBundlePayloadRow row = (WixBundlePayloadRow)payloadTable.CreateRow(this.BundleRow.SourceLineNumbers);
row.Id = Common.GenerateIdentifier("ux", "BootstrapperApplicationData.xml");
row.Name = "BootstrapperApplicationData.xml";
row.SourceFile = baManifestPath;
row.Compressed = YesNoDefaultType.Yes;
row.UnresolvedSourceFile = baManifestPath;
row.Container = Compiler.BurnUXContainerId;
row.EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnUXContainerEmbeddedIdFormat, this.LastUXPayloadIndex);
row.Packaging = PackagingType.Embedded;
writer.WriteStartElement("WixBundleProperties");
FileInfo fileInfo = new FileInfo(row.SourceFile);
writer.WriteAttributeString("DisplayName", this.BundleTuple.Name);
writer.WriteAttributeString("LogPathVariable", this.BundleTuple.LogPathVariable);
writer.WriteAttributeString("Compressed", this.BundleTuple.Compressed == true ? "yes" : "no");
writer.WriteAttributeString("BundleId", this.BundleTuple.BundleId.ToUpperInvariant());
writer.WriteAttributeString("UpgradeCode", this.BundleTuple.UpgradeCode);
writer.WriteAttributeString("PerMachine", this.BundleTuple.PerMachine ? "yes" : "no");
row.FileSize = (int)fileInfo.Length;
row.Hash = Common.GetFileHash(fileInfo.FullName);
return row;
writer.WriteEndElement();
}
private void WritePackageInfo(XmlTextWriter writer)
{
foreach (var package in this.ChainPackages)
{
var packagePayload = this.Payloads[package.PackageTuple.PayloadRef];
var size = package.PackageTuple.Size.ToString(CultureInfo.InvariantCulture);
writer.WriteStartElement("WixBundleProperties");
writer.WriteAttributeString("Package", package.PackageId);
writer.WriteAttributeString("Vital", package.PackageTuple.Vital == true ? "yes" : "no");
writer.WriteAttributeString("DisplayName", package.PackageTuple.DisplayName);
writer.WriteAttributeString("Description", package.PackageTuple.Description);
writer.WriteAttributeString("DownloadSize", size);
writer.WriteAttributeString("PackageSize", size);
writer.WriteAttributeString("InstalledSize", package.PackageTuple.InstallSize?.ToString(CultureInfo.InvariantCulture) ?? size);
writer.WriteAttributeString("PackageType", package.PackageTuple.Type.ToString());
writer.WriteAttributeString("Permanent", package.PackageTuple.Permanent ? "yes" : "no");
writer.WriteAttributeString("LogPathVariable", package.PackageTuple.LogPathVariable);
writer.WriteAttributeString("RollbackLogPathVariable", package.PackageTuple.RollbackLogPathVariable);
writer.WriteAttributeString("Compressed", packagePayload.Compressed == true ? "yes" : "no");
if (package.SpecificPackageTuple is WixBundleMsiPackageTuple msiPackage)
{
writer.WriteAttributeString("DisplayInternalUI", msiPackage.DisplayInternalUI ? "yes" : "no");
if (!String.IsNullOrEmpty(msiPackage.ProductCode))
{
writer.WriteAttributeString("ProductCode", msiPackage.ProductCode);
}
if (!String.IsNullOrEmpty(msiPackage.UpgradeCode))
{
writer.WriteAttributeString("UpgradeCode", msiPackage.UpgradeCode);
}
}
else if (package.SpecificPackageTuple is WixBundleMspPackageTuple mspPackage)
{
writer.WriteAttributeString("DisplayInternalUI", mspPackage.DisplayInternalUI ? "yes" : "no");
if (!String.IsNullOrEmpty(mspPackage.PatchCode))
{
writer.WriteAttributeString("ProductCode", mspPackage.PatchCode);
}
}
if (!String.IsNullOrEmpty(package.PackageTuple.Version))
{
writer.WriteAttributeString("Version", package.PackageTuple.Version);
}
if (!String.IsNullOrEmpty(package.PackageTuple.InstallCondition))
{
writer.WriteAttributeString("InstallCondition", package.PackageTuple.InstallCondition);
}
switch (package.PackageTuple.Cache)
{
case YesNoAlwaysType.No:
writer.WriteAttributeString("Cache", "no");
break;
case YesNoAlwaysType.Yes:
writer.WriteAttributeString("Cache", "yes");
break;
case YesNoAlwaysType.Always:
writer.WriteAttributeString("Cache", "always");
break;
}
writer.WriteEndElement();
}
}
private void WriteFeatureInfo(XmlTextWriter writer)
{
var featureTuples = this.Section.Tuples.OfType<WixBundleMsiFeatureTuple>();
foreach (var featureTuple in featureTuples)
{
writer.WriteStartElement("WixPackageFeatureInfo");
writer.WriteAttributeString("Package", featureTuple.PackageRef);
writer.WriteAttributeString("Feature", featureTuple.Name);
writer.WriteAttributeString("Size", featureTuple.Size.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString("Parent", featureTuple.Parent);
writer.WriteAttributeString("Title", featureTuple.Title);
writer.WriteAttributeString("Description", featureTuple.Description);
writer.WriteAttributeString("Display", featureTuple.Display.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString("Level", featureTuple.Level.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString("Directory", featureTuple.Directory);
writer.WriteAttributeString("Attributes", featureTuple.Attributes.ToString(CultureInfo.InvariantCulture));
writer.WriteEndElement();
}
}
private void WritePayloadInfo(XmlTextWriter writer)
{
var payloadTuples = this.Section.Tuples.OfType<WixBundlePayloadTuple>();
foreach (var payloadTuple in payloadTuples)
{
writer.WriteStartElement("WixPackageFeatureInfo");
writer.WriteAttributeString("Id", payloadTuple.Id.Id);
writer.WriteAttributeString("Package", payloadTuple.PackageRef);
writer.WriteAttributeString("Container", payloadTuple.ContainerRef);
writer.WriteAttributeString("Name", payloadTuple.Name);
writer.WriteAttributeString("Size", payloadTuple.FileSize.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString("DownloadUrl", payloadTuple.DownloadUrl);
writer.WriteAttributeString("LayoutOnly", payloadTuple.LayoutOnly ? "yes" : "no");
writer.WriteEndElement();
}
}
private void WriteCustomBootstrapperApplicationData(XmlTextWriter writer)
{
var dataTuplesGroupedByDefinitionName = this.Section.Tuples
.Where(t => t.Definition.HasTag(BurnConstants.BootstrapperApplicationDataTupleDefinitionTag))
.GroupBy(t => t.Definition);
foreach (var group in dataTuplesGroupedByDefinitionName)
{
var definition = group.Key;
// We simply assert that the table (and field) name is valid, because
// this is up to the extension developer to get right. An author will
// only affect the attribute value, and that will get properly escaped.
#if DEBUG
Debug.Assert(Common.IsIdentifier(definition.Name));
foreach (var fieldDef in definition.FieldDefinitions)
{
Debug.Assert(Common.IsIdentifier(fieldDef.Name));
}
#endif // DEBUG
foreach (var row in group)
{
writer.WriteStartElement(definition.Name);
foreach (var field in row.Fields)
{
if (!field.IsNull())
{
writer.WriteAttributeString(field.Definition.Name, field.AsString());
}
}
writer.WriteEndElement();
}
}
}
private WixBundlePayloadTuple CreateBootstrapperApplicationManifestPayloadRow(string baManifestPath)
{
var generatedId = Common.GenerateIdentifier("ux", "BootstrapperApplicationData.xml");
var tuple = new WixBundlePayloadTuple(this.BundleTuple.SourceLineNumbers, new Identifier(AccessModifier.Private, generatedId))
{
Name = "BootstrapperApplicationData.xml",
SourceFile = new IntermediateFieldPathValue { Path = baManifestPath },
Compressed = true,
UnresolvedSourceFile = baManifestPath,
ContainerRef = BurnConstants.BurnUXContainerName,
EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnUXContainerEmbeddedIdFormat, this.LastUXPayloadIndex),
Packaging = PackagingType.Embedded,
};
var fileInfo = new FileInfo(baManifestPath);
tuple.FileSize = (int)fileInfo.Length;
tuple.Hash = BundleHashAlgorithm.Hash(fileInfo);
this.Section.Tuples.Add(tuple);
return tuple;
}
#endif
}
}

Просмотреть файл

@ -0,0 +1,171 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.Burn.Bundles
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using WixToolset.Data;
using WixToolset.Data.Burn;
using WixToolset.Data.Tuples;
using WixToolset.Extensibility.Data;
using WixToolset.Extensibility.Services;
internal class CreateBundleExeCommand
{
public CreateBundleExeCommand(IMessaging messaging, IBackendHelper backendHelper, string intermediateFolder, string outputPath, WixBundleTuple bundleTuple, WixBundleContainerTuple uxContainer, IEnumerable<WixBundleContainerTuple> containers, string burnStubPath)
{
this.Messaging = messaging;
this.BackendHelper = backendHelper;
this.IntermediateFolder = intermediateFolder;
this.OutputPath = outputPath;
this.BundleTuple = bundleTuple;
this.UXContainer = uxContainer;
this.Containers = containers;
this.BurnStubPath = burnStubPath;
}
public IFileTransfer Transfer { get; private set; }
private IMessaging Messaging { get; }
private IBackendHelper BackendHelper { get; }
private string IntermediateFolder { get; }
private string OutputPath { get; }
private WixBundleTuple BundleTuple { get; }
private WixBundleContainerTuple UXContainer { get; }
private IEnumerable<WixBundleContainerTuple> Containers { get; }
private string BurnStubPath { get; }
public void Execute()
{
var bundleFilename = Path.GetFileName(this.OutputPath);
// Copy the burn.exe to a writable location then mark it to be moved to its final build location. Note
// that today, the x64 Burn uses the x86 stub.
var stubFile = this.BurnStubPath;
if (String.IsNullOrEmpty(stubFile))
{
var stubPlatform = (Platform.X64 == this.BundleTuple.Platform) ? "x86" : this.BundleTuple.Platform.ToString();
stubFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), stubPlatform, "burn.exe");
}
var bundleTempPath = Path.Combine(this.IntermediateFolder, bundleFilename);
this.Messaging.Write(VerboseMessages.GeneratingBundle(bundleTempPath, stubFile));
if ("setup.exe".Equals(bundleFilename, StringComparison.OrdinalIgnoreCase))
{
this.Messaging.Write(ErrorMessages.InsecureBundleFilename(bundleFilename));
}
this.Transfer = this.BackendHelper.CreateFileTransfer(bundleTempPath, this.OutputPath, true, this.BundleTuple.SourceLineNumbers);
File.Copy(stubFile, bundleTempPath, true);
File.SetAttributes(bundleTempPath, FileAttributes.Normal);
this.UpdateBurnResources(bundleTempPath, this.OutputPath, this.BundleTuple);
// Update the .wixburn section to point to at the UX and attached container(s) then attach the containers
// if they should be attached.
using (var writer = BurnWriter.Open(this.Messaging, bundleTempPath))
{
var burnStubFile = new FileInfo(bundleTempPath);
writer.InitializeBundleSectionData(burnStubFile.Length, this.BundleTuple.BundleId);
// Always attach the UX container first
writer.AppendContainer(this.UXContainer.WorkingPath, BurnWriter.Container.UX);
// Now append all other attached containers
foreach (var container in this.Containers)
{
if (ContainerType.Attached == container.Type)
{
// The container was only created if it had payloads.
if (!String.IsNullOrEmpty(container.WorkingPath) && BurnConstants.BurnUXContainerName != container.Id.Id)
{
writer.AppendContainer(container.WorkingPath, BurnWriter.Container.Attached);
}
}
}
}
}
private void UpdateBurnResources(string bundleTempPath, string outputPath, WixBundleTuple bundleInfo)
{
var resources = new Dtf.Resources.ResourceCollection();
var version = new Dtf.Resources.VersionResource("#1", 1033);
version.Load(bundleTempPath);
resources.Add(version);
// Ensure the bundle info provides a full four part version.
var fourPartVersion = new Version(bundleInfo.Version);
var major = (fourPartVersion.Major < 0) ? 0 : fourPartVersion.Major;
var minor = (fourPartVersion.Minor < 0) ? 0 : fourPartVersion.Minor;
var build = (fourPartVersion.Build < 0) ? 0 : fourPartVersion.Build;
var revision = (fourPartVersion.Revision < 0) ? 0 : fourPartVersion.Revision;
if (UInt16.MaxValue < major || UInt16.MaxValue < minor || UInt16.MaxValue < build || UInt16.MaxValue < revision)
{
throw new WixException(ErrorMessages.InvalidModuleOrBundleVersion(bundleInfo.SourceLineNumbers, "Bundle", bundleInfo.Version));
}
fourPartVersion = new Version(major, minor, build, revision);
version.FileVersion = fourPartVersion;
version.ProductVersion = fourPartVersion;
var strings = version[1033];
strings["LegalCopyright"] = bundleInfo.Copyright;
strings["OriginalFilename"] = Path.GetFileName(outputPath);
strings["FileVersion"] = bundleInfo.Version; // string versions do not have to be four parts.
strings["ProductVersion"] = bundleInfo.Version; // string versions do not have to be four parts.
if (!String.IsNullOrEmpty(bundleInfo.Name))
{
strings["ProductName"] = bundleInfo.Name;
strings["FileDescription"] = bundleInfo.Name;
}
if (!String.IsNullOrEmpty(bundleInfo.Manufacturer))
{
strings["CompanyName"] = bundleInfo.Manufacturer;
}
else
{
strings["CompanyName"] = String.Empty;
}
if (!String.IsNullOrEmpty(bundleInfo.IconSourceFile))
{
var iconGroup = new Dtf.Resources.GroupIconResource("#1", 1033);
iconGroup.ReadFromFile(bundleInfo.IconSourceFile);
resources.Add(iconGroup);
foreach (var icon in iconGroup.Icons)
{
resources.Add(icon);
}
}
if (!String.IsNullOrEmpty(bundleInfo.SplashScreenSourceFile))
{
var bitmap = new Dtf.Resources.BitmapResource("#1", 1033);
bitmap.ReadFromFile(bundleInfo.SplashScreenSourceFile);
resources.Add(bitmap);
}
resources.Save(bundleTempPath);
}
}
}

Просмотреть файл

@ -6,76 +6,103 @@ namespace WixToolset.Core.Burn.Bundles
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using WixToolset.Data;
using WixToolset.Data.Burn;
using WixToolset.Data.Tuples;
using WixToolset.Extensibility;
using WixToolset.Extensibility.Services;
internal class CreateBurnManifestCommand
{
#if TODO
public IEnumerable<IBurnBackendExtension> BackendExtensions { private get; set; }
public CreateBurnManifestCommand(IMessaging messaging, IEnumerable<IBurnBackendExtension> backendExtensions, string executableName, IntermediateSection section, WixBundleTuple bundleTuple, IEnumerable<WixBundleContainerTuple> containers, WixChainTuple chainTuple, IEnumerable<PackageFacade> orderedPackages, IEnumerable<WixBundleRollbackBoundaryTuple> boundaries, IEnumerable<WixBundlePayloadTuple> uxPayloads, Dictionary<string, WixBundlePayloadTuple> allPayloadsById, IEnumerable<SearchFacade> orderedSearches, IEnumerable<WixBundleCatalogTuple> catalogs, string intermediateFolder)
{
this.Messaging = messaging;
this.BackendExtensions = backendExtensions;
this.ExecutableName = executableName;
this.Section = section;
this.BundleTuple = bundleTuple;
this.Chain = chainTuple;
this.Containers = containers;
this.OrderedPackages = orderedPackages;
this.RollbackBoundaries = boundaries;
this.UXContainerPayloads = uxPayloads;
this.Payloads = allPayloadsById;
this.OrderedSearches = orderedSearches;
this.Catalogs = catalogs;
this.IntermediateFolder = intermediateFolder;
}
public Output Output { private get; set; }
public string OutputPath { get; private set; }
public string ExecutableName { private get; set; }
private IMessaging Messaging { get; }
public WixBundleRow BundleInfo { private get; set; }
private IEnumerable<IBurnBackendExtension> BackendExtensions { get; }
public WixChainRow Chain { private get; set; }
private string ExecutableName { get; }
public string OutputPath { private get; set; }
private IntermediateSection Section { get; }
public IEnumerable<WixBundleRollbackBoundaryRow> RollbackBoundaries { private get; set; }
private WixBundleTuple BundleTuple { get; }
public IEnumerable<PackageFacade> OrderedPackages { private get; set; }
private WixChainTuple Chain { get; }
public IEnumerable<WixSearchInfo> OrderedSearches { private get; set; }
private IEnumerable<WixBundleRollbackBoundaryTuple> RollbackBoundaries { get; }
public Dictionary<string, WixBundlePayloadRow> Payloads { private get; set; }
private IEnumerable<PackageFacade> OrderedPackages { get; }
public Dictionary<string, WixBundleContainerRow> Containers { private get; set; }
private IEnumerable<SearchFacade> OrderedSearches { get; }
public IEnumerable<WixBundlePayloadRow> UXContainerPayloads { private get; set; }
private Dictionary<string, WixBundlePayloadTuple> Payloads { get; }
public IEnumerable<WixBundleCatalogRow> Catalogs { private get; set; }
private IEnumerable<WixBundleContainerTuple> Containers { get; }
private IEnumerable<WixBundlePayloadTuple> UXContainerPayloads { get; }
private IEnumerable<WixBundleCatalogTuple> Catalogs { get; }
private string IntermediateFolder { get; }
public void Execute()
{
using (XmlTextWriter writer = new XmlTextWriter(this.OutputPath, Encoding.UTF8))
this.OutputPath = Path.Combine(this.IntermediateFolder, "bundle-manifest.xml");
using (var writer = new XmlTextWriter(this.OutputPath, Encoding.UTF8))
{
writer.WriteStartDocument();
writer.WriteStartElement("BurnManifest", BurnCommon.BurnNamespace);
// Write the condition, if there is one
if (null != this.BundleInfo.Condition)
if (null != this.BundleTuple.Condition)
{
writer.WriteElementString("Condition", this.BundleInfo.Condition);
writer.WriteElementString("Condition", this.BundleTuple.Condition);
}
// Write the log element if default logging wasn't disabled.
if (!String.IsNullOrEmpty(this.BundleInfo.LogPrefix))
if (!String.IsNullOrEmpty(this.BundleTuple.LogPrefix))
{
writer.WriteStartElement("Log");
if (!String.IsNullOrEmpty(this.BundleInfo.LogPathVariable))
if (!String.IsNullOrEmpty(this.BundleTuple.LogPathVariable))
{
writer.WriteAttributeString("PathVariable", this.BundleInfo.LogPathVariable);
writer.WriteAttributeString("PathVariable", this.BundleTuple.LogPathVariable);
}
writer.WriteAttributeString("Prefix", this.BundleInfo.LogPrefix);
writer.WriteAttributeString("Extension", this.BundleInfo.LogExtension);
writer.WriteAttributeString("Prefix", this.BundleTuple.LogPrefix);
writer.WriteAttributeString("Extension", this.BundleTuple.LogExtension);
writer.WriteEndElement();
}
// Get update if specified.
WixBundleUpdateRow updateRow = this.Output.Tables["WixBundleUpdate"].RowsAs<WixBundleUpdateRow>().FirstOrDefault();
var updateTuple = this.Section.Tuples.OfType<WixBundleUpdateTuple>().FirstOrDefault();
if (null != updateRow)
if (null != updateTuple)
{
writer.WriteStartElement("Update");
writer.WriteAttributeString("Location", updateRow.Location);
writer.WriteAttributeString("Location", updateTuple.Location);
writer.WriteEndElement(); // </Update>
}
@ -83,23 +110,27 @@ namespace WixToolset.Core.Burn.Bundles
// For the related bundles with duplicated identifiers the second instance is ignored (i.e. the Duplicates
// enumeration in the index row list is not used).
RowIndexedList<WixRelatedBundleRow> relatedBundles = new RowIndexedList<WixRelatedBundleRow>(this.Output.Tables["WixRelatedBundle"]);
var relatedBundles = this.Section.Tuples.OfType<WixRelatedBundleTuple>();
var distinctRelatedBundles = new HashSet<string>();
foreach (WixRelatedBundleRow relatedBundle in relatedBundles)
foreach (var relatedBundle in relatedBundles)
{
writer.WriteStartElement("RelatedBundle");
writer.WriteAttributeString("Id", relatedBundle.Id);
writer.WriteAttributeString("Action", Convert.ToString(relatedBundle.Action, CultureInfo.InvariantCulture));
writer.WriteEndElement();
if (distinctRelatedBundles.Add(relatedBundle.BundleId))
{
writer.WriteStartElement("RelatedBundle");
writer.WriteAttributeString("Id", relatedBundle.BundleId);
writer.WriteAttributeString("Action", relatedBundle.Action.ToString());
writer.WriteEndElement();
}
}
// Write the variables
IEnumerable<WixBundleVariableRow> variables = this.Output.Tables["WixBundleVariable"].RowsAs<WixBundleVariableRow>();
var variables = this.Section.Tuples.OfType<WixBundleVariableTuple>();
foreach (WixBundleVariableRow variable in variables)
foreach (var variable in variables)
{
writer.WriteStartElement("Variable");
writer.WriteAttributeString("Id", variable.Id);
writer.WriteAttributeString("Id", variable.Id.Id);
if (null != variable.Type)
{
writer.WriteAttributeString("Value", variable.Value);
@ -111,20 +142,20 @@ namespace WixToolset.Core.Burn.Bundles
}
// Write the searches
foreach (WixSearchInfo searchinfo in this.OrderedSearches)
foreach (var searchinfo in this.OrderedSearches)
{
searchinfo.WriteXml(writer);
}
// write the UX element
writer.WriteStartElement("UX");
if (!String.IsNullOrEmpty(this.BundleInfo.SplashScreenBitmapPath))
if (!String.IsNullOrEmpty(this.BundleTuple.SplashScreenSourceFile))
{
writer.WriteAttributeString("SplashScreen", "yes");
}
// write the UX allPayloads...
foreach (WixBundlePayloadRow payload in this.UXContainerPayloads)
foreach (var payload in this.UXContainerPayloads)
{
writer.WriteStartElement("Payload");
this.WriteBurnManifestPayloadAttributes(writer, payload, true, this.Payloads);
@ -136,18 +167,18 @@ namespace WixToolset.Core.Burn.Bundles
// write the catalog elements
if (this.Catalogs.Any())
{
foreach (WixBundleCatalogRow catalog in this.Catalogs)
foreach (var catalog in this.Catalogs)
{
writer.WriteStartElement("Catalog");
writer.WriteAttributeString("Id", catalog.Id);
writer.WriteAttributeString("Payload", catalog.Payload);
writer.WriteAttributeString("Id", catalog.Id.Id);
writer.WriteAttributeString("Payload", catalog.PayloadRef);
writer.WriteEndElement();
}
}
foreach (WixBundleContainerRow container in this.Containers.Values)
foreach (var container in this.Containers)
{
if (!String.IsNullOrEmpty(container.WorkingPath) && Compiler.BurnUXContainerId != container.Id)
if (!String.IsNullOrEmpty(container.WorkingPath) && BurnConstants.BurnUXContainerName != container.Id.Id)
{
writer.WriteStartElement("Container");
this.WriteBurnManifestContainerAttributes(writer, this.ExecutableName, container);
@ -155,9 +186,9 @@ namespace WixToolset.Core.Burn.Bundles
}
}
foreach (WixBundlePayloadRow payload in this.Payloads.Values)
foreach (var payload in this.Payloads.Values)
{
if (PackagingType.Embedded == payload.Packaging && Compiler.BurnUXContainerId != payload.Container)
if (PackagingType.Embedded == payload.Packaging && BurnConstants.BurnUXContainerName != payload.ContainerRef)
{
writer.WriteStartElement("Payload");
this.WriteBurnManifestPayloadAttributes(writer, payload, true, this.Payloads);
@ -171,77 +202,78 @@ namespace WixToolset.Core.Burn.Bundles
}
}
foreach (WixBundleRollbackBoundaryRow rollbackBoundary in this.RollbackBoundaries)
foreach (var rollbackBoundary in this.RollbackBoundaries)
{
writer.WriteStartElement("RollbackBoundary");
writer.WriteAttributeString("Id", rollbackBoundary.ChainPackageId);
writer.WriteAttributeString("Vital", YesNoType.Yes == rollbackBoundary.Vital ? "yes" : "no");
writer.WriteAttributeString("Transaction", YesNoType.Yes == rollbackBoundary.Transaction ? "yes" : "no");
writer.WriteAttributeString("Id", rollbackBoundary.Id.Id);
writer.WriteAttributeString("Vital", rollbackBoundary.Vital == false ? "no" : "yes");
writer.WriteAttributeString("Transaction", rollbackBoundary.Transaction == true ? "yes" : "no");
writer.WriteEndElement();
}
// Write the registration information...
writer.WriteStartElement("Registration");
writer.WriteAttributeString("Id", this.BundleInfo.BundleId.ToString("B"));
writer.WriteAttributeString("Id", this.BundleTuple.BundleId);
writer.WriteAttributeString("ExecutableName", this.ExecutableName);
writer.WriteAttributeString("PerMachine", this.BundleInfo.PerMachine ? "yes" : "no");
writer.WriteAttributeString("Tag", this.BundleInfo.Tag);
writer.WriteAttributeString("Version", this.BundleInfo.Version);
writer.WriteAttributeString("ProviderKey", this.BundleInfo.ProviderKey);
writer.WriteAttributeString("PerMachine", this.BundleTuple.PerMachine ? "yes" : "no");
writer.WriteAttributeString("Tag", this.BundleTuple.Tag);
writer.WriteAttributeString("Version", this.BundleTuple.Version);
writer.WriteAttributeString("ProviderKey", this.BundleTuple.ProviderKey);
writer.WriteStartElement("Arp");
writer.WriteAttributeString("Register", (0 < this.BundleInfo.DisableModify && this.BundleInfo.DisableRemove) ? "no" : "yes"); // do not register if disabled modify and remove.
writer.WriteAttributeString("DisplayName", this.BundleInfo.Name);
writer.WriteAttributeString("DisplayVersion", this.BundleInfo.Version);
writer.WriteAttributeString("Register", (this.BundleTuple.DisableModify || this.BundleTuple.SingleChangeUninstallButton) && this.BundleTuple.DisableRemove ? "no" : "yes"); // do not register if disabled modify and remove.
writer.WriteAttributeString("DisplayName", this.BundleTuple.Name);
writer.WriteAttributeString("DisplayVersion", this.BundleTuple.Version);
if (!String.IsNullOrEmpty(this.BundleInfo.Publisher))
if (!String.IsNullOrEmpty(this.BundleTuple.Manufacturer))
{
writer.WriteAttributeString("Publisher", this.BundleInfo.Publisher);
writer.WriteAttributeString("Publisher", this.BundleTuple.Manufacturer);
}
if (!String.IsNullOrEmpty(this.BundleInfo.HelpLink))
if (!String.IsNullOrEmpty(this.BundleTuple.HelpUrl))
{
writer.WriteAttributeString("HelpLink", this.BundleInfo.HelpLink);
writer.WriteAttributeString("HelpLink", this.BundleTuple.HelpUrl);
}
if (!String.IsNullOrEmpty(this.BundleInfo.HelpTelephone))
if (!String.IsNullOrEmpty(this.BundleTuple.HelpTelephone))
{
writer.WriteAttributeString("HelpTelephone", this.BundleInfo.HelpTelephone);
writer.WriteAttributeString("HelpTelephone", this.BundleTuple.HelpTelephone);
}
if (!String.IsNullOrEmpty(this.BundleInfo.AboutUrl))
if (!String.IsNullOrEmpty(this.BundleTuple.AboutUrl))
{
writer.WriteAttributeString("AboutUrl", this.BundleInfo.AboutUrl);
writer.WriteAttributeString("AboutUrl", this.BundleTuple.AboutUrl);
}
if (!String.IsNullOrEmpty(this.BundleInfo.UpdateUrl))
if (!String.IsNullOrEmpty(this.BundleTuple.UpdateUrl))
{
writer.WriteAttributeString("UpdateUrl", this.BundleInfo.UpdateUrl);
writer.WriteAttributeString("UpdateUrl", this.BundleTuple.UpdateUrl);
}
if (!String.IsNullOrEmpty(this.BundleInfo.ParentName))
if (!String.IsNullOrEmpty(this.BundleTuple.ParentName))
{
writer.WriteAttributeString("ParentDisplayName", this.BundleInfo.ParentName);
writer.WriteAttributeString("ParentDisplayName", this.BundleTuple.ParentName);
}
if (1 == this.BundleInfo.DisableModify)
if (this.BundleTuple.DisableModify)
{
writer.WriteAttributeString("DisableModify", "yes");
}
else if (2 == this.BundleInfo.DisableModify)
{
writer.WriteAttributeString("DisableModify", "button");
}
if (this.BundleInfo.DisableRemove)
if (this.BundleTuple.DisableRemove)
{
writer.WriteAttributeString("DisableRemove", "yes");
}
if (this.BundleTuple.SingleChangeUninstallButton)
{
writer.WriteAttributeString("DisableModify", "button");
}
writer.WriteEndElement(); // </Arp>
// Get update registration if specified.
WixUpdateRegistrationRow updateRegistrationInfo = this.Output.Tables["WixUpdateRegistration"].RowsAs<WixUpdateRegistrationRow>().FirstOrDefault();
var updateRegistrationInfo = this.Section.Tuples.OfType<WixUpdateRegistrationTuple>().FirstOrDefault();
if (null != updateRegistrationInfo)
{
@ -263,9 +295,9 @@ namespace WixToolset.Core.Burn.Bundles
writer.WriteEndElement(); // </Update>
}
IEnumerable<Row> bundleTags = this.Output.Tables["WixBundleTag"].RowsAs<Row>();
foreach (Row row in bundleTags)
#if TODO // Handle SWID Tags
var bundleTags = this.Output.Tables["WixBundleTag"].RowsAs<Row>();
foreach (var row in bundleTags)
{
writer.WriteStartElement("SoftwareTag");
writer.WriteAttributeString("Filename", (string)row[0]);
@ -273,6 +305,7 @@ namespace WixToolset.Core.Burn.Bundles
writer.WriteCData((string)row[4]);
writer.WriteEndElement();
}
#endif
writer.WriteEndElement(); // </Register>
@ -294,25 +327,28 @@ namespace WixToolset.Core.Burn.Bundles
}
// Index a few tables by package.
ILookup<string, WixBundlePatchTargetCodeRow> targetCodesByPatch = this.Output.Tables["WixBundlePatchTargetCode"].RowsAs<WixBundlePatchTargetCodeRow>().ToLookup(r => r.MspPackageId);
ILookup<string, WixBundleMsiFeatureRow> msiFeaturesByPackage = this.Output.Tables["WixBundleMsiFeature"].RowsAs<WixBundleMsiFeatureRow>().ToLookup(r => r.ChainPackageId);
ILookup<string, WixBundleMsiPropertyRow> msiPropertiesByPackage = this.Output.Tables["WixBundleMsiProperty"].RowsAs<WixBundleMsiPropertyRow>().ToLookup(r => r.ChainPackageId);
ILookup<string, WixBundlePayloadRow> payloadsByPackage = this.Payloads.Values.ToLookup(p => p.Package);
ILookup<string, WixBundleRelatedPackageRow> relatedPackagesByPackage = this.Output.Tables["WixBundleRelatedPackage"].RowsAs<WixBundleRelatedPackageRow>().ToLookup(r => r.ChainPackageId);
ILookup<string, WixBundleSlipstreamMspRow> slipstreamMspsByPackage = this.Output.Tables["WixBundleSlipstreamMsp"].RowsAs<WixBundleSlipstreamMspRow>().ToLookup(r => r.ChainPackageId);
ILookup<string, WixBundlePackageExitCodeRow> exitCodesByPackage = this.Output.Tables["WixBundlePackageExitCode"].RowsAs<WixBundlePackageExitCodeRow>().ToLookup(r => r.ChainPackageId);
ILookup<string, WixBundlePackageCommandLineRow> commandLinesByPackage = this.Output.Tables["WixBundlePackageCommandLine"].RowsAs<WixBundlePackageCommandLineRow>().ToLookup(r => r.ChainPackageId);
var targetCodesByPatch = this.Section.Tuples.OfType<WixBundlePatchTargetCodeTuple>().ToLookup(r => r.PackageRef);
var msiFeaturesByPackage = this.Section.Tuples.OfType<WixBundleMsiFeatureTuple>().ToLookup(r => r.PackageRef);
var msiPropertiesByPackage = this.Section.Tuples.OfType<WixBundleMsiPropertyTuple>().ToLookup(r => r.PackageRef);
var payloadsByPackage = this.Payloads.Values.ToLookup(p => p.PackageRef);
var relatedPackagesByPackage = this.Section.Tuples.OfType<WixBundleRelatedPackageTuple>().ToLookup(r => r.PackageRef);
var slipstreamMspsByPackage = this.Section.Tuples.OfType<WixBundleSlipstreamMspTuple>().ToLookup(r => r.MspPackageRef);
var exitCodesByPackage = this.Section.Tuples.OfType<WixBundlePackageExitCodeTuple>().ToLookup(r => r.ChainPackageId);
var commandLinesByPackage = this.Section.Tuples.OfType<WixBundlePackageCommandLineTuple>().ToLookup(r => r.WixBundlePackageRef);
var dependenciesByPackage = this.Section.Tuples.OfType<ProvidesDependencyTuple>().ToLookup(p => p.PackageRef);
// Build up the list of target codes from all the MSPs in the chain.
List<WixBundlePatchTargetCodeRow> targetCodes = new List<WixBundlePatchTargetCodeRow>();
var targetCodes = new List<WixBundlePatchTargetCodeTuple>();
foreach (PackageFacade package in this.OrderedPackages)
foreach (var package in this.OrderedPackages)
{
writer.WriteStartElement(String.Format(CultureInfo.InvariantCulture, "{0}Package", package.Package.Type));
writer.WriteStartElement(String.Format(CultureInfo.InvariantCulture, "{0}Package", package.PackageTuple.Type));
writer.WriteAttributeString("Id", package.Package.WixChainItemId);
writer.WriteAttributeString("Id", package.PackageId);
switch (package.Package.Cache)
switch (package.PackageTuple.Cache)
{
case YesNoAlwaysType.No:
writer.WriteAttributeString("Cache", "no");
@ -325,74 +361,74 @@ namespace WixToolset.Core.Burn.Bundles
break;
}
writer.WriteAttributeString("CacheId", package.Package.CacheId);
writer.WriteAttributeString("InstallSize", Convert.ToString(package.Package.InstallSize));
writer.WriteAttributeString("Size", Convert.ToString(package.Package.Size));
writer.WriteAttributeString("PerMachine", YesNoDefaultType.Yes == package.Package.PerMachine ? "yes" : "no");
writer.WriteAttributeString("Permanent", package.Package.Permanent ? "yes" : "no");
writer.WriteAttributeString("Vital", (YesNoType.Yes == package.Package.Vital) ? "yes" : "no");
writer.WriteAttributeString("CacheId", package.PackageTuple.CacheId);
writer.WriteAttributeString("InstallSize", Convert.ToString(package.PackageTuple.InstallSize));
writer.WriteAttributeString("Size", Convert.ToString(package.PackageTuple.Size));
writer.WriteAttributeString("PerMachine", YesNoDefaultType.Yes == package.PackageTuple.PerMachine ? "yes" : "no");
writer.WriteAttributeString("Permanent", package.PackageTuple.Permanent ? "yes" : "no");
writer.WriteAttributeString("Vital", package.PackageTuple.Vital == false ? "no" : "yes");
if (null != package.Package.RollbackBoundary)
if (null != package.PackageTuple.RollbackBoundaryRef)
{
writer.WriteAttributeString("RollbackBoundaryForward", package.Package.RollbackBoundary);
writer.WriteAttributeString("RollbackBoundaryForward", package.PackageTuple.RollbackBoundaryRef);
}
if (!String.IsNullOrEmpty(package.Package.RollbackBoundaryBackward))
if (!String.IsNullOrEmpty(package.PackageTuple.RollbackBoundaryBackwardRef))
{
writer.WriteAttributeString("RollbackBoundaryBackward", package.Package.RollbackBoundaryBackward);
writer.WriteAttributeString("RollbackBoundaryBackward", package.PackageTuple.RollbackBoundaryBackwardRef);
}
if (!String.IsNullOrEmpty(package.Package.LogPathVariable))
if (!String.IsNullOrEmpty(package.PackageTuple.LogPathVariable))
{
writer.WriteAttributeString("LogPathVariable", package.Package.LogPathVariable);
writer.WriteAttributeString("LogPathVariable", package.PackageTuple.LogPathVariable);
}
if (!String.IsNullOrEmpty(package.Package.RollbackLogPathVariable))
if (!String.IsNullOrEmpty(package.PackageTuple.RollbackLogPathVariable))
{
writer.WriteAttributeString("RollbackLogPathVariable", package.Package.RollbackLogPathVariable);
writer.WriteAttributeString("RollbackLogPathVariable", package.PackageTuple.RollbackLogPathVariable);
}
if (!String.IsNullOrEmpty(package.Package.InstallCondition))
if (!String.IsNullOrEmpty(package.PackageTuple.InstallCondition))
{
writer.WriteAttributeString("InstallCondition", package.Package.InstallCondition);
writer.WriteAttributeString("InstallCondition", package.PackageTuple.InstallCondition);
}
if (WixBundlePackageType.Exe == package.Package.Type)
if (package.SpecificPackageTuple is WixBundleExePackageTuple exePackage) // EXE
{
writer.WriteAttributeString("DetectCondition", package.ExePackage.DetectCondition);
writer.WriteAttributeString("InstallArguments", package.ExePackage.InstallCommand);
writer.WriteAttributeString("UninstallArguments", package.ExePackage.UninstallCommand);
writer.WriteAttributeString("RepairArguments", package.ExePackage.RepairCommand);
writer.WriteAttributeString("Repairable", package.ExePackage.Repairable ? "yes" : "no");
if (!String.IsNullOrEmpty(package.ExePackage.ExeProtocol))
writer.WriteAttributeString("DetectCondition", exePackage.DetectCondition);
writer.WriteAttributeString("InstallArguments", exePackage.InstallCommand);
writer.WriteAttributeString("UninstallArguments", exePackage.UninstallCommand);
writer.WriteAttributeString("RepairArguments", exePackage.RepairCommand);
writer.WriteAttributeString("Repairable", exePackage.Repairable ? "yes" : "no");
if (!String.IsNullOrEmpty(exePackage.ExeProtocol))
{
writer.WriteAttributeString("Protocol", package.ExePackage.ExeProtocol);
writer.WriteAttributeString("Protocol", exePackage.ExeProtocol);
}
}
else if (WixBundlePackageType.Msi == package.Package.Type)
else if (package.SpecificPackageTuple is WixBundleMsiPackageTuple msiPackage) // MSI
{
writer.WriteAttributeString("ProductCode", package.MsiPackage.ProductCode);
writer.WriteAttributeString("Language", package.MsiPackage.ProductLanguage.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString("Version", package.MsiPackage.ProductVersion);
writer.WriteAttributeString("DisplayInternalUI", package.MsiPackage.DisplayInternalUI ? "yes" : "no");
if (!String.IsNullOrEmpty(package.MsiPackage.UpgradeCode))
writer.WriteAttributeString("ProductCode", msiPackage.ProductCode);
writer.WriteAttributeString("Language", msiPackage.ProductLanguage.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString("Version", msiPackage.ProductVersion);
writer.WriteAttributeString("DisplayInternalUI", msiPackage.DisplayInternalUI ? "yes" : "no");
if (!String.IsNullOrEmpty(msiPackage.UpgradeCode))
{
writer.WriteAttributeString("UpgradeCode", package.MsiPackage.UpgradeCode);
writer.WriteAttributeString("UpgradeCode", msiPackage.UpgradeCode);
}
}
else if (WixBundlePackageType.Msp == package.Package.Type)
else if (package.SpecificPackageTuple is WixBundleMspPackageTuple mspPackage) // MSP
{
writer.WriteAttributeString("PatchCode", package.MspPackage.PatchCode);
writer.WriteAttributeString("PatchXml", package.MspPackage.PatchXml);
writer.WriteAttributeString("DisplayInternalUI", package.MspPackage.DisplayInternalUI ? "yes" : "no");
writer.WriteAttributeString("PatchCode", mspPackage.PatchCode);
writer.WriteAttributeString("PatchXml", mspPackage.PatchXml);
writer.WriteAttributeString("DisplayInternalUI", mspPackage.DisplayInternalUI ? "yes" : "no");
// If there is still a chance that all of our patches will target a narrow set of
// product codes, add the patch list to the overall list.
if (null != targetCodes)
{
if (!package.MspPackage.TargetUnspecified)
if (!mspPackage.TargetUnspecified)
{
IEnumerable<WixBundlePatchTargetCodeRow> patchTargetCodes = targetCodesByPatch[package.MspPackage.ChainPackageId];
var patchTargetCodes = targetCodesByPatch[mspPackage.Id.Id];
targetCodes.AddRange(patchTargetCodes);
}
@ -402,24 +438,24 @@ namespace WixToolset.Core.Burn.Bundles
}
}
}
else if (WixBundlePackageType.Msu == package.Package.Type)
else if (package.SpecificPackageTuple is WixBundleMsuPackageTuple msuPackage) // MSU
{
writer.WriteAttributeString("DetectCondition", package.MsuPackage.DetectCondition);
writer.WriteAttributeString("KB", package.MsuPackage.MsuKB);
writer.WriteAttributeString("DetectCondition", msuPackage.DetectCondition);
writer.WriteAttributeString("KB", msuPackage.MsuKB);
}
IEnumerable<WixBundleMsiFeatureRow> packageMsiFeatures = msiFeaturesByPackage[package.Package.WixChainItemId];
var packageMsiFeatures = msiFeaturesByPackage[package.PackageId];
foreach (WixBundleMsiFeatureRow feature in packageMsiFeatures)
foreach (var feature in packageMsiFeatures)
{
writer.WriteStartElement("MsiFeature");
writer.WriteAttributeString("Id", feature.Name);
writer.WriteEndElement();
}
IEnumerable<WixBundleMsiPropertyRow> packageMsiProperties = msiPropertiesByPackage[package.Package.WixChainItemId];
var packageMsiProperties = msiPropertiesByPackage[package.PackageId];
foreach (WixBundleMsiPropertyRow msiProperty in packageMsiProperties)
foreach (var msiProperty in packageMsiProperties)
{
writer.WriteStartElement("MsiProperty");
writer.WriteAttributeString("Id", msiProperty.Name);
@ -431,18 +467,18 @@ namespace WixToolset.Core.Burn.Bundles
writer.WriteEndElement();
}
IEnumerable<WixBundleSlipstreamMspRow> packageSlipstreamMsps = slipstreamMspsByPackage[package.Package.WixChainItemId];
var packageSlipstreamMsps = slipstreamMspsByPackage[package.PackageId];
foreach (WixBundleSlipstreamMspRow slipstreamMsp in packageSlipstreamMsps)
foreach (var slipstreamMsp in packageSlipstreamMsps)
{
writer.WriteStartElement("SlipstreamMsp");
writer.WriteAttributeString("Id", slipstreamMsp.MspPackageId);
writer.WriteAttributeString("Id", slipstreamMsp.MspPackageRef);
writer.WriteEndElement();
}
IEnumerable<WixBundlePackageExitCodeRow> packageExitCodes = exitCodesByPackage[package.Package.WixChainItemId];
var packageExitCodes = exitCodesByPackage[package.PackageId];
foreach (WixBundlePackageExitCodeRow exitCode in packageExitCodes)
foreach (var exitCode in packageExitCodes)
{
writer.WriteStartElement("ExitCode");
@ -459,9 +495,9 @@ namespace WixToolset.Core.Burn.Bundles
writer.WriteEndElement();
}
IEnumerable<WixBundlePackageCommandLineRow> packageCommandLines = commandLinesByPackage[package.Package.WixChainItemId];
var packageCommandLines = commandLinesByPackage[package.PackageId];
foreach (WixBundlePackageCommandLineRow commandLine in packageCommandLines)
foreach (var commandLine in packageCommandLines)
{
writer.WriteStartElement("CommandLine");
writer.WriteAttributeString("InstallArgument", commandLine.InstallArgument);
@ -472,18 +508,38 @@ namespace WixToolset.Core.Burn.Bundles
}
// Output the dependency information.
foreach (ProvidesDependency dependency in package.Provides)
var dependencies = dependenciesByPackage[package.PackageId];
foreach (var dependency in dependencies)
{
// TODO: Add to wixpdb as an imported table, or link package wixpdbs to bundle wixpdbs.
dependency.WriteXml(writer);
writer.WriteStartElement("Provides");
writer.WriteAttributeString("Key", dependency.Key);
if (!String.IsNullOrEmpty(dependency.Version))
{
writer.WriteAttributeString("Version", dependency.Version);
}
if (!String.IsNullOrEmpty(dependency.DisplayName))
{
writer.WriteAttributeString("DisplayName", dependency.DisplayName);
}
if (dependency.Imported)
{
// The package dependency was explicitly authored into the manifest.
writer.WriteAttributeString("Imported", "yes");
}
writer.WriteEndElement();
}
IEnumerable<WixBundleRelatedPackageRow> packageRelatedPackages = relatedPackagesByPackage[package.Package.WixChainItemId];
var packageRelatedPackages = relatedPackagesByPackage[package.PackageId];
foreach (WixBundleRelatedPackageRow related in packageRelatedPackages)
foreach (var related in packageRelatedPackages)
{
writer.WriteStartElement("RelatedPackage");
writer.WriteAttributeString("Id", related.Id);
writer.WriteAttributeString("Id", related.RelatedId);
if (!String.IsNullOrEmpty(related.MinVersion))
{
writer.WriteAttributeString("MinVersion", related.MinVersion);
@ -496,7 +552,7 @@ namespace WixToolset.Core.Burn.Bundles
}
writer.WriteAttributeString("OnlyDetect", related.OnlyDetect ? "yes" : "no");
string[] relatedLanguages = related.Languages.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var relatedLanguages = related.Languages.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (0 < relatedLanguages.Length)
{
@ -513,17 +569,17 @@ namespace WixToolset.Core.Burn.Bundles
// Write any contained Payloads with the PackagePayload being first
writer.WriteStartElement("PayloadRef");
writer.WriteAttributeString("Id", package.Package.PackagePayload);
writer.WriteAttributeString("Id", package.PackageTuple.PayloadRef);
writer.WriteEndElement();
IEnumerable<WixBundlePayloadRow> packagePayloads = payloadsByPackage[package.Package.WixChainItemId];
var packagePayloads = payloadsByPackage[package.PackageId];
foreach (WixBundlePayloadRow payload in packagePayloads)
foreach (var payload in packagePayloads)
{
if (payload.Id != package.Package.PackagePayload)
if (payload.Id.Id != package.PackageTuple.PayloadRef)
{
writer.WriteStartElement("PayloadRef");
writer.WriteAttributeString("Id", payload.Id);
writer.WriteAttributeString("Id", payload.Id.Id);
writer.WriteEndElement();
}
}
@ -534,7 +590,7 @@ namespace WixToolset.Core.Burn.Bundles
if (null != targetCodes)
{
foreach (WixBundlePatchTargetCodeRow targetCode in targetCodes)
foreach (var targetCode in targetCodes)
{
writer.WriteStartElement("PatchTargetCode");
writer.WriteAttributeString("TargetCode", targetCode.TargetCode);
@ -544,12 +600,12 @@ namespace WixToolset.Core.Burn.Bundles
}
// Write the ApprovedExeForElevation elements.
IEnumerable<WixApprovedExeForElevationRow> approvedExesForElevation = this.Output.Tables["WixApprovedExeForElevation"].RowsAs<WixApprovedExeForElevationRow>();
var approvedExesForElevation = this.Section.Tuples.OfType<WixApprovedExeForElevationTuple>();
foreach (WixApprovedExeForElevationRow approvedExeForElevation in approvedExesForElevation)
foreach (var approvedExeForElevation in approvedExesForElevation)
{
writer.WriteStartElement("ApprovedExeForElevation");
writer.WriteAttributeString("Id", approvedExeForElevation.Id);
writer.WriteAttributeString("Id", approvedExeForElevation.Id.Id);
writer.WriteAttributeString("Key", approvedExeForElevation.Key);
if (!String.IsNullOrEmpty(approvedExeForElevation.ValueName))
@ -569,15 +625,15 @@ namespace WixToolset.Core.Burn.Bundles
}
}
private void WriteBurnManifestContainerAttributes(XmlTextWriter writer, string executableName, WixBundleContainerRow container)
private void WriteBurnManifestContainerAttributes(XmlTextWriter writer, string executableName, WixBundleContainerTuple container)
{
writer.WriteAttributeString("Id", container.Id);
writer.WriteAttributeString("Id", container.Id.Id);
writer.WriteAttributeString("FileSize", container.Size.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString("Hash", container.Hash);
if (ContainerType.Detached == container.Type)
{
string resolvedUrl = this.ResolveUrl(container.DownloadUrl, null, null, container.Id, container.Name);
string resolvedUrl = this.ResolveUrl(container.DownloadUrl, null, null, container.Id.Id, container.Name);
if (!String.IsNullOrEmpty(resolvedUrl))
{
writer.WriteAttributeString("DownloadUrl", resolvedUrl);
@ -593,7 +649,7 @@ namespace WixToolset.Core.Burn.Bundles
{
if (!String.IsNullOrEmpty(container.DownloadUrl))
{
Messaging.Instance.OnMessage(WixWarnings.DownloadUrlNotSupportedForAttachedContainers(container.SourceLineNumbers, container.Id));
this.Messaging.Write(WarningMessages.DownloadUrlNotSupportedForAttachedContainers(container.SourceLineNumbers, container.Id.Id));
}
writer.WriteAttributeString("FilePath", executableName); // attached containers use the name of the bundle since they are attached to the executable.
@ -603,11 +659,11 @@ namespace WixToolset.Core.Burn.Bundles
}
}
private void WriteBurnManifestPayloadAttributes(XmlTextWriter writer, WixBundlePayloadRow payload, bool embeddedOnly, Dictionary<string, WixBundlePayloadRow> allPayloads)
private void WriteBurnManifestPayloadAttributes(XmlTextWriter writer, WixBundlePayloadTuple payload, bool embeddedOnly, Dictionary<string, WixBundlePayloadTuple> allPayloads)
{
Debug.Assert(!embeddedOnly || PackagingType.Embedded == payload.Packaging);
writer.WriteAttributeString("Id", payload.Id);
writer.WriteAttributeString("Id", payload.Id.Id);
writer.WriteAttributeString("FilePath", payload.Name);
writer.WriteAttributeString("FileSize", payload.FileSize.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString("Hash", payload.Hash);
@ -632,22 +688,22 @@ namespace WixToolset.Core.Burn.Bundles
case PackagingType.Embedded: // this means it's in a container.
if (!String.IsNullOrEmpty(payload.DownloadUrl))
{
Messaging.Instance.OnMessage(WixWarnings.DownloadUrlNotSupportedForEmbeddedPayloads(payload.SourceLineNumbers, payload.Id));
this.Messaging.Write(WarningMessages.DownloadUrlNotSupportedForEmbeddedPayloads(payload.SourceLineNumbers, payload.Id.Id));
}
writer.WriteAttributeString("Packaging", "embedded");
writer.WriteAttributeString("SourcePath", payload.EmbeddedId);
if (Compiler.BurnUXContainerId != payload.Container)
if (BurnConstants.BurnUXContainerName != payload.ContainerRef)
{
writer.WriteAttributeString("Container", payload.Container);
writer.WriteAttributeString("Container", payload.ContainerRef);
}
break;
case PackagingType.External:
string packageId = payload.ParentPackagePayload;
string parentUrl = payload.ParentPackagePayload == null ? null : allPayloads[payload.ParentPackagePayload].DownloadUrl;
string resolvedUrl = this.ResolveUrl(payload.DownloadUrl, parentUrl, packageId, payload.Id, payload.Name);
var packageId = payload.ParentPackagePayloadRef;
var parentUrl = payload.ParentPackagePayloadRef == null ? null : allPayloads[payload.ParentPackagePayloadRef].DownloadUrl;
var resolvedUrl = this.ResolveUrl(payload.DownloadUrl, parentUrl, packageId, payload.Id.Id, payload.Name);
if (!String.IsNullOrEmpty(resolvedUrl))
{
writer.WriteAttributeString("DownloadUrl", resolvedUrl);
@ -662,9 +718,9 @@ namespace WixToolset.Core.Burn.Bundles
break;
}
if (!String.IsNullOrEmpty(payload.Catalog))
if (!String.IsNullOrEmpty(payload.CatalogRef))
{
writer.WriteAttributeString("Catalog", payload.Catalog);
writer.WriteAttributeString("Catalog", payload.CatalogRef);
}
}
@ -682,6 +738,5 @@ namespace WixToolset.Core.Burn.Bundles
return resolved;
}
#endif
}
}

Просмотреть файл

@ -4,24 +4,39 @@ namespace WixToolset.Core.Burn.Bundles
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using WixToolset.Core.Native;
using WixToolset.Data;
using WixToolset.Data.Tuples;
/// <summary>
/// Creates cabinet files.
/// </summary>
internal class CreateContainerCommand
{
#if TODO
public CompressionLevel DefaultCompressionLevel { private get; set; }
public CreateContainerCommand(IEnumerable<WixBundlePayloadTuple> payloads, string outputPath, CompressionLevel? compressionLevel)
{
this.Payloads = payloads;
this.OutputPath = outputPath;
this.CompressionLevel = compressionLevel;
}
public IEnumerable<WixBundlePayloadRow> Payloads { private get; set; }
public CreateContainerCommand(string manifestPath, IEnumerable<WixBundlePayloadTuple> payloads, string outputPath, CompressionLevel? compressionLevel)
{
this.ManifestFile = manifestPath;
this.Payloads = payloads;
this.OutputPath = outputPath;
this.CompressionLevel = compressionLevel;
}
public string ManifestFile { private get; set; }
private CompressionLevel? CompressionLevel { get; }
public string OutputPath { private get; set; }
private string ManifestFile { get; }
private string OutputPath { get; }
private IEnumerable<WixBundlePayloadTuple> Payloads { get; }
public string Hash { get; private set; }
@ -29,40 +44,34 @@ namespace WixToolset.Core.Burn.Bundles
public void Execute()
{
int payloadCount = this.Payloads.Count(); // The number of embedded payloads
var payloadCount = this.Payloads.Count(); // The number of embedded payloads
if (!String.IsNullOrEmpty(this.ManifestFile))
{
++payloadCount;
}
using (var cab = new WixCreateCab(Path.GetFileName(this.OutputPath), Path.GetDirectoryName(this.OutputPath), payloadCount, 0, 0, this.DefaultCompressionLevel))
var cabinetPath = Path.GetFullPath(this.OutputPath);
var files = new List<CabinetCompressFile>();
// If a manifest was provided always add it as "payload 0" to the container.
if (!String.IsNullOrEmpty(this.ManifestFile))
{
// If a manifest was provided always add it as "payload 0" to the container.
if (!String.IsNullOrEmpty(this.ManifestFile))
{
cab.AddFile(this.ManifestFile, "0");
}
foreach (WixBundlePayloadRow payload in this.Payloads)
{
Debug.Assert(PackagingType.Embedded == payload.Packaging);
Messaging.Instance.OnMessage(WixVerboses.LoadingPayload(payload.FullFileName));
cab.AddFile(payload.FullFileName, payload.EmbeddedId);
}
cab.Complete();
files.Add(new CabinetCompressFile(this.ManifestFile, "0"));
}
// Now that the container is created, set the outputs of the command.
FileInfo fileInfo = new FileInfo(this.OutputPath);
files.AddRange(this.Payloads.Select(p => new CabinetCompressFile(p.SourceFile.Path, p.EmbeddedId)));
this.Hash = Common.GetFileHash(fileInfo.FullName);
var cab = new Cabinet(cabinetPath);
cab.Compress(files, this.CompressionLevel ?? Data.CompressionLevel.Mszip);
// Now that the container is created, set the outputs of the command.
var fileInfo = new FileInfo(cabinetPath);
this.Hash = BundleHashAlgorithm.Hash(fileInfo);
this.Size = fileInfo.Length;
}
#endif
}
}

Просмотреть файл

@ -0,0 +1,134 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.Burn.Bundles
{
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using WixToolset.Data;
using WixToolset.Data.Burn;
using WixToolset.Data.Tuples;
using WixToolset.Extensibility.Data;
using WixToolset.Extensibility.Services;
internal class CreateNonUXContainers
{
public CreateNonUXContainers(IBackendHelper backendHelper, IntermediateSection section, WixBootstrapperApplicationTuple bootstrapperApplicationTuple, Dictionary<string, WixBundlePayloadTuple> payloadTuples, string intermediateFolder, string layoutFolder, CompressionLevel? defaultCompressionLevel)
{
this.BackendHelper = backendHelper;
this.Section = section;
this.BootstrapperApplicationTuple = bootstrapperApplicationTuple;
this.PayloadTuples = payloadTuples;
this.IntermediateFolder = intermediateFolder;
this.LayoutFolder = layoutFolder;
this.DefaultCompressionLevel = defaultCompressionLevel;
}
public IEnumerable<IFileTransfer> FileTransfers { get; private set; }
public WixBundleContainerTuple UXContainer { get; set; }
public IEnumerable<WixBundlePayloadTuple> UXContainerPayloads { get; private set; }
public IEnumerable<WixBundleContainerTuple> Containers { get; private set; }
private IBackendHelper BackendHelper { get; }
private IntermediateSection Section { get; }
private WixBootstrapperApplicationTuple BootstrapperApplicationTuple { get; }
private Dictionary<string, WixBundlePayloadTuple> PayloadTuples { get; }
private string IntermediateFolder { get; }
private string LayoutFolder { get; }
private CompressionLevel? DefaultCompressionLevel { get; }
public void Execute()
{
var fileTransfers = new List<IFileTransfer>();
var uxPayloadTuples = new List<WixBundlePayloadTuple>();
var attachedContainerIndex = 1; // count starts at one because UX container is "0".
var containerTuples = this.Section.Tuples.OfType<WixBundleContainerTuple>().ToList();
var payloadsByContainer = this.PayloadTuples.Values.ToLookup(p => p.ContainerRef);
foreach (var container in containerTuples)
{
var containerId = container.Id.Id;
var containerPayloads = payloadsByContainer[containerId];
if (!containerPayloads.Any())
{
if (containerId != BurnConstants.BurnDefaultAttachedContainerName)
{
// TODO: display warning that we're ignoring container that ended up with no paylods in it.
}
}
else if (BurnConstants.BurnUXContainerName == containerId)
{
this.UXContainer = container;
container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name);
container.AttachedContainerIndex = 0;
// Gather the list of UX payloads but ensure the BootstrapperApplication Payload is the first
// in the list since that is the Payload that Burn attempts to load.
var baPayloadId = this.BootstrapperApplicationTuple.Id.Id;
foreach (var uxPayload in containerPayloads)
{
if (uxPayload.Id.Id == baPayloadId)
{
uxPayloadTuples.Insert(0, uxPayload);
}
else
{
uxPayloadTuples.Add(uxPayload);
}
}
}
else
{
container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name);
// Add detached containers to the list of file transfers.
if (ContainerType.Detached == container.Type)
{
var transfer = this.BackendHelper.CreateFileTransfer(container.WorkingPath, Path.Combine(this.LayoutFolder, container.Name), true, container.SourceLineNumbers);
fileTransfers.Add(transfer);
}
else // update the attached container index.
{
Debug.Assert(ContainerType.Attached == container.Type);
container.AttachedContainerIndex = attachedContainerIndex;
++attachedContainerIndex;
}
this.CreateContainer(container, containerPayloads, null);
}
}
this.Containers = containerTuples;
this.UXContainerPayloads = uxPayloadTuples;
this.FileTransfers = fileTransfers;
}
private void CreateContainer(WixBundleContainerTuple container, IEnumerable<WixBundlePayloadTuple> containerPayloads, string manifestFile)
{
var command = new CreateContainerCommand(containerPayloads, container.WorkingPath, this.DefaultCompressionLevel);
command.Execute();
container.Hash = command.Hash;
container.Size = command.Size;
}
}
}

Просмотреть файл

@ -3,61 +3,69 @@
namespace WixToolset.Core.Burn.Bundles
{
using System.Collections.Generic;
using System.Linq;
using WixToolset.Data;
using WixToolset.Data.Tuples;
internal class GetPackageFacadesCommand
{
#if TODO
public Table PackageTable { private get; set; }
public GetPackageFacadesCommand(IEnumerable<WixBundlePackageTuple> chainPackageTuples, IntermediateSection section)
{
this.ChainPackageTuples = chainPackageTuples;
this.Section = section;
}
public Table ExePackageTable { private get; set; }
private IEnumerable<WixBundlePackageTuple> ChainPackageTuples { get; }
public Table MsiPackageTable { private get; set; }
public Table MspPackageTable { private get; set; }
public Table MsuPackageTable { private get; set; }
private IntermediateSection Section { get; }
public IDictionary<string, PackageFacade> PackageFacades { get; private set; }
public void Execute()
{
RowDictionary<WixBundleExePackageRow> exePackages = new RowDictionary<WixBundleExePackageRow>(this.ExePackageTable);
RowDictionary<WixBundleMsiPackageRow> msiPackages = new RowDictionary<WixBundleMsiPackageRow>(this.MsiPackageTable);
RowDictionary<WixBundleMspPackageRow> mspPackages = new RowDictionary<WixBundleMspPackageRow>(this.MspPackageTable);
RowDictionary<WixBundleMsuPackageRow> msuPackages = new RowDictionary<WixBundleMsuPackageRow>(this.MsuPackageTable);
var exePackages = this.Section.Tuples.OfType<WixBundleExePackageTuple>().ToDictionary(t => t.Id.Id);
var msiPackages = this.Section.Tuples.OfType<WixBundleMsiPackageTuple>().ToDictionary(t => t.Id.Id);
var mspPackages = this.Section.Tuples.OfType<WixBundleMspPackageTuple>().ToDictionary(t => t.Id.Id);
var msuPackages = this.Section.Tuples.OfType<WixBundleMsuPackageTuple>().ToDictionary(t => t.Id.Id);
Dictionary<string, PackageFacade> facades = new Dictionary<string, PackageFacade>(this.PackageTable.Rows.Count);
var facades = new Dictionary<string, PackageFacade>();
foreach (WixBundlePackageRow package in this.PackageTable.Rows)
foreach (var package in this.ChainPackageTuples)
{
string id = package.WixChainItemId;
PackageFacade facade = null;
var id = package.Id.Id;
switch (package.Type)
{
case WixBundlePackageType.Exe:
facade = new PackageFacade(package, exePackages.Get(id));
break;
case WixBundlePackageType.Exe:
if (exePackages.TryGetValue(id, out var exePackage))
{
facades.Add(id, new PackageFacade(package, exePackage));
}
break;
case WixBundlePackageType.Msi:
facade = new PackageFacade(package, msiPackages.Get(id));
break;
case WixBundlePackageType.Msi:
if (msiPackages.TryGetValue(id, out var msiPackage))
{
facades.Add(id, new PackageFacade(package, msiPackage));
}
break;
case WixBundlePackageType.Msp:
facade = new PackageFacade(package, mspPackages.Get(id));
break;
case WixBundlePackageType.Msp:
if (mspPackages.TryGetValue(id, out var mspPackage))
{
facades.Add(id, new PackageFacade(package, mspPackage));
}
break;
case WixBundlePackageType.Msu:
facade = new PackageFacade(package, msuPackages.Get(id));
break;
case WixBundlePackageType.Msu:
if (msuPackages.TryGetValue(id, out var msuPackage))
{
facades.Add(id, new PackageFacade(package, msuPackage));
}
break;
}
facades.Add(id, facade);
}
this.PackageFacades = facades;
}
#endif
}
}

Просмотреть файл

@ -5,24 +5,35 @@ namespace WixToolset.Core.Burn.Bundles
using System;
using System.Collections.Generic;
using WixToolset.Data;
using WixToolset.Data.Tuples;
using WixToolset.Extensibility.Services;
internal class OrderPackagesAndRollbackBoundariesCommand
{
#if TODO
public Table WixGroupTable { private get; set; }
public OrderPackagesAndRollbackBoundariesCommand(IMessaging messaging, IEnumerable<WixGroupTuple> groupTuples, Dictionary<string, WixBundleRollbackBoundaryTuple> boundaryTuples, IDictionary<string, PackageFacade> packageFacades)
{
this.Messaging = messaging;
this.GroupTuples = groupTuples;
this.Boundaries = boundaryTuples;
this.PackageFacades = packageFacades;
}
public RowDictionary<WixBundleRollbackBoundaryRow> Boundaries { private get; set; }
private IMessaging Messaging { get; }
public IDictionary<string, PackageFacade> PackageFacades { private get; set; }
public IEnumerable<WixGroupTuple> GroupTuples { get; }
public Dictionary<string, WixBundleRollbackBoundaryTuple> Boundaries { get; }
public IDictionary<string, PackageFacade> PackageFacades { get; }
public IEnumerable<PackageFacade> OrderedPackageFacades { get; private set; }
public IEnumerable<WixBundleRollbackBoundaryRow> UsedRollbackBoundaries { get; private set; }
public IEnumerable<WixBundleRollbackBoundaryTuple> UsedRollbackBoundaries { get; private set; }
public void Execute()
{
List<PackageFacade> orderedFacades = new List<PackageFacade>();
List<WixBundleRollbackBoundaryRow> usedBoundaries = new List<WixBundleRollbackBoundaryRow>();
var orderedFacades = new List<PackageFacade>();
var usedBoundaries = new List<WixBundleRollbackBoundaryTuple>();
// Process the chain of packages to add them in the correct order
// and assign the forward rollback boundaries as appropriate. Remember
@ -33,44 +44,44 @@ namespace WixToolset.Core.Burn.Bundles
// We handle uninstall (aka: backwards) rollback boundaries after
// we get these install/repair (aka: forward) rollback boundaries
// defined.
WixBundleRollbackBoundaryRow previousRollbackBoundary = null;
WixBundleRollbackBoundaryRow lastRollbackBoundary = null;
bool boundaryHadX86Package = false;
WixBundleRollbackBoundaryTuple previousRollbackBoundary = null;
WixBundleRollbackBoundaryTuple lastRollbackBoundary = null;
var boundaryHadX86Package = false;
foreach (WixGroupRow row in this.WixGroupTable.Rows)
foreach (var groupTuple in this.GroupTuples)
{
if (ComplexReferenceChildType.Package == row.ChildType && ComplexReferenceParentType.PackageGroup == row.ParentType && "WixChain" == row.ParentId)
if (ComplexReferenceChildType.Package == groupTuple.ChildType && ComplexReferenceParentType.PackageGroup == groupTuple.ParentType && "WixChain" == groupTuple.ParentId)
{
PackageFacade facade = null;
if (PackageFacades.TryGetValue(row.ChildId, out facade))
if (this.PackageFacades.TryGetValue(groupTuple.ChildId, out var facade))
{
if (null != previousRollbackBoundary)
{
usedBoundaries.Add(previousRollbackBoundary);
facade.Package.RollbackBoundary = previousRollbackBoundary.ChainPackageId;
facade.PackageTuple.RollbackBoundaryRef = previousRollbackBoundary.Id.Id;
previousRollbackBoundary = null;
boundaryHadX86Package = (facade.Package.x64 == YesNoType.Yes);
boundaryHadX86Package = facade.PackageTuple.Win64;
}
// Error if MSI transaction has x86 package preceding x64 packages
if ((lastRollbackBoundary != null) && (lastRollbackBoundary.Transaction == YesNoType.Yes)
if ((lastRollbackBoundary != null)
&& lastRollbackBoundary.Transaction == true
&& boundaryHadX86Package
&& (facade.Package.x64 == YesNoType.Yes))
&& facade.PackageTuple.Win64)
{
Messaging.Instance.OnMessage(WixErrors.MsiTransactionX86BeforeX64(lastRollbackBoundary.SourceLineNumbers));
this.Messaging.Write(ErrorMessages.MsiTransactionX86BeforeX64(lastRollbackBoundary.SourceLineNumbers));
}
boundaryHadX86Package = boundaryHadX86Package || (facade.Package.x64 == YesNoType.No);
boundaryHadX86Package |= facade.PackageTuple.Win64;
orderedFacades.Add(facade);
}
else // must be a rollback boundary.
{
// Discard the next rollback boundary if we have a previously defined boundary.
WixBundleRollbackBoundaryRow nextRollbackBoundary = Boundaries.Get(row.ChildId);
var nextRollbackBoundary = this.Boundaries[groupTuple.ChildId];
if (null != previousRollbackBoundary)
{
Messaging.Instance.OnMessage(WixWarnings.DiscardedRollbackBoundary(nextRollbackBoundary.SourceLineNumbers, nextRollbackBoundary.ChainPackageId));
this.Messaging.Write(WarningMessages.DiscardedRollbackBoundary(nextRollbackBoundary.SourceLineNumbers, nextRollbackBoundary.Id.Id));
}
else
{
@ -83,7 +94,7 @@ namespace WixToolset.Core.Burn.Bundles
if (null != previousRollbackBoundary)
{
Messaging.Instance.OnMessage(WixWarnings.DiscardedRollbackBoundary(previousRollbackBoundary.SourceLineNumbers, previousRollbackBoundary.ChainPackageId));
this.Messaging.Write(WarningMessages.DiscardedRollbackBoundary(previousRollbackBoundary.SourceLineNumbers, previousRollbackBoundary.Id.Id));
}
// With the forward rollback boundaries assigned, we can now go
@ -120,14 +131,14 @@ namespace WixToolset.Core.Burn.Bundles
foreach (PackageFacade package in orderedFacades)
{
if (null != package.Package.RollbackBoundary)
if (null != package.PackageTuple.RollbackBoundaryRef)
{
if (null != previousFacade)
{
previousFacade.Package.RollbackBoundaryBackward = previousRollbackBoundaryId;
previousFacade.PackageTuple.RollbackBoundaryBackwardRef = previousRollbackBoundaryId;
}
previousRollbackBoundaryId = package.Package.RollbackBoundary;
previousRollbackBoundaryId = package.PackageTuple.RollbackBoundaryRef;
}
previousFacade = package;
@ -135,12 +146,11 @@ namespace WixToolset.Core.Burn.Bundles
if (!String.IsNullOrEmpty(previousRollbackBoundaryId) && null != previousFacade)
{
previousFacade.Package.RollbackBoundaryBackward = previousRollbackBoundaryId;
previousFacade.PackageTuple.RollbackBoundaryBackwardRef = previousRollbackBoundaryId;
}
this.OrderedPackageFacades = orderedFacades;
this.UsedRollbackBoundaries = usedBoundaries;
}
#endif
}
}

Просмотреть файл

@ -2,57 +2,24 @@
namespace WixToolset.Core.Burn.Bundles
{
using System.Diagnostics;
using WixToolset.Data;
using WixToolset.Data.Tuples;
internal class PackageFacade
{
#if TODO
private PackageFacade(WixBundlePackageRow package)
public PackageFacade(WixBundlePackageTuple packageTuple, IntermediateTuple specificPackageTuple)
{
this.Package = package;
this.Provides = new ProvidesDependencyCollection();
Debug.Assert(packageTuple.Id.Id == specificPackageTuple.Id.Id);
this.PackageTuple = packageTuple;
this.SpecificPackageTuple = specificPackageTuple;
}
public PackageFacade(WixBundlePackageRow package, WixBundleExePackageRow exePackage)
: this(package)
{
this.ExePackage = exePackage;
}
public string PackageId => this.PackageTuple.Id.Id;
public PackageFacade(WixBundlePackageRow package, WixBundleMsiPackageRow msiPackage)
: this(package)
{
this.MsiPackage = msiPackage;
}
public WixBundlePackageTuple PackageTuple { get; }
public PackageFacade(WixBundlePackageRow package, WixBundleMspPackageRow mspPackage)
: this(package)
{
this.MspPackage = mspPackage;
}
public PackageFacade(WixBundlePackageRow package, WixBundleMsuPackageRow msuPackage)
: this(package)
{
this.MsuPackage = msuPackage;
}
public WixBundlePackageRow Package { get; private set; }
public WixBundleExePackageRow ExePackage { get; private set; }
public WixBundleMsiPackageRow MsiPackage { get; private set; }
public WixBundleMspPackageRow MspPackage { get; private set; }
public WixBundleMsuPackageRow MsuPackage { get; private set; }
/// <summary>
/// The provides dependencies authored and imported for this package.
/// </summary>
/// <remarks>
/// TODO: Eventually this collection should turn into Rows so they are tracked in the PDB but
/// the relationship with the extension makes it much trickier to pull off.
/// </remarks>
public ProvidesDependencyCollection Provides { get; private set; }
#endif
public IntermediateTuple SpecificPackageTuple { get; }
}
}

Просмотреть файл

@ -3,32 +3,37 @@
namespace WixToolset.Core.Burn.Bundles
{
using System;
using WixToolset.Data;
using System.Collections.Generic;
using WixToolset.Data.Tuples;
/// <summary>
/// Initializes package state from the Exe contents.
/// </summary>
internal class ProcessExePackageCommand
{
#if TODO
public RowDictionary<WixBundlePayloadRow> AuthoredPayloads { private get; set; }
public ProcessExePackageCommand(PackageFacade facade, Dictionary<string, WixBundlePayloadTuple> payloadTuples)
{
this.AuthoredPayloads = payloadTuples;
this.Facade = facade;
}
public PackageFacade Facade { private get; set; }
public Dictionary<string, WixBundlePayloadTuple> AuthoredPayloads { get; }
public PackageFacade Facade { get; }
/// <summary>
/// Processes the Exe packages to add properties and payloads from the Exe packages.
/// </summary>
public void Execute()
{
WixBundlePayloadRow packagePayload = this.AuthoredPayloads.Get(this.Facade.Package.PackagePayload);
var packagePayload = this.AuthoredPayloads[this.Facade.PackageTuple.PayloadRef];
if (String.IsNullOrEmpty(this.Facade.Package.CacheId))
if (String.IsNullOrEmpty(this.Facade.PackageTuple.CacheId))
{
this.Facade.Package.CacheId = packagePayload.Hash;
this.Facade.PackageTuple.CacheId = packagePayload.Hash;
}
this.Facade.Package.Version = packagePayload.Version;
this.Facade.PackageTuple.Version = packagePayload.Version;
}
#endif
}
}

Просмотреть файл

@ -3,7 +3,6 @@
namespace WixToolset.Core.Burn.Bundles
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
@ -11,47 +10,62 @@ namespace WixToolset.Core.Burn.Bundles
using System.Linq;
using WixToolset.Data;
using WixToolset.Extensibility;
using WixToolset.Core.Native;
using Dtf = WixToolset.Dtf.WindowsInstaller;
using WixToolset.Data.Bind;
using WixToolset.Extensibility.Services;
using WixToolset.Data.Tuples;
using WixToolset.Data.WindowsInstaller;
using WixToolset.Extensibility.Data;
/// <summary>
/// Initializes package state from the MSI contents.
/// </summary>
internal class ProcessMsiPackageCommand
{
#if TODO
private const string PropertySqlFormat = "SELECT `Value` FROM `Property` WHERE `Property` = '{0}'";
public RowDictionary<WixBundlePayloadRow> AuthoredPayloads { private get; set; }
public ProcessMsiPackageCommand(IServiceProvider serviceProvider, IEnumerable<IBurnBackendExtension> backendExtensions, IntermediateSection section, PackageFacade facade, Dictionary<string, WixBundlePayloadTuple> payloadTuples)
{
this.Messaging = serviceProvider.GetService<IMessaging>();
this.BackendHelper = serviceProvider.GetService<IBackendHelper>();
this.PathResolver = serviceProvider.GetService<IPathResolver>();
public PackageFacade Facade { private get; set; }
this.BackendExtensions = backendExtensions;
public IEnumerable<IBurnBackendExtension> BackendExtensions { private get; set; }
this.AuthoredPayloads = payloadTuples;
this.Section = section;
this.Facade = facade;
}
public Table MsiFeatureTable { private get; set; }
private IMessaging Messaging { get; }
public Table MsiPropertyTable { private get; set; }
private IBackendHelper BackendHelper { get; }
public Table PayloadTable { private get; set; }
private IPathResolver PathResolver { get; }
public Table RelatedPackageTable { private get; set; }
private IEnumerable<IBurnBackendExtension> BackendExtensions { get; }
private Dictionary<string, WixBundlePayloadTuple> AuthoredPayloads { get; }
private PackageFacade Facade { get; }
private IntermediateSection Section { get; }
/// <summary>
/// Processes the MSI packages to add properties and payloads from the MSI packages.
/// </summary>
public void Execute()
{
WixBundlePayloadRow packagePayload = this.AuthoredPayloads.Get(this.Facade.Package.PackagePayload);
var packagePayload = this.AuthoredPayloads[this.Facade.PackageTuple.PayloadRef];
string sourcePath = packagePayload.FullFileName;
bool longNamesInImage = false;
bool compressed = false;
bool x64 = false;
var msiPackage = (WixBundleMsiPackageTuple)this.Facade.SpecificPackageTuple;
var sourcePath = packagePayload.SourceFile.Path;
var longNamesInImage = false;
var compressed = false;
try
{
// Read data out of the msi database...
using (Dtf.SummaryInfo sumInfo = new Dtf.SummaryInfo(sourcePath, false))
using (var sumInfo = new Dtf.SummaryInfo(sourcePath, false))
{
// 1 is the Word Count summary information stream bit that means
// the MSI uses short file names when set. We care about long file
@ -62,83 +76,84 @@ namespace WixToolset.Core.Burn.Bundles
// files are compressed in the MSI by default when the bit is set.
compressed = 2 == (sumInfo.WordCount & 2);
x64 = (sumInfo.Template.Contains("x64") || sumInfo.Template.Contains("Intel64"));
// 8 is the Word Count summary information stream bit that means
// "Elevated privileges are not required to install this package."
// in MSI 4.5 and below, if this bit is 0, elevation is required.
this.Facade.Package.PerMachine = (0 == (sumInfo.WordCount & 8)) ? YesNoDefaultType.Yes : YesNoDefaultType.No;
this.Facade.Package.x64 = x64 ? YesNoType.Yes : YesNoType.No;
var perMachine = (0 == (sumInfo.WordCount & 8));
var x64 = (sumInfo.Template.Contains("x64") || sumInfo.Template.Contains("Intel64"));
this.Facade.PackageTuple.PerMachine = perMachine ? YesNoDefaultType.Yes : YesNoDefaultType.No;
this.Facade.PackageTuple.Win64 = x64;
}
using (Dtf.Database db = new Dtf.Database(sourcePath))
using (var db = new Dtf.Database(sourcePath))
{
this.Facade.MsiPackage.ProductCode = ProcessMsiPackageCommand.GetProperty(db, "ProductCode");
this.Facade.MsiPackage.UpgradeCode = ProcessMsiPackageCommand.GetProperty(db, "UpgradeCode");
this.Facade.MsiPackage.Manufacturer = ProcessMsiPackageCommand.GetProperty(db, "Manufacturer");
this.Facade.MsiPackage.ProductLanguage = Convert.ToInt32(ProcessMsiPackageCommand.GetProperty(db, "ProductLanguage"), CultureInfo.InvariantCulture);
this.Facade.MsiPackage.ProductVersion = ProcessMsiPackageCommand.GetProperty(db, "ProductVersion");
msiPackage.ProductCode = ProcessMsiPackageCommand.GetProperty(db, "ProductCode");
msiPackage.UpgradeCode = ProcessMsiPackageCommand.GetProperty(db, "UpgradeCode");
msiPackage.Manufacturer = ProcessMsiPackageCommand.GetProperty(db, "Manufacturer");
msiPackage.ProductLanguage = Convert.ToInt32(ProcessMsiPackageCommand.GetProperty(db, "ProductLanguage"), CultureInfo.InvariantCulture);
msiPackage.ProductVersion = ProcessMsiPackageCommand.GetProperty(db, "ProductVersion");
if (!Common.IsValidModuleOrBundleVersion(this.Facade.MsiPackage.ProductVersion))
if (!Common.IsValidModuleOrBundleVersion(msiPackage.ProductVersion))
{
// not a proper .NET version (e.g., five fields); can we get a valid four-part version number?
string version = null;
string[] versionParts = this.Facade.MsiPackage.ProductVersion.Split('.');
int count = versionParts.Length;
string[] versionParts = msiPackage.ProductVersion.Split('.');
var count = versionParts.Length;
if (0 < count)
{
version = versionParts[0];
for (int i = 1; i < 4 && i < count; ++i)
for (var i = 1; i < 4 && i < count; ++i)
{
version = String.Concat(version, ".", versionParts[i]);
}
}
if (!String.IsNullOrEmpty(version) && Common.IsValidModuleOrBundleVersion(version))
{
Messaging.Instance.OnMessage(WixWarnings.VersionTruncated(this.Facade.Package.SourceLineNumbers, this.Facade.MsiPackage.ProductVersion, sourcePath, version));
this.Facade.MsiPackage.ProductVersion = version;
this.Messaging.Write(WarningMessages.VersionTruncated(this.Facade.PackageTuple.SourceLineNumbers, msiPackage.ProductVersion, sourcePath, version));
msiPackage.ProductVersion = version;
}
else
{
Messaging.Instance.OnMessage(WixErrors.InvalidProductVersion(this.Facade.Package.SourceLineNumbers, this.Facade.MsiPackage.ProductVersion, sourcePath));
this.Messaging.Write(ErrorMessages.InvalidProductVersion(this.Facade.PackageTuple.SourceLineNumbers, msiPackage.ProductVersion, sourcePath));
}
}
if (String.IsNullOrEmpty(this.Facade.Package.CacheId))
if (String.IsNullOrEmpty(this.Facade.PackageTuple.CacheId))
{
this.Facade.Package.CacheId = String.Format("{0}v{1}", this.Facade.MsiPackage.ProductCode, this.Facade.MsiPackage.ProductVersion);
this.Facade.PackageTuple.CacheId = String.Format("{0}v{1}", msiPackage.ProductCode, msiPackage.ProductVersion);
}
if (String.IsNullOrEmpty(this.Facade.Package.DisplayName))
if (String.IsNullOrEmpty(this.Facade.PackageTuple.DisplayName))
{
this.Facade.Package.DisplayName = ProcessMsiPackageCommand.GetProperty(db, "ProductName");
this.Facade.PackageTuple.DisplayName = ProcessMsiPackageCommand.GetProperty(db, "ProductName");
}
if (String.IsNullOrEmpty(this.Facade.Package.Description))
if (String.IsNullOrEmpty(this.Facade.PackageTuple.Description))
{
this.Facade.Package.Description = ProcessMsiPackageCommand.GetProperty(db, "ARPCOMMENTS");
this.Facade.PackageTuple.Description = ProcessMsiPackageCommand.GetProperty(db, "ARPCOMMENTS");
}
ISet<string> payloadNames = this.GetPayloadTargetNames();
var payloadNames = this.GetPayloadTargetNames(packagePayload.Id.Id);
ISet<string> msiPropertyNames = this.GetMsiPropertyNames();
var msiPropertyNames = this.GetMsiPropertyNames(packagePayload.Id.Id);
this.SetPerMachineAppropriately(db, sourcePath);
this.SetPerMachineAppropriately(db, msiPackage, sourcePath);
// Ensure the MSI package is appropriately marked visible or not.
this.SetPackageVisibility(db, msiPropertyNames);
this.SetPackageVisibility(db, msiPackage, msiPropertyNames);
// Unless the MSI or setup code overrides the default, set MSIFASTINSTALL for best performance.
if (!msiPropertyNames.Contains("MSIFASTINSTALL") && !ProcessMsiPackageCommand.HasProperty(db, "MSIFASTINSTALL"))
{
this.AddMsiProperty("MSIFASTINSTALL", "7");
this.AddMsiProperty(msiPackage, "MSIFASTINSTALL", "7");
}
this.CreateRelatedPackages(db);
// If feature selection is enabled, represent the Feature table in the manifest.
if (this.Facade.MsiPackage.EnableFeatureSelection)
if ((msiPackage.Attributes & WixBundleMsiPackageAttributes.EnableFeatureSelection) == WixBundleMsiPackageAttributes.EnableFeatureSelection)
{
this.CreateMsiFeatures(db);
}
@ -148,90 +163,92 @@ namespace WixToolset.Core.Burn.Bundles
// Add all external files as package payloads and calculate the total install size as the rollup of
// File table's sizes.
this.Facade.Package.InstallSize = this.ImportExternalFileAsPayloadsAndReturnInstallSize(db, packagePayload, longNamesInImage, compressed, payloadNames);
this.Facade.PackageTuple.InstallSize = this.ImportExternalFileAsPayloadsAndReturnInstallSize(db, packagePayload, longNamesInImage, compressed, payloadNames);
// Add all dependency providers from the MSI.
this.ImportDependencyProviders(db);
this.ImportDependencyProviders(msiPackage, db);
}
}
catch (Dtf.InstallerException e)
{
Messaging.Instance.OnMessage(WixErrors.UnableToReadPackageInformation(this.Facade.Package.SourceLineNumbers, sourcePath, e.Message));
this.Messaging.Write(ErrorMessages.UnableToReadPackageInformation(this.Facade.PackageTuple.SourceLineNumbers, sourcePath, e.Message));
}
}
private ISet<string> GetPayloadTargetNames()
private ISet<string> GetPayloadTargetNames(string packageId)
{
IEnumerable<string> payloadNames = this.PayloadTable.RowsAs<WixBundlePayloadRow>()
.Where(r => r.Package == this.Facade.Package.WixChainItemId)
.Select(r => r.Name);
var payloadNames = this.Section.Tuples.OfType<WixBundlePayloadTuple>()
.Where(p => p.PackageRef == packageId)
.Select(p => p.Name);
return new HashSet<string>(payloadNames, StringComparer.OrdinalIgnoreCase);
}
private ISet<string> GetMsiPropertyNames()
private ISet<string> GetMsiPropertyNames(string packageId)
{
IEnumerable<string> properties = this.MsiPropertyTable.RowsAs<WixBundleMsiPropertyRow>()
.Where(r => r.ChainPackageId == this.Facade.Package.WixChainItemId)
.Select(r => r.Name);
var properties = this.Section.Tuples.OfType<WixBundleMsiPropertyTuple>()
.Where(p => p.Id.Id == packageId)
.Select(p => p.Name);
return new HashSet<string>(properties, StringComparer.Ordinal);
}
private void SetPerMachineAppropriately(Dtf.Database db, string sourcePath)
private void SetPerMachineAppropriately(Dtf.Database db, WixBundleMsiPackageTuple msiPackage, string sourcePath)
{
if (this.Facade.MsiPackage.ForcePerMachine)
if (msiPackage.ForcePerMachine)
{
if (YesNoDefaultType.No == this.Facade.Package.PerMachine)
if (YesNoDefaultType.No == this.Facade.PackageTuple.PerMachine)
{
Messaging.Instance.OnMessage(WixWarnings.PerUserButForcingPerMachine(this.Facade.Package.SourceLineNumbers, sourcePath));
this.Facade.Package.PerMachine = YesNoDefaultType.Yes; // ensure that we think the package is per-machine.
this.Messaging.Write(WarningMessages.PerUserButForcingPerMachine(this.Facade.PackageTuple.SourceLineNumbers, sourcePath));
this.Facade.PackageTuple.PerMachine = YesNoDefaultType.Yes; // ensure that we think the package is per-machine.
}
// Force ALLUSERS=1 via the MSI command-line.
this.AddMsiProperty("ALLUSERS", "1");
this.AddMsiProperty(msiPackage, "ALLUSERS", "1");
}
else
{
string allusers = ProcessMsiPackageCommand.GetProperty(db, "ALLUSERS");
var allusers = ProcessMsiPackageCommand.GetProperty(db, "ALLUSERS");
if (String.IsNullOrEmpty(allusers))
{
// Not forced per-machine and no ALLUSERS property, flip back to per-user.
if (YesNoDefaultType.Yes == this.Facade.Package.PerMachine)
if (YesNoDefaultType.Yes == this.Facade.PackageTuple.PerMachine)
{
Messaging.Instance.OnMessage(WixWarnings.ImplicitlyPerUser(this.Facade.Package.SourceLineNumbers, sourcePath));
this.Facade.Package.PerMachine = YesNoDefaultType.No;
this.Messaging.Write(WarningMessages.ImplicitlyPerUser(this.Facade.PackageTuple.SourceLineNumbers, sourcePath));
this.Facade.PackageTuple.PerMachine = YesNoDefaultType.No;
}
}
else if (allusers.Equals("1", StringComparison.Ordinal))
{
if (YesNoDefaultType.No == this.Facade.Package.PerMachine)
if (YesNoDefaultType.No == this.Facade.PackageTuple.PerMachine)
{
Messaging.Instance.OnMessage(WixErrors.PerUserButAllUsersEquals1(this.Facade.Package.SourceLineNumbers, sourcePath));
this.Messaging.Write(ErrorMessages.PerUserButAllUsersEquals1(this.Facade.PackageTuple.SourceLineNumbers, sourcePath));
}
}
else if (allusers.Equals("2", StringComparison.Ordinal))
{
Messaging.Instance.OnMessage(WixWarnings.DiscouragedAllUsersValue(this.Facade.Package.SourceLineNumbers, sourcePath, (YesNoDefaultType.Yes == this.Facade.Package.PerMachine) ? "machine" : "user"));
this.Messaging.Write(WarningMessages.DiscouragedAllUsersValue(this.Facade.PackageTuple.SourceLineNumbers, sourcePath, (YesNoDefaultType.Yes == this.Facade.PackageTuple.PerMachine) ? "machine" : "user"));
}
else
{
Messaging.Instance.OnMessage(WixErrors.UnsupportedAllUsersValue(this.Facade.Package.SourceLineNumbers, sourcePath, allusers));
this.Messaging.Write(ErrorMessages.UnsupportedAllUsersValue(this.Facade.PackageTuple.SourceLineNumbers, sourcePath, allusers));
}
}
}
private void SetPackageVisibility(Dtf.Database db, ISet<string> msiPropertyNames)
private void SetPackageVisibility(Dtf.Database db, WixBundleMsiPackageTuple msiPackage, ISet<string> msiPropertyNames)
{
bool alreadyVisible = !ProcessMsiPackageCommand.HasProperty(db, "ARPSYSTEMCOMPONENT");
var alreadyVisible = !ProcessMsiPackageCommand.HasProperty(db, "ARPSYSTEMCOMPONENT");
var visible = (this.Facade.PackageTuple.Attributes & WixBundlePackageAttributes.Visible) == WixBundlePackageAttributes.Visible;
if (alreadyVisible != this.Facade.Package.Visible) // if not already set to the correct visibility.
// If not already set to the correct visibility.
if (alreadyVisible != visible)
{
// If the authoring specifically added "ARPSYSTEMCOMPONENT", don't do it again.
if (!msiPropertyNames.Contains("ARPSYSTEMCOMPONENT"))
{
this.AddMsiProperty("ARPSYSTEMCOMPONENT", this.Facade.Package.Visible ? String.Empty : "1");
this.AddMsiProperty(msiPackage, "ARPSYSTEMCOMPONENT", visible ? String.Empty : "1");
}
}
}
@ -241,30 +258,35 @@ namespace WixToolset.Core.Burn.Bundles
// Represent the Upgrade table as related packages.
if (db.Tables.Contains("Upgrade"))
{
using (Dtf.View view = db.OpenView("SELECT `UpgradeCode`, `VersionMin`, `VersionMax`, `Language`, `Attributes` FROM `Upgrade`"))
using (var view = db.OpenView("SELECT `UpgradeCode`, `VersionMin`, `VersionMax`, `Language`, `Attributes` FROM `Upgrade`"))
{
view.Execute();
while (true)
{
using (Dtf.Record record = view.Fetch())
using (var record = view.Fetch())
{
if (null == record)
{
break;
}
WixBundleRelatedPackageRow related = (WixBundleRelatedPackageRow)this.RelatedPackageTable.CreateRow(this.Facade.Package.SourceLineNumbers);
related.ChainPackageId = this.Facade.Package.WixChainItemId;
related.Id = record.GetString(1);
related.MinVersion = record.GetString(2);
related.MaxVersion = record.GetString(3);
related.Languages = record.GetString(4);
var recordAttributes = record.GetInteger(5);
int attributes = record.GetInteger(5);
related.OnlyDetect = (attributes & MsiInterop.MsidbUpgradeAttributesOnlyDetect) == MsiInterop.MsidbUpgradeAttributesOnlyDetect;
related.MinInclusive = (attributes & MsiInterop.MsidbUpgradeAttributesVersionMinInclusive) == MsiInterop.MsidbUpgradeAttributesVersionMinInclusive;
related.MaxInclusive = (attributes & MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive) == MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive;
related.LangInclusive = (attributes & MsiInterop.MsidbUpgradeAttributesLanguagesExclusive) == 0;
var attributes = WixBundleRelatedPackageAttributes.None;
attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect) == WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect ? WixBundleRelatedPackageAttributes.OnlyDetect : 0;
attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive ? WixBundleRelatedPackageAttributes.MinInclusive : 0;
attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive ? WixBundleRelatedPackageAttributes.MaxInclusive : 0;
attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive ? WixBundleRelatedPackageAttributes.LangInclusive : 0;
var related = new WixBundleRelatedPackageTuple(this.Facade.PackageTuple.SourceLineNumbers)
{
PackageRef = this.Facade.PackageId,
RelatedId = record.GetString(1),
MinVersion = record.GetString(2),
MaxVersion = record.GetString(3),
Languages = record.GetString(4),
Attributes = attributes,
};
}
}
}
@ -275,26 +297,26 @@ namespace WixToolset.Core.Burn.Bundles
{
if (db.Tables.Contains("Feature"))
{
using (Dtf.View featureView = db.OpenView("SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = ?"))
using (Dtf.View componentView = db.OpenView("SELECT `FileSize` FROM `File` WHERE `Component_` = ?"))
using (var featureView = db.OpenView("SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = ?"))
using (var componentView = db.OpenView("SELECT `FileSize` FROM `File` WHERE `Component_` = ?"))
{
using (Dtf.Record featureRecord = new Dtf.Record(1))
using (Dtf.Record componentRecord = new Dtf.Record(1))
using (var featureRecord = new Dtf.Record(1))
using (var componentRecord = new Dtf.Record(1))
{
using (Dtf.View allFeaturesView = db.OpenView("SELECT * FROM `Feature`"))
using (var allFeaturesView = db.OpenView("SELECT * FROM `Feature`"))
{
allFeaturesView.Execute();
while (true)
{
using (Dtf.Record allFeaturesResultRecord = allFeaturesView.Fetch())
using (var allFeaturesResultRecord = allFeaturesView.Fetch())
{
if (null == allFeaturesResultRecord)
{
break;
}
string featureName = allFeaturesResultRecord.GetString(1);
var featureName = allFeaturesResultRecord.GetString(1);
// Calculate the Feature size.
featureRecord.SetString(1, featureName);
@ -304,43 +326,46 @@ namespace WixToolset.Core.Burn.Bundles
long size = 0;
while (true)
{
using (Dtf.Record componentResultRecord = featureView.Fetch())
using (var componentResultRecord = featureView.Fetch())
{
if (null == componentResultRecord)
{
break;
}
string component = componentResultRecord.GetString(1);
var component = componentResultRecord.GetString(1);
componentRecord.SetString(1, component);
componentView.Execute(componentRecord);
while (true)
{
using (Dtf.Record fileResultRecord = componentView.Fetch())
using (var fileResultRecord = componentView.Fetch())
{
if (null == fileResultRecord)
{
break;
}
string fileSize = fileResultRecord.GetString(1);
var fileSize = fileResultRecord.GetString(1);
size += Convert.ToInt32(fileSize, CultureInfo.InvariantCulture.NumberFormat);
}
}
}
}
WixBundleMsiFeatureRow feature = (WixBundleMsiFeatureRow)this.MsiFeatureTable.CreateRow(this.Facade.Package.SourceLineNumbers);
feature.ChainPackageId = this.Facade.Package.WixChainItemId;
feature.Name = featureName;
feature.Parent = allFeaturesResultRecord.GetString(2);
feature.Title = allFeaturesResultRecord.GetString(3);
feature.Description = allFeaturesResultRecord.GetString(4);
feature.Display = allFeaturesResultRecord.GetInteger(5);
feature.Level = allFeaturesResultRecord.GetInteger(6);
feature.Directory = allFeaturesResultRecord.GetString(7);
feature.Attributes = allFeaturesResultRecord.GetInteger(8);
feature.Size = size;
var feature = new WixBundleMsiFeatureTuple(this.Facade.PackageTuple.SourceLineNumbers, new Identifier(AccessModifier.Private, this.Facade.PackageId, featureName))
{
PackageRef = this.Facade.PackageId,
Name = featureName,
Parent = allFeaturesResultRecord.GetString(2),
Title = allFeaturesResultRecord.GetString(3),
Description = allFeaturesResultRecord.GetString(4),
Display = allFeaturesResultRecord.GetInteger(5),
Level = allFeaturesResultRecord.GetInteger(6),
Directory = allFeaturesResultRecord.GetString(7),
Attributes = allFeaturesResultRecord.GetInteger(8),
Size = size
};
}
}
}
@ -349,113 +374,119 @@ namespace WixToolset.Core.Burn.Bundles
}
}
private void ImportExternalCabinetAsPayloads(Dtf.Database db, WixBundlePayloadRow packagePayload, ISet<string> payloadNames)
private void ImportExternalCabinetAsPayloads(Dtf.Database db, WixBundlePayloadTuple packagePayload, ISet<string> payloadNames)
{
if (db.Tables.Contains("Media"))
{
foreach (string cabinet in db.ExecuteStringQuery("SELECT `Cabinet` FROM `Media`"))
foreach (var cabinet in db.ExecuteStringQuery("SELECT `Cabinet` FROM `Media`"))
{
if (!String.IsNullOrEmpty(cabinet) && !cabinet.StartsWith("#", StringComparison.Ordinal))
{
// If we didn't find the Payload as an existing child of the package, we need to
// add it. We expect the file to exist on-disk in the same relative location as
// the MSI expects to find it...
string cabinetName = Path.Combine(Path.GetDirectoryName(packagePayload.Name), cabinet);
var cabinetName = Path.Combine(Path.GetDirectoryName(packagePayload.Name), cabinet);
if (!payloadNames.Contains(cabinetName))
{
string generatedId = Common.GenerateIdentifier("cab", packagePayload.Id, cabinet);
string payloadSourceFile = this.ResolveRelatedFile(packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.Package.SourceLineNumbers, BindStage.Normal);
var generatedId = Common.GenerateIdentifier("cab", packagePayload.Id.Id, cabinet);
var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.PackageTuple.SourceLineNumbers, BindStage.Normal);
WixBundlePayloadRow payload = (WixBundlePayloadRow)this.PayloadTable.CreateRow(this.Facade.Package.SourceLineNumbers);
payload.Id = generatedId;
payload.Name = cabinetName;
payload.SourceFile = payloadSourceFile;
payload.Compressed = packagePayload.Compressed;
payload.UnresolvedSourceFile = cabinetName;
payload.Package = packagePayload.Package;
payload.Container = packagePayload.Container;
payload.ContentFile = true;
payload.EnableSignatureValidation = packagePayload.EnableSignatureValidation;
payload.Packaging = packagePayload.Packaging;
payload.ParentPackagePayload = packagePayload.Id;
var tuple = new WixBundlePayloadTuple(this.Facade.PackageTuple.SourceLineNumbers, new Identifier(AccessModifier.Private, generatedId))
{
Name = cabinetName,
SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile },
Compressed = packagePayload.Compressed,
UnresolvedSourceFile = cabinetName,
PackageRef = packagePayload.PackageRef,
ContainerRef = packagePayload.ContainerRef,
ContentFile = true,
EnableSignatureValidation = packagePayload.EnableSignatureValidation,
Packaging = packagePayload.Packaging,
ParentPackagePayloadRef = packagePayload.Id.Id,
};
this.Section.Tuples.Add(tuple);
}
}
}
}
}
private long ImportExternalFileAsPayloadsAndReturnInstallSize(Dtf.Database db, WixBundlePayloadRow packagePayload, bool longNamesInImage, bool compressed, ISet<string> payloadNames)
private long ImportExternalFileAsPayloadsAndReturnInstallSize(Dtf.Database db, WixBundlePayloadTuple packagePayload, bool longNamesInImage, bool compressed, ISet<string> payloadNames)
{
long size = 0;
if (db.Tables.Contains("Component") && db.Tables.Contains("Directory") && db.Tables.Contains("File"))
{
Hashtable directories = new Hashtable();
var directories = new Dictionary<string, IResolvedDirectory>();
// Load up the directory hash table so we will be able to resolve source paths
// for files in the MSI database.
using (Dtf.View view = db.OpenView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`"))
using (var view = db.OpenView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`"))
{
view.Execute();
while (true)
{
using (Dtf.Record record = view.Fetch())
using (var record = view.Fetch())
{
if (null == record)
{
break;
}
string sourceName = Common.GetName(record.GetString(3), true, longNamesInImage);
directories.Add(record.GetString(1), new ResolvedDirectory(record.GetString(2), sourceName));
var sourceName = Common.GetName(record.GetString(3), true, longNamesInImage);
var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(record.GetString(2), sourceName);
directories.Add(record.GetString(1), resolvedDirectory);
}
}
}
// Resolve the source paths to external files and add each file size to the total
// install size of the package.
using (Dtf.View view = db.OpenView("SELECT `Directory_`, `File`, `FileName`, `File`.`Attributes`, `FileSize` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_`"))
using (var view = db.OpenView("SELECT `Directory_`, `File`, `FileName`, `File`.`Attributes`, `FileSize` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_`"))
{
view.Execute();
while (true)
{
using (Dtf.Record record = view.Fetch())
using (var record = view.Fetch())
{
if (null == record)
{
break;
}
// Skip adding the loose files as payloads if it was suppressed.
if (!this.Facade.MsiPackage.SuppressLooseFilePayloadGeneration)
// If the file is explicitly uncompressed or the MSI is uncompressed and the file is not
// explicitly marked compressed then this is an external file.
var compressionBit = record.GetInteger(4);
if (WindowsInstallerConstants.MsidbFileAttributesNoncompressed == (compressionBit & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) ||
(!compressed && 0 == (compressionBit & WindowsInstallerConstants.MsidbFileAttributesCompressed)))
{
// If the file is explicitly uncompressed or the MSI is uncompressed and the file is not
// explicitly marked compressed then this is an external file.
if (MsiInterop.MsidbFileAttributesNoncompressed == (record.GetInteger(4) & MsiInterop.MsidbFileAttributesNoncompressed) ||
(!compressed && 0 == (record.GetInteger(4) & MsiInterop.MsidbFileAttributesCompressed)))
string fileSourcePath = this.PathResolver.GetFileSourcePath(directories, record.GetString(1), record.GetString(3), compressed, longNamesInImage);
var name = Path.Combine(Path.GetDirectoryName(packagePayload.Name), fileSourcePath);
if (!payloadNames.Contains(name))
{
string fileSourcePath = Binder.GetFileSourcePath(directories, record.GetString(1), record.GetString(3), compressed, longNamesInImage);
string name = Path.Combine(Path.GetDirectoryName(packagePayload.Name), fileSourcePath);
var generatedId = Common.GenerateIdentifier("f", packagePayload.Id.Id, record.GetString(2));
var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.PackageTuple.SourceLineNumbers, BindStage.Normal);
if (!payloadNames.Contains(name))
var tuple = new WixBundlePayloadTuple(this.Facade.PackageTuple.SourceLineNumbers, new Identifier(AccessModifier.Private, generatedId))
{
string generatedId = Common.GenerateIdentifier("f", packagePayload.Id, record.GetString(2));
string payloadSourceFile = this.ResolveRelatedFile(packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.Package.SourceLineNumbers, BindStage.Normal);
Name = name,
SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile },
Compressed = packagePayload.Compressed,
UnresolvedSourceFile = name,
PackageRef = packagePayload.PackageRef,
ContainerRef = packagePayload.ContainerRef,
ContentFile = true,
EnableSignatureValidation = packagePayload.EnableSignatureValidation,
Packaging = packagePayload.Packaging,
ParentPackagePayloadRef = packagePayload.Id.Id,
};
WixBundlePayloadRow payload = (WixBundlePayloadRow)this.PayloadTable.CreateRow(this.Facade.Package.SourceLineNumbers);
payload.Id = generatedId;
payload.Name = name;
payload.SourceFile = payloadSourceFile;
payload.Compressed = packagePayload.Compressed;
payload.UnresolvedSourceFile = name;
payload.Package = packagePayload.Package;
payload.Container = packagePayload.Container;
payload.ContentFile = true;
payload.EnableSignatureValidation = packagePayload.EnableSignatureValidation;
payload.Packaging = packagePayload.Packaging;
payload.ParentPackagePayload = packagePayload.Id;
}
this.Section.Tuples.Add(tuple);
}
}
@ -468,26 +499,30 @@ namespace WixToolset.Core.Burn.Bundles
return size;
}
private void AddMsiProperty(string name, string value)
private void AddMsiProperty(WixBundleMsiPackageTuple msiPackage, string name, string value)
{
WixBundleMsiPropertyRow row = (WixBundleMsiPropertyRow)this.MsiPropertyTable.CreateRow(this.Facade.MsiPackage.SourceLineNumbers);
row.ChainPackageId = this.Facade.Package.WixChainItemId;
row.Name = name;
row.Value = value;
var tuple = new WixBundleMsiPropertyTuple(msiPackage.SourceLineNumbers, new Identifier(AccessModifier.Private, msiPackage.Id.Id, name))
{
PackageRef = msiPackage.Id.Id,
Name = name,
Value = value
};
this.Section.Tuples.Add(tuple);
}
private void ImportDependencyProviders(Dtf.Database db)
private void ImportDependencyProviders(WixBundleMsiPackageTuple msiPackage, Dtf.Database db)
{
if (db.Tables.Contains("WixDependencyProvider"))
{
string query = "SELECT `ProviderKey`, `Version`, `DisplayName`, `Attributes` FROM `WixDependencyProvider`";
var query = "SELECT `ProviderKey`, `Version`, `DisplayName`, `Attributes` FROM `WixDependencyProvider`";
using (Dtf.View view = db.OpenView(query))
using (var view = db.OpenView(query))
{
view.Execute();
while (true)
{
using (Dtf.Record record = view.Fetch())
using (var record = view.Fetch())
{
if (null == record)
{
@ -495,34 +530,51 @@ namespace WixToolset.Core.Burn.Bundles
}
// Import the provider key and attributes.
string providerKey = record.GetString(1);
string version = record.GetString(2) ?? this.Facade.MsiPackage.ProductVersion;
string displayName = record.GetString(3) ?? this.Facade.Package.DisplayName;
int attributes = record.GetInteger(4);
var tuple = new ProvidesDependencyTuple(msiPackage.SourceLineNumbers)
{
PackageRef = msiPackage.Id.Id,
Key = record.GetString(1),
Version = record.GetString(2) ?? msiPackage.ProductVersion,
DisplayName = record.GetString(3) ?? this.Facade.PackageTuple.DisplayName,
Attributes = record.GetInteger(4),
Imported = true
};
ProvidesDependency dependency = new ProvidesDependency(providerKey, version, displayName, attributes);
dependency.Imported = true;
this.Facade.Provides.Add(dependency);
this.Section.Tuples.Add(tuple);
}
}
}
}
}
private string ResolveRelatedFile(string sourceFile, string relatedSource, string type, SourceLineNumber sourceLineNumbers, BindStage stage)
private string ResolveRelatedFile(string resolvedSource, string unresolvedSource, string relatedSource, string type, SourceLineNumber sourceLineNumbers, BindStage stage)
{
var checkedPaths = new List<string>();
foreach (var extension in this.BackendExtensions)
{
var relatedFile = extension.ResolveRelatedFile(sourceFile, relatedSource, type, sourceLineNumbers, stage);
var resolved = extension.ResolveRelatedFile(unresolvedSource, relatedSource, type, sourceLineNumbers, stage);
if (!String.IsNullOrEmpty(relatedFile))
if (resolved?.CheckedPaths != null)
{
return relatedFile;
checkedPaths.AddRange(resolved.CheckedPaths);
}
if (!String.IsNullOrEmpty(resolved?.Path))
{
return resolved?.Path;
}
}
return null;
var resolvedPath = Path.Combine(Path.GetDirectoryName(resolvedSource), relatedSource);
if (!File.Exists(resolvedPath))
{
checkedPaths.Add(resolvedPath);
this.Messaging.Write(ErrorMessages.FileNotFound(sourceLineNumbers, resolvedPath, type, checkedPaths));
}
return resolvedPath;
}
/// <summary>
@ -571,6 +623,5 @@ namespace WixToolset.Core.Burn.Bundles
return String.Format(CultureInfo.InvariantCulture, ProcessMsiPackageCommand.PropertySqlFormat, property);
}
#endif
}
}

Просмотреть файл

@ -10,6 +10,8 @@ namespace WixToolset.Core.Burn.Bundles
using System.Text;
using System.Xml;
using WixToolset.Data;
using WixToolset.Data.Tuples;
using WixToolset.Extensibility.Services;
using Dtf = WixToolset.Dtf.WindowsInstaller;
/// <summary>
@ -17,80 +19,92 @@ namespace WixToolset.Core.Burn.Bundles
/// </summary>
internal class ProcessMspPackageCommand
{
#if TODO
private const string PatchMetadataFormat = "SELECT `Value` FROM `MsiPatchMetadata` WHERE `Property` = '{0}'";
private static readonly Encoding XmlOutputEncoding = new UTF8Encoding(false);
public RowDictionary<WixBundlePayloadRow> AuthoredPayloads { private get; set; }
public ProcessMspPackageCommand(IMessaging messaging, IntermediateSection section, PackageFacade facade, Dictionary<string, WixBundlePayloadTuple> payloadTuples)
{
this.Messaging = messaging;
this.AuthoredPayloads = payloadTuples;
this.Section = section;
this.Facade = facade;
}
public IMessaging Messaging { get; }
public Dictionary<string, WixBundlePayloadTuple> AuthoredPayloads { private get; set; }
public PackageFacade Facade { private get; set; }
public Table WixBundlePatchTargetCodeTable { private get; set; }
public IntermediateSection Section { get; }
/// <summary>
/// Processes the Msp packages to add properties and payloads from the Msp packages.
/// </summary>
public void Execute()
{
WixBundlePayloadRow packagePayload = this.AuthoredPayloads.Get(this.Facade.Package.PackagePayload);
var packagePayload = this.AuthoredPayloads[this.Facade.PackageTuple.PayloadRef];
string sourcePath = packagePayload.FullFileName;
var mspPackage = (WixBundleMspPackageTuple)this.Facade.SpecificPackageTuple;
var sourcePath = packagePayload.SourceFile.Path;
try
{
// Read data out of the msp database...
using (Dtf.SummaryInfo sumInfo = new Dtf.SummaryInfo(sourcePath, false))
using (var sumInfo = new Dtf.SummaryInfo(sourcePath, false))
{
this.Facade.MspPackage.PatchCode = sumInfo.RevisionNumber.Substring(0, 38);
mspPackage.PatchCode = sumInfo.RevisionNumber.Substring(0, 38);
}
using (Dtf.Database db = new Dtf.Database(sourcePath))
using (var db = new Dtf.Database(sourcePath))
{
if (String.IsNullOrEmpty(this.Facade.Package.DisplayName))
if (String.IsNullOrEmpty(this.Facade.PackageTuple.DisplayName))
{
this.Facade.Package.DisplayName = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "DisplayName");
this.Facade.PackageTuple.DisplayName = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "DisplayName");
}
if (String.IsNullOrEmpty(this.Facade.Package.Description))
if (String.IsNullOrEmpty(this.Facade.PackageTuple.Description))
{
this.Facade.Package.Description = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "Description");
this.Facade.PackageTuple.Description = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "Description");
}
this.Facade.MspPackage.Manufacturer = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "ManufacturerName");
mspPackage.Manufacturer = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "ManufacturerName");
}
this.ProcessPatchXml(packagePayload, sourcePath);
this.ProcessPatchXml(packagePayload, mspPackage, sourcePath);
}
catch (Dtf.InstallerException e)
{
Messaging.Instance.OnMessage(WixErrors.UnableToReadPackageInformation(packagePayload.SourceLineNumbers, sourcePath, e.Message));
this.Messaging.Write(ErrorMessages.UnableToReadPackageInformation(packagePayload.SourceLineNumbers, sourcePath, e.Message));
return;
}
if (String.IsNullOrEmpty(this.Facade.Package.CacheId))
if (String.IsNullOrEmpty(this.Facade.PackageTuple.CacheId))
{
this.Facade.Package.CacheId = this.Facade.MspPackage.PatchCode;
this.Facade.PackageTuple.CacheId = mspPackage.PatchCode;
}
}
private void ProcessPatchXml(WixBundlePayloadRow packagePayload, string sourcePath)
private void ProcessPatchXml(WixBundlePayloadTuple packagePayload, WixBundleMspPackageTuple mspPackage, string sourcePath)
{
HashSet<string> uniqueTargetCodes = new HashSet<string>();
var uniqueTargetCodes = new HashSet<string>();
string patchXml = Dtf.Installer.ExtractPatchXmlData(sourcePath);
var patchXml = Dtf.Installer.ExtractPatchXmlData(sourcePath);
XmlDocument doc = new XmlDocument();
var doc = new XmlDocument();
doc.LoadXml(patchXml);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
var nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("p", "http://www.microsoft.com/msi/patch_applicability.xsd");
// Determine target ProductCodes and/or UpgradeCodes.
foreach (XmlNode node in doc.SelectNodes("/p:MsiPatch/p:TargetProduct", nsmgr))
{
// If this patch targets a product code, this is the best case.
XmlNode targetCodeElement = node.SelectSingleNode("p:TargetProductCode", nsmgr);
WixBundlePatchTargetCodeAttributes attributes = WixBundlePatchTargetCodeAttributes.None;
var targetCodeElement = node.SelectSingleNode("p:TargetProductCode", nsmgr);
var attributes = WixBundlePatchTargetCodeAttributes.None;
if (ProcessMspPackageCommand.TargetsCode(targetCodeElement))
{
@ -105,45 +119,49 @@ namespace WixToolset.Core.Burn.Bundles
}
else // this patch targets an unknown number of products
{
this.Facade.MspPackage.Attributes |= WixBundleMspPackageAttributes.TargetUnspecified;
mspPackage.Attributes |= WixBundleMspPackageAttributes.TargetUnspecified;
}
}
string targetCode = targetCodeElement.InnerText;
var targetCode = targetCodeElement.InnerText;
if (uniqueTargetCodes.Add(targetCode))
{
WixBundlePatchTargetCodeRow row = (WixBundlePatchTargetCodeRow)this.WixBundlePatchTargetCodeTable.CreateRow(packagePayload.SourceLineNumbers);
row.MspPackageId = packagePayload.Id;
row.TargetCode = targetCode;
row.Attributes = attributes;
var tuple = new WixBundlePatchTargetCodeTuple(packagePayload.SourceLineNumbers)
{
PackageRef = packagePayload.Id.Id,
TargetCode = targetCode,
Attributes = attributes
};
this.Section.Tuples.Add(tuple);
}
}
// Suppress patch sequence data for improved performance.
XmlNode root = doc.DocumentElement;
var root = doc.DocumentElement;
foreach (XmlNode node in root.SelectNodes("p:SequenceData", nsmgr))
{
root.RemoveChild(node);
}
// Save the XML as compact as possible.
using (StringWriter writer = new StringWriter())
using (var writer = new StringWriter())
{
XmlWriterSettings settings = new XmlWriterSettings()
var settings = new XmlWriterSettings()
{
Encoding = ProcessMspPackageCommand.XmlOutputEncoding,
Indent = false,
NewLineChars = string.Empty,
NewLineChars = String.Empty,
NewLineHandling = NewLineHandling.Replace,
};
using (XmlWriter xmlWriter = XmlWriter.Create(writer, settings))
using (var xmlWriter = XmlWriter.Create(writer, settings))
{
doc.WriteTo(xmlWriter);
}
this.Facade.MspPackage.PatchXml = writer.ToString();
mspPackage.PatchXml = writer.ToString();
}
}
@ -175,16 +193,6 @@ namespace WixToolset.Core.Burn.Bundles
return String.Format(CultureInfo.InvariantCulture, ProcessMspPackageCommand.PatchMetadataFormat, property);
}
private static bool TargetsCode(XmlNode node)
{
if (null != node)
{
XmlAttribute attr = node.Attributes["Validate"];
return null != attr && "true".Equals(attr.Value);
}
return false;
}
#endif
private static bool TargetsCode(XmlNode node) => "true" == node?.Attributes["Validate"]?.Value;
}
}

Просмотреть файл

@ -3,29 +3,35 @@
namespace WixToolset.Core.Burn.Bundles
{
using System;
using System.Collections.Generic;
using WixToolset.Data;
using WixToolset.Data.Tuples;
/// <summary>
/// Processes the Msu packages to add properties and payloads from the Msu packages.
/// </summary>
internal class ProcessMsuPackageCommand
{
#if TODO
public RowDictionary<WixBundlePayload> AuthoredPayloads { private get; set; }
public ProcessMsuPackageCommand(PackageFacade facade, Dictionary<string, WixBundlePayloadTuple> payloadTuples)
{
this.AuthoredPayloads = payloadTuples;
this.Facade = facade;
}
public Dictionary<string, WixBundlePayloadTuple> AuthoredPayloads { private get; set; }
public PackageFacade Facade { private get; set; }
public void Execute()
{
WixBundlePayloadRow packagePayload = this.AuthoredPayloads.Get(this.Facade.Package.PackagePayload);
var packagePayload = this.AuthoredPayloads[this.Facade.PackageTuple.PayloadRef];
if (String.IsNullOrEmpty(this.Facade.Package.CacheId))
if (String.IsNullOrEmpty(this.Facade.PackageTuple.CacheId))
{
this.Facade.Package.CacheId = packagePayload.Hash;
this.Facade.PackageTuple.CacheId = packagePayload.Hash;
}
this.Facade.Package.PerMachine = YesNoDefaultType.Yes; // MSUs are always per-machine.
this.Facade.PackageTuple.PerMachine = YesNoDefaultType.Yes; // MSUs are always per-machine.
}
#endif
}
}

Просмотреть файл

@ -9,58 +9,73 @@ namespace WixToolset.Core.Burn.Bundles
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using WixToolset.Data;
using WixToolset.Data.Burn;
using WixToolset.Data.Tuples;
using WixToolset.Extensibility.Data;
using WixToolset.Extensibility.Services;
internal class ProcessPayloadsCommand
{
#if TODO
private static readonly Version EmptyVersion = new Version(0, 0, 0, 0);
public IEnumerable<WixBundlePayloadRow> Payloads { private get; set; }
public ProcessPayloadsCommand(IServiceProvider serviceProvider, IBackendHelper backendHelper, IEnumerable<WixBundlePayloadTuple> payloads, PackagingType defaultPackaging, string layoutDirectory)
{
this.Messaging = serviceProvider.GetService<IMessaging>();
public PackagingType DefaultPackaging { private get; set; }
this.BackendHelper = backendHelper;
this.Payloads = payloads;
this.DefaultPackaging = defaultPackaging;
this.LayoutDirectory = layoutDirectory;
}
public string LayoutDirectory { private get; set; }
public IEnumerable<IFileTransfer> FileTransfers { get; private set; }
public IEnumerable<FileTransfer> FileTransfers { get; private set; }
private IMessaging Messaging { get; }
private IBackendHelper BackendHelper { get; }
private IEnumerable<WixBundlePayloadTuple> Payloads { get; }
private PackagingType DefaultPackaging { get; }
private string LayoutDirectory { get; }
public void Execute()
{
List<FileTransfer> fileTransfers = new List<FileTransfer>();
var fileTransfers = new List<IFileTransfer>();
foreach (WixBundlePayloadRow payload in this.Payloads)
foreach (var payload in this.Payloads)
{
string normalizedPath = payload.Name.Replace('\\', '/');
var normalizedPath = payload.Name.Replace('\\', '/');
if (normalizedPath.StartsWith("../", StringComparison.Ordinal) || normalizedPath.Contains("/../"))
{
Messaging.Instance.OnMessage(WixErrors.PayloadMustBeRelativeToCache(payload.SourceLineNumbers, "Payload", "Name", payload.Name));
this.Messaging.Write(ErrorMessages.PayloadMustBeRelativeToCache(payload.SourceLineNumbers, "Payload", "Name", payload.Name));
}
// Embedded files (aka: files from binary .wixlibs) are not content files (because they are hidden
// in the .wixlib).
ObjectField field = (ObjectField)payload.Fields[2];
payload.ContentFile = !field.EmbeddedFileIndex.HasValue;
var sourceFile = payload.SourceFile;
payload.ContentFile = !sourceFile.EmbeddedFileIndex.HasValue;
this.UpdatePayloadPackagingType(payload);
if (String.IsNullOrEmpty(payload.SourceFile))
if (String.IsNullOrEmpty(sourceFile?.Path))
{
// Remote payloads obviously cannot be embedded.
Debug.Assert(PackagingType.Embedded != payload.Packaging);
}
else // not a remote payload so we have a lot more to update.
{
this.UpdatePayloadFileInformation(payload);
this.UpdatePayloadFileInformation(payload, sourceFile);
this.UpdatePayloadVersionInformation(payload);
this.UpdatePayloadVersionInformation(payload, sourceFile);
// External payloads need to be transfered.
if (PackagingType.External == payload.Packaging)
{
FileTransfer transfer;
if (FileTransfer.TryCreate(payload.FullFileName, Path.Combine(this.LayoutDirectory, payload.Name), false, "Payload", payload.SourceLineNumbers, out transfer))
{
fileTransfers.Add(transfer);
}
var transfer = this.BackendHelper.CreateFileTransfer(sourceFile.Path, Path.Combine(this.LayoutDirectory, payload.Name), false, payload.SourceLineNumbers);
fileTransfers.Add(transfer);
}
}
}
@ -68,41 +83,41 @@ namespace WixToolset.Core.Burn.Bundles
this.FileTransfers = fileTransfers;
}
private void UpdatePayloadPackagingType(WixBundlePayloadRow payload)
private void UpdatePayloadPackagingType(WixBundlePayloadTuple payload)
{
if (PackagingType.Unknown == payload.Packaging)
{
if (YesNoDefaultType.Yes == payload.Compressed)
if (!payload.Compressed.HasValue)
{
payload.Packaging = this.DefaultPackaging;
}
else if (payload.Compressed.Value)
{
payload.Packaging = PackagingType.Embedded;
}
else if (YesNoDefaultType.No == payload.Compressed)
{
payload.Packaging = PackagingType.External;
}
else
{
payload.Packaging = this.DefaultPackaging;
payload.Packaging = PackagingType.External;
}
}
// Embedded payloads that are not assigned a container already are placed in the default attached
// container.
if (PackagingType.Embedded == payload.Packaging && String.IsNullOrEmpty(payload.Container))
if (PackagingType.Embedded == payload.Packaging && String.IsNullOrEmpty(payload.ContainerRef))
{
payload.Container = Compiler.BurnDefaultAttachedContainerId;
payload.ContainerRef = BurnConstants.BurnDefaultAttachedContainerName;
}
}
private void UpdatePayloadFileInformation(WixBundlePayloadRow payload)
private void UpdatePayloadFileInformation(WixBundlePayloadTuple payload, IntermediateFieldPathValue sourceFile)
{
FileInfo fileInfo = new FileInfo(payload.SourceFile);
var fileInfo = new FileInfo(sourceFile.Path);
if (null != fileInfo)
{
payload.FileSize = (int)fileInfo.Length;
payload.Hash = Common.GetFileHash(fileInfo.FullName);
payload.Hash = BundleHashAlgorithm.Hash(fileInfo);
// Try to get the certificate if the payload is a signed file and we're not suppressing signature validation.
if (payload.EnableSignatureValidation)
@ -122,9 +137,10 @@ namespace WixToolset.Core.Burn.Bundles
byte[] publicKeyIdentifierHash = new byte[128];
uint publicKeyIdentifierHashSize = (uint)publicKeyIdentifierHash.Length;
WixToolset.Core.Native.NativeMethods.HashPublicKeyInfo(certificate.Handle, publicKeyIdentifierHash, ref publicKeyIdentifierHashSize);
StringBuilder sb = new StringBuilder(((int)publicKeyIdentifierHashSize + 1) * 2);
for (int i = 0; i < publicKeyIdentifierHashSize; ++i)
Native.NativeMethods.HashPublicKeyInfo(certificate.Handle, publicKeyIdentifierHash, ref publicKeyIdentifierHashSize);
var sb = new StringBuilder(((int)publicKeyIdentifierHashSize + 1) * 2);
for (var i = 0; i < publicKeyIdentifierHashSize; ++i)
{
sb.AppendFormat("{0:X2}", publicKeyIdentifierHash[i]);
}
@ -136,14 +152,14 @@ namespace WixToolset.Core.Burn.Bundles
}
}
private void UpdatePayloadVersionInformation(WixBundlePayloadRow payload)
private void UpdatePayloadVersionInformation(WixBundlePayloadTuple payload, IntermediateFieldPathValue sourceFile)
{
FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(payload.SourceFile);
var versionInfo = FileVersionInfo.GetVersionInfo(sourceFile.Path);
if (null != versionInfo)
{
// Use the fixed version info block for the file since the resource text may not be a dotted quad.
Version version = new Version(versionInfo.ProductMajorPart, versionInfo.ProductMinorPart, versionInfo.ProductBuildPart, versionInfo.ProductPrivatePart);
var version = new Version(versionInfo.ProductMajorPart, versionInfo.ProductMinorPart, versionInfo.ProductBuildPart, versionInfo.ProductPrivatePart);
if (ProcessPayloadsCommand.EmptyVersion != version)
{
@ -154,6 +170,5 @@ namespace WixToolset.Core.Burn.Bundles
payload.DisplayName = versionInfo.ProductName;
}
}
#endif
}
}

Просмотреть файл

@ -9,31 +9,42 @@ namespace WixToolset.Core.Burn.Bundles
using System.Runtime.InteropServices;
using System.Text;
using WixToolset.Data;
using WixToolset.Data.Tuples;
using WixToolset.Extensibility.Services;
internal class VerifyPayloadsWithCatalogCommand
{
#if TODO
public IEnumerable<WixBundleCatalogRow> Catalogs { private get; set; }
public VerifyPayloadsWithCatalogCommand(IMessaging messaging, IEnumerable<WixBundleCatalogTuple> catalogs, IEnumerable<WixBundlePayloadTuple> payloads)
{
this.Messaging = messaging;
this.Catalogs = catalogs;
this.Payloads = payloads;
}
public IEnumerable<WixBundlePayloadRow> Payloads { private get; set; }
private IMessaging Messaging { get; }
private IEnumerable<WixBundleCatalogTuple> Catalogs { get; }
private IEnumerable<WixBundlePayloadTuple> Payloads { get; }
public void Execute()
{
List<CatalogIdWithPath> catalogIdsWithPaths = this.Catalogs
var catalogIdsWithPaths = this.Catalogs
.Join(this.Payloads,
catalog => catalog.Payload,
payload => payload.Id,
(catalog, payload) => new CatalogIdWithPath() { Id = catalog.Id, FullPath = Path.GetFullPath(payload.SourceFile) })
catalog => catalog.PayloadRef,
payload => payload.Id.Id,
(catalog, payload) => new CatalogIdWithPath() { Id = catalog.Id.Id, FullPath = Path.GetFullPath(payload.SourceFile.Path) })
.ToList();
foreach (WixBundlePayloadRow payloadInfo in this.Payloads)
foreach (var payloadInfo in this.Payloads)
{
// Payloads that are not embedded should be verfied.
if (String.IsNullOrEmpty(payloadInfo.EmbeddedId))
{
bool validated = false;
var sourceFile = payloadInfo.SourceFile.Path;
var validated = false;
foreach (CatalogIdWithPath catalog in catalogIdsWithPaths)
foreach (var catalog in catalogIdsWithPaths)
{
if (!validated)
{
@ -41,11 +52,10 @@ namespace WixToolset.Core.Burn.Bundles
uint cryptHashSize = 20;
byte[] cryptHashBytes = new byte[cryptHashSize];
int error;
IntPtr fileHandle = IntPtr.Zero;
using (FileStream payloadStream = File.OpenRead(payloadInfo.FullFileName))
using (var payloadStream = File.OpenRead(sourceFile))
{
// Get the file handle
fileHandle = payloadStream.SafeFileHandle.DangerousGetHandle();
var fileHandle = payloadStream.SafeFileHandle.DangerousGetHandle();
// 20 bytes is usually the hash size. Future hashes may be bigger
if (!VerifyInterop.CryptCATAdminCalcHashFromFileHandle(fileHandle, ref cryptHashSize, cryptHashBytes, 0))
@ -64,7 +74,7 @@ namespace WixToolset.Core.Burn.Bundles
if (0 != error)
{
Messaging.Instance.OnMessage(WixErrors.CatalogFileHashFailed(payloadInfo.FullFileName, error));
this.Messaging.Write(ErrorMessages.CatalogFileHashFailed(sourceFile, error));
}
}
}
@ -79,15 +89,15 @@ namespace WixToolset.Core.Burn.Bundles
catalogData.pbCalculatedFileHash = Marshal.AllocCoTaskMem((int)cryptHashSize);
Marshal.Copy(cryptHashBytes, 0, catalogData.pbCalculatedFileHash, (int)cryptHashSize);
StringBuilder hashString = new StringBuilder();
foreach (byte hashByte in cryptHashBytes)
var hashString = new StringBuilder();
foreach (var hashByte in cryptHashBytes)
{
hashString.Append(hashByte.ToString("X2"));
}
catalogData.pcwszMemberTag = hashString.ToString();
// The file names need to be lower case for older OSes
catalogData.pcwszMemberFilePath = payloadInfo.FullFileName.ToLowerInvariant();
catalogData.pcwszMemberFilePath = sourceFile.ToLowerInvariant();
catalogData.pcwszCatalogFilePath = catalog.FullPath.ToLowerInvariant();
// Create WINTRUST_DATA structure
@ -108,7 +118,7 @@ namespace WixToolset.Core.Burn.Bundles
long verifyResult = VerifyInterop.WinVerifyTrust(noWindow, ref verifyGuid, ref trustData);
if (0 == verifyResult)
{
payloadInfo.Catalog = catalog.Id;
payloadInfo.CatalogRef = catalog.Id;
validated = true;
break;
}
@ -132,7 +142,7 @@ namespace WixToolset.Core.Burn.Bundles
// Error message if the file was not validated by one of the catalogs
if (!validated)
{
Messaging.Instance.OnMessage(WixErrors.CatalogVerificationFailed(payloadInfo.FullFileName));
this.Messaging.Write(ErrorMessages.CatalogVerificationFailed(sourceFile));
}
}
}
@ -144,6 +154,5 @@ namespace WixToolset.Core.Burn.Bundles
public string FullPath { get; set; }
}
#endif
}
}

Просмотреть файл

@ -1,11 +1,10 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.Burn
{
using System;
using System.IO;
using WixToolset.Extensibility;
using WixToolset.Extensibility.Data;
internal class BurnBackendFactory : IBackendFactory
{

Просмотреть файл

@ -3,8 +3,6 @@
namespace WixToolset
{
using System;
using System.Collections;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
internal class VerifyInterop

Просмотреть файл

@ -15,6 +15,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Security.Permissions" Version="4.6.0" />
<PackageReference Include="WixToolset.Core.Native" Version="4.0.*" />
<PackageReference Include="WixToolset.Dtf.Resources" Version="4.0.*" NoWarn="NU1701" />
<PackageReference Include="WixToolset.Dtf.WindowsInstaller" Version="4.0.*" NoWarn="NU1701" />

Просмотреть файл

@ -30,6 +30,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
this.BackendHelper = context.ServiceProvider.GetService<IBackendHelper>();
this.PathResolver = this.ServiceProvider.GetService<IPathResolver>();
this.TableDefinitions = WindowsInstallerStandardInternal.GetTableDefinitions();
this.CabbingThreadCount = context.CabbingThreadCount;
@ -54,6 +56,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
private IBackendHelper BackendHelper { get; }
private IPathResolver PathResolver { get; }
private int Codepage { get; }
private int CabbingThreadCount { get; }
@ -241,7 +245,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
// Set generated component guids.
{
var command = new CalculateComponentGuids(this.Messaging, this.BackendHelper, section);
var command = new CalculateComponentGuids(this.Messaging, this.BackendHelper, this.PathResolver, section);
command.Execute();
}
@ -501,7 +505,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
// Process uncompressed files.
if (!this.Messaging.EncounteredError && !this.SuppressLayout && uncompressedFiles.Any())
{
var command = new ProcessUncompressedFilesCommand(section, this.BackendHelper);
var command = new ProcessUncompressedFilesCommand(section, this.BackendHelper, this.PathResolver);
command.Compressed = compressed;
command.FileFacades = uncompressedFiles;
command.LayoutDirectory = layoutDirectory;

Просмотреть файл

@ -6,9 +6,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
using System.Collections.Generic;
using System.IO;
using System.Linq;
using WixToolset.Core.Native;
using WixToolset.Data;
using WixToolset.Data.Tuples;
using WixToolset.Extensibility.Data;
using WixToolset.Extensibility.Services;
/// <summary>
@ -16,10 +16,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
/// </summary>
internal class CalculateComponentGuids
{
internal CalculateComponentGuids(IMessaging messaging, IBackendHelper helper, IntermediateSection section)
internal CalculateComponentGuids(IMessaging messaging, IBackendHelper helper, IPathResolver pathResolver, IntermediateSection section)
{
this.Messaging = messaging;
this.BackendHelper = helper;
this.PathResolver = pathResolver;
this.Section = section;
}
@ -27,12 +28,14 @@ namespace WixToolset.Core.WindowsInstaller.Bind
private IBackendHelper BackendHelper { get; }
private IPathResolver PathResolver { get; }
private IntermediateSection Section { get; }
public void Execute()
{
Dictionary<string, RegistryTuple> registryKeyRows = null;
Dictionary<string, ResolvedDirectory> targetPathsByDirectoryId = null;
Dictionary<string, IResolvedDirectory> targetPathsByDirectoryId = null;
Dictionary<string, string> componentIdGenSeeds = null;
Dictionary<string, List<FileTuple>> filesByComponentId = null;
@ -73,7 +76,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
{
var directories = this.Section.Tuples.OfType<DirectoryTuple>().ToList();
targetPathsByDirectoryId = new Dictionary<string, ResolvedDirectory>(directories.Count);
targetPathsByDirectoryId = new Dictionary<string, IResolvedDirectory>(directories.Count);
// Get the target paths for all directories.
foreach (var directory in directories)
@ -86,7 +89,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
continue;
}
targetPathsByDirectoryId.Add(directory.Id.Id, new ResolvedDirectory(directory.ParentDirectoryRef, directory.Name));
var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(directory.ParentDirectoryRef, directory.Name);
targetPathsByDirectoryId.Add(directory.Id.Id, resolvedDirectory);
}
}
@ -131,7 +135,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
if (fileRow.Id.Id == componentTuple.KeyPath)
{
// calculate the key file's canonical target path
string directoryPath = PathResolver.GetDirectoryPath(targetPathsByDirectoryId, componentIdGenSeeds, componentTuple.DirectoryRef, true);
string directoryPath = this.PathResolver.GetDirectoryPath(targetPathsByDirectoryId, componentIdGenSeeds, componentTuple.DirectoryRef, true);
string fileName = Common.GetName(fileRow.Name, false, true).ToLowerInvariant();
path = Path.Combine(directoryPath, fileName);

Просмотреть файл

@ -8,7 +8,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using WixToolset.Core.Bind;
using WixToolset.Data;
using WixToolset.Data.Tuples;

Просмотреть файл

@ -105,6 +105,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind
this.AddMsiEmbeddedUITuple((MsiEmbeddedUITuple)tuple, output);
break;
case TupleDefinitionType.MsiFileHash:
this.AddMsiFileHashTuple((MsiFileHashTuple)tuple, output);
break;
case TupleDefinitionType.MsiServiceConfig:
this.AddMsiServiceConfigTuple((MsiServiceConfigTuple)tuple, output);
break;
@ -500,6 +504,18 @@ namespace WixToolset.Core.WindowsInstaller.Bind
row[4] = tuple.Source;
}
private void AddMsiFileHashTuple(MsiFileHashTuple tuple, Output output)
{
var table = output.EnsureTable(this.TableDefinitions["MsiFileHash"]);
var row = table.CreateRow(tuple.SourceLineNumbers);
row[0] = tuple.Id.Id;
row[1] = tuple.Options;
row[2] = tuple.HashPart1;
row[3] = tuple.HashPart2;
row[4] = tuple.HashPart3;
row[5] = tuple.HashPart4;
}
private void AddMsiServiceConfigTuple(MsiServiceConfigTuple tuple, Output output)
{
var events = tuple.OnInstall ? WindowsInstallerConstants.MsidbServiceConfigEventInstall : 0;

Просмотреть файл

@ -18,16 +18,19 @@ namespace WixToolset.Core.WindowsInstaller.Bind
/// </summary>
internal class ProcessUncompressedFilesCommand
{
public ProcessUncompressedFilesCommand(IntermediateSection section, IBackendHelper backendHelper)
public ProcessUncompressedFilesCommand(IntermediateSection section, IBackendHelper backendHelper, IPathResolver pathResolver)
{
this.Section = section;
this.BackendHelper = backendHelper;
this.PathResolver = pathResolver;
}
private IntermediateSection Section { get; }
public IBackendHelper BackendHelper { get; }
public IPathResolver PathResolver { get; }
public string DatabasePath { private get; set; }
public IEnumerable<FileFacade> FileFacades { private get; set; }
@ -50,7 +53,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
var trackedFiles = new List<ITrackedFile>();
var directories = new Dictionary<string, ResolvedDirectory>();
var directories = new Dictionary<string, IResolvedDirectory>();
var mediaRows = this.Section.Tuples.OfType<MediaTuple>().ToDictionary(t => t.DiskId);
@ -69,7 +72,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
string sourceName = Common.GetName(directoryRecord.GetString(3), true, this.LongNamesInImage);
directories.Add(directoryRecord.GetString(1), new ResolvedDirectory(directoryRecord.GetString(2), sourceName));
var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(directoryRecord.GetString(2), sourceName);
directories.Add(directoryRecord.GetString(1), resolvedDirectory);
}
}
}
@ -99,7 +104,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
throw new WixException(ErrorMessages.FileIdentifierNotFound(facade.File.SourceLineNumbers, facade.File.Id.Id));
}
relativeFileLayoutPath = PathResolver.GetFileSourcePath(directories, fileRecord[1], fileRecord[2], this.Compressed, this.LongNamesInImage);
relativeFileLayoutPath = this.PathResolver.GetFileSourcePath(directories, fileRecord[1], fileRecord[2], this.Compressed, this.LongNamesInImage);
}
// finally put together the base media layout path and the relative file layout path

Просмотреть файл

@ -1,31 +0,0 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.WindowsInstaller.Bind
{
/// <summary>
/// Structure used for resolved directory information.
/// </summary>
internal struct ResolvedDirectory
{
/// <summary>
/// Constructor for ResolvedDirectory.
/// </summary>
/// <param name="directoryParent">Parent directory.</param>
/// <param name="name">The directory name.</param>
public ResolvedDirectory(string directoryParent, string name)
{
this.DirectoryParent = directoryParent;
this.Name = name;
this.Path = null;
}
/// <summary>The directory parent.</summary>
public string DirectoryParent { get; set; }
/// <summary>The name of this directory.</summary>
public string Name { get; set; }
/// <summary>The path of this directory.</summary>
public string Path { get; set; }
}
}

Просмотреть файл

@ -162,7 +162,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
this.Section.Tuples.Add(facade.Hash);
}
facade.Hash.FileRef = facade.File.Id.Id;
facade.Hash.Options = 0;
facade.Hash.HashPart1 = hash[0];
facade.Hash.HashPart2 = hash[1];

Просмотреть файл

@ -30,10 +30,10 @@ namespace WixToolset.Core.Bind
{
// If the uri to the file that contains the embedded file does not already have embedded files
// being extracted, create the dictionary to track that.
if (!filesWithEmbeddedFiles.TryGetValue(uri, out var extracts))
if (!this.filesWithEmbeddedFiles.TryGetValue(uri, out var extracts))
{
extracts = new SortedList<int, string>();
filesWithEmbeddedFiles.Add(uri, extracts);
this.filesWithEmbeddedFiles.Add(uri, extracts);
}
// If the embedded file is not already tracked in the dictionary of extracts, add it.
@ -52,7 +52,7 @@ namespace WixToolset.Core.Bind
public IEnumerable<ExpectedExtractFile> GetExpectedEmbeddedFiles()
{
foreach (var uriWithExtracts in filesWithEmbeddedFiles)
foreach (var uriWithExtracts in this.filesWithEmbeddedFiles)
{
foreach (var extracts in uriWithExtracts.Value)
{
@ -68,7 +68,7 @@ namespace WixToolset.Core.Bind
public IEnumerable<ExpectedExtractFile> GetExtractFilesForUri(Uri uri)
{
if (!filesWithEmbeddedFiles.TryGetValue(uri, out var extracts))
if (!this.filesWithEmbeddedFiles.TryGetValue(uri, out var extracts))
{
extracts = new SortedList<int, string>();
}

Просмотреть файл

@ -70,11 +70,17 @@ namespace WixToolset.Core.Bind
/// <param name="type">Optional type of source file being resolved.</param>
/// <param name="sourceLineNumbers">Optional source line of source file being resolved.</param>
/// <param name="bindStage">The binding stage used to determine what collection of bind paths will be used</param>
/// <param name="alreadyCheckedPaths">Optional collection of paths already checked.</param>
/// <returns>Should return a valid path for the stream to be imported.</returns>
public string ResolveFile(string source, IntermediateTupleDefinition tupleDefinition, SourceLineNumber sourceLineNumbers, BindStage bindStage)
public string ResolveFile(string source, IntermediateTupleDefinition tupleDefinition, SourceLineNumber sourceLineNumbers, BindStage bindStage, IEnumerable<string> alreadyCheckedPaths = null)
{
var checkedPaths = new List<string>();
if (alreadyCheckedPaths != null)
{
checkedPaths.AddRange(alreadyCheckedPaths);
}
foreach (var extension in this.ResolverExtensions)
{
var resolved = extension.ResolveFile(source, tupleDefinition, sourceLineNumbers, bindStage);

Просмотреть файл

@ -113,7 +113,7 @@ namespace WixToolset.Core.Bind
}
}
public static string ResolveDelayedVariables(SourceLineNumber sourceLineNumbers, string value, IDictionary<string, string> resolutionData)
private static string ResolveDelayedVariables(SourceLineNumber sourceLineNumbers, string value, IDictionary<string, string> resolutionData)
{
var matches = Common.WixVariableRegex.Matches(value);

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core
{
@ -19,6 +19,8 @@ namespace WixToolset.Core
public IEnumerable<BindPath> BindPaths { get; set; }
public string BurnStubPath { get; set; }
public int CabbingThreadCount { get; set; }
public string CabCachePath { get; set; }

Просмотреть файл

@ -122,7 +122,7 @@ namespace WixToolset.Core.CommandLine
}
else
{
this.BindPhase(wixipl, wxls, filterCultures, this.commandLine.CabCachePath, this.commandLine.BindPaths);
this.BindPhase(wixipl, wxls, filterCultures, this.commandLine.CabCachePath, this.commandLine.BindPaths, this.commandLine.BurnStubPath);
}
}
}
@ -257,7 +257,7 @@ namespace WixToolset.Core.CommandLine
return linker.Link(context);
}
private void BindPhase(Intermediate output, IEnumerable<Localization> localizations, IEnumerable<string> filterCultures, string cabCachePath, IEnumerable<IBindPath> bindPaths)
private void BindPhase(Intermediate output, IEnumerable<Localization> localizations, IEnumerable<string> filterCultures, string cabCachePath, IEnumerable<IBindPath> bindPaths, string burnStubPath)
{
var intermediateFolder = this.IntermediateFolder;
if (String.IsNullOrEmpty(intermediateFolder))
@ -290,6 +290,7 @@ namespace WixToolset.Core.CommandLine
{
var context = this.ServiceProvider.GetService<IBindContext>();
//context.CabbingThreadCount = this.CabbingThreadCount;
context.BurnStubPath = burnStubPath;
context.CabCachePath = cabCachePath;
context.Codepage = resolveResult.Codepage;
//context.DefaultCompressionLevel = this.DefaultCompressionLevel;
@ -399,6 +400,8 @@ namespace WixToolset.Core.CommandLine
public List<IBindPath> BindPaths { get; } = new List<IBindPath>();
public string BurnStubPath { get; private set; }
public string CabCachePath { get; private set; }
public List<string> Cultures { get; } = new List<string>();
@ -480,6 +483,10 @@ namespace WixToolset.Core.CommandLine
}
break;
}
case "burnstub":
this.BurnStubPath = parser.GetNextArgumentOrError(arg);
return true;
case "cc":
this.CabCachePath = parser.GetNextArgumentOrError(arg);
return true;

Просмотреть файл

@ -818,7 +818,7 @@ namespace WixToolset.Core
{
this.Core.AddTuple(new IconTuple(sourceLineNumbers, id)
{
Data = sourceFile
Data = new IntermediateFieldPathValue { Path = sourceFile }
});
}

Просмотреть файл

@ -9,6 +9,7 @@ namespace WixToolset.Core
using System.IO;
using System.Xml.Linq;
using WixToolset.Data;
using WixToolset.Data.Burn;
using WixToolset.Data.Tuples;
using WixToolset.Extensibility;
@ -17,15 +18,9 @@ namespace WixToolset.Core
/// </summary>
internal partial class Compiler : ICompiler
{
public static readonly Identifier BurnUXContainerId = new Identifier(AccessModifier.Private, "WixUXContainer");
public static readonly Identifier BurnDefaultAttachedContainerId = new Identifier(AccessModifier.Private, "WixAttachedContainer");
public static readonly Identifier BundleLayoutOnlyPayloads = new Identifier(AccessModifier.Private, "BundleLayoutOnlyPayloads");
// The following constants must stay in sync with src\burn\engine\core.h
private const string BURN_BUNDLE_NAME = "WixBundleName";
private const string BURN_BUNDLE_ORIGINAL_SOURCE = "WixBundleOriginalSource";
private const string BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER = "WixBundleOriginalSourceFolder";
private const string BURN_BUNDLE_LAST_USED_SOURCE = "WixBundleLastUsedSource";
private static readonly Identifier BurnUXContainerId = new Identifier(AccessModifier.Private, BurnConstants.BurnUXContainerName);
private static readonly Identifier BurnDefaultAttachedContainerId = new Identifier(AccessModifier.Private, BurnConstants.BurnDefaultAttachedContainerName);
private static readonly Identifier BundleLayoutOnlyPayloads = new Identifier(AccessModifier.Private, BurnConstants.BundleLayoutOnlyPayloadsName);
/// <summary>
/// Parses an ApprovedExeForElevation element.
@ -78,11 +73,11 @@ namespace WixToolset.Core
this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key"));
}
var attributes = BundleApprovedExeForElevationAttributes.None;
var attributes = WixApprovedExeForElevationAttributes.None;
if (win64 == YesNoType.Yes)
{
attributes |= BundleApprovedExeForElevationAttributes.Win64;
attributes |= WixApprovedExeForElevationAttributes.Win64;
}
this.Core.ParseForExtensionElements(node);
@ -92,7 +87,7 @@ namespace WixToolset.Core
var tuple = new WixApprovedExeForElevationTuple(sourceLineNumbers, id)
{
Key = key,
Value = valueName,
ValueName = valueName,
Attributes = attributes
};
@ -110,8 +105,7 @@ namespace WixToolset.Core
string copyright = null;
string aboutUrl = null;
var compressed = YesNoDefaultType.Default;
var disableModify = -1;
var disableRemove = YesNoType.NotSet;
WixBundleAttributes attributes = 0;
string helpTelephone = null;
string helpUrl = null;
string manufacturer = null;
@ -152,13 +146,12 @@ namespace WixToolset.Core
switch (value)
{
case "button":
disableModify = 2;
attributes |= WixBundleAttributes.SingleChangeUninstallButton;
break;
case "yes":
disableModify = 1;
attributes |= WixBundleAttributes.DisableModify;
break;
case "no":
disableModify = 0;
break;
default:
this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, value, "button", "yes", "no"));
@ -166,10 +159,10 @@ namespace WixToolset.Core
}
break;
case "DisableRemove":
disableRemove = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "DisableRepair":
this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName));
if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= WixBundleAttributes.DisableRemove;
}
break;
case "HelpTelephone":
helpTelephone = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
@ -239,13 +232,13 @@ namespace WixToolset.Core
if (String.IsNullOrEmpty(name))
{
logVariablePrefixAndExtension = String.Concat("WixBundleLog:Setup.log");
logVariablePrefixAndExtension = String.Concat("WixBundleLog:Setup:.log");
}
else
{
// Ensure only allowable path characters are in "name" (and change spaces to underscores).
fileSystemSafeBundleName = CompilerCore.MakeValidLongFileName(name.Replace(' ', '_'), "_");
logVariablePrefixAndExtension = String.Concat("WixBundleLog:", fileSystemSafeBundleName, ".log");
logVariablePrefixAndExtension = String.Concat("WixBundleLog:", fileSystemSafeBundleName, ":.log");
}
this.activeName = String.IsNullOrEmpty(name) ? Common.GenerateGuid() : name;
@ -351,6 +344,37 @@ namespace WixToolset.Core
if (!this.Core.EncounteredError)
{
var tuple = new WixBundleTuple(sourceLineNumbers)
{
UpgradeCode = upgradeCode,
Version = version,
Copyright = copyright,
Name = name,
Manufacturer = manufacturer,
Attributes = attributes,
AboutUrl = aboutUrl,
HelpUrl = helpUrl,
HelpTelephone = helpTelephone,
UpdateUrl = updateUrl,
Compressed = YesNoDefaultType.Yes == compressed ? true : YesNoDefaultType.No == compressed ? (bool?)false : null,
IconSourceFile = iconSourceFile,
SplashScreenSourceFile = splashScreenSourceFile,
Condition = condition,
Tag = tag,
Platform = this.CurrentPlatform,
ParentName = parentName,
};
if (!String.IsNullOrEmpty(logVariablePrefixAndExtension))
{
var split = logVariablePrefixAndExtension.Split(':');
tuple.LogPathVariable = split[0];
tuple.LogPrefix = split[1];
tuple.LogExtension = split[2];
}
this.Core.AddTuple(tuple);;
if (null != upgradeCode)
{
this.Core.AddTuple(new WixRelatedBundleTuple(sourceLineNumbers)
@ -360,64 +384,32 @@ namespace WixToolset.Core
});
}
this.Core.AddTuple(new WixBundleContainerTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, Compiler.BurnDefaultAttachedContainerId))
this.Core.AddTuple(new WixBundleContainerTuple(sourceLineNumbers, Compiler.BurnDefaultAttachedContainerId)
{
Name = "bundle-attached.cab",
Type = ContainerType.Attached
});
var bundleTuple = this.Core.CreateTuple(sourceLineNumbers, TupleDefinitionType.WixBundle);
bundleTuple.Set(0, version);
bundleTuple.Set(1, copyright);
bundleTuple.Set(2, name);
bundleTuple.Set(3, aboutUrl);
if (-1 != disableModify)
{
bundleTuple.Set(4, disableModify);
}
if (YesNoType.NotSet != disableRemove)
{
bundleTuple.Set(5, (YesNoType.Yes == disableRemove) ? 1 : 0);
}
// row.Set(6] - (deprecated) "disable repair"
bundleTuple.Set(7, helpTelephone);
bundleTuple.Set(8, helpUrl);
bundleTuple.Set(9, manufacturer);
bundleTuple.Set(10, updateUrl);
if (YesNoDefaultType.Default != compressed)
{
bundleTuple.Set(11, (YesNoDefaultType.Yes == compressed) ? 1 : 0);
}
bundleTuple.Set(12, logVariablePrefixAndExtension);
bundleTuple.Set(13, iconSourceFile);
bundleTuple.Set(14, splashScreenSourceFile);
bundleTuple.Set(15, condition);
bundleTuple.Set(16, tag);
bundleTuple.Set(17, this.CurrentPlatform.ToString());
bundleTuple.Set(18, parentName);
bundleTuple.Set(19, upgradeCode);
// Ensure that the bundle stores the well-known persisted values.
this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, Compiler.BURN_BUNDLE_NAME))
this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, BurnConstants.BURN_BUNDLE_NAME))
{
Hidden = false,
Persisted = true
});
this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, Compiler.BURN_BUNDLE_ORIGINAL_SOURCE))
this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, BurnConstants.BURN_BUNDLE_ORIGINAL_SOURCE))
{
Hidden = false,
Persisted = true
});
this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, Compiler.BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER))
this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, BurnConstants.BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER))
{
Hidden = false,
Persisted = true
});
this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, Compiler.BURN_BUNDLE_LAST_USED_SOURCE))
this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, BurnConstants.BURN_BUNDLE_LAST_USED_SOURCE))
{
Hidden = false,
Persisted = true
@ -473,7 +465,7 @@ namespace WixToolset.Core
this.Core.ParseForExtensionElements(node);
return YesNoType.Yes == disableLog ? null : String.Concat(variable, ":", logPrefix, logExtension);
return YesNoType.Yes == disableLog ? null : String.Join(":", variable, logPrefix, logExtension);
}
/// <summary>
@ -1126,9 +1118,9 @@ namespace WixToolset.Core
tuple = new WixBundlePayloadTuple(sourceLineNumbers, id)
{
Name = String.IsNullOrEmpty(name) ? Path.GetFileName(sourceFile) : name,
SourceFile = sourceFile,
SourceFile = new IntermediateFieldPathValue { Path = sourceFile },
DownloadUrl = downloadUrl,
Compressed = compressed,
Compressed = (compressed == YesNoDefaultType.Yes) ? true : (compressed == YesNoDefaultType.No) ? (bool?)false : null,
UnresolvedSourceFile = sourceFile, // duplicate of sourceFile but in a string column so it won't get resolved to a full path during binding.
DisplayName = displayName,
Description = description,
@ -1665,14 +1657,12 @@ namespace WixToolset.Core
var vital = YesNoType.Yes;
string installCommand = null;
string repairCommand = null;
var repairable = YesNoType.NotSet;
string uninstallCommand = null;
var perMachine = YesNoDefaultType.NotSet;
string detectCondition = null;
string protocol = null;
var installSize = CompilerConstants.IntegerNotSet;
string msuKB = null;
var suppressLooseFilePayloadGeneration = YesNoType.NotSet;
var enableSignatureVerification = YesNoType.No;
var compressed = YesNoDefaultType.Default;
var displayInternalUI = YesNoType.NotSet;
@ -1779,7 +1769,6 @@ namespace WixToolset.Core
break;
case "RepairCommand":
repairCommand = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty);
repairable = YesNoType.Yes;
allowed = (packageType == WixBundlePackageType.Exe);
break;
case "UninstallCommand":
@ -1808,11 +1797,6 @@ namespace WixToolset.Core
case "Compressed":
compressed = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
break;
case "SuppressLooseFilePayloadGeneration":
this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName));
suppressLooseFilePayloadGeneration = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
allowed = (packageType == WixBundlePackageType.Msi);
break;
case "EnableSignatureVerification":
enableSignatureVerification = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
@ -2076,7 +2060,7 @@ namespace WixToolset.Core
case WixBundlePackageType.Exe:
this.Core.AddTuple(new WixBundleExePackageTuple(sourceLineNumbers, id)
{
Attributes = (YesNoType.Yes == repairable) ? WixBundleExePackageAttributes.Repairable : 0,
Attributes = WixBundleExePackageAttributes.None,
DetectCondition = detectCondition,
InstallCommand = installCommand,
RepairCommand = repairCommand,
@ -2090,7 +2074,6 @@ namespace WixToolset.Core
msiAttributes |= (YesNoType.Yes == displayInternalUI) ? WixBundleMsiPackageAttributes.DisplayInternalUI : 0;
msiAttributes |= (YesNoType.Yes == enableFeatureSelection) ? WixBundleMsiPackageAttributes.EnableFeatureSelection : 0;
msiAttributes |= (YesNoType.Yes == forcePerMachine) ? WixBundleMsiPackageAttributes.ForcePerMachine : 0;
msiAttributes |= (YesNoType.Yes == suppressLooseFilePayloadGeneration) ? WixBundleMsiPackageAttributes.SuppressLooseFilePayloadGeneration : 0;
this.Core.AddTuple(new WixBundleMsiPackageTuple(sourceLineNumbers, id)
{
@ -2458,9 +2441,9 @@ namespace WixToolset.Core
if (!this.Core.EncounteredError)
{
var tuple = new WixBundleMsiPropertyTuple(sourceLineNumbers)
var tuple = new WixBundleMsiPropertyTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, packageId, name))
{
WixBundlePackageRef = packageId,
PackageRef = packageId,
Name = name,
Value = value
};
@ -2514,10 +2497,10 @@ namespace WixToolset.Core
if (!this.Core.EncounteredError)
{
this.Core.AddTuple(new WixBundleSlipstreamMspTuple(sourceLineNumbers)
this.Core.AddTuple(new WixBundleSlipstreamMspTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, packageId, id))
{
WixBundlePackageRef = packageId,
MspWixBundlePackageRef = id
TargetPackageRef = packageId,
MspPackageRef = id
});
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.ExtensibilityServices
{
@ -40,6 +40,15 @@ namespace WixToolset.Core.ExtensibilityServices
return Uuid.NewUuid(namespaceGuid, value).ToString("B").ToUpperInvariant();
}
public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name)
{
return new ResolvedDirectory
{
DirectoryParent = directoryParent,
Name = name
};
}
public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null)
{
return new TrackedFile(path, type, sourceLineNumbers);

Просмотреть файл

@ -1,24 +1,18 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.WindowsInstaller.Bind
namespace WixToolset.Core.ExtensibilityServices
{
using System;
using System.Collections.Generic;
using System.IO;
using WixToolset.Data;
using WixToolset.Data.WindowsInstaller;
using WixToolset.Extensibility.Data;
using WixToolset.Extensibility.Services;
internal static class PathResolver
internal class PathResolver : IPathResolver
{
/// <summary>
/// Get the source path of a directory.
/// </summary>
/// <param name="directories">All cached directories.</param>
/// <param name="componentIdGenSeeds">Hash table of Component GUID generation seeds indexed by directory id.</param>
/// <param name="directory">Directory identifier.</param>
/// <param name="canonicalize">Canonicalize the path for standard directories.</param>
/// <returns>Source path of a directory.</returns>
public static string GetDirectoryPath(Dictionary<string, ResolvedDirectory> directories, Dictionary<string, string> componentIdGenSeeds, string directory, bool canonicalize)
public string GetDirectoryPath(Dictionary<string, IResolvedDirectory> directories, Dictionary<string, string> componentIdGenSeeds, string directory, bool canonicalize)
{
if (!directories.TryGetValue(directory, out var resolvedDirectory))
{
@ -51,7 +45,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
}
else
{
string parentPath = GetDirectoryPath(directories, componentIdGenSeeds, resolvedDirectory.DirectoryParent, canonicalize);
var parentPath = this.GetDirectoryPath(directories, componentIdGenSeeds, resolvedDirectory.DirectoryParent, canonicalize);
if (null != resolvedDirectory.Name)
{
@ -68,18 +62,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
return resolvedDirectory.Path;
}
/// <summary>
/// Gets the source path of a file.
/// </summary>
/// <param name="directories">All cached directories in <see cref="ResolvedDirectory"/>.</param>
/// <param name="directoryId">Parent directory identifier.</param>
/// <param name="fileName">File name (in long|source format).</param>
/// <param name="compressed">Specifies the package is compressed.</param>
/// <param name="useLongName">Specifies the package uses long file names.</param>
/// <returns>Source path of file relative to package directory.</returns>
public static string GetFileSourcePath(Dictionary<string, ResolvedDirectory> directories, string directoryId, string fileName, bool compressed, bool useLongName)
public string GetFileSourcePath(Dictionary<string, IResolvedDirectory> directories, string directoryId, string fileName, bool compressed, bool useLongName)
{
string fileSourcePath = Common.GetName(fileName, true, useLongName);
var fileSourcePath = Common.GetName(fileName, true, useLongName);
if (compressed)
{
@ -90,7 +75,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
{
// Get the relative path of where we want the file to be layed out as specified
// in the Directory table.
string directoryPath = PathResolver.GetDirectoryPath(directories, null, directoryId, false);
var directoryPath = this.GetDirectoryPath(directories, null, directoryId, false);
fileSourcePath = Path.Combine(directoryPath, fileSourcePath);
}

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.ExtensibilityServices
{
using WixToolset.Extensibility.Data;
internal class ResolvedDirectory : IResolvedDirectory
{
public string DirectoryParent { get; set; }
public string Name { get; set; }
public string Path { get; set; }
}
}

Просмотреть файл

@ -1,8 +1,7 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Core.ExtensibilityServices
{
using System;
using System.Linq;
using WixToolset.Data;
using WixToolset.Data.WindowsInstaller;
@ -10,14 +9,9 @@ namespace WixToolset.Core.ExtensibilityServices
internal class WindowsInstallerBackendHelper : IWindowsInstallerBackendHelper
{
public WindowsInstallerBackendHelper(IServiceProvider serviceProvider)
{
this.ServiceProvider = serviceProvider;
}
public bool TryAddTupleToOutputMatchingTableDefinitions(IntermediateTuple tuple, Output output, TableDefinition[] tableDefinitions) => this.TryAddTupleToOutputMatchingTableDefinitions(tuple, output, tableDefinitions, false);
private IServiceProvider ServiceProvider { get; }
public bool TryAddTupleToOutputMatchingTableDefinitions(IntermediateTuple tuple, Output output, TableDefinition[] tableDefinitions)
public bool TryAddTupleToOutputMatchingTableDefinitions(IntermediateTuple tuple, Output output, TableDefinition[] tableDefinitions, bool columnZeroIsId)
{
var tableDefinition = tableDefinitions.FirstOrDefault(t => t.Name == tuple.Definition.Name);
@ -28,6 +22,14 @@ namespace WixToolset.Core.ExtensibilityServices
var table = output.EnsureTable(tableDefinition);
var row = table.CreateRow(tuple.SourceLineNumbers);
var rowOffset = 0;
if (columnZeroIsId)
{
row[0] = tuple.Id.Id;
rowOffset = 1;
}
for (var i = 0; i < tuple.Fields.Length; ++i)
{
if (i < tableDefinition.Columns.Length)
@ -36,13 +38,13 @@ namespace WixToolset.Core.ExtensibilityServices
switch (column.Type)
{
case ColumnType.Number:
row[i] = tuple.AsNumber(i);
break;
case ColumnType.Number:
row[i + rowOffset] = column.Nullable ? tuple.AsNullableNumber(i) : tuple.AsNumber(i);
break;
default:
row[i] = tuple.AsString(i);
break;
default:
row[i + rowOffset] = tuple.AsString(i);
break;
}
}
}

Просмотреть файл

@ -12,19 +12,19 @@ namespace WixToolset.Core.Link
using WixToolset.Data;
using WixToolset.Data.Tuples;
using WixToolset.Extensibility.Services;
using WixToolset.Data.Burn;
/// <summary>
/// Grouping and Ordering class of the WiX toolset.
/// </summary>
internal class WixGroupingOrdering
{
private readonly IMessaging messageHandler;
private readonly IMessaging Messaging;
private List<string> groupTypes;
private List<string> itemTypes;
private ItemCollection items;
private readonly List<int> rowsUsed;
private bool loaded;
private bool encounteredError;
/// <summary>
/// Creates a WixGroupingOrdering object.
@ -36,11 +36,10 @@ namespace WixToolset.Core.Link
public WixGroupingOrdering(IntermediateSection entrySections, IMessaging messageHandler)
{
this.EntrySection = entrySections;
this.messageHandler = messageHandler;
this.Messaging = messageHandler;
this.rowsUsed = new List<int>();
this.loaded = false;
this.encounteredError = false;
}
private IntermediateSection EntrySection { get; }
@ -71,7 +70,7 @@ namespace WixToolset.Core.Link
Debug.Assert(this.groupTypes.Contains(parentTypeString));
this.CreateOrderedList(parentTypeString, parentId, out var orderedItems);
if (this.encounteredError)
if (this.Messaging.EncounteredError)
{
return;
}
@ -95,7 +94,7 @@ namespace WixToolset.Core.Link
Debug.Assert(this.groupTypes.Contains(parentTypeString));
this.LoadFlattenOrderGroups();
if (this.encounteredError)
if (this.Messaging.EncounteredError)
{
return;
}
@ -127,14 +126,14 @@ namespace WixToolset.Core.Link
orderedItems = null;
this.LoadFlattenOrderGroups();
if (this.encounteredError)
if (this.Messaging.EncounteredError)
{
return;
}
if (!this.items.TryGetValue(parentType, parentId, out var parentItem))
{
this.messageHandler.Write(ErrorMessages.IdentifierNotFound(parentType, parentId));
this.Messaging.Write(ErrorMessages.IdentifierNotFound(parentType, parentId));
return;
}
@ -216,7 +215,7 @@ namespace WixToolset.Core.Link
// dependencies. Group references, however, we can check directly.
this.FindCircularGroupReferences();
if (!this.encounteredError)
if (!this.Messaging.EncounteredError)
{
this.FlattenGroups();
this.FlattenOrdering();
@ -304,7 +303,7 @@ namespace WixToolset.Core.Link
if (this.FindCircularGroupReference(item, item, itemsSeen, out circularReference))
{
itemsInKnownLoops.Add(itemsSeen);
this.messageHandler.Write(ErrorMessages.ReferenceLoopDetected(item.Row.SourceLineNumbers, circularReference));
this.Messaging.Write(ErrorMessages.ReferenceLoopDetected(item.Row.SourceLineNumbers, circularReference));
}
}
}
@ -376,12 +375,12 @@ namespace WixToolset.Core.Link
if (!this.items.TryGetValue(rowItemType, rowItemName, out var item))
{
this.messageHandler.Write(ErrorMessages.IdentifierNotFound(rowItemType, rowItemName));
this.Messaging.Write(ErrorMessages.IdentifierNotFound(rowItemType, rowItemName));
}
if (!this.items.TryGetValue(rowDependsOnType, rowDependsOnName, out var dependsOn))
{
this.messageHandler.Write(ErrorMessages.IdentifierNotFound(rowDependsOnType, rowDependsOnName));
this.Messaging.Write(ErrorMessages.IdentifierNotFound(rowDependsOnType, rowDependsOnName));
}
if (null == item || null == dependsOn)
@ -389,7 +388,7 @@ namespace WixToolset.Core.Link
continue;
}
item.AddAfter(dependsOn, this.messageHandler);
item.AddAfter(dependsOn, this.Messaging);
}
}
@ -404,12 +403,12 @@ namespace WixToolset.Core.Link
// ordering.
foreach (Item item in this.items)
{
item.PropagateAfterToChildItems(this.messageHandler);
item.PropagateAfterToChildItems(this.Messaging);
}
foreach (Item item in this.items)
{
item.FlattenAfters(this.messageHandler);
item.FlattenAfters(this.Messaging);
}
}
@ -668,7 +667,7 @@ namespace WixToolset.Core.Link
{
if (String.Equals(nameof(ComplexReferenceChildType.Package), this.Type, StringComparison.Ordinal) ||
(String.Equals(nameof(ComplexReferenceParentType.Container), this.Type, StringComparison.Ordinal) &&
!String.Equals(Compiler.BurnUXContainerId.Id, this.Id, StringComparison.Ordinal)))
!String.Equals(BurnConstants.BurnUXContainerName, this.Id, StringComparison.Ordinal)))
{
return false;
}

Просмотреть файл

@ -24,7 +24,8 @@ namespace WixToolset.Core
this.AddService((provider, singletons) => AddSingleton<IParseHelper>(singletons, new ParseHelper(provider)));
this.AddService((provider, singletons) => AddSingleton<IPreprocessHelper>(singletons, new PreprocessHelper(provider)));
this.AddService((provider, singletons) => AddSingleton<IBackendHelper>(singletons, new BackendHelper(provider)));
this.AddService((provider, singletons) => AddSingleton<IWindowsInstallerBackendHelper>(singletons, new WindowsInstallerBackendHelper(provider)));
this.AddService((provider, singletons) => AddSingleton<IPathResolver>(singletons, new PathResolver()));
this.AddService((provider, singletons) => AddSingleton<IWindowsInstallerBackendHelper>(singletons, new WindowsInstallerBackendHelper()));
// Transients.
this.AddService<ICommandLineArguments>((provider, singletons) => new CommandLineArguments(provider));
@ -47,6 +48,7 @@ namespace WixToolset.Core
this.AddService<IDecompileResult>((provider, singletons) => new DecompileResult());
this.AddService<IIncludedFile>((provider, singletons) => new IncludedFile());
this.AddService<IPreprocessResult>((provider, singletons) => new PreprocessResult());
this.AddService<IResolvedDirectory>((provider, singletons) => new ResolvedDirectory());
this.AddService<IResolveFileResult>((provider, singletons) => new ResolveFileResult());
this.AddService<IResolveResult>((provider, singletons) => new ResolveResult());
this.AddService<IResolvedCabinet>((provider, singletons) => new ResolvedCabinet());

Просмотреть файл

@ -0,0 +1,52 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolsetTest.CoreIntegration
{
using System.IO;
using System.Linq;
using WixBuildTools.TestSupport;
using WixToolset.Core.TestPackage;
using WixToolset.Data;
using WixToolset.Data.Tuples;
using Xunit;
public class BundleFixture
{
[Fact]
public void CanBuildSimpleBundle()
{
var burnStubPath = TestData.Get(@"TestData\.Data\burn.exe");
var folder = TestData.Get(@"TestData\SimpleBundle");
using (var fs = new DisposableFileSystem())
{
var baseFolder = fs.GetFolder();
var intermediateFolder = Path.Combine(baseFolder, "obj");
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,
"-burnStub", burnStubPath,
"-o", Path.Combine(baseFolder, @"bin\test.exe")
});
result.AssertSuccess();
Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.exe")));
#if TODO
Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb")));
#endif
var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"test.wir"));
var section = intermediate.Sections.Single();
var msiTuple = section.Tuples.OfType<WixBundlePackageTuple>().Single();
Assert.Equal("test.msi", msiTuple.Id.Id );
}
}
}
}

Двоичные данные
src/test/WixToolsetTest.CoreIntegration/TestData/.Data/burn.exe Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains the declaration of all the localizable strings.
-->
<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
<String Id="BundleName">~TestBundle</String>
</WixLocalization>

Просмотреть файл

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Bundle Name="!(loc.BundleName)" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
<BootstrapperApplication SourceFile="fakeba.dll" />
<Chain>
<MsiPackage SourceFile="test.msi">
<MsiProperty Name="TEST" Value="1" />
</MsiPackage>
</Chain>
</Bundle>
</Wix>

Просмотреть файл

@ -0,0 +1 @@
This is Shared.dll.

Просмотреть файл

@ -0,0 +1 @@
This is test.txt

Просмотреть файл

@ -0,0 +1 @@
This is a fakeba.dll

Двоичный файл не отображается.

Просмотреть файл

@ -13,6 +13,7 @@
</PropertyGroup>
<ItemGroup>
<Content Include="TestData\.Data\burn.exe" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\AppSearch\ComponentSearch.wxs" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\AppSearch\DirectorySearch.wxs" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\AppSearch\FileSearch.wxs" CopyToOutputDirectory="PreserveNewest" />
@ -31,6 +32,9 @@
<Content Include="TestData\ReserveCost\ReserveCost.wxs" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\ServiceInstall\OwnProcess.wxs" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\Shortcut\ShortcutProperty.wxs" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\SimpleBundle\data\fakeba.dll" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\SimpleBundle\data\MsiPackage\Shared.dll" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\SimpleBundle\data\MsiPackage\test.txt" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\SimpleModule\data\test.txt" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\SimpleModule\Module.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\SimpleModule\Module.wxs" CopyToOutputDirectory="PreserveNewest" />
@ -66,6 +70,9 @@
<Content Include="TestData\SetProperty\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\SetProperty\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\SetProperty\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\SimpleBundle\data\test.msi" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\SimpleBundle\Bundle.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\SimpleBundle\Bundle.wxs" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\SingleFile\data\test.txt" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\SingleFile\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
<Content Include="TestData\SingleFile\Package.wxs" CopyToOutputDirectory="PreserveNewest" />