|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using Microsoft.Build.Framework;
using Microsoft.Build.ObjectModelRemoting;
using Microsoft.Build.Shared;
#nullable disable
namespace Microsoft.Build.Construction
{
/// <summary>
/// Initializes a ProjectImportElement instance.
/// </summary>
[DebuggerDisplay("Project={Project} Condition={Condition}")]
public class ProjectImportElement : ProjectElement
{
internal ProjectImportElementLink ImportLink => (ProjectImportElementLink)Link;
private ImplicitImportLocation _implicitImportLocation;
private ProjectElement _originalElement;
/// <summary>
/// External projects support
/// </summary>
internal ProjectImportElement(ProjectImportElementLink link)
: base(link)
{
}
/// <summary>
/// Initialize a parented ProjectImportElement
/// </summary>
internal ProjectImportElement(XmlElementWithLocation xmlElement, ProjectElementContainer parent, ProjectRootElement containingProject, SdkReference sdkReference = null)
: base(xmlElement, parent, containingProject)
{
ErrorUtilities.VerifyThrowArgumentNull(parent);
SdkReference = sdkReference;
}
/// <summary>
/// Initialize an unparented ProjectImportElement
/// </summary>
internal ProjectImportElement(XmlElementWithLocation xmlElement, ProjectRootElement containingProject)
: base(xmlElement, null, containingProject)
{
}
/// <summary>
/// Gets or sets the Project value.
/// </summary>
public string Project
{
get => FileUtilities.FixFilePath(GetAttributeValue(XMakeAttributes.project));
set
{
ErrorUtilities.VerifyThrowArgumentLength(value, XMakeAttributes.project);
SetOrRemoveAttribute(XMakeAttributes.project, value, "Set Import Project {0}", value);
}
}
/// <summary>
/// Location of the project attribute
/// </summary>
public ElementLocation ProjectLocation => GetAttributeLocation(XMakeAttributes.project);
/// <summary>
/// Gets or sets the SDK that contains the import.
/// </summary>
public string Sdk
{
get => FileUtilities.FixFilePath(GetAttributeValue(XMakeAttributes.sdk));
set
{
ErrorUtilities.VerifyThrowArgumentLength(value, XMakeAttributes.sdk);
if (UpdateSdkReference(name: value, SdkReference?.Version, SdkReference?.MinimumVersion))
{
SetOrRemoveAttribute(XMakeAttributes.sdk, value, "Set Import Sdk {0}", value);
}
}
}
/// <summary>
/// Gets or sets the version associated with this SDK import
/// </summary>
public string Version
{
get => GetAttributeValue(XMakeAttributes.sdkVersion);
set
{
if (UpdateSdkReference(SdkReference?.Name, version: value, SdkReference?.MinimumVersion))
{
SetOrRemoveAttribute(XMakeAttributes.sdkVersion, value, "Set Import Version {0}", value);
}
}
}
/// <summary>
/// Gets or sets the minimum SDK version required by this import.
/// </summary>
public string MinimumVersion
{
get => GetAttributeValue(XMakeAttributes.sdkMinimumVersion);
set
{
if (UpdateSdkReference(SdkReference?.Name, SdkReference?.Version, minimumVersion: value))
{
SetOrRemoveAttribute(XMakeAttributes.sdkMinimumVersion, value, "Set Import Minimum Version {0}", value);
}
}
}
/// <summary>
/// Location of the Sdk attribute
/// </summary>
public ElementLocation SdkLocation => GetAttributeLocation(XMakeAttributes.sdk);
/// <summary>
/// Gets the <see cref="ImplicitImportLocation"/> of the import. This indicates if the import was implicitly
/// added because of the <see cref="ProjectRootElement.Sdk"/> attribute and the location where the project was
/// imported.
/// </summary>
public ImplicitImportLocation ImplicitImportLocation { get => Link != null ? ImportLink.ImplicitImportLocation : _implicitImportLocation; internal set => _implicitImportLocation = value; }
/// <summary>
/// If the import is an implicit one (<see cref="ImplicitImportLocation"/> != None) then this element points
/// to the original element which generated this implicit import.
/// </summary>
public ProjectElement OriginalElement { get => Link != null ? ImportLink.OriginalElement : _originalElement; internal set => _originalElement = value; }
/// <summary>
/// <see cref="Framework.SdkReference"/> if applicable to this import element.
/// </summary>
internal SdkReference SdkReference { get; set; }
/// <summary>
/// Creates an unparented ProjectImportElement, wrapping an unparented XmlElement.
/// Validates the project value.
/// Caller should then ensure the element is added to a parent
/// </summary>
internal static ProjectImportElement CreateDisconnected(string project, ProjectRootElement containingProject)
{
XmlElementWithLocation element = containingProject.CreateElement(XMakeElements.import);
return new ProjectImportElement(element, containingProject) { Project = project };
}
/// <summary>
/// Creates an implicit ProjectImportElement as if it was in the project.
/// </summary>
/// <returns></returns>
internal static ProjectImportElement CreateImplicit(
string project,
ProjectRootElement containingProject,
ImplicitImportLocation implicitImportLocation,
SdkReference sdkReference,
ProjectElement originalElement)
{
XmlElementWithLocation element = containingProject.CreateElement(XMakeElements.import);
return new ProjectImportElement(element, containingProject)
{
Project = project,
Sdk = sdkReference.ToString(),
ImplicitImportLocation = implicitImportLocation,
SdkReference = sdkReference,
OriginalElement = originalElement
};
}
/// <summary>
/// Overridden to verify that the potential parent and siblings
/// are acceptable. Throws InvalidOperationException if they are not.
/// </summary>
internal override void VerifyThrowInvalidOperationAcceptableLocation(ProjectElementContainer parent, ProjectElement previousSibling, ProjectElement nextSibling)
{
ErrorUtilities.VerifyThrowInvalidOperation(parent is ProjectRootElement || parent is ProjectImportGroupElement, "OM_CannotAcceptParent");
}
/// <inheritdoc />
protected override ProjectElement CreateNewInstance(ProjectRootElement owner)
{
return owner.CreateImportElement(Project);
}
/// <summary>
/// Helper method to update the <see cref="SdkReference" /> property if necessary (update only when changed).
/// </summary>
/// <returns>True if the <see cref="SdkReference" /> property was updated, otherwise false (no update necessary).</returns>
private bool UpdateSdkReference(string name, string version, string minimumVersion)
{
SdkReference sdk = new SdkReference(name, version, minimumVersion);
if (sdk.Equals(SdkReference))
{
return false;
}
SdkReference = sdk;
return true;
}
}
}
|