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

Commit 736e17b

Browse files
authored
Merge branch 'main' into dev/jorobich/update-arcade
2 parents eb429dc + 3799b68 commit 736e17b

9 files changed

Lines changed: 115 additions & 14 deletions

File tree

src/MSBuild.Abstractions/BaselineProject.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ public BaselineProject(UnconfiguredProject project, ImmutableArray<string> globa
2626

2727
private static string AdjustTargetTFM(ProjectStyle projectStyle, ProjectOutputType outputType, string candidateTargetTFM)
2828
{
29+
if (candidateTargetTFM.ContainsIgnoreCase(MSBuildFacts.Net6) && projectStyle is ProjectStyle.WindowsDesktop)
30+
{
31+
return MSBuildFacts.Net6Windows;
32+
}
33+
2934
if (candidateTargetTFM.ContainsIgnoreCase(MSBuildFacts.Net5) && projectStyle is ProjectStyle.WindowsDesktop)
3035
{
3136
return MSBuildFacts.Net5Windows;
@@ -60,8 +65,8 @@ private static string GetCurrentTFM(ImmutableArray<string> globalProperties, Unc
6065
$"{MSBuildFacts.TargetFrameworkNodeName} is not set in {nameof(project.FirstConfiguredProject)}");
6166
}
6267

63-
// This is pretty much never gonna happen, but it was cheap to write the code
64-
return MSBuildHelpers.IsNotNetFramework(rawTFM) ? StripDecimals(rawTFM) : rawTFM;
68+
// MSBuildHelpers.IsWindows(rawTFM) can happen when coverting a UWP
69+
return MSBuildHelpers.IsNotNetFramework(rawTFM) && !MSBuildHelpers.IsWindows(rawTFM) ? StripDecimals(rawTFM) : rawTFM;
6570

6671
static string StripDecimals(string tfm)
6772
{

src/MSBuild.Abstractions/MSBuildConversionWorkspace.cs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ private bool TryCreateSdkBaselineProject(string projectFilePath, IProject projec
139139
break;
140140
case ProjectStyle.WindowsDesktop:
141141
rootElement.Sdk =
142-
tfm.ContainsIgnoreCase(MSBuildFacts.Net5)
142+
tfm.ContainsIgnoreCase(MSBuildFacts.Net5) || tfm.ContainsIgnoreCase(MSBuildFacts.Net6)
143143
? MSBuildFacts.DefaultSDKAttribute
144144
: DesktopFacts.WinSDKAttribute; // pre-.NET 5 apps need a special SDK attribute.
145145
break;
@@ -165,6 +165,7 @@ private bool TryCreateSdkBaselineProject(string projectFilePath, IProject projec
165165
ProjectOutputType.Exe => MSBuildFacts.ExeOutputType,
166166
ProjectOutputType.Library => MSBuildFacts.LibraryOutputType,
167167
ProjectOutputType.WinExe => MSBuildFacts.WinExeOutputType,
168+
ProjectOutputType.AppContainerExe => MSBuildFacts.WinExeOutputType,
168169
_ => project.GetPropertyValue(MSBuildFacts.OutputTypeNodeName)
169170
};
170171
propGroup.AddProperty(MSBuildFacts.OutputTypeNodeName, outputTypeValue ?? throw new InvalidOperationException($"OutputType is not set! '{projectFilePath}'"));
@@ -185,7 +186,7 @@ private bool TryCreateSdkBaselineProject(string projectFilePath, IProject projec
185186
MSBuildHelpers.AddUseWinForms(propGroup);
186187
}
187188

188-
if (MSBuildHelpers.HasWPFOrWinForms(propGroup) && tfm.ContainsIgnoreCase(MSBuildFacts.Net5))
189+
if (MSBuildHelpers.HasWPFOrWinForms(propGroup) && tfm.ContainsIgnoreCase(MSBuildFacts.Net5) || tfm.ContainsIgnoreCase(MSBuildFacts.Net6))
189190
{
190191
MSBuildHelpers.AddImportWindowsDesktopTargets(propGroup);
191192
}
@@ -213,22 +214,29 @@ private bool TryCreateSdkBaselineProject(string projectFilePath, IProject projec
213214
propertiesInTheBaseline = propertiesInTheBaseline.Add(DesktopFacts.UseWPFPropertyName);
214215
}
215216

216-
tfm =
217-
projectStyle == ProjectStyle.WindowsDesktop && tfm.ContainsIgnoreCase(MSBuildFacts.Net5)
218-
? MSBuildFacts.Net5Windows
219-
: tfm;
220-
217+
tfm = GetTFMString(projectStyle, tfm);
221218

222219
baselineProject = new BaselineProject(newProject, propertiesInTheBaseline, projectStyle, outputType, tfm, keepCurrentTFMs);
223220
return true;
224221
}
222+
static string GetTFMString(ProjectStyle projectStyle, string tfm) {
223+
if (projectStyle == ProjectStyle.WindowsDesktop)
224+
{
225+
if (tfm.ContainsIgnoreCase(MSBuildFacts.Net5))
226+
return MSBuildFacts.Net5Windows;
227+
if (tfm.ContainsIgnoreCase(MSBuildFacts.Net6))
228+
return MSBuildFacts.Net6Windows;
229+
}
230+
return tfm;
231+
}
225232

226233
private bool IsSupportedOutputType(ProjectOutputType type) =>
227234
type switch
228235
{
229236
ProjectOutputType.Exe => true,
230237
ProjectOutputType.Library => true,
231238
ProjectOutputType.WinExe => true,
239+
ProjectOutputType.AppContainerExe => true,
232240
_ => false
233241
};
234242

@@ -271,6 +279,10 @@ private ProjectOutputType GetProjectOutputType(IProjectRootElement root, Project
271279
{
272280
return ProjectOutputType.WinExe;
273281
}
282+
else if (ProjectPropertyHelpers.IsAppContainerExeOutputType(outputTypeNode))
283+
{
284+
return ProjectOutputType.AppContainerExe;
285+
}
274286
else
275287
{
276288
return ProjectOutputType.Other;
@@ -298,7 +310,7 @@ private ProjectStyle GetProjectStyle(IProjectRootElement projectRootElement)
298310
{
299311
return ProjectStyle.MSTest;
300312
}
301-
else if (MSBuildHelpers.IsWPF(projectRootElement) || MSBuildHelpers.IsWinForms(projectRootElement) || MSBuildHelpers.IsDesktop(projectRootElement))
313+
else if (MSBuildHelpers.IsWPF(projectRootElement) || MSBuildHelpers.IsWinForms(projectRootElement) || MSBuildHelpers.IsDesktop(projectRootElement) || MSBuildHelpers.IsUwp(projectRootElement))
302314
{
303315
return ProjectStyle.WindowsDesktop;
304316
}

src/MSBuild.Abstractions/MSBuildHelpers.cs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ public static bool FrameworkHasAValueTuple(string tfm) =>
142142
tfm.StartsWith(MSBuildFacts.NetstandardPrelude, StringComparison.OrdinalIgnoreCase)
143143
|| tfm.StartsWith(MSBuildFacts.NetcoreappPrelude, StringComparison.OrdinalIgnoreCase)
144144
|| tfm.StartsWith(MSBuildFacts.Net5, StringComparison.OrdinalIgnoreCase)
145+
|| tfm.StartsWith(MSBuildFacts.Net6, StringComparison.OrdinalIgnoreCase)
145146
|| tfm.StartsWith(MSBuildFacts.LowestFrameworkVersionWithSystemValueTuple, StringComparison.OrdinalIgnoreCase);
146147

147148
/// <summary>
@@ -150,6 +151,12 @@ public static bool FrameworkHasAValueTuple(string tfm) =>
150151
private static IEnumerable<ProjectItemElement> GetReferences(ProjectItemGroupElement itemGroup) =>
151152
itemGroup.Items.Where(item => item.ElementName.Equals(MSBuildFacts.MSBuildReferenceName, StringComparison.OrdinalIgnoreCase));
152153

154+
/// <summary>
155+
/// Gets all PackageReference items from a given item group.
156+
/// </summary>
157+
private static IEnumerable<ProjectItemElement> GetPackageReferences(ProjectItemGroupElement itemGroup) =>
158+
itemGroup.Items.Where(item => item.ElementName.Equals(MSBuildFacts.MSBuildPackageReferenceName, StringComparison.OrdinalIgnoreCase));
159+
153160
/// <summary>
154161
/// Checks if a root has a project type guids node.
155162
/// </summary>
@@ -211,6 +218,26 @@ public static bool IsDesktop(IProjectRootElement projectRoot)
211218
}
212219
}
213220

221+
/// <summary>
222+
/// Determines if a given project is UWP
223+
/// </summary>
224+
public static bool IsUwp(IProjectRootElement projectRoot)
225+
{
226+
if (projectRoot.PropertyGroups.Any(g => g.Properties.Any(p => p.Name == "TargetPlatformIdentifier" && p.Value == "UAP")))
227+
{
228+
return true;
229+
}
230+
var packageReferences = projectRoot.ItemGroups.SelectMany(GetPackageReferences)?.Select(elem => elem.Include.Split(',').First());
231+
if (packageReferences is null)
232+
{
233+
return false;
234+
}
235+
else
236+
{
237+
return DesktopFacts.KnownUwpReferences.Any(reference => packageReferences.Contains(reference, StringComparer.OrdinalIgnoreCase));
238+
}
239+
}
240+
214241
/// <summary>
215242
/// Determines if a given project references ASP.NET assemblies.
216243
/// </summary>
@@ -240,7 +267,7 @@ public static bool IsWebApp(IProjectRootElement projectRoot) =>
240267
/// </summary>
241268
public static bool IsAspNetCore(IProjectRootElement projectRoot, string tfm) =>
242269
IsWebApp(projectRoot) || projectRoot.Sdk.Equals(WebFacts.WebSDKAttribute)
243-
|| (IsWeb(projectRoot) && new[] { MSBuildFacts.Net5, MSBuildFacts.NetcoreappPrelude }.Any(s => tfm.StartsWith(s, StringComparison.OrdinalIgnoreCase)));
270+
|| (IsWeb(projectRoot) && new[] { MSBuildFacts.Net6, MSBuildFacts.Net5, MSBuildFacts.NetcoreappPrelude }.Any(s => tfm.StartsWith(s, StringComparison.OrdinalIgnoreCase)));
244271

245272
/// <summary>
246273
/// Determines if a project is a .NET Framework MSTest project by looking at its references.
@@ -273,6 +300,12 @@ public static bool IsNotNetFramework(string tfm) =>
273300
!tfm.ContainsIgnoreCase(MSBuildFacts.NetcoreappPrelude)
274301
&& !tfm.ContainsIgnoreCase(MSBuildFacts.NetstandardPrelude);
275302

303+
/// <summary>
304+
/// Checks if a given TFM include -windows
305+
/// </summary>
306+
public static bool IsWindows(string tfm) =>
307+
tfm.ContainsIgnoreCase(MSBuildFacts.WindowsSuffix);
308+
276309
/// <summary>
277310
/// Finds the item group where a packages.config is included. Assumes only one.
278311
/// </summary>
@@ -295,6 +328,11 @@ public static ProjectItemElement GetPackagesConfigItem(ProjectItemGroupElement p
295328
/// </summary>
296329
public static void AddUseWPF(ProjectPropertyGroupElement propGroup) => propGroup.AddProperty(DesktopFacts.UseWPFPropertyName, "true");
297330

331+
/// <summary>
332+
/// Adds the UseWinUI=true property to the top-level project property group.
333+
/// </summary>
334+
public static void AddUseWinUI(ProjectPropertyGroupElement propGroup) => propGroup.AddProperty(DesktopFacts.UseWinUIPropertyName, "true");
335+
298336
/// <summary>
299337
/// Adds the ImportWindowsDesktopTargets=true property to ensure builds targeting .NET Framework will succeed.
300338
/// </summary>
@@ -368,7 +406,7 @@ public static bool ArePropertyGroupElementsIdentical(ProjectPropertyGroupElement
368406
/// <returns>true if string is successfuly unquoted</returns>
369407
private static bool UnquoteString(ref string s)
370408
{
371-
if (s.Length < 2 || s[0] != '\'' || s[^1] != '\'')
409+
if (s.Length < 2 || s[0] != '\'' || s[^1] != '\'' || s[1..^1].Contains('\''))
372410
{
373411
return false;
374412
}

src/MSBuild.Abstractions/ProjectExtensions.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,28 @@ public static string GetTargetFramework(this IProject project)
4343
{
4444
".NETFramework" => "net",
4545
".NETStandard" => "netstandard",
46+
".NETCore" => "net", // UWP
4647
".NETCoreApp" => "netcoreapp",
4748
".NETPortable" => "netstandard",
4849
"MonoAndroid" => "net",
4950
"Xamarin.iOS" => "net",
5051
_ => throw new InvalidOperationException($"Unknown {MSBuildFacts.LegacyTargetFrameworkPropertyNodeName}: {tfi}"),
5152
};
5253

54+
if (tfi == ".NETCore")
55+
{
56+
var targetPlatformIdentifier = project.GetPropertyValue(MSBuildFacts.TargetPlatformIdentifierNodeName);
57+
if (targetPlatformIdentifier.Equals(MSBuildFacts.UapValue, StringComparison.OrdinalIgnoreCase))
58+
{
59+
var targetPlatformVersion = project.GetPropertyValue(MSBuildFacts.TargetPlatformVersionNodeName);
60+
if (!string.IsNullOrWhiteSpace(targetPlatformVersion))
61+
{
62+
tf = $"net6.0-windows{targetPlatformVersion}";
63+
return tf;
64+
}
65+
}
66+
}
67+
5368
if (tfi.Equals(MSBuildFacts.NETPortableTFValuePrefix, StringComparison.OrdinalIgnoreCase))
5469
{
5570
var profile = project.GetPropertyValue(MSBuildFacts.LegacyTargetFrameworkProfileNodeName);

src/MSBuild.Abstractions/ProjectOutputType.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public enum ProjectOutputType
1212
Library,
1313
Exe,
1414
WinExe,
15+
AppContainerExe,
1516
Other,
1617
None
1718
}

src/MSBuild.Abstractions/ProjectPropertyHelpers.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,20 @@ public static bool IsExeOutputType(ProjectPropertyElement prop) =>
156156
prop.ElementName.Equals(MSBuildFacts.OutputTypeNodeName, StringComparison.OrdinalIgnoreCase)
157157
&& prop.Value.Equals(MSBuildFacts.ExeOutputType, StringComparison.OrdinalIgnoreCase);
158158

159+
/// <summary>
160+
/// Checks if an OutputType node is AppContainerExe.
161+
/// </summary>
162+
public static bool IsAppContainerExeOutputType(ProjectPropertyElement prop) =>
163+
prop.ElementName.Equals(MSBuildFacts.OutputTypeNodeName, StringComparison.OrdinalIgnoreCase)
164+
&& prop.Value.Equals(MSBuildFacts.AppContainerExeOutputType, StringComparison.OrdinalIgnoreCase);
165+
159166
/// <summary>
160167
/// Checks if an OutputType node is Exe.
161168
/// </summary>
162169
public static bool IsWinExeOutputType(ProjectPropertyElement prop) =>
163170
prop.ElementName.Equals(MSBuildFacts.OutputTypeNodeName, StringComparison.OrdinalIgnoreCase)
164171
&& prop.Value.Equals(MSBuildFacts.WinExeOutputType, StringComparison.OrdinalIgnoreCase);
165172

166-
167173
public static bool IsVisualBasicProject(ProjectPropertyElement prop) =>
168174
IsProjectTypeGuidsNode(prop) && prop.Value.Split(';').Any(guidString => Guid.Parse(guidString) == MSBuildFacts.LanguageProjectTypeVisualBasic);
169175

src/MSBuild.Conversion.Facts/DesktopFacts.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ public static class DesktopFacts
4646
"WindowsBase"
4747
);
4848

49+
public static ImmutableArray<string> KnownUwpReferences => ImmutableArray.Create(
50+
"Microsoft.NETCore.UniversalWindowsPlatform"
51+
);
52+
4953
public static ImmutableArray<Guid> KnownSupportedDesktopProjectTypeGuids => ImmutableArray.Create(
5054
MSBuildFacts.LanguageProjectTypeVisualBasic, // VB.NET
5155
Guid.Parse("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"), // C#
@@ -55,6 +59,7 @@ public static class DesktopFacts
5559
public const string WinSDKAttribute = "Microsoft.NET.Sdk.WindowsDesktop";
5660
public const string UseWPFPropertyName = "UseWPF";
5761
public const string UseWinFormsPropertyName = "UseWindowsForms";
62+
public const string UseWinUIPropertyName = "UseWinUI";
5863
public const string ImportWindowsDesktopTargetsName = "ImportWindowsDesktopTargets";
5964
public const string DesignerSuffix = ".Designer.cs";
6065
public const string XamlFileExtension = ".xaml";

src/MSBuild.Conversion.Facts/MSBuildFacts.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,11 @@ public static class MSBuildFacts
106106

107107
// No longer used in ASP.NET Core
108108
"MvcProjectUpgradeChecked",
109-
"UseGlobalApplicationHostFile"
109+
"UseGlobalApplicationHostFile",
110+
111+
// Not needed for converted UWP apps
112+
"TargetPlatformIdentifier",
113+
"TargetPlatformVersion"
110114
);
111115

112116
public static ImmutableArray<string> DefaultDefineConstants => ImmutableArray.Create(
@@ -268,6 +272,7 @@ public static class MSBuildFacts
268272
public const string NetcoreappPrelude = "netcoreapp";
269273
public const string NetstandardPrelude = "netstandard";
270274
public const string MSBuildReferenceName = "Reference";
275+
public const string MSBuildPackageReferenceName = "PackageReference";
271276
public const string DesignerSubType = "Designer";
272277
public const string CodeSubTypeValue = "Code";
273278
public const string TargetFrameworkNodeName = "TargetFramework";
@@ -284,6 +289,7 @@ public static class MSBuildFacts
284289
public const string LibraryOutputType = "Library";
285290
public const string ExeOutputType = "Exe";
286291
public const string WinExeOutputType = "WinExe";
292+
public const string AppContainerExeOutputType = "AppContainerExe";
287293
public const string NuGetPackageImportStampNodeName = "NuGetPackageImportStamp";
288294
public const string ReferencePathNodeName = "ReferencePath";
289295
public const string LegacyTargetFrameworkPropertyNodeName = "TargetFrameworkIdentifier";
@@ -297,9 +303,15 @@ public static class MSBuildFacts
297303
public const string NetStandard20 = "netstandard2.0";
298304
public const string NetCoreApp31 = "netcoreapp3.1";
299305
public const string Net5 = "net5.0";
306+
public const string WindowsSuffix = "-windows";
300307
public const string Net5Windows = "net5.0-windows";
308+
public const string Net6 = "net6.0";
309+
public const string Net6Windows = "net6.0-windows";
301310
public const string AppConfig = "App.config";
302311
public const string EmbeddedResourceGeneratorProperty = "Generator";
303312
public const string SettingsSingleFileGenerator = "SettingsSingleFileGenerator";
313+
public const string TargetPlatformIdentifierNodeName = "TargetPlatformIdentifier";
314+
public const string UapValue = "UAP";
315+
public const string TargetPlatformVersionNodeName = "TargetPlatformVersion";
304316
}
305317
}

src/MSBuild.Conversion.Project/ProjectRootElementExtensionsForConversion.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public static IProjectRootElement UpdateOutputTypeProperty(this IProjectRootElem
7575
ProjectOutputType.Exe => MSBuildFacts.ExeOutputType,
7676
ProjectOutputType.Library => MSBuildFacts.LibraryOutputType,
7777
ProjectOutputType.WinExe => MSBuildFacts.WinExeOutputType,
78+
ProjectOutputType.AppContainerExe => MSBuildFacts.WinExeOutputType,
7879
_ => throw new InvalidOperationException("Unsupported output type: " + baselineProject.OutputType)
7980
};
8081
}
@@ -460,6 +461,12 @@ public static IProjectRootElement AddDesktopProperties(this IProjectRootElement
460461
MSBuildHelpers.AddUseWPF(propGroup);
461462
}
462463

464+
if (!baselineProject.GlobalProperties.Contains(DesktopFacts.UseWinUIPropertyName, StringComparer.OrdinalIgnoreCase)
465+
&& MSBuildHelpers.IsUwp(projectRootElement))
466+
{
467+
MSBuildHelpers.AddUseWinUI(propGroup);
468+
}
469+
463470
if (!baselineProject.GlobalProperties.Contains(DesktopFacts.ImportWindowsDesktopTargetsName, StringComparer.OrdinalIgnoreCase)
464471
&& !projectRootElement.Sdk.Equals(DesktopFacts.WinSDKAttribute)
465472
&& (MSBuildHelpers.IsWPF(projectRootElement) || MSBuildHelpers.IsWinForms(projectRootElement)))

0 commit comments

Comments
 (0)