private IEnumerable <XElement> GetItems(MsbuildFile msbuildFile, Project project, string friendlyQualifierName) { if (project.Items.Count == 0) { return(EmptyArray <XElement>()); } string evaluatedQualifierComparisonValue = null; if (friendlyQualifierName != null) { evaluatedQualifierComparisonValue = msbuildFile.GetQualifierComparisonValue(friendlyQualifierName); } var items = project.Items.OrderBy(grouping => grouping.Key).Select( grouping => new XElement( ItemGroupXName, string.IsNullOrEmpty(evaluatedQualifierComparisonValue) ? EmptyArray <XAttribute>() : (object)new XAttribute("Condition", $"'{msbuildFile.UnevaluatedQualifierComparisonProperty}' == '{evaluatedQualifierComparisonValue}'"), grouping .Where(item => !IsExcludedItemInclude(ValueToMsBuild(item.Include, msbuildFile))) .OrderBy(item => ValueToMsBuild(item.Include, msbuildFile), StringComparer.OrdinalIgnoreCase) .Select( item => new XElement( XName.Get(grouping.Key, MsBuildNamespace), new XAttribute("Include", ValueToMsBuild(item.Include, msbuildFile)), item.Metadata .OrderBy(kv => kv.Key) .Select(kv => new XElement(XName.Get(kv.Key, MsBuildNamespace), ValueToMsBuild(kv.Value, msbuildFile))))))); return(items); }
/// <summary> /// Merge all projects which are generated from the same spec file with different qualifiers /// After merging them, we will have knowledge about which properties or items are conditioned. /// </summary> private static void CreateConditionedProjects(MsbuildFile msbuildFile) { // Create a new process project for each old process project. The new ones will not have items and properties. // We will put new items and properties below. var oldProjects = msbuildFile.ProjectsByQualifier.Values.ToArray(); var numProjects = oldProjects.Length; if (numProjects == 0) { return; } // create new projects with same qualifiers var newProjects = new Project[oldProjects.Length]; for (int i = 0; i < oldProjects.Length; i++) { newProjects[i] = new Project(oldProjects[i].FriendlyQualifier); } // Find the unconditioned items. HashSet <(string, object)> unconditionedValues = null; HashSet <(string, object)> projectValues = new HashSet <ValueTuple <string, object> >(); foreach (var project in oldProjects) { projectValues.Clear(); projectValues.UnionWith(project.Items.SelectMany(grouping => grouping.Select(item => (grouping.Key, item.Include)))); Context.HandledItemTypes.UnionWith(project.Items.Select(grouping => grouping.Key)); if (unconditionedValues == null) { unconditionedValues = new HashSet <(string, object)>(projectValues); } else { unconditionedValues.IntersectWith(projectValues); } } // Create an unconditioned project with an empty qualifier and populate it with the unconditioned (common) values var unconditionedProject = new Project(string.Empty); for (int i = 0; i < oldProjects.Length; i++) { foreach (var itemGroup in oldProjects[i].Items) { foreach (var item in itemGroup) { if (!unconditionedValues.Contains((itemGroup.Key, item.Include))) { newProjects[i].AddItem(itemGroup.Key, item); }
private IReadOnlyList <MsbuildFile> GenerateMsbuildFiles() { var msbuildFiles = new List <MsbuildFile>(); // Retrieve Process pip nodes. Then, hydrate them and group by their spec path. var specFileGroupedProcessPips = m_context .ScheduledGraph .Nodes .Where(nodeId => m_context.PipGraph.PipTable.GetPipType(nodeId.ToPipId()) == PipType.Process) .Select(nodeId => m_context.PipGraph.PipTable.HydratePip(nodeId.ToPipId(), BuildXL.Pips.PipQueryContext.IdeGenerator)) .GroupBy(p => p.Provenance.Token.Path); foreach (var processPips in specFileGroupedProcessPips) { var specFile = processPips.Key; var categorizedProcesses = processPips.OfType <Process>().Select(p => ProcessWithType.Categorize(m_context, p)); MsbuildFile msbuildFile = null; if (categorizedProcesses.Any(a => a.Type == ProcessType.Csc)) { msbuildFile = new CsprojFile(m_context, specFile); } else if (categorizedProcesses.Any(a => a.Type == ProcessType.Cl)) { msbuildFile = new VcxprojFile(m_context, specFile); } if (msbuildFile != null) { msbuildFile.VisitProcesses(categorizedProcesses); // SealDirectories might not be scheduled so look at the full graph to find them. foreach (var directory in m_context.PipGraph.GetPipsPerSpecFile(specFile).OfType <SealDirectory>()) { msbuildFile.VisitDirectory(directory); } msbuildFile.EndVisitingProject(); msbuildFiles.Add(msbuildFile); } } return(msbuildFiles); }
private string ValueToMsBuild(object value, MsbuildFile msbuildFile, bool isProperty = false) { if (value is string) { return(ExpandString((string)value)); } if (value is PathAtom) { return(((PathAtom)value).ToString(m_context.PathTable.StringTable)); } if (value is AbsolutePath) { AbsolutePath absolutePath = (AbsolutePath)value; if (msbuildFile != null && msbuildFile.SpecDirectory != absolutePath) { RelativePath relativePath; // If it is a property, the relative path must be only to the enlistment root. if (!isProperty && msbuildFile.SpecDirectory.TryGetRelative(m_context.PathTable, absolutePath, out relativePath)) { var relativePathStr = relativePath.ToString(m_context.PathTable.StringTable); // If we write the project files somewhere else (e.g., out\vs\projects\), combine it with SpecRoot. if (!m_context.CanWriteToSrc) { return(Path.Combine("$(SpecRoot)", relativePathStr)); } return(relativePathStr); } } return(ExpandAbsolutePath(absolutePath)); } if (value is RelativePath) { return(((RelativePath)value).ToString(m_context.PathTable.StringTable)); } throw new InvalidOperationException("Unexpected content"); }
private IEnumerable <XElement> GetProperties(MsbuildFile msbuildFile, Project project, string friendlyQualifierName) { string evaluatedQualifierComparisonValue = null; if (friendlyQualifierName != null) { evaluatedQualifierComparisonValue = msbuildFile.GetQualifierComparisonValue(friendlyQualifierName); } var properties = new XElement( PropertyGroupXName, string.IsNullOrEmpty(evaluatedQualifierComparisonValue) ? EmptyArray <XAttribute>() : (object)new XAttribute("Condition", $"'{msbuildFile.UnevaluatedQualifierComparisonProperty}' == '{evaluatedQualifierComparisonValue}'"), project.Properties.OrderBy(kv => kv.Key, StringComparer.OrdinalIgnoreCase) .Select(kv => new XElement(XName.Get(kv.Key, MsBuildNamespace), ValueToMsBuild(kv.Value, msbuildFile, true)))); if (properties.HasElements) { yield return(properties); } }