|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Microsoft.Build.Shared;
using Microsoft.Build.Shared.FileSystem;
#nullable disable
namespace Microsoft.Build.Utilities
{
/// <summary>
/// Structure to represent the information contained in Platform.xml
/// </summary>
internal class PlatformManifest
{
/// <summary>
/// Location of Platform.xml
/// </summary>
private readonly string _pathToManifest;
/// <summary>
/// Constructor
/// Takes the location of Platform.xml and populates the structure with manifest data
/// </summary>
public PlatformManifest(string pathToManifest)
{
ErrorUtilities.VerifyThrowArgumentLength(pathToManifest);
_pathToManifest = pathToManifest;
LoadManifestFile();
}
/// <summary>
/// Platform name
/// </summary>
public string Name { get; private set; }
/// <summary>
/// Platform friendly name
/// </summary>
public string FriendlyName { get; private set; }
/// <summary>
/// Platform version
/// </summary>
public string PlatformVersion { get; private set; }
/// <summary>
/// The platforms that this platform depends on.
/// Item1: Platform name
/// Item2: Platform version
/// </summary>
public ICollection<DependentPlatform> DependentPlatforms { get; private set; }
/// <summary>
/// The contracts contained by this platform
/// Item1: Contract name
/// Item2: Contract version
/// </summary>
public ICollection<ApiContract> ApiContracts { get; private set; }
public bool VersionedContent { get; private set; }
/// <summary>
/// Flag set to true if an exception occurred while reading the manifest
/// </summary>
public bool ReadError => !string.IsNullOrEmpty(ReadErrorMessage);
/// <summary>
/// Message from exception thrown while reading manifest
/// </summary>
public string ReadErrorMessage { get; private set; }
/// <summary>
/// Load content of Platform.xml
/// </summary>
private void LoadManifestFile()
{
/*
Platform.xml format:
<ApplicationPlatform name="UAP" friendlyName="Universal Application Platform" version="1.0.0.0">
<DependentPlatform name="UAP" version="1.0.0.0" />
<ContainedApiContracts>
<ApiContract name="UAP" version="1.0.0.0" />
</ContainedApiContracts>
</ApplicationPlatform>
*/
try
{
string platformManifestPath = Path.Combine(_pathToManifest, "Platform.xml");
if (FileSystems.Default.FileExists(platformManifestPath))
{
XmlDocument doc = new XmlDocument();
XmlReaderSettings readerSettings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore, CloseInput = true };
FileStream fs = File.OpenRead(platformManifestPath);
using (XmlReader xmlReader = XmlReader.Create(fs, readerSettings))
{
doc.Load(xmlReader);
}
XmlElement rootElement = null;
foreach (XmlNode childNode in doc.ChildNodes)
{
if (childNode.NodeType == XmlNodeType.Element &&
string.Equals(childNode.Name, Elements.ApplicationPlatform, StringComparison.Ordinal))
{
rootElement = (XmlElement)childNode;
break;
}
}
DependentPlatforms = new List<DependentPlatform>();
ApiContracts = new List<ApiContract>();
if (rootElement != null)
{
Name = rootElement.GetAttribute(Attributes.Name);
FriendlyName = rootElement.GetAttribute(Attributes.FriendlyName);
PlatformVersion = rootElement.GetAttribute(Attributes.Version);
foreach (XmlNode childNode in rootElement.ChildNodes)
{
if (!(childNode is XmlElement childElement))
{
continue;
}
if (ApiContract.IsContainedApiContractsElement(childElement.Name))
{
ApiContract.ReadContractsElement(childElement, ApiContracts);
}
else if (ApiContract.IsVersionedContentElement(childElement.Name))
{
bool.TryParse(childElement.InnerText, out bool versionedContent);
VersionedContent = versionedContent;
}
else if (string.Equals(childElement.Name, Elements.DependentPlatform, StringComparison.Ordinal))
{
DependentPlatforms.Add(new DependentPlatform(childElement.GetAttribute(Attributes.Name), childElement.GetAttribute(Attributes.Version)));
}
}
}
}
else
{
ReadErrorMessage = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("PlatformManifest.MissingPlatformXml", platformManifestPath);
}
}
catch (Exception e) when (!ExceptionHandling.IsCriticalException(e))
{
ReadErrorMessage = e.Message;
}
}
/// <summary>
/// Represents a dependency on another platform
/// </summary>
internal struct DependentPlatform
{
/// <summary>
/// Name of the platform on which this platform depends
/// </summary>
internal readonly string Name;
/// <summary>
/// Version of the platform on which this platform depends
/// </summary>
internal readonly string Version;
/// <summary>
/// Constructor
/// </summary>
internal DependentPlatform(string name, string version)
{
Name = name;
Version = version;
}
}
/// <summary>
/// Helper class with element names in Platform.xml
/// </summary>
private static class Elements
{
/// <summary>
/// Root element
/// </summary>
public const string ApplicationPlatform = "ApplicationPlatform";
/// <summary>
/// Element describing a platform this platform is dependent on
/// </summary>
public const string DependentPlatform = "DependentPlatform";
}
/// <summary>
/// Helper class with attribute names in Platform.xml
/// </summary>
private static class Attributes
{
/// <summary>
/// Name associated with this element
/// </summary>
public const string Name = "name";
/// <summary>
/// Friendly name associated with this element
/// </summary>
public const string FriendlyName = "friendlyName";
/// <summary>
/// Version associated with this element
/// </summary>
public const string Version = "version";
}
}
}
|