Skip to content
This repository has been archived by the owner on May 17, 2024. It is now read-only.

Commit

Permalink
Merge pull request #310 from cartermp/support-net5
Browse files Browse the repository at this point in the history
  • Loading branch information
cartermp authored Oct 9, 2020
2 parents 3e9cb46 + 5447be7 commit 56a750a
Show file tree
Hide file tree
Showing 28 changed files with 420 additions and 128 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -356,4 +356,6 @@ MigrationBackup/

# Local testing files
**/*/launchSettings.json
**/*/FolderProfile.pubxml
**/*/FolderProfile.pubxml

.tools/*
22 changes: 11 additions & 11 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MajorVersion>0</MajorVersion>
<MinorVersion>5</MinorVersion>
<MinorVersion>6</MinorVersion>
<!-- Build release-only package. -->
<PreReleaseVersionLabel />
</PropertyGroup>
Expand All @@ -11,21 +11,21 @@
-->
<PropertyGroup>
<MicrosoftBuildLocatorVersion>1.2.6</MicrosoftBuildLocatorVersion>
<MicrosoftBuildVersion>16.0.461</MicrosoftBuildVersion>
<MicrosoftWin32RegistryVersion>4.7.0</MicrosoftWin32RegistryVersion>
<NewtonsoftJsonVersion>12.0.2</NewtonsoftJsonVersion>
<NuGetVersioningVersion>5.5.0</NuGetVersioningVersion>
<SystemCollectionsImmutableVersion>1.5.0</SystemCollectionsImmutableVersion>
<SystemCommandLineVersion> 2.0.0-beta1.20214.1</SystemCommandLineVersion>
<SystemConfigurationConfigurationManagerVersion>4.7.0</SystemConfigurationConfigurationManagerVersion>
<SystemSecurityPrincipalWindowsVersion>4.7.0</SystemSecurityPrincipalWindowsVersion>
<MicrosoftBuildVersion>16.7</MicrosoftBuildVersion>
<MicrosoftWin32RegistryVersion>5.0.0-rc.1.20451.14</MicrosoftWin32RegistryVersion>
<NewtonsoftJsonVersion>12.0.3</NewtonsoftJsonVersion>
<NuGetVersioningVersion>5.8.0-preview.3.6823</NuGetVersioningVersion>
<SystemCollectionsImmutableVersion>5.0.0-rc.1.20451.14</SystemCollectionsImmutableVersion>
<SystemCommandLineVersion>2.0.0-beta1.20371.2</SystemCommandLineVersion>
<SystemConfigurationConfigurationManagerVersion>5.0.0-rc.1.20451.14</SystemConfigurationConfigurationManagerVersion>
<SystemSecurityPrincipalWindowsVersion>5.0.0-rc.1.20451.14</SystemSecurityPrincipalWindowsVersion>
</PropertyGroup>
<!--
Nuget package versions for tests
-->
<PropertyGroup>
<CoverletCollectorVersion>1.0.1</CoverletCollectorVersion>
<MoqVersion>4.13.0</MoqVersion>
<CoverletCollectorVersion>1.3.0 </CoverletCollectorVersion>
<MoqVersion>4.14.6 </MoqVersion>
</PropertyGroup>
<PropertyGroup>
<DiscoverEditorConfigFiles>true</DiscoverEditorConfigFiles>
Expand Down
31 changes: 25 additions & 6 deletions src/MSBuild.Abstractions/BaselineProject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,46 @@ public struct BaselineProject
public readonly UnconfiguredProject Project;
public readonly ProjectStyle ProjectStyle;
public readonly ProjectOutputType OutputType;
public readonly string TargetTFM;

public BaselineProject(UnconfiguredProject project, ImmutableArray<string> globalProperties, ProjectStyle projectStyle, ProjectOutputType outputType) : this()
public BaselineProject(UnconfiguredProject project, ImmutableArray<string> globalProperties, ProjectStyle projectStyle, ProjectOutputType outputType, string candidateTargetTFM, bool keepCurrentTFMs) : this()
{
GlobalProperties = globalProperties;
Project = project ?? throw new ArgumentNullException(nameof(project));
ProjectStyle = projectStyle;
OutputType = outputType;
TargetTFM = keepCurrentTFMs
? GetCurrentTFM(globalProperties, project)
: AdjustTargetTFM(projectStyle, outputType, candidateTargetTFM);
}

public string GetTfm()
private static string AdjustTargetTFM(ProjectStyle projectStyle, ProjectOutputType outputType, string candidateTargetTFM)
{
if (GlobalProperties.Contains(MSBuildFacts.TargetFrameworkNodeName, StringComparer.OrdinalIgnoreCase))
if (candidateTargetTFM.ContainsIgnoreCase(MSBuildFacts.Net5) && projectStyle == ProjectStyle.WindowsDesktop)
{
return MSBuildFacts.Net5Windows;
}

if (outputType == ProjectOutputType.Library)
{
return MSBuildFacts.NetStandard20;
}

return candidateTargetTFM;
}

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));
return globalProperties.First(p => p.Equals(MSBuildFacts.TargetFrameworkNodeName, StringComparison.OrdinalIgnoreCase));
}
var rawTFM = Project.FirstConfiguredProject.GetProperty(MSBuildFacts.TargetFrameworkNodeName)?.EvaluatedValue;
var rawTFM = project.FirstConfiguredProject.GetProperty(MSBuildFacts.TargetFrameworkNodeName)?.EvaluatedValue;
if (rawTFM == null)
{
throw new InvalidOperationException(
$"{MSBuildFacts.TargetFrameworkNodeName} is not set in {nameof(Project.FirstConfiguredProject)}");
$"{MSBuildFacts.TargetFrameworkNodeName} is not set in {nameof(project.FirstConfiguredProject)}");
}

// This is pretty much never gonna happen, but it was cheap to write the code
Expand Down
18 changes: 13 additions & 5 deletions src/MSBuild.Abstractions/MSBuildConversionWorkspace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class MSBuildConversionWorkspace
{
public ImmutableArray<MSBuildConversionWorkspaceItem> WorkspaceItems { get; }

public MSBuildConversionWorkspace(ImmutableArray<string> paths, bool noBackup)
public MSBuildConversionWorkspace(ImmutableArray<string> paths, bool noBackup, string tfm, bool keepCurrentTFMs)
{
var items = ImmutableArray.CreateBuilder<MSBuildConversionWorkspaceItem>();

Expand Down Expand Up @@ -49,7 +49,7 @@ public MSBuildConversionWorkspace(ImmutableArray<string> paths, bool noBackup)
var unconfiguredProject = new UnconfiguredProject(configurations);
unconfiguredProject.LoadProjects(collection, globalProperties, path);

var baseline = CreateSdkBaselineProject(path, unconfiguredProject.FirstConfiguredProject, root, configurations);
var baseline = CreateSdkBaselineProject(path, unconfiguredProject.FirstConfiguredProject, root, configurations, tfm, keepCurrentTFMs);
root.Reload(throwIfUnsavedChanges: false, preserveFormatting: true);

var item = new MSBuildConversionWorkspaceItem(root, unconfiguredProject, baseline);
Expand Down Expand Up @@ -90,7 +90,7 @@ public ImmutableDictionary<string, ImmutableDictionary<string, string>> Determin
/// 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)
private BaselineProject CreateSdkBaselineProject(string projectFilePath, IProject project, IProjectRootElement root, ImmutableDictionary<string, ImmutableDictionary<string, string>> configurations, string tfm, bool keepCurrentTFMs)
{
var projectStyle = GetProjectStyle(root);
var outputType = GetProjectOutputType(root);
Expand All @@ -105,7 +105,10 @@ private BaselineProject CreateSdkBaselineProject(string projectFilePath, IProjec
rootElement.Sdk = MSBuildFacts.DefaultSDKAttribute;
break;
case ProjectStyle.WindowsDesktop:
rootElement.Sdk = DesktopFacts.WinSDKAttribute;
rootElement.Sdk =
tfm.ContainsIgnoreCase(MSBuildFacts.Net5)
? MSBuildFacts.DefaultSDKAttribute
: DesktopFacts.WinSDKAttribute; // pre-.NET 5 apps need a special SDK attribute.
break;
default:
throw new NotSupportedException($"This project has custom imports in a manner that's not supported. '{projectFilePath}'");
Expand Down Expand Up @@ -158,7 +161,12 @@ private BaselineProject CreateSdkBaselineProject(string projectFilePath, IProjec
propertiesInTheBaseline = propertiesInTheBaseline.Add(DesktopFacts.UseWPFPropertyName);
}

return new BaselineProject(newProject, propertiesInTheBaseline, projectStyle, outputType);
tfm =
projectStyle == ProjectStyle.WindowsDesktop && tfm.ContainsIgnoreCase(MSBuildFacts.Net5)
? MSBuildFacts.Net5Windows
: tfm;

return new BaselineProject(newProject, propertiesInTheBaseline, projectStyle, outputType, tfm, keepCurrentTFMs);
}

private bool IsSupportedOutputType(ProjectOutputType type) =>
Expand Down
4 changes: 2 additions & 2 deletions src/MSBuild.Abstractions/MSBuildConversionWorkspaceLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public MSBuildConversionWorkspaceLoader(string workspacePath, MSBuildConversionW
_workspaceType = workspaceType;
}

public MSBuildConversionWorkspace LoadWorkspace(string path, bool noBackup)
public MSBuildConversionWorkspace LoadWorkspace(string path, bool noBackup, string tfm, bool keepCurrentTFMs)
{
var projectPaths =
_workspaceType switch
Expand All @@ -42,7 +42,7 @@ public MSBuildConversionWorkspace LoadWorkspace(string path, bool noBackup)
_ => throw new InvalidOperationException("Somehow, an enum that isn't possible was passed in here.")
};

return new MSBuildConversionWorkspace(projectPaths, noBackup);
return new MSBuildConversionWorkspace(projectPaths, noBackup, tfm, keepCurrentTFMs);

static bool IsSupportedSolutionItemType(ProjectInSolution project)
{
Expand Down
39 changes: 33 additions & 6 deletions src/MSBuild.Abstractions/MSBuildHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;

using Microsoft.Build.Construction;
Expand Down Expand Up @@ -173,7 +172,14 @@ public static IEnumerable<string> GetAllProjectTypeGuids(IProjectRootElement roo
public static bool IsWPF(IProjectRootElement projectRoot)
{
var references = projectRoot.ItemGroups.SelectMany(GetReferences)?.Select(elem => elem.Include.Split(',').First());
return DesktopFacts.KnownWPFReferences.Any(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase));
if (references is null)
{
return false;
}
else
{
return DesktopFacts.KnownWPFReferences.Any(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase));
}
}

/// <summary>
Expand All @@ -182,7 +188,14 @@ public static bool IsWPF(IProjectRootElement projectRoot)
public static bool IsWinForms(IProjectRootElement projectRoot)
{
var references = projectRoot.ItemGroups.SelectMany(GetReferences)?.Select(elem => elem.Include.Split(',').First());
return DesktopFacts.KnownWinFormsReferences.Any(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase));
if (references is null)
{
return false;
}
else
{
return DesktopFacts.KnownWinFormsReferences.Any(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase));
}
}

/// <summary>
Expand All @@ -191,7 +204,14 @@ public static bool IsWinForms(IProjectRootElement projectRoot)
public static bool IsDesktop(IProjectRootElement projectRoot)
{
var references = projectRoot.ItemGroups.SelectMany(GetReferences)?.Select(elem => elem.Include.Split(',').First());
return DesktopFacts.KnownDesktopReferences.Any(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase));
if (references is null)
{
return false;
}
else
{
return DesktopFacts.KnownDesktopReferences.Any(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase));
}
}

/// <summary>
Expand All @@ -202,7 +222,14 @@ public static bool IsDesktop(IProjectRootElement projectRoot)
public static bool IsNETFrameworkMSTestProject(IProjectRootElement projectRoot)
{
var references = projectRoot.ItemGroups.SelectMany(GetReferences)?.Select(elem => elem.Include.Split(',').First());
return MSTestFacts.MSTestReferences.All(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase));
if (references is null)
{
return false;
}
else
{
return MSTestFacts.MSTestReferences.All(reference => references.Contains(reference, StringComparer.OrdinalIgnoreCase));
}
}

public static bool HasWPFOrWinForms(ProjectPropertyGroupElement propGroup)
Expand All @@ -221,7 +248,7 @@ public static bool IsNotNetFramework(string tfm) =>
/// <summary>
/// Finds the item group where a packages.config is included. Assumes only one.
/// </summary>
public static ProjectItemGroupElement GetPackagesConfigItemGroup(IProjectRootElement root) =>
public static ProjectItemGroupElement? GetPackagesConfigItemGroup(IProjectRootElement root) =>
root.ItemGroups.FirstOrDefault(pige => pige.Items.Any(pe => pe.Include.Equals(PackageFacts.PackagesConfigIncludeName, StringComparison.OrdinalIgnoreCase)));

/// <summary>
Expand Down
6 changes: 6 additions & 0 deletions src/MSBuild.Abstractions/ProjectExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,13 @@ private static string GetTargetFrameworkFromProjectJson(IProject project)
var json = JObject.Parse(projectJsonContents);

var frameworks = json["frameworks"];
if (frameworks is null)
{
throw new InvalidOperationException($"No target framework set in this 'project.json' file located at '{projectJsonPath}'.");
}

var tf = ((JProperty)frameworks.Single()).Name;

return tf;
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/MSBuild.Abstractions/ProjectItemHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public static bool IsSpecificPacakgeReference(ProjectItemElement element, string
public static bool DesktopReferencesNeedsRemoval(ProjectItemElement item) =>
DesktopFacts.ReferencesThatNeedRemoval.Contains(item.Include, StringComparer.OrdinalIgnoreCase)
|| DesktopFacts.KnownWPFReferences.Contains(item.Include, StringComparer.OrdinalIgnoreCase)
|| DesktopFacts.KnownWinFormsReferences.Contains(item.Include, StringComparer.OrdinalIgnoreCase);
|| DesktopFacts.KnownWinFormsReferences.Contains(item.Include, StringComparer.OrdinalIgnoreCase)
|| DesktopFacts.KnownDesktopReferences.Contains(item.Include, StringComparer.OrdinalIgnoreCase);

/// <summary>
/// Checks if a given item is a desktop item that is globbed, so long as the metadata is a form type.
Expand Down
6 changes: 4 additions & 2 deletions src/MSBuild.Conversion.Facts/MSBuildFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,10 @@ public static class MSBuildFacts
public const string TargetsSuffix = ".targets";
public const string PropsSuffix = ".props";
public const string PackagesSubstring = @"\packages";
public const string Netstandard20 = "netstandard2.0";
public const string Netcoreapp31 = "netcoreapp3.1";
public const string NetStandard20 = "netstandard2.0";
public const string NetCoreApp31 = "netcoreapp3.1";
public const string Net5 = "net5.0";
public const string Net5Windows = "net5.0-windows";
public const string AppConfig = "App.config";
}
}
58 changes: 14 additions & 44 deletions src/MSBuild.Conversion.Project/Converter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
using System.Xml.Linq;

using MSBuild.Abstractions;
using MSBuild.Conversion.Facts;
using MSBuild.Conversion.SDK;

namespace MSBuild.Conversion.Project
{
Expand All @@ -25,65 +23,30 @@ public Converter(UnconfiguredProject project, BaselineProject sdkBaselineProject
_differs = GetDiffers();
}

public void Convert(string outputPath, string? specifiedTFM, bool keepCurrentTfm, bool usePreviewSDK)
public void Convert(string outputPath)
{
ConvertProjectFile(specifiedTFM, keepCurrentTfm, usePreviewSDK);
ConvertProjectFile();
CleanUpProjectFile(outputPath);
}

internal IProjectRootElement? ConvertProjectFile(string? specifiedTFM, bool keepCurrentTfm, bool usePreviewSDK)
internal IProjectRootElement? ConvertProjectFile()
{
var tfm = GetBestTFM(_sdkBaselineProject, keepCurrentTfm, specifiedTFM, usePreviewSDK);

return _projectRootElement
// Let's convert packages first, since that's what you should do manually anyways
.ConvertAndAddPackages(_sdkBaselineProject.ProjectStyle, tfm)
.ConvertAndAddPackages(_sdkBaselineProject.ProjectStyle, _sdkBaselineProject.TargetTFM)

// Now we can convert the project over
.ChangeImportsAndAddSdkAttribute(_sdkBaselineProject)
.RemoveDefaultedProperties(_sdkBaselineProject, _differs)
.RemoveUnnecessaryPropertiesNotInSDKByDefault(_sdkBaselineProject.ProjectStyle)
.AddTargetFrameworkProperty(_sdkBaselineProject, tfm)
.AddTargetFrameworkProperty(_sdkBaselineProject, _sdkBaselineProject.TargetTFM)
.AddGenerateAssemblyInfoAsFalse()
.AddDesktopProperties(_sdkBaselineProject)
.AddCommonPropertiesToTopLevelPropertyGroup()
.RemoveOrUpdateItems(_differs, _sdkBaselineProject, tfm)
.RemoveOrUpdateItems(_differs, _sdkBaselineProject, _sdkBaselineProject.TargetTFM)
.AddItemRemovesForIntroducedItems(_differs)
.RemoveUnnecessaryTargetsIfTheyExist()
.ModifyProjectElement();

static string GetBestTFM(BaselineProject baselineProject, bool keepCurrentTfm, string? specifiedTFM, bool usePreviewSDK)
{
if (string.IsNullOrWhiteSpace(specifiedTFM))
{
// Let's figure this out, friends
var tfmForApps = TargetFrameworkHelper.FindHighestInstalledTargetFramework(usePreviewSDK);

if (keepCurrentTfm)
{
specifiedTFM = baselineProject.GetTfm();
}
else if (baselineProject.ProjectStyle == ProjectStyle.WindowsDesktop || baselineProject.ProjectStyle == ProjectStyle.MSTest)
{
specifiedTFM = tfmForApps;
}
else if (baselineProject.OutputType == ProjectOutputType.Library)
{
specifiedTFM = MSBuildFacts.Netstandard20;
}
else if (baselineProject.OutputType == ProjectOutputType.Exe)
{
specifiedTFM = tfmForApps;
}
else
{
// Default is to just use what exists in the project
specifiedTFM = baselineProject.GetTfm();
}
}

return specifiedTFM;
}
}

internal ImmutableDictionary<string, Differ> GetDiffers() =>
Expand All @@ -97,7 +60,14 @@ private void CleanUpProjectFile(string outputPath)
projectXml.Descendants().Attributes().Where(x => x.IsNamespaceDeclaration).Remove();
foreach (var element in projectXml.Descendants())
{
element.Name = element.Name.LocalName;
if (element is null)
{
continue;
}

// Appears to be a nullability bug?
// Also the diagnostic doesn't show in the editor
element.Name = element.Name.LocalName!;
}

// remove all use of ProductVersion
Expand Down
Loading

0 comments on commit 56a750a

Please sign in to comment.