Static helper methods for working with general MSBuildisms.
Ejemplo n.º 1
0
        public ImmutableDictionary <string, ImmutableDictionary <string, string> > DetermineConfigurations(IProjectRootElement projectRootElement)
        {
            var builder = ImmutableDictionary.CreateBuilder <string, ImmutableDictionary <string, string> >();

            foreach (var propertyGroup in projectRootElement.PropertyGroups)
            {
                if (MSBuildHelpers.ConditionToDimensionValues(propertyGroup.Condition, out var dimensionValues))
                {
                    var name = MSBuildHelpers.GetConfigurationName(dimensionValues);
                    if (!builder.ContainsKey(name))
                    {
                        builder.Add(name, dimensionValues.ToImmutableDictionary());
                        foreach (var dimensionValuePair in dimensionValues)
                        {
                            if (!builder.ContainsKey(dimensionValuePair.Value))
                            {
                                var dimensionValueDictionary = new Dictionary <string, string> {
                                    { dimensionValuePair.Key, dimensionValuePair.Value }
                                };
                                builder.Add(dimensionValuePair.Value, dimensionValueDictionary.ToImmutableDictionary());
                            }
                        }
                    }
                }
            }
            return(builder.ToImmutable());
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Clear out the project's construction model and add a simple SDK-based project to get a baseline.
        /// We need to use the same name as the original csproj and same path so that all the default that derive
        /// from name\path get the right values (there are a lot of them).
        /// </summary>
        private BaselineProject CreateSdkBaselineProject(string projectFilePath, IProject project, IProjectRootElement root, ImmutableDictionary <string, ImmutableDictionary <string, string> > configurations)
        {
            var projectStyle = GetProjectStyle(root);
            var outputType   = GetProjectOutputType(root);
            var rootElement  = ProjectRootElement.Open(projectFilePath);

            rootElement.RemoveAllChildren();
            switch (projectStyle)
            {
            case ProjectStyle.Default:
            case ProjectStyle.DefaultSubset:
            case ProjectStyle.MSTest:
                rootElement.Sdk = MSBuildFacts.DefaultSDKAttribute;
                break;

            case ProjectStyle.WindowsDesktop:
                rootElement.Sdk = DesktopFacts.WinSDKAttribute;
                break;

            default:
                throw new NotSupportedException($"This project has custom imports in a manner that's not supported. '{projectFilePath}'");
            }

            var propGroup = rootElement.AddPropertyGroup();

            propGroup.AddProperty(MSBuildFacts.TargetFrameworkNodeName, project.GetTargetFramework());
            propGroup.AddProperty(MSBuildFacts.OutputTypeNodeName,
                                  project.GetPropertyValue(MSBuildFacts.OutputTypeNodeName) ?? throw new InvalidOperationException($"OutputType is not set! '{projectFilePath}'"));

            if (projectStyle == ProjectStyle.WindowsDesktop)
            {
                if (MSBuildHelpers.IsWinForms(root))
                {
                    MSBuildHelpers.AddUseWinForms(propGroup);
                }

                if (MSBuildHelpers.IsWPF(root))
                {
                    MSBuildHelpers.AddUseWPF(propGroup);
                }

                // User is referencing WindowsBase only
                if (MSBuildHelpers.IsDesktop(root) && !MSBuildHelpers.HasWPFOrWinForms(propGroup))
                {
                    MSBuildHelpers.AddUseWinForms(propGroup);
                }
            }

            // Create a new collection because a project with this name has already been loaded into the global collection.
            using var pc = new ProjectCollection();
            var newProject = new UnconfiguredProject(configurations);

            newProject.LoadProjects(pc, rootElement);

            // If the original project had the TargetFramework property don't touch it during conversion.
            var propertiesInTheBaseline = ImmutableArray.Create(MSBuildFacts.OutputTypeNodeName);

            if (project.GetProperty(MSBuildFacts.TargetFrameworkNodeName) is { })
Ejemplo n.º 3
0
        private static string GetCurrentTFM(ImmutableArray <string> globalProperties, UnconfiguredProject project)
        {
            if (globalProperties.Contains(MSBuildFacts.TargetFrameworkNodeName, StringComparer.OrdinalIgnoreCase))
            {
                // The original project had a TargetFramework property. No need to add it again.
                return(globalProperties.First(p => p.Equals(MSBuildFacts.TargetFrameworkNodeName, StringComparison.OrdinalIgnoreCase)));
            }
            var rawTFM = project.FirstConfiguredProject.GetProperty(MSBuildFacts.TargetFrameworkNodeName)?.EvaluatedValue;

            if (rawTFM == null)
            {
                throw new InvalidOperationException(
                          $"{MSBuildFacts.TargetFrameworkNodeName} is not set in {nameof(project.FirstConfiguredProject)}");
            }

            // This is pretty much never gonna happen, but it was cheap to write the code
            return(MSBuildHelpers.IsNotNetFramework(rawTFM) ? StripDecimals(rawTFM) : rawTFM);
Ejemplo n.º 4
0
 /// <summary>
 /// Checks if an item is an explicit System.ValueTuple and if the given TFM correspondes with an in-box System.ValueTuple type.
 /// </summary>
 public static bool IsExplicitValueTupleReferenceThatCanBeRemoved(ProjectItemElement item, string tfm) =>
 item.ElementName.Equals(MSBuildFacts.MSBuildReferenceName, StringComparison.OrdinalIgnoreCase) &&
 item.Include.Equals(MSBuildFacts.SystemValueTupleName, StringComparison.OrdinalIgnoreCase) &&
 MSBuildHelpers.FrameworkHasAValueTuple(tfm);
Ejemplo n.º 5
0
        /// <summary>
        /// Clear out the project's construction model and add a simple SDK-based project to get a baseline.
        /// We need to use the same name as the original csproj and same path so that all the default that derive
        /// from name\path get the right values (there are a lot of them).
        /// </summary>
        private bool TryCreateSdkBaselineProject(string projectFilePath, IProject project, IProjectRootElement root, ImmutableDictionary <string, ImmutableDictionary <string, string> > configurations, string tfm, bool keepCurrentTFMs, [NotNullWhen(true)] out BaselineProject?baselineProject)
        {
            var projectStyle = GetProjectStyle(root);
            var outputType   = GetProjectOutputType(root);
            var rootElement  = ProjectRootElement.Open(projectFilePath);

            rootElement.RemoveAllChildren();
            switch (projectStyle)
            {
            case ProjectStyle.Default:
            case ProjectStyle.DefaultSubset:
            case ProjectStyle.MSTest:
                rootElement.Sdk = MSBuildFacts.DefaultSDKAttribute;
                break;

            case ProjectStyle.WindowsDesktop:
                rootElement.Sdk =
                    tfm.ContainsIgnoreCase(MSBuildFacts.Net5)
                            ? MSBuildFacts.DefaultSDKAttribute
                            : DesktopFacts.WinSDKAttribute; // pre-.NET 5 apps need a special SDK attribute.
                break;

            case ProjectStyle.Web:
                rootElement.Sdk = WebFacts.WebSDKAttribute;
                break;

            default:
                baselineProject = null;
                return(false);
            }

            var propGroup = rootElement.AddPropertyGroup();

            propGroup.AddProperty(MSBuildFacts.TargetFrameworkNodeName, project.GetTargetFramework());

            var outputTypeValue = outputType switch
            {
                ProjectOutputType.Exe => MSBuildFacts.ExeOutputType,
                ProjectOutputType.Library => MSBuildFacts.LibraryOutputType,
                ProjectOutputType.WinExe => MSBuildFacts.WinExeOutputType,
                _ => project.GetPropertyValue(MSBuildFacts.OutputTypeNodeName)
            };

            propGroup.AddProperty(MSBuildFacts.OutputTypeNodeName, outputTypeValue ?? throw new InvalidOperationException($"OutputType is not set! '{projectFilePath}'"));

            if (projectStyle == ProjectStyle.WindowsDesktop)
            {
                if (MSBuildHelpers.IsWinForms(root))
                {
                    MSBuildHelpers.AddUseWinForms(propGroup);
                }

                if (MSBuildHelpers.IsWPF(root))
                {
                    MSBuildHelpers.AddUseWPF(propGroup);
                }

                // User is referencing WindowsBase only
                if (MSBuildHelpers.IsDesktop(root) && !MSBuildHelpers.HasWPFOrWinForms(propGroup))
                {
                    MSBuildHelpers.AddUseWinForms(propGroup);
                }
            }

            // Create a new collection because a project with this name has already been loaded into the global collection.
            using var pc = new ProjectCollection();
            var newProject = new UnconfiguredProject(configurations);

            newProject.LoadProjects(pc, rootElement);

            // If the original project had the TargetFramework property don't touch it during conversion.
            var propertiesInTheBaseline = ImmutableArray.Create(MSBuildFacts.OutputTypeNodeName);

            if (project.GetProperty(MSBuildFacts.TargetFrameworkNodeName) is { })