From 7045264a3093ad3df7528741202f45f168ff5e44 Mon Sep 17 00:00:00 2001 From: hwthomas Date: Sun, 4 Sep 2022 17:34:10 +0100 Subject: [PATCH 01/11] Remove local implementation of MSBuild IntrinsicFunctions and update MSBuildEvaluationContext.cs accordingly IntrinsicFunctions are now loaded at runtime from the current version of Microsoft.Build.dll, as identified by the active runtime. The old IntrinsicFunctions test is no longer meaningful and has been removed This fixes Issue #75 so that all project properties are now evaluated correctly. --- .../MonoDevelop.Core/MonoDevelop.Core.csproj | 2 - .../IntrinsicFunctions.Extensions.cs | 35 -- .../IntrinsicFunctions.cs | 513 ------------------ .../MSBuildEvaluationContext.cs | 169 +++--- .../MonoDevelop.Core.Tests.csproj | 3 +- .../IntrinsicFunctionsTests.cs | 50 -- 6 files changed, 91 insertions(+), 681 deletions(-) delete mode 100644 main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IntrinsicFunctions.Extensions.cs delete mode 100644 main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IntrinsicFunctions.cs delete mode 100644 main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/IntrinsicFunctionsTests.cs diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj index ff4ea57a667..f9357ac8d7f 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj @@ -629,7 +629,6 @@ - @@ -747,7 +746,6 @@ - diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IntrinsicFunctions.Extensions.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IntrinsicFunctions.Extensions.cs deleted file mode 100644 index 68e79fa7e24..00000000000 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IntrinsicFunctions.Extensions.cs +++ /dev/null @@ -1,35 +0,0 @@ -// -// IntrinsicFunctions.Extensions.cs -// -// Author: -// Marius Ungureanu -// -// Copyright (c) 2019 Microsoft Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -namespace Microsoft.Build.Evaluation -{ - internal static partial class IntrinsicFunctions - { - // Similar to https://github.com/microsoft/msbuild/pull/4731 - // This avoids creating a string copy for the purpose of evaluation in metadata items. - internal static string Copy (string value) => value; - } -} diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IntrinsicFunctions.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IntrinsicFunctions.cs deleted file mode 100644 index ef0da6883ca..00000000000 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IntrinsicFunctions.cs +++ /dev/null @@ -1,513 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -//----------------------------------------------------------------------- -// -// Definition of functions which can be accessed from MSBuild files. -//----------------------------------------------------------------------- - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text.RegularExpressions; - -using Microsoft.Build.Internal; -using Microsoft.Build.Shared; -using Microsoft.Win32; - -using MonoDevelop.Core; -using MonoDevelop.Core.Assemblies; - - -namespace Microsoft.Build.Evaluation -{ - /// - /// The Intrinsic class provides static methods that can be accessed from MSBuild's - /// property functions using $([MSBuild]::Function(x,y)) - /// - internal static partial class IntrinsicFunctions - { - /// - /// Add two doubles - /// - internal static double Add (double a, double b) - { - return a + b; - } - - /// - /// Add two longs - /// - internal static long Add (long a, long b) - { - return a + b; - } - - /// - /// Subtract two doubles - /// - internal static double Subtract (double a, double b) - { - return a - b; - } - - /// - /// Subtract two longs - /// - internal static long Subtract (long a, long b) - { - return a - b; - } - - /// - /// Multiply two doubles - /// - internal static double Multiply (double a, double b) - { - return a * b; - } - - /// - /// Multiply two longs - /// - internal static long Multiply (long a, long b) - { - return a * b; - } - - /// - /// Divide two doubles - /// - internal static double Divide (double a, double b) - { - return a / b; - } - - /// - /// Divide two longs - /// - internal static long Divide (long a, long b) - { - return a / b; - } - - /// - /// Modulo two doubles - /// - internal static double Modulo (double a, double b) - { - return a % b; - } - - /// - /// Modulo two longs - /// - internal static long Modulo (long a, long b) - { - return a % b; - } - - /// - /// Escape the string according to MSBuild's escaping rules - /// - internal static string Escape (string unescaped) - { - return EscapingUtilities.Escape (unescaped); - } - - /// - /// Unescape the string according to MSBuild's escaping rules - /// - internal static string Unescape (string escaped) - { - return EscapingUtilities.UnescapeAll (escaped); - } - - /// - /// Perform a bitwise OR on the first and second (first | second) - /// - internal static int BitwiseOr (int first, int second) - { - return first | second; - } - - /// - /// Perform a bitwise AND on the first and second (first & second) - /// - internal static int BitwiseAnd (int first, int second) - { - return first & second; - } - - /// - /// Perform a bitwise XOR on the first and second (first ^ second) - /// - internal static int BitwiseXor (int first, int second) - { - return first ^ second; - } - - /// - /// Perform a bitwise NOT on the first and second (~first) - /// - internal static int BitwiseNot (int first) - { - return ~first; - } - - /// - /// Get the value of the registry key and value, default value is null - /// - internal static object GetRegistryValue(string keyName, string valueName) - { - return Registry.GetValue(keyName, valueName, null /* null to match the $(Regsitry:XYZ@ZBC) behaviour */); - } - - /// - /// Get the value of the registry key and value - /// - internal static object GetRegistryValue(string keyName, string valueName, object defaultValue) - { - return Registry.GetValue(keyName, valueName, defaultValue); - } - - /// - /// Get the value of the registry key from one of the RegistryView's specified - /// - internal static object GetRegistryValueFromView(string keyName, string valueName, object defaultValue, params object[] views) - { - string subKeyName; - - // We will take on handing of default value - // A we need to act on the null return from the GetValue call below - // so we can keep searching other registry views - object result = defaultValue; - - // If we haven't been passed any views, then we'll just use the default view - if (views == null || views.Length == 0) - { - views = new object[] { RegistryView.Default }; - } - - foreach (object viewObject in views) - { - string viewAsString = viewObject as string; - - if (viewAsString != null) - { - string typeLeafName = typeof(RegistryView).Name + "."; - string typeFullName = typeof(RegistryView).FullName + "."; - - // We'll allow the user to specify the leaf or full type name on the RegistryView enum - viewAsString = viewAsString.Replace(typeFullName, "").Replace(typeLeafName, ""); - - // This may throw - and that's fine as the user will receive a controlled version - // of that error. - RegistryView view = (RegistryView)Enum.Parse(typeof(RegistryView), viewAsString, true); - - if (!Platform.IsWindows && !keyName.StartsWith("HKEY_CURRENT_USER", StringComparison.OrdinalIgnoreCase)) - { - // Fake common requests to HKLM that we can resolve - - - // See if this asks for a specific SDK - var m = Regex.Match(keyName, - @"^HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Microsoft SDKs\\Windows\\v(\d+\.\d+)$", - RegexOptions.IgnoreCase); - if (m.Success && m.Groups.Count >= 1 && valueName.Equals("InstallRoot", StringComparison.OrdinalIgnoreCase)) - { - var mr = MonoDevelop.Core.Runtime.SystemAssemblyService.DefaultRuntime as MonoTargetRuntime; - if (mr != null) - return Path.Combine (mr.MonoDirectory, m.Groups [0].Value) + Path.DirectorySeparatorChar; - } - - return string.Empty; - } - - using (RegistryKey key = GetBaseKeyFromKeyName(keyName, view, out subKeyName)) - { - if (key != null) - { - using (RegistryKey subKey = key.OpenSubKey(subKeyName, false)) - { - // If we managed to retrieve the subkey, then move onto locating the value - if (subKey != null) - { - result = subKey.GetValue(valueName); - } - - // We've found a value, so stop looking - if (result != null) - { - break; - } - } - } - } - } - } - - // We will have either found a result or defaultValue if one wasn't found at this point - return result; - } - - /// - /// Given the absolute location of a file, and a disc location, returns relative file path to that disk location. - /// Throws UriFormatException. - /// - /// - /// The base path we want to relativize to. Must be absolute. - /// Should not include a filename as the last segment will be interpreted as a directory. - /// - /// - /// The path we need to make relative to basePath. The path can be either absolute path or a relative path in which case it is relative to the base path. - /// If the path cannot be made relative to the base path (for example, it is on another drive), it is returned verbatim. - /// - /// relative path (can be the full path) - internal static string MakeRelative (string basePath, string path) - { - string result = FileService.AbsoluteToRelativePath (basePath, path); - - return result; - } - - /// - /// Locate a file in either the directory specified or a location in the - /// direcorty structure above that directory. - /// - internal static string GetDirectoryNameOfFileAbove (string startingDirectory, string fileName) - { - // Canonicalize our starting location - string lookInDirectory = Path.GetFullPath (startingDirectory); - - do { - // Construct the path that we will use to test against - string possibleFileDirectory = Path.Combine (lookInDirectory, fileName); - - // If we successfully locate the file in the directory that we're - // looking in, simply return that location. Otherwise we'll - // keep moving up the tree. - if (File.Exists (possibleFileDirectory)) { - // We've found the file, return the directory we found it in - return lookInDirectory; - } else { - // GetDirectoryName will return null when we reach the root - // terminating our search - lookInDirectory = Path.GetDirectoryName (lookInDirectory); - } - } - while (lookInDirectory != null); - - // When we didn't find the location, then return an empty string - return String.Empty; - } - - /// - /// Searches for a file based on the specified . - /// - /// The file to search for. - /// An optional directory to start the search in. The default location is the directory - /// of the file containing the property funciton. - /// The full path of the file if it is found, otherwise an empty string. - internal static string GetPathOfFileAbove (string file, string startingDirectory) - { - // This method does not accept a path, only a file name - if (file.Any (i => i.Equals (Path.DirectorySeparatorChar) || i.Equals (Path.AltDirectorySeparatorChar))) { - throw new ArgumentException ("InvalidGetPathOfFileAboveParameter", file); - } - - // Search for a directory that contains that file - string directoryName = GetDirectoryNameOfFileAbove (startingDirectory, file); - - return String.IsNullOrWhiteSpace (directoryName) ? String.Empty : NormalizePath (directoryName, file); - } - - /// - /// Return the string in parameter 'defaultValue' only if parameter 'conditionValue' is empty - /// else, return the value conditionValue - /// - internal static string ValueOrDefault (string conditionValue, string defaultValue) - { - if (String.IsNullOrEmpty (conditionValue)) { - return defaultValue; - } else { - return conditionValue; - } - } - - /// - /// Returns true if a task host exists that can service the requested runtime and architecture - /// values, and false otherwise. - /// - internal static bool DoesTaskHostExist (string runtime, string architecture) - { - return false; - } - - /// - /// If the given path doesn't have a trailing slash then add one. - /// If the path is an empty string, does not modify it. - /// - /// The path to check. - /// The specified path with a trailing slash. - internal static string EnsureTrailingSlash (string path) - { - return FileUtilities.EnsureTrailingSlash (path); - } - - /// - /// Gets the canonicalized full path of the provided directory and ensures it contains the correct directory separator characters for the current operating system - /// while ensuring it has a trailing slash. - /// - /// One or more directory paths to combine and normalize. - /// A canonicalized full directory path with the correct directory separators and a trailing slash. - internal static string NormalizeDirectory (params string [] path) - { - return EnsureTrailingSlash (NormalizePath (path)); - } - - /// - /// Gets the canonicalized full path of the provided path and ensures it contains the correct directory separator characters for the current operating system. - /// - /// One or more paths to combine and normalize. - /// A canonicalized full path with the correct directory separators. - internal static string NormalizePath (params string [] path) - { - return FileUtilities.NormalizePath (Path.Combine (path)); - } - - /// - /// Specify whether the current OS platform is - /// - /// The platform string. Must be a member of . Case Insensitive - /// - internal static bool IsOSPlatform (string platformString) - { - return RuntimeInformation.IsOSPlatform (OSPlatform.Create (platformString.ToUpperInvariant ())); - } - - /// - /// True if current OS is a Unix system. - /// - /// - internal static bool IsOsUnixLike () - { - return !Platform.IsWindows; - } - - //public static string GetCurrentToolsDirectory () - //{ - // return BuildEnvironmentHelper.Instance.CurrentMSBuildToolsDirectory; - //} - - //public static string GetToolsDirectory32 () - //{ - // return BuildEnvironmentHelper.Instance.MSBuildToolsDirectory32; - //} - - //public static string GetToolsDirectory64 () - //{ - // return BuildEnvironmentHelper.Instance.MSBuildToolsDirectory64; - //} - - //public static string GetMSBuildSDKsPath () - //{ - // return BuildEnvironmentHelper.Instance.MSBuildSDKsPath; - //} - - //public static string GetVsInstallRoot () - //{ - // return BuildEnvironmentHelper.Instance.VisualStudioInstallRootDirectory; - //} - - //public static string GetProgramFiles32 () - //{ - // return FrameworkLocationHelper.programFiles32; - //} - - //public static string GetMSBuildExtensionsPath () - //{ - // return BuildEnvironmentHelper.Instance.MSBuildExtensionsPath; - //} - - #region Debug only intrinsics - - /// - /// returns if the string contains escaped wildcards - /// - internal static List __GetListTest () - { - return new List { "A", "B", "C", "D" }; - } - - #endregion - - /// - /// Following function will parse a keyName and returns the basekey for it. - /// It will also store the subkey name in the out parameter. - /// If the keyName is not valid, we will throw ArgumentException. - /// The return value shouldn't be null. - /// Taken from: \ndp\clr\src\BCL\Microsoft\Win32\Registry.cs - /// - private static RegistryKey GetBaseKeyFromKeyName(string keyName, RegistryView view, out string subKeyName) - { - if (keyName == null) - { - throw new ArgumentNullException("keyName"); - } - - string basekeyName; - int i = keyName.IndexOf('\\'); - if (i != -1) - { - basekeyName = keyName.Substring(0, i).ToUpperInvariant(); - } - else - { - basekeyName = keyName.ToUpperInvariant(); - } - - RegistryKey basekey = null; - - switch (basekeyName) - { - case "HKEY_CURRENT_USER": - basekey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, view); - break; - case "HKEY_LOCAL_MACHINE": - basekey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view); - break; - case "HKEY_CLASSES_ROOT": - basekey = RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, view); - break; - case "HKEY_USERS": - basekey = RegistryKey.OpenBaseKey(RegistryHive.Users, view); - break; - case "HKEY_PERFORMANCE_DATA": - basekey = RegistryKey.OpenBaseKey(RegistryHive.PerformanceData, view); - break; - case "HKEY_CURRENT_CONFIG": - basekey = RegistryKey.OpenBaseKey(RegistryHive.CurrentConfig, view); - break; - case "HKEY_DYN_DATA": - basekey = RegistryKey.OpenBaseKey(RegistryHive.DynData, view); - break; - default: - throw new ArgumentException (keyName); - } - - if (i == -1 || i == keyName.Length) - { - subKeyName = string.Empty; - } - else - { - subKeyName = keyName.Substring(i + 1, keyName.Length - i - 1); - } - - return basekey; - } - } -} \ No newline at end of file diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs index 34d9058f179..11190095108 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs @@ -89,10 +89,10 @@ public MSBuildEvaluationContext (MSBuildEvaluationContext parentContext) internal void InitEvaluation (MSBuildProject project) { - this.project = project; - - // Project file properties - + this.project = project; + + // Project file properties + properties.Add ("MSBuildThisFile", Path.GetFileName (project.FileName)); properties.Add ("MSBuildThisFileName", project.FileName.FileNameWithoutExtension); properties.Add ("MSBuildThisFileExtension", Path.GetExtension (project.FileName)); @@ -100,10 +100,10 @@ internal void InitEvaluation (MSBuildProject project) string dir = Path.GetDirectoryName (project.FileName) + Path.DirectorySeparatorChar; properties.Add ("MSBuildThisFileDirectory", MSBuildProjectService.ToMSBuildPath (null, dir)); - properties.Add ("MSBuildThisFileDirectoryNoRoot", MSBuildProjectService.ToMSBuildPath (null, dir.Substring (Path.GetPathRoot (dir).Length))); - - // Properties only set for the root project, not for imported projects - + properties.Add ("MSBuildThisFileDirectoryNoRoot", MSBuildProjectService.ToMSBuildPath (null, dir.Substring (Path.GetPathRoot (dir).Length))); + + // Properties only set for the root project, not for imported projects + if (parentContext == null) { properties.Add ("VisualStudioReferenceAssemblyVersion", project.ToolsVersion + ".0.0"); properties.Add ("MSBuildProjectDefaultTargets", project.DefaultTargets); @@ -117,10 +117,14 @@ internal void InitEvaluation (MSBuildProject project) properties.Add ("MSBuildProjectDirectoryNoRoot", MSBuildProjectService.ToMSBuildPath (null, dir.Substring (Path.GetPathRoot (dir).Length))); InitEngineProperties (project.TargetRuntime ?? Runtime.SystemAssemblyService.DefaultRuntime, properties, out searchPaths); - } + } } - static void InitEngineProperties (Core.Assemblies.TargetRuntime runtime, Dictionary properties, out List searchPaths) + // These are initialised in 'InitEngineProperties' below + static Type typeofIntrinsicFunctions; // = typeof ("Microsoft.Build.Evaluation.IntrinsicFunctions") + static Dictionary cachedIntrinsicFunctions; + + static void InitEngineProperties (Core.Assemblies.TargetRuntime runtime, Dictionary properties, out List searchPaths) { string toolsVersion = "Current"; string visualStudioVersion = "16.0"; @@ -150,39 +154,50 @@ static void InitEngineProperties (Core.Assemblies.TargetRuntime runtime, Diction var frameworkToolsPath = ToolLocationHelper.GetPathToDotNetFramework (TargetDotNetFrameworkVersion.VersionLatest); var frameworkToolsPathEscaped = MSBuildProjectService.ToMSBuildPath (null, frameworkToolsPath); properties.Add ("MSBuildFrameworkToolsPath", frameworkToolsPathEscaped); - properties.Add ("MSBuildFrameworkToolsPath32", frameworkToolsPathEscaped); - + properties.Add ("MSBuildFrameworkToolsPath32", frameworkToolsPathEscaped); + searchPaths = MSBuildProjectService.GetProjectImportSearchPaths (runtime, true).ToList (); - if (Platform.IsWindows) { - //first use extensions path relative to bindir (MSBuild/15.0/Bin). this works for dev15 isolated install. - var msBuildExtensionsPath = Path.GetFullPath (Path.Combine (msBuildBinPath, "..", "..")); - var msBuildExtensionsPathEscaped = MSBuildProjectService.ToMSBuildPath (null, msBuildExtensionsPath); - properties.Add ("MSBuildExtensionsPath", msBuildExtensionsPathEscaped); - properties.Add ("MSBuildExtensionsPath32", msBuildExtensionsPathEscaped); - properties.Add ("MSBuildExtensionsPath64", msBuildExtensionsPathEscaped); - + // initialise the static Dictionary 'cachedIntrinsicFunctions' from Microsoft.Build.dll IntrinsicFunctions + // this avoids re-importing all msBuild IntrinsicFunctions into MonoDevelop code whenever they change (ie often) + + Assembly microsoftBuild = Assembly.LoadFrom (msBuildBinPath + "/Microsoft.Build.dll"); + typeofIntrinsicFunctions = microsoftBuild.GetType ("Microsoft.Build.Evaluation.IntrinsicFunctions"); + + cachedIntrinsicFunctions = typeofIntrinsicFunctions + .GetMethods (BindingFlags.NonPublic | BindingFlags.IgnoreCase | BindingFlags.Static) + .ToLookup (x => x.Name) + .ToDictionary (x => x.Key, x => x.ToArray (), StringComparer.OrdinalIgnoreCase); + + if (Platform.IsWindows) { + //first use extensions path relative to bindir (MSBuild/15.0/Bin). this works for dev15 isolated install. + var msBuildExtensionsPath = Path.GetFullPath (Path.Combine (msBuildBinPath, "..", "..")); + var msBuildExtensionsPathEscaped = MSBuildProjectService.ToMSBuildPath (null, msBuildExtensionsPath); + properties.Add ("MSBuildExtensionsPath", msBuildExtensionsPathEscaped); + properties.Add ("MSBuildExtensionsPath32", msBuildExtensionsPathEscaped); + properties.Add ("MSBuildExtensionsPath64", msBuildExtensionsPathEscaped); + var vsToolsPathEscaped = MSBuildProjectService.ToMSBuildPath (null, Path.Combine (msBuildExtensionsPath, "Microsoft", "VisualStudio", "v" + visualStudioVersion)); - properties.Add ("VSToolsPath", vsToolsPathEscaped); - - //like the dev15 toolset, add fallbacks to the old global paths - - // Taken from MSBuild source: + properties.Add ("VSToolsPath", vsToolsPathEscaped); + + //like the dev15 toolset, add fallbacks to the old global paths + + // Taken from MSBuild source: var programFiles = Environment.GetFolderPath (Environment.SpecialFolder.ProgramFiles); var programFiles32 = Environment.GetFolderPath (Environment.SpecialFolder.ProgramFilesX86); if (string.IsNullOrEmpty (programFiles32)) - programFiles32 = programFiles; // 32 bit box - + programFiles32 = programFiles; // 32 bit box + string programFiles64; - if (programFiles == programFiles32) { - // either we're in a 32-bit window, or we're on a 32-bit machine. - // if we're on a 32-bit machine, ProgramW6432 won't exist - // if we're on a 64-bit machine, ProgramW6432 will point to the correct Program Files. + if (programFiles == programFiles32) { + // either we're in a 32-bit window, or we're on a 32-bit machine. + // if we're on a 32-bit machine, ProgramW6432 won't exist + // if we're on a 64-bit machine, ProgramW6432 will point to the correct Program Files. programFiles64 = Environment.GetEnvironmentVariable ("ProgramW6432"); } - else { - // 64-bit window on a 64-bit machine; %ProgramFiles% points to the 64-bit - // Program Files already. + else { + // 64-bit window on a 64-bit machine; %ProgramFiles% points to the 64-bit + // Program Files already. programFiles64 = programFiles; } @@ -191,16 +206,16 @@ static void InitEngineProperties (Core.Assemblies.TargetRuntime runtime, Diction if (programFiles64 != null) { var extensionsPath64Escaped = MSBuildProjectService.ToMSBuildPath (null, Path.Combine (programFiles64, "MSBuild")); - searchPaths.Insert (0, new ImportSearchPathExtensionNode { Property = "MSBuildExtensionsPath64", Path = extensionsPath64Escaped }); - } - - //yes, dev15's toolset has the 64-bit path fall back to the 32-bit one - searchPaths.Insert (0, new ImportSearchPathExtensionNode { Property = "MSBuildExtensionsPath64", Path = extensionsPath32Escaped }); - - // MSBuildExtensionsPath: The way this used to work is that it would point to "Program Files\MSBuild" on both - // 32-bit and 64-bit machines. We have a switch to continue using that behavior; however the default is now for - // MSBuildExtensionsPath to always point to the same location as MSBuildExtensionsPath32. - + searchPaths.Insert (0, new ImportSearchPathExtensionNode { Property = "MSBuildExtensionsPath64", Path = extensionsPath64Escaped }); + } + + //yes, dev15's toolset has the 64-bit path fall back to the 32-bit one + searchPaths.Insert (0, new ImportSearchPathExtensionNode { Property = "MSBuildExtensionsPath64", Path = extensionsPath32Escaped }); + + // MSBuildExtensionsPath: The way this used to work is that it would point to "Program Files\MSBuild" on both + // 32-bit and 64-bit machines. We have a switch to continue using that behavior; however the default is now for + // MSBuildExtensionsPath to always point to the same location as MSBuildExtensionsPath32. + bool useLegacyMSBuildExtensionsPathBehavior = !string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("MSBUILDLEGACYEXTENSIONSPATH")); string extensionsPath; @@ -215,23 +230,23 @@ static void InitEngineProperties (Core.Assemblies.TargetRuntime runtime, Diction var msBuildExtensionsPathEscaped = MSBuildProjectService.ToMSBuildPath (null, msBuildExtensionsPath); properties.Add ("MSBuildExtensionsPath", msBuildExtensionsPathEscaped); properties.Add ("MSBuildExtensionsPath32", msBuildExtensionsPathEscaped); - properties.Add ("MSBuildExtensionsPath64", msBuildExtensionsPathEscaped); - + properties.Add ("MSBuildExtensionsPath64", msBuildExtensionsPathEscaped); + var vsToolsPathEscaped = MSBuildProjectService.ToMSBuildPath (null, Path.Combine (msBuildExtensionsPath, "Microsoft", "VisualStudio", "v" + visualStudioVersion)); properties.Add ("VSToolsPath", vsToolsPathEscaped); - } - - // Environment - - properties.Add ("MSBuildProgramFiles32", MSBuildProjectService.ToMSBuildPath (null, Environment.GetFolderPath (Environment.SpecialFolder.ProgramFilesX86))); - - // Custom override of MSBuildExtensionsPath using an env var - + } + + // Environment + + properties.Add ("MSBuildProgramFiles32", MSBuildProjectService.ToMSBuildPath (null, Environment.GetFolderPath (Environment.SpecialFolder.ProgramFilesX86))); + + // Custom override of MSBuildExtensionsPath using an env var + var customExtensionsPath = Environment.GetEnvironmentVariable ("MSBuildExtensionsPath"); if (!string.IsNullOrEmpty (customExtensionsPath)) { - if (IsExternalMSBuildExtensionsPath (customExtensionsPath)) - // This is actually an override of the mono extensions path. Don't replace the default MSBuildExtensionsPath value since - // core targets still need to be loaded from there. + if (IsExternalMSBuildExtensionsPath (customExtensionsPath)) + // This is actually an override of the mono extensions path. Don't replace the default MSBuildExtensionsPath value since + // core targets still need to be loaded from there. searchPaths.Insert (0, new ImportSearchPathExtensionNode { Property = "MSBuildExtensionsPath", Path = customExtensionsPath }); else properties["MSBuildExtensionsPath"] = MSBuildProjectService.ToMSBuildPath (null, customExtensionsPath); @@ -457,8 +472,10 @@ string Evaluate (string str, StringBuilder sb, List evalua int j = i; object val; bool nie; + if (!EvaluateReference (str.AsSpan (), evaluatedItemsCollection, ref j, out val, out nie)) allResolved = false; + needsItemEvaluation |= nie; sb.Append (ValueToString (val)); last = j; @@ -557,6 +574,7 @@ bool EvaluateProperty (ReadOnlySpan prop, bool ignorePropsWithTransforms, { needsItemEvaluation = false; val = null; + if (prop [0] == '[') { int i = prop.IndexOf (']'); if (i == -1 || (prop.Length - i) < 3 || prop [i + 1] != ':' || prop [i + 2] != ':') @@ -604,7 +622,6 @@ bool EvaluateMemberOrIndexer (Type type, object instance, ReadOnlySpan str internal bool EvaluateMember (Type type, object instance, ReadOnlySpan str, int i, out object val) { val = null; - // Find the delimiter of the member int j = str.IndexOfAny (MemberDelimiter, i); if (j == -1) @@ -618,6 +635,7 @@ internal bool EvaluateMember (Type type, object instance, ReadOnlySpan str // It is a method invocation object [] parameterValues; j++; + if (!EvaluateParameters (str, ref j, out parameterValues)) return false; @@ -690,6 +708,7 @@ internal bool EvaluateMember (ReadOnlySpan str, Type type, string memberNa var member = ResolveMember (type, memberName, instance == null, MemberTypes.Method); if (member == null || member.Length == 0) return false; + return EvaluateMethod (str, member, instance, parameterValues, out val); } @@ -704,13 +723,13 @@ bool EvaluateMethod (ReadOnlySpan str, MemberInfo[] member, object instanc try { // Convert the given parameters to the types specified in the method signature - var convertedArgs = (methodParams.Length == parameterValues.Length) ? parameterValues : new object [methodParams.Length]; + var convertedArgs = (methodParams.Length == parameterValues.Length) ? parameterValues : new object [methodParams.Length]; int numArgs = methodParams.Length; if (paramsArgType != null) numArgs--; - if (method.DeclaringType == typeof (IntrinsicFunctions) && method.Name == nameof (IntrinsicFunctions.GetPathOfFileAbove) && parameterValues.Length == methodParams.Length - 1) { + if (method.DeclaringType == typeofIntrinsicFunctions && method.Name == "GetPathOfFileAbove" && parameterValues.Length == methodParams.Length - 1) { string startingDirectory = String.IsNullOrWhiteSpace (FullFileName) ? String.Empty : Path.GetDirectoryName (FullFileName); var last = convertedArgs.Length - 1; convertedArgs [last] = ConvertArg (method, last, startingDirectory, methodParams [last].ParameterType); @@ -758,6 +777,7 @@ bool EvaluateMethod (ReadOnlySpan str, MemberInfo[] member, object instanc } } val = method.Invoke (instance, convertedArgs); + } catch (Exception ex) { LoggingService.LogError ("MSBuild property evaluation failed: " + str.ToString (), ex); return false; @@ -817,7 +837,7 @@ internal bool EvaluateParameters (ReadOnlySpan str, ref int i, out object[ var argInfo = m.GetParameters (); if (args.Length == argInfo.Length - 1) { - if (m.DeclaringType == typeof (IntrinsicFunctions) && m.Name == nameof (IntrinsicFunctions.GetPathOfFileAbove)) { + if (m.DeclaringType == typeofIntrinsicFunctions && m.Name == "GetPathOfFileAbove") { validMatch = (m, argInfo); continue; } @@ -986,7 +1006,7 @@ object ConvertArg (MethodBase method, int argNum, object value, Type parameterTy else if (method.DeclaringType == typeof (System.IO.Path)) // The windows path is already converted to a native path, but it may contain escape sequences res = MSBuildProjectService.UnescapePath ((string)res); - else if (method.DeclaringType == typeof (IntrinsicFunctions)) { + else if (method.DeclaringType == typeofIntrinsicFunctions) { if (method.Name == "MakeRelative") convertPath = true; else if (method.Name == "GetDirectoryNameOfFileAbove" && argNum == 0) @@ -1017,7 +1037,7 @@ bool EvaluateList (ReadOnlySpan prop, List evaluated Type ResolveType (string typeName) { if (typeName == "MSBuild") - return typeof (Microsoft.Build.Evaluation.IntrinsicFunctions); + return typeofIntrinsicFunctions; foreach (var kvp in supportedTypeMembers) { if (kvp.Key.FullName == typeName) @@ -1026,24 +1046,15 @@ Type ResolveType (string typeName) return null; } - static readonly Dictionary cachedIntrinsicFunctions = typeof (IntrinsicFunctions) - .GetMethods (BindingFlags.NonPublic | BindingFlags.IgnoreCase | BindingFlags.Static) - .ToLookup (x => x.Name) - .ToDictionary(x => x.Key, x => x.ToArray (), StringComparer.OrdinalIgnoreCase); - - MemberInfo[] ResolveMember (Type type, string memberName, bool isStatic, MemberTypes memberTypes) + MemberInfo [] ResolveMember (Type type, string memberName, bool isStatic, MemberTypes memberTypes) { - if (type == typeof (string)) { - if (memberName == "new" || memberName == "Copy") { - type = typeof (IntrinsicFunctions); - memberName = "Copy"; - } - } else { - if (type.IsArray) - type = typeof (Array); - } + if (type == typeof (string) && memberName == "new") + memberName = "Copy"; + + if (type.IsArray) + type = typeof (Array); - if (type == typeof(IntrinsicFunctions)) { + if (type == typeofIntrinsicFunctions) { return cachedIntrinsicFunctions.TryGetValue (memberName, out var result) ? result : null; } diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj index 55a13d5855c..2bedae1a920 100644 --- a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj +++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj @@ -126,8 +126,7 @@ - - + {7525BB88-6142-4A26-93B9-A30C6983390A} diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/IntrinsicFunctionsTests.cs b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/IntrinsicFunctionsTests.cs deleted file mode 100644 index d2fb49edfec..00000000000 --- a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Projects/IntrinsicFunctionsTests.cs +++ /dev/null @@ -1,50 +0,0 @@ -// -// IntrinsicFunctionsTests.cs -// -// Author: -// Marius Ungureanu -// -// Copyright (c) 2019 Microsoft Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using System.Reflection; -using System.Runtime.CompilerServices; -using Microsoft.Build.Evaluation; -using NUnit.Framework; - -namespace MonoDevelop.Projects -{ - [TestFixture] - public class IntrinsicFunctionsTests - { - [Test] - public void TypeContainsOnlyMethods() - { - // MSBuildEvaluationContext.cachedIntrinsicFunctions only caches methods and code path only takes that into account - foreach (var member in typeof(IntrinsicFunctions).GetMembers(BindingFlags.NonPublic | BindingFlags.Static)) { - // Skip compiler generated code, such as lambda classes - if (member.IsDefined (typeof (CompilerGeneratedAttribute))) - continue; - - Assert.AreEqual (MemberTypes.Method, member.MemberType); - } - } - } -} From 21031632fd1484734b7c3fedd1f2ec5d6329c9f7 Mon Sep 17 00:00:00 2001 From: hwthomas Date: Sun, 4 Sep 2022 16:08:41 +0100 Subject: [PATCH 02/11] Update checks so .NETStandard2.0/2.1 is supported for Mono versions 6.4 or greater or for DotNetCore (runtime) versions 3.x or greater (ie includes .net5.0+) previously only netstandard2.0 was supported for mono 5.2 AND netcore3.0 installed --- ...NetCoreProjectSupportedTargetFrameworks.cs | 2 +- .../DotNetCoreRuntime.cs | 6 ++++- .../DotNetCoreVersion.cs | 14 ++++++++++- .../MonoRuntimeInfoExtensions.cs | 6 +++-- .../TargetFrameworkExtensions.cs | 4 ++-- .../SystemAssemblyService.cs | 12 ++++++---- .../TargetFramework.cs | 23 +++++++++++++++++-- 7 files changed, 53 insertions(+), 14 deletions(-) diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectSupportedTargetFrameworks.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectSupportedTargetFrameworks.cs index 6726991945c..29896551502 100644 --- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectSupportedTargetFrameworks.cs +++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectSupportedTargetFrameworks.cs @@ -96,7 +96,7 @@ static IEnumerable GetKnownNetCoreAppFrameworks () public static IEnumerable GetNetStandardTargetFrameworks () { - if (DotNetCoreRuntime.IsNetCore30Installed () || MonoRuntimeInfoExtensions.CurrentRuntimeVersion.SupportsNetStandard21 ()) + if (DotNetCoreRuntime.IsNetCore3xOrHigherInstalled () || MonoRuntimeInfoExtensions.CurrentRuntimeVersion.SupportsNetStandard21 ()) yield return CreateTargetFramework (".NETStandard", "2.1"); if (DotNetCoreRuntime.IsNetCore2xInstalled () || MonoRuntimeInfoExtensions.CurrentRuntimeVersion.SupportsNetStandard20 ()) diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreRuntime.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreRuntime.cs index a8ff897af09..b7e24b927d5 100644 --- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreRuntime.cs +++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreRuntime.cs @@ -25,7 +25,7 @@ // THE SOFTWARE. using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using MonoDevelop.Core; @@ -124,6 +124,10 @@ internal static bool IsNetCore30Installed () return Versions.Any (version => version.Major == 3 && version.Minor == 0); } + internal static bool IsNetCore3xOrHigherInstalled () + { + return Versions.Any (version => version.Major >= 3); + } /// /// Used by unit tests to fake having different .NET Core sdks installed. diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreVersion.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreVersion.cs index 5cb247939ce..d65de6eef6b 100644 --- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreVersion.cs +++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreVersion.cs @@ -34,12 +34,14 @@ namespace MonoDevelop.DotNetCore { class DotNetCoreVersion : IEquatable, IComparable, IComparable { - internal static readonly DotNetCoreVersion MinimumSupportedSdkVersion = new DotNetCoreVersion (2, 1, 602); + internal static readonly DotNetCoreVersion MinimumSupportedSdkVersion = new DotNetCoreVersion (2, 1, 30); internal static readonly DotNetCoreVersion MinimumSupportedSdkVersion22 = new DotNetCoreVersion (2, 2, 202); internal static readonly DotNetCoreVersion MinimumSupportedSdkVersion30 = new DotNetCoreVersion (3, 0, 100) { ReleaseLabel = "preview3-010431", IsPrerelease = true }; + internal static readonly DotNetCoreVersion MinimumSupportedSdkVersion50 = new DotNetCoreVersion (5, 0, 400); + internal static readonly DotNetCoreVersion MinimumSupportedSdkVersion60 = new DotNetCoreVersion (6, 0, 6); internal DotNetCoreVersion (int major, int minor, int patch) : this (new Version (major, minor, patch)) @@ -244,6 +246,16 @@ public static bool IsSdkSupported (DotNetCoreVersion version) return version >= MinimumSupportedSdkVersion30; } + if (version.Major == 5) { + return version >= MinimumSupportedSdkVersion50; + } + + if (version.Major == 6) { + return version >= MinimumSupportedSdkVersion60; + } + + + return false; } } diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/MonoRuntimeInfoExtensions.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/MonoRuntimeInfoExtensions.cs index 2e9a3999082..b97fc2e7dbb 100644 --- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/MonoRuntimeInfoExtensions.cs +++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/MonoRuntimeInfoExtensions.cs @@ -32,8 +32,10 @@ namespace MonoDevelop.DotNetCore static class MonoRuntimeInfoExtensions { static readonly Version MonoVersion5_4 = new Version (5, 4, 0); + static readonly Version MonoVersion6_4 = new Version (6, 4, 0); static readonly Version DotNetCore2_1 = new Version (2, 1); + internal static Version CurrentRuntimeVersion { get; set; } = MonoRuntimeInfo.FromCurrentRuntime ()?.RuntimeVersion ?? new Version (); public static bool SupportsNetStandard20 (this Version monoVersion) @@ -43,8 +45,8 @@ public static bool SupportsNetStandard20 (this Version monoVersion) public static bool SupportsNetStandard21 (this Version monoVersion) { - //FIXME: update this: which Mono version will support .NET Standadrd 2.1 - return false; + // ref https://www.mono-project.com/docs/about-mono/releases/6.4.0/ + return monoVersion >= MonoVersion6_4; ; } public static bool SupportsNetCore (this Version monoVersion, string netCoreVersion) diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/TargetFrameworkExtensions.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/TargetFrameworkExtensions.cs index 6f66e358944..a953efbd90d 100644 --- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/TargetFrameworkExtensions.cs +++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/TargetFrameworkExtensions.cs @@ -100,9 +100,9 @@ public static string GetDisplayName (this TargetFramework framework) if (framework.IsNetCoreApp ()) { // Display shortened framework names for .net5.0 and above in NewProject dialog if (version.Major >= 5) { - return string.Format (".net {0}", framework.Id.Version); + return string.Format (".net{0}", framework.Id.Version); } else { - return string.Format (".NET Core {0}", framework.Id.Version); + return string.Format (".netcoreapp{0}", framework.Id.Version); } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs index 5eb2a9b08d5..663135e0e8e 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs @@ -182,17 +182,19 @@ public TargetFramework GetTargetFramework (TargetFrameworkMoniker id) { TargetFramework fx; if (frameworks.TryGetValue (id, out fx)) - return fx; + return fx; // found on first check against known .NETFrameworks - LoggingService.LogDebug ("Unknown TargetFramework '{0}' is being requested from SystemAssemblyService, ensuring runtimes initialized and trying again", id); + // otherwise, ensure runtimes have been initialised, then try again foreach (var r in runtimes) r.EnsureInitialized (); if (frameworks.TryGetValue (id, out fx)) return fx; - - LoggingService.LogWarning ("Unknown TargetFramework '{0}' is being requested from SystemAssemblyService, returning empty TargetFramework", id); - UpdateFrameworks (new [] { new TargetFramework (id) }); + // still not found - don't warn, but add .NETCoreApp and .NETStandard frameworks via 'UpdateFrameworks' + // LoggingService.LogWarning ("Unknown TargetFramework '{0}' is being requested from SystemAssemblyService, returning empty TargetFramework", id); + + var tf = new TargetFramework (id); + UpdateFrameworks (new [] {tf}); return frameworks [id]; } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFramework.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFramework.cs index 92f979c70fd..7c1f30fc0c3 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFramework.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFramework.cs @@ -61,15 +61,34 @@ internal TargetFramework (TargetFrameworkMoniker id) this.name = id.Profile == null ? string.Format ("{0} {1}", id.Identifier, id.Version) : string.Format ("{0} {1} {2} Profile", id.Identifier, id.Version, id.Profile); + + if (id.Identifier == ".NETCoreApp") { + int i = id.Version.IndexOf ('.'); + int majorVersion = int.Parse (id.Version.Substring (0, i)); + if (majorVersion >= 5) { + this.name = id.Profile == null + ? string.Format (".net{0}", id.Version) + : string.Format (".net{0} {1}", id.Version, id.Profile); + } + } Assemblies = new AssemblyInfo [0]; } public string Name { get { if (string.IsNullOrEmpty (name)) { - return string.IsNullOrEmpty (id.Profile) + name = id.Profile == null ? string.Format ("{0} {1}", id.Identifier, id.Version) - : string.Format ("{0} {1} ({2})", id.Identifier, id.Version, id.Profile); + : string.Format ("{0} {1} {2} Profile", id.Identifier, id.Version, id.Profile); + } + if (id.Identifier == ".NETCoreApp") { + int i = id.Version.IndexOf ('.'); + int majorVersion = int.Parse (id.Version.Substring (0, i)); + if (majorVersion >= 5) { + name = id.Profile == null + ? string.Format (".net{0}", id.Version) + : string.Format (".net{0} {1}", id.Version, id.Profile); + } } return name; } From 3365b2200ffd09004c8980b0de8d69f8bb1e0ca6 Mon Sep 17 00:00:00 2001 From: hwthomas Date: Mon, 5 Sep 2022 16:56:10 +0100 Subject: [PATCH 03/11] Update CI_workflow to build with dotnet-sdk-5.0 --- .github/workflows/monodevelop.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/monodevelop.yml b/.github/workflows/monodevelop.yml index b7f246f5b88..672dc1f47d9 100644 --- a/.github/workflows/monodevelop.yml +++ b/.github/workflows/monodevelop.yml @@ -31,14 +31,14 @@ jobs: sudo dpkg -i packages-microsoft-prod.deb sudo apt-get install -y apt-transport-https sudo apt-get update - sudo apt-get install -y dotnet-sdk-3.1 + sudo apt-get install -y dotnet-sdk-5.0 # Install mono and msbuild sudo apt-get install -y gnupg ca-certificates sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF # Reference mono and msbuild from stable repo for versions 6.12.0.122 (mono) and 16.6.0.15201 (msbuild) - echo "deb https://download.mono-project.com/repo/ubuntu stable-focal main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list + # echo "deb https://download.mono-project.com/repo/ubuntu stable-focal main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list # Reference mono and msbuild from preview repo for versions 6.12.0.147 (mono) and 16.10.1 (msbuild) - # echo "deb https://download.mono-project.com/repo/ubuntu preview-focal main" | sudo tee /etc/apt/sources.list.d/mono-official-preview.list + echo "deb https://download.mono-project.com/repo/ubuntu preview-focal main" | sudo tee /etc/apt/sources.list.d/mono-official-preview.list sudo apt-get update # Install mono-complete and ca-certificates-mono sudo apt-get install -y mono-complete ca-certificates-mono @@ -56,8 +56,9 @@ jobs: mono -V msbuild -version dotnet --info + git config --global --add safe.directory "$GITHUB_WORKSPACE" # Checkout, configure and build - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: true - name: Checkout configure and build From 18270c51c10772ff06f47915f7da9af3d6fdd8d4 Mon Sep 17 00:00:00 2001 From: hwthomas Date: Sun, 18 Sep 2022 18:04:18 +0100 Subject: [PATCH 04/11] Extend SupportedSDK list and add Sdk5.0/6.0 templates to MonoDevelop.DotnetCore.addin.xml and MonoDevelop.ASpNetCore.addin.xml to allow net5.0 and net6.0 projects to be created These template updates were overlooked in the menu limit changes in PR#76 --- .../MonoDevelop.AspNetCore.addin.xml | 347 +++++++++++ ...NetCoreProjectTemplateStringTagProvider.cs | 2 +- .../DotNetCoreProjectTemplateWizard.cs | 1 + .../MonoDevelop.DotNetCore.addin.xml | 575 ++++++++++++++++++ .../RoslynClassificationHighlighting.cs | 2 +- 5 files changed, 925 insertions(+), 2 deletions(-) diff --git a/main/src/addins/MonoDevelop.AspNetCore/Properties/MonoDevelop.AspNetCore.addin.xml b/main/src/addins/MonoDevelop.AspNetCore/Properties/MonoDevelop.AspNetCore.addin.xml index 65267a36850..6df895b7001 100644 --- a/main/src/addins/MonoDevelop.AspNetCore/Properties/MonoDevelop.AspNetCore.addin.xml +++ b/main/src/addins/MonoDevelop.AspNetCore/Properties/MonoDevelop.AspNetCore.addin.xml @@ -83,6 +83,351 @@ For example, .NET Core 1.1 SDK does not have a Razor template so having the 1.1 templates first would cause the Razor template to be last in the New Project dialog if both 1.1 and 2.x templates are available. --> + + + +