diff --git a/ref/Microsoft.Build/net/Microsoft.Build.cs b/ref/Microsoft.Build/net/Microsoft.Build.cs index 147305e312c..808a0c01c6a 100644 --- a/ref/Microsoft.Build/net/Microsoft.Build.cs +++ b/ref/Microsoft.Build/net/Microsoft.Build.cs @@ -1126,6 +1126,7 @@ public partial class ProjectInstance public ProjectInstance(Microsoft.Build.Construction.ProjectRootElement xml) { } public ProjectInstance(Microsoft.Build.Construction.ProjectRootElement xml, System.Collections.Generic.IDictionary globalProperties, string toolsVersion, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { } public ProjectInstance(Microsoft.Build.Construction.ProjectRootElement xml, System.Collections.Generic.IDictionary globalProperties, string toolsVersion, string subToolsetVersion, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { } + public ProjectInstance(Microsoft.Build.Evaluation.Project project, Microsoft.Build.Execution.ProjectInstanceSettings settings) { } public ProjectInstance(string projectFile) { } public ProjectInstance(string projectFile, System.Collections.Generic.IDictionary globalProperties, string toolsVersion) { } public ProjectInstance(string projectFile, System.Collections.Generic.IDictionary globalProperties, string toolsVersion, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { } @@ -1982,6 +1983,7 @@ protected ProjectLink() { } public abstract bool Build(string[] targets, System.Collections.Generic.IEnumerable loggers, System.Collections.Generic.IEnumerable remoteLoggers, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext); public abstract Microsoft.Build.Execution.ProjectInstance CreateProjectInstance(Microsoft.Build.Execution.ProjectInstanceSettings settings, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext); public abstract string ExpandString(string unexpandedValue); + public abstract System.Collections.Generic.List GetAllGlobs(); public abstract System.Collections.Generic.List GetAllGlobs(Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext); public abstract System.Collections.Generic.List GetAllGlobs(string itemType, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext); public abstract System.Collections.Generic.List GetItemProvenance(Microsoft.Build.Evaluation.ProjectItem item, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext); diff --git a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs index 395d69a8f6e..6707dd41599 100644 --- a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs +++ b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs @@ -1120,6 +1120,7 @@ public partial class ProjectInstance public ProjectInstance(Microsoft.Build.Construction.ProjectRootElement xml) { } public ProjectInstance(Microsoft.Build.Construction.ProjectRootElement xml, System.Collections.Generic.IDictionary globalProperties, string toolsVersion, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { } public ProjectInstance(Microsoft.Build.Construction.ProjectRootElement xml, System.Collections.Generic.IDictionary globalProperties, string toolsVersion, string subToolsetVersion, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { } + public ProjectInstance(Microsoft.Build.Evaluation.Project project, Microsoft.Build.Execution.ProjectInstanceSettings settings) { } public ProjectInstance(string projectFile) { } public ProjectInstance(string projectFile, System.Collections.Generic.IDictionary globalProperties, string toolsVersion) { } public ProjectInstance(string projectFile, System.Collections.Generic.IDictionary globalProperties, string toolsVersion, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { } @@ -1976,6 +1977,7 @@ protected ProjectLink() { } public abstract bool Build(string[] targets, System.Collections.Generic.IEnumerable loggers, System.Collections.Generic.IEnumerable remoteLoggers, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext); public abstract Microsoft.Build.Execution.ProjectInstance CreateProjectInstance(Microsoft.Build.Execution.ProjectInstanceSettings settings, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext); public abstract string ExpandString(string unexpandedValue); + public abstract System.Collections.Generic.List GetAllGlobs(); public abstract System.Collections.Generic.List GetAllGlobs(Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext); public abstract System.Collections.Generic.List GetAllGlobs(string itemType, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext); public abstract System.Collections.Generic.List GetItemProvenance(Microsoft.Build.Evaluation.ProjectItem item, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext); diff --git a/src/Build.OM.UnitTests/Instance/ProjectInstance_Tests.cs b/src/Build.OM.UnitTests/Instance/ProjectInstance_Tests.cs index d032033dd27..dc1e3cfdc23 100644 --- a/src/Build.OM.UnitTests/Instance/ProjectInstance_Tests.cs +++ b/src/Build.OM.UnitTests/Instance/ProjectInstance_Tests.cs @@ -449,6 +449,48 @@ public void CreateProjectInstanceWithItemsContainingProjects() Assert.Equal(projAInstanceItem.MetadataCount, projAInstanceItem.MetadataNames.Count); } + /// + /// Constructs a new ProjectInstances from Project. + /// + [Fact] + public void CreateProjectInstanceFromProject() + { + const string CapturedMetadataName = "DefiningProjectFullPath"; + var pc = new ProjectCollection(); + var projA = ProjectRootElement.Create(pc); + var projB = ProjectRootElement.Create(pc); + projA.FullPath = Path.Combine(Path.GetTempPath(), "a.proj"); + projB.FullPath = Path.Combine(Path.GetTempPath(), "b.proj"); + projB.AddImport("a.proj"); + projA.AddItem("Compile", "aItem.cs"); + projB.AddItem("Compile", "bItem.cs"); + + var loadSettings = ProjectLoadSettings.RecordDuplicateButNotCircularImports + | ProjectLoadSettings.RejectCircularImports + | ProjectLoadSettings.IgnoreEmptyImports + | ProjectLoadSettings.IgnoreMissingImports + | ProjectLoadSettings.IgnoreInvalidImports; + + var projBEval = new Project(projB, null, null, pc, loadSettings); + var projBInstance = new ProjectInstance(projBEval, ProjectInstanceSettings.ImmutableWithFastItemLookup); + var projBInstanceItem = projBInstance.GetItemsByItemTypeAndEvaluatedInclude("Compile", "bItem.cs").Single(); + var projAInstanceItem = projBInstance.GetItemsByItemTypeAndEvaluatedInclude("Compile", "aItem.cs").Single(); + Assert.Equal(projB.FullPath, projBInstanceItem.GetMetadataValue(CapturedMetadataName)); + Assert.Equal(projA.FullPath, projAInstanceItem.GetMetadataValue(CapturedMetadataName)); + + // Although GetMetadataValue returns non-null, GetMetadata returns null... + Assert.Null(projAInstanceItem.GetMetadata(CapturedMetadataName)); + + // .. Just like built-in metadata does: (this segment just demonstrates similar functionality -- it's not meant to test built-in metadata) + Assert.NotNull(projAInstanceItem.GetMetadataValue("Identity")); + Assert.Null(projAInstanceItem.GetMetadata("Identity")); + + Assert.True(projAInstanceItem.HasMetadata(CapturedMetadataName)); + Assert.False(projAInstanceItem.Metadata.Any()); + Assert.Contains(CapturedMetadataName, projAInstanceItem.MetadataNames); + Assert.Equal(projAInstanceItem.MetadataCount, projAInstanceItem.MetadataNames.Count); + } + /// /// Verifies that the built-in metadata for specialized ProjectInstances is present when items are based on wildcards in the construction model. /// diff --git a/src/Build.OM.UnitTests/ObjectModelRemoting/RemoteProjectsProviderMock/EvaluationLinkMocks/MockProjectLink.cs b/src/Build.OM.UnitTests/ObjectModelRemoting/RemoteProjectsProviderMock/EvaluationLinkMocks/MockProjectLink.cs index 253ceac7972..d268d30df18 100644 --- a/src/Build.OM.UnitTests/ObjectModelRemoting/RemoteProjectsProviderMock/EvaluationLinkMocks/MockProjectLink.cs +++ b/src/Build.OM.UnitTests/ObjectModelRemoting/RemoteProjectsProviderMock/EvaluationLinkMocks/MockProjectLink.cs @@ -187,7 +187,12 @@ public override bool Build(string[] targets, IEnumerable loggers, IEnum public override string ExpandString(string unexpandedValue) => this.Proxy.ExpandString(unexpandedValue); -// TODO: Glob is not needed for the CSproj, but we might want to test it at least + // TODO: Glob is not needed for the CSproj, but we might want to test it at least + public override List GetAllGlobs() + { + throw new NotImplementedException(); + } + public override List GetAllGlobs(EvaluationContext evaluationContext) { throw new NotImplementedException(); diff --git a/src/Build/Definition/Project.cs b/src/Build/Definition/Project.cs index 285c4cc592a..014f8e68993 100644 --- a/src/Build/Definition/Project.cs +++ b/src/Build/Definition/Project.cs @@ -2421,6 +2421,14 @@ public override bool IsBuildEnabled /// internal ILoggingService LoggingService => ProjectCollection.LoggingService; + /// + /// See . + /// + public override List GetAllGlobs() + { + return GetAllGlobs(evaluationContext: null); + } + /// /// See . /// diff --git a/src/Build/Instance/ProjectInstance.cs b/src/Build/Instance/ProjectInstance.cs index bd160b2f66c..632b057bd4f 100644 --- a/src/Build/Instance/ProjectInstance.cs +++ b/src/Build/Instance/ProjectInstance.cs @@ -326,6 +326,59 @@ public ProjectInstance(ProjectRootElement xml, IDictionary globa { } + /// + /// Creates a ProjectInstance from an external created . + /// Properties and items are cloned immediately and only the instance data is stored. + /// + public ProjectInstance(Project project, ProjectInstanceSettings settings) + { + ErrorUtilities.VerifyThrowInternalNull(project, nameof(project)); + + var projectPath = project.FullPath; + _directory = Path.GetDirectoryName(projectPath); + _projectFileLocation = ElementLocation.Create(projectPath); + _hostServices = project.ProjectCollection.HostServices; + + EvaluationId = project.EvaluationCounter; + + var immutable = (settings & ProjectInstanceSettings.Immutable) == ProjectInstanceSettings.Immutable; + this.CreatePropertiesSnapshot(project.Properties, immutable); + this.CreateItemDefinitionsSnapshot(project.ItemDefinitions); + + var keepEvaluationCache = (settings & ProjectInstanceSettings.ImmutableWithFastItemLookup) == ProjectInstanceSettings.ImmutableWithFastItemLookup; + var projectItemToInstanceMap = this.CreateItemsSnapshot(project.Items, project.ItemTypes.Count, keepEvaluationCache); + + this.CreateEvaluatedIncludeSnapshotIfRequested(keepEvaluationCache, project.Items, projectItemToInstanceMap); + + _globalProperties = new PropertyDictionary(project.GlobalProperties.Count); + foreach (var property in project.GlobalProperties) + { + _globalProperties.Set(ProjectPropertyInstance.Create(property.Key, property.Value)); + } + + this.CreateEnvironmentVariablePropertiesSnapshot(project.ProjectCollection.EnvironmentProperties); + this.CreateTargetsSnapshot(project.Targets, null, null, null, null); + this.CreateImportsSnapshot(project.Imports, project.ImportsIncludingDuplicates); + + this.Toolset = project.ProjectCollection.GetToolset(project.ToolsVersion); + this.SubToolsetVersion = project.SubToolsetVersion; + this.TaskRegistry = new TaskRegistry(Toolset, project.ProjectCollection.ProjectRootElementCache); + + this.ProjectRootElementCache = project.ProjectCollection.ProjectRootElementCache; + + this.EvaluatedItemElements = new List(project.Items.Count); + foreach (var item in project.Items) + { + this.EvaluatedItemElements.Add(item.Xml); + } + + _usingDifferentToolsVersionFromProjectFile = false; + _originalProjectToolsVersion = project.ToolsVersion; + _explicitToolsVersionSpecified = project.SubToolsetVersion != null; + + _isImmutable = immutable; + } + /// /// Creates a ProjectInstance directly. /// No intermediate Project object is created. @@ -461,18 +514,18 @@ internal ProjectInstance(Evaluation.Project.Data data, string directory, string EvaluationId = data.EvaluationId; var immutable = (settings & ProjectInstanceSettings.Immutable) == ProjectInstanceSettings.Immutable; - this.CreatePropertiesSnapshot(data, immutable); + this.CreatePropertiesSnapshot(new ReadOnlyCollection(data.Properties), immutable); - this.CreateItemDefinitionsSnapshot(data); + this.CreateItemDefinitionsSnapshot(data.ItemDefinitions); var keepEvaluationCache = (settings & ProjectInstanceSettings.ImmutableWithFastItemLookup) == ProjectInstanceSettings.ImmutableWithFastItemLookup; - var projectItemToInstanceMap = this.CreateItemsSnapshot(data, keepEvaluationCache); + var projectItemToInstanceMap = this.CreateItemsSnapshot(new ReadOnlyCollection(data.Items), data.ItemTypes.Count, keepEvaluationCache); - this.CreateEvaluatedIncludeSnapshotIfRequested(keepEvaluationCache, data, projectItemToInstanceMap); - this.CreateGlobalPropertiesSnapshot(data); + this.CreateEvaluatedIncludeSnapshotIfRequested(keepEvaluationCache, new ReadOnlyCollection(data.Items), projectItemToInstanceMap); + this.CreateGlobalPropertiesSnapshot(data.GlobalPropertiesDictionary); this.CreateEnvironmentVariablePropertiesSnapshot(environmentVariableProperties); - this.CreateTargetsSnapshot(data); - this.CreateImportsSnapshot(data); + this.CreateTargetsSnapshot(data.Targets, data.DefaultTargets, data.InitialTargets, data.BeforeTargets, data.AfterTargets); + this.CreateImportsSnapshot(data.ImportClosure, data.ImportClosureWithDuplicates); this.Toolset = data.Toolset; // UNDONE: This isn't immutable, should be cloned or made immutable; it currently has a pointer to project collection this.SubToolsetVersion = data.SubToolsetVersion; @@ -548,13 +601,13 @@ private ProjectInstance(ProjectInstance that, bool isImmutable, RequestedProject this.DefaultTargets = new List(that.DefaultTargets); this.InitialTargets = new List(that.InitialTargets); ((IEvaluatorData) this).BeforeTargets = CreateCloneDictionary( + ProjectItemDefinitionInstance>)this).BeforeTargets = CreateCloneDictionary( ((IEvaluatorData) that).BeforeTargets, StringComparer.OrdinalIgnoreCase); + ProjectItemDefinitionInstance>)that).BeforeTargets, StringComparer.OrdinalIgnoreCase); ((IEvaluatorData) this).AfterTargets = CreateCloneDictionary( + ProjectItemDefinitionInstance>)this).AfterTargets = CreateCloneDictionary( ((IEvaluatorData) that).AfterTargets, StringComparer.OrdinalIgnoreCase); + ProjectItemDefinitionInstance>)that).AfterTargets, StringComparer.OrdinalIgnoreCase); this.TaskRegistry = that.TaskRegistry; // UNDONE: This isn't immutable, should be cloned or made immutable; it currently has a pointer to project collection @@ -2023,7 +2076,7 @@ private void TranslateProperties(ITranslator translator) translator.TranslateDictionary(ref _globalProperties, ProjectPropertyInstance.FactoryForDeserialization); translator.TranslateDictionary(ref _properties, ProjectPropertyInstance.FactoryForDeserialization); - var globalPropertiesToTreatAsLocal = (HashSet) _globalPropertiesToTreatAsLocal; + var globalPropertiesToTreatAsLocal = (HashSet)_globalPropertiesToTreatAsLocal; translator.Translate(ref globalPropertiesToTreatAsLocal); if (translator.Mode == TranslationDirection.ReadFromStream) @@ -2727,24 +2780,29 @@ private IEnumerable GetItemsByEvaluatedInclude(string evalu /// /// Create various target snapshots /// - private void CreateTargetsSnapshot(Evaluation.Project.Data data) + private void CreateTargetsSnapshot( + IDictionary targets, + List defaultTargets, + List initialTargets, + IDictionary> beforeTargets, + IDictionary> afterTargets) { - this.DefaultTargets = new List(data.DefaultTargets); - this.InitialTargets = new List(data.InitialTargets); - ((IEvaluatorData)this).BeforeTargets = CreateCloneDictionary(data.BeforeTargets, StringComparer.OrdinalIgnoreCase); - ((IEvaluatorData)this).AfterTargets = CreateCloneDictionary(data.AfterTargets, StringComparer.OrdinalIgnoreCase); - // ProjectTargetInstances are immutable so only the dictionary must be cloned - _targets = CreateCloneDictionary(data.Targets); + _targets = CreateCloneDictionary(targets); + + this.DefaultTargets = defaultTargets == null ? new List(0) : new List(defaultTargets); + this.InitialTargets = defaultTargets == null ? new List(0) : new List(initialTargets); + ((IEvaluatorData)this).BeforeTargets = CreateCloneDictionary(beforeTargets, StringComparer.OrdinalIgnoreCase); + ((IEvaluatorData)this).AfterTargets = CreateCloneDictionary(afterTargets, StringComparer.OrdinalIgnoreCase); } /// /// Create various imports snapshots /// - private void CreateImportsSnapshot(Evaluation.Project.Data data) + private void CreateImportsSnapshot(IList importClosure, IList importClosureWithDuplicates) { - _importPaths = new List(data.ImportClosure.Count - 1 /* outer project */); - foreach (var resolvedImport in data.ImportClosure) + _importPaths = new List(importClosure.Count - 1 /* outer project */); + foreach (var resolvedImport in importClosure) { // Exclude outer project itself if (resolvedImport.ImportingElement != null) @@ -2755,8 +2813,8 @@ private void CreateImportsSnapshot(Evaluation.Project.Data data) ImportPaths = _importPaths.AsReadOnly(); - _importPathsIncludingDuplicates = new List(data.ImportClosureWithDuplicates.Count - 1 /* outer project */); - foreach (var resolvedImport in data.ImportClosureWithDuplicates) + _importPathsIncludingDuplicates = new List(importClosureWithDuplicates.Count - 1 /* outer project */); + foreach (var resolvedImport in importClosureWithDuplicates) { // Exclude outer project itself if (resolvedImport.ImportingElement != null) @@ -2784,11 +2842,11 @@ private void CreateEnvironmentVariablePropertiesSnapshot(PropertyDictionary /// Create global properties snapshot /// - private void CreateGlobalPropertiesSnapshot(Evaluation.Project.Data data) + private void CreateGlobalPropertiesSnapshot(PropertyDictionary globalPropertiesDictionary) { - _globalProperties = new PropertyDictionary(data.GlobalPropertiesDictionary.Count); + _globalProperties = new PropertyDictionary(globalPropertiesDictionary.Count); - foreach (ProjectPropertyInstance globalProperty in data.GlobalPropertiesDictionary) + foreach (ProjectPropertyInstance globalProperty in globalPropertiesDictionary) { _globalProperties.Set(globalProperty.DeepClone()); } @@ -2797,7 +2855,7 @@ private void CreateGlobalPropertiesSnapshot(Evaluation.Project.Data data) /// /// Create evaluated include cache snapshot /// - private void CreateEvaluatedIncludeSnapshotIfRequested(bool keepEvaluationCache, Evaluation.Project.Data data, Dictionary projectItemToInstanceMap) + private void CreateEvaluatedIncludeSnapshotIfRequested(bool keepEvaluationCache, ICollection items, Dictionary projectItemToInstanceMap) { if (!keepEvaluationCache) { @@ -2805,26 +2863,22 @@ private void CreateEvaluatedIncludeSnapshotIfRequested(bool keepEvaluationCache, } _itemsByEvaluatedInclude = new MultiDictionary(StringComparer.OrdinalIgnoreCase); - foreach (var key in data.ItemsByEvaluatedIncludeCache.Keys) + foreach (var item in items) { - var projectItems = data.ItemsByEvaluatedIncludeCache[key]; - foreach (var projectItem in projectItems) - { - _itemsByEvaluatedInclude.Add(key, projectItemToInstanceMap[projectItem]); - } + _itemsByEvaluatedInclude.Add(item.EvaluatedInclude, projectItemToInstanceMap[item]); } } /// /// Create Items snapshot /// - private Dictionary CreateItemsSnapshot(Evaluation.Project.Data data, bool keepEvaluationCache) + private Dictionary CreateItemsSnapshot(ICollection items, int itemTypecount, bool keepEvaluationCache) { - _items = new ItemDictionary(data.ItemTypes.Count); + _items = new ItemDictionary(itemTypecount); - var projectItemToInstanceMap = keepEvaluationCache ? new Dictionary(data.Items.Count) : null; + var projectItemToInstanceMap = keepEvaluationCache ? new Dictionary(items.Count) : null; - foreach (ProjectItem item in data.Items) + foreach (ProjectItem item in items) { List inheritedItemDefinitions = null; @@ -2865,11 +2919,11 @@ private Dictionary CreateItemsSnapshot(Evaluat /// /// Create ItemDefinitions snapshot /// - private void CreateItemDefinitionsSnapshot(Evaluation.Project.Data data) + private void CreateItemDefinitionsSnapshot(IDictionary itemDefinitions) { _itemDefinitions = new RetrievableEntryHashSet(MSBuildNameIgnoreCaseComparer.Default); - foreach (ProjectItemDefinition definition in data.ItemDefinitions.Values) + foreach (ProjectItemDefinition definition in itemDefinitions.Values) { _itemDefinitions.Add(new ProjectItemDefinitionInstance(definition)); } @@ -2878,11 +2932,11 @@ private void CreateItemDefinitionsSnapshot(Evaluation.Project.Data data) /// /// create property snapshot /// - private void CreatePropertiesSnapshot(Evaluation.Project.Data data, bool isImmutable) + private void CreatePropertiesSnapshot(ICollection properties, bool isImmutable) { - _properties = new PropertyDictionary(data.Properties.Count); + _properties = new PropertyDictionary(properties.Count); - foreach (ProjectProperty property in data.Properties) + foreach (ProjectProperty property in properties) { // Allow reserved property names, since this is how they are added to the project instance. // The caller has prevented users setting them themselves. diff --git a/src/Build/ObjectModelRemoting/DefinitionObjectsLinks/ProjectLink.cs b/src/Build/ObjectModelRemoting/DefinitionObjectsLinks/ProjectLink.cs index c89d4ee4323..77fe8e0fcda 100644 --- a/src/Build/ObjectModelRemoting/DefinitionObjectsLinks/ProjectLink.cs +++ b/src/Build/ObjectModelRemoting/DefinitionObjectsLinks/ProjectLink.cs @@ -128,6 +128,11 @@ public abstract class ProjectLink /// public abstract int LastEvaluationId { get; } + /// + /// Facilitate remoting the . + /// + public abstract List GetAllGlobs(); + /// /// Facilitate remoting the . ///