// 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.Mba.Core
{
using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.XPath;
///
/// The type of package.
///
public enum PackageType
{
///
/// Invalid type.
///
Unknown,
///
/// ExePackage
///
Exe,
///
/// MsiPackage
///
Msi,
///
/// MspPackage
///
Msp,
///
/// MsuPackage
///
Msu,
///
/// Related bundle of type Upgrade
///
UpgradeBundle,
///
/// Related bundle of type Addon
///
AddonBundle,
///
/// Related bundle of type Patch
///
PatchBundle,
///
/// Related bundle of type Update
///
UpdateBundle,
///
/// BundlePackage
///
ChainBundle,
}
///
/// Metadata for BAs like WixInternalUIBootstrapperApplication that only support one main package.
///
public enum PrimaryPackageType
{
///
/// Not a primary package.
///
None,
///
/// The default package if no architecture specific package is available for the current architecture.
///
Default,
///
/// The package to use on x86 machines.
///
X86,
///
/// The package to use on x64 machines.
///
X64,
///
/// The package to use on ARM64 machines.
///
ARM64,
}
///
/// Default implementation of .
///
public class PackageInfo : IPackageInfo
{
///
public string Id { get; internal set; }
///
public string DisplayName { get; internal set; }
///
public string Description { get; internal set; }
///
public PackageType Type { get; internal set; }
///
public bool Permanent { get; internal set; }
///
public bool Vital { get; internal set; }
///
public string DisplayInternalUICondition { get; internal set; }
///
public string ProductCode { get; internal set; }
///
public string UpgradeCode { get; internal set; }
///
public string Version { get; internal set; }
///
public string InstallCondition { get; internal set; }
///
public string RepairCondition { get; internal set; }
///
public BOOTSTRAPPER_CACHE_TYPE CacheType { get; internal set; }
///
public bool PrereqPackage { get; internal set; }
///
public string PrereqLicenseFile { get; internal set; }
///
public string PrereqLicenseUrl { get; internal set; }
///
public PrimaryPackageType PrimaryPackageType { get; internal set; }
///
public object CustomData { get; set; }
internal PackageInfo() { }
///
/// Parse packages from BootstrapperApplicationData.xml.
///
/// The root node.
/// A dictionary of the packages by Id.
public static IDictionary ParsePackagesFromXml(XPathNavigator root)
{
var packagesById = new Dictionary();
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(root.NameTable);
namespaceManager.AddNamespace("p", BootstrapperApplicationData.XMLNamespace);
XPathNodeIterator nodes = root.Select("/p:BootstrapperApplicationData/p:WixPackageProperties", namespaceManager);
foreach (XPathNavigator node in nodes)
{
var package = new PackageInfo();
string id = BootstrapperApplicationData.GetAttribute(node, "Package");
if (id == null)
{
throw new Exception("Failed to get package identifier for package.");
}
package.Id = id;
package.DisplayName = BootstrapperApplicationData.GetAttribute(node, "DisplayName");
package.Description = BootstrapperApplicationData.GetAttribute(node, "Description");
PackageType? packageType = GetPackageTypeAttribute(node, "PackageType");
if (!packageType.HasValue)
{
throw new Exception("Failed to get package type for package.");
}
package.Type = packageType.Value;
bool? permanent = BootstrapperApplicationData.GetYesNoAttribute(node, "Permanent");
if (!permanent.HasValue)
{
throw new Exception("Failed to get permanent settings for package.");
}
package.Permanent = permanent.Value;
bool? vital = BootstrapperApplicationData.GetYesNoAttribute(node, "Vital");
if (!vital.HasValue)
{
throw new Exception("Failed to get vital setting for package.");
}
package.Vital = vital.Value;
package.ProductCode = BootstrapperApplicationData.GetAttribute(node, "ProductCode");
package.UpgradeCode = BootstrapperApplicationData.GetAttribute(node, "UpgradeCode");
package.Version = BootstrapperApplicationData.GetAttribute(node, "Version");
package.InstallCondition = BootstrapperApplicationData.GetAttribute(node, "InstallCondition");
package.RepairCondition = BootstrapperApplicationData.GetAttribute(node, "RepairCondition");
BOOTSTRAPPER_CACHE_TYPE? cacheType = GetCacheTypeAttribute(node, "Cache");
if (!cacheType.HasValue)
{
throw new Exception("Failed to get cache type for package.");
}
package.CacheType = cacheType.Value;
packagesById.Add(package.Id, package);
}
ParseBalPackageInfoFromXml(root, namespaceManager, packagesById);
return packagesById;
}
///
/// Parse the cache type attribute.
///
/// Package node
/// Attribute name
/// The cache type
public static BOOTSTRAPPER_CACHE_TYPE? GetCacheTypeAttribute(XPathNavigator node, string attributeName)
{
string attributeValue = BootstrapperApplicationData.GetAttribute(node, attributeName);
if (attributeValue == null)
{
return null;
}
if (attributeValue.Equals("keep", StringComparison.InvariantCulture))
{
return BOOTSTRAPPER_CACHE_TYPE.Keep;
}
else if (attributeValue.Equals("force", StringComparison.InvariantCulture))
{
return BOOTSTRAPPER_CACHE_TYPE.Force;
}
else
{
return BOOTSTRAPPER_CACHE_TYPE.Remove;
}
}
///
/// Parse the package type attribute
///
/// Package node
/// Attribute name
/// The package type
public static PackageType? GetPackageTypeAttribute(XPathNavigator node, string attributeName)
{
string attributeValue = BootstrapperApplicationData.GetAttribute(node, attributeName);
if (attributeValue == null)
{
return null;
}
if (attributeValue.Equals("Bundle", StringComparison.InvariantCulture))
{
return PackageType.ChainBundle;
}
else if (attributeValue.Equals("Exe", StringComparison.InvariantCulture))
{
return PackageType.Exe;
}
else if (attributeValue.Equals("Msi", StringComparison.InvariantCulture))
{
return PackageType.Msi;
}
else if (attributeValue.Equals("Msp", StringComparison.InvariantCulture))
{
return PackageType.Msp;
}
else if (attributeValue.Equals("Msu", StringComparison.InvariantCulture))
{
return PackageType.Msu;
}
else
{
return PackageType.Unknown;
}
}
///
/// Create from a related bundle.
///
/// Package id
/// Relation type
/// Whether the related bundle is per-machine
/// The related bundle's version
/// The package info
public static IPackageInfo GetRelatedBundleAsPackage(string id, RelationType relationType, bool perMachine, string version)
{
PackageInfo package = new PackageInfo();
package.Id = id;
package.Version = version;
switch (relationType)
{
case RelationType.Addon:
package.Type = PackageType.AddonBundle;
break;
case RelationType.Patch:
package.Type = PackageType.PatchBundle;
break;
case RelationType.Upgrade:
package.Type = PackageType.UpgradeBundle;
break;
default:
throw new Exception(String.Format("Unknown related bundle type: {0}", relationType));
}
return package;
}
///
/// Create from an update bundle.
///
/// Package id
/// The package info
public static IPackageInfo GetUpdateBundleAsPackage(string id)
{
PackageInfo package = new PackageInfo();
package.Id = id;
package.Type = PackageType.UpdateBundle;
return package;
}
internal static void ParseBalPackageInfoFromXml(XPathNavigator root, XmlNamespaceManager namespaceManager, Dictionary packagesById)
{
XPathNodeIterator nodes = root.Select("/p:BootstrapperApplicationData/p:WixBalPackageInfo", namespaceManager);
foreach (XPathNavigator node in nodes)
{
string id = BootstrapperApplicationData.GetAttribute(node, "PackageId");
if (id == null)
{
throw new Exception("Failed to get package identifier for WixBalPackageInfo.");
}
if (!packagesById.TryGetValue(id, out var ipackage))
{
throw new Exception(String.Format("Failed to find package specified in WixBalPackageInfo: {0}", id));
}
var package = (PackageInfo)ipackage;
package.DisplayInternalUICondition = BootstrapperApplicationData.GetAttribute(node, "DisplayInternalUICondition");
}
nodes = root.Select("/p:BootstrapperApplicationData/p:WixPrereqInformation", namespaceManager);
foreach (XPathNavigator node in nodes)
{
string id = BootstrapperApplicationData.GetAttribute(node, "PackageId");
if (id == null)
{
throw new Exception("Failed to get package identifier for WixPrereqInformation.");
}
if (!packagesById.TryGetValue(id, out var ipackage))
{
throw new Exception(String.Format("Failed to find package specified in WixPrereqInformation: {0}", id));
}
var package = (PackageInfo)ipackage;
package.PrereqPackage = true;
package.PrereqLicenseFile = BootstrapperApplicationData.GetAttribute(node, "LicenseFile");
package.PrereqLicenseUrl = BootstrapperApplicationData.GetAttribute(node, "LicenseUrl");
}
}
}
}