com.unity.ide.visualstudio@2.0.20

## [2.0.20] - 2023-06-27

Integration:

- Internal API refactoring.

## [2.0.19] - 2023-06-14

Integration:

- Add support for Visual Studio Code.

Project generation:

- Add support for Sdk Style poject generation.
- Fix an issue related to missing properties with 2021.3.
This commit is contained in:
Unity Technologies
2023-06-27 00:00:00 +00:00
parent ebe8973267
commit d1e4dd05ad
24 changed files with 1390 additions and 625 deletions

View File

@@ -39,12 +39,14 @@ namespace Microsoft.Unity.VisualStudio.Editor
public class ProjectGeneration : IGenerator
{
// do not remove because of the Validation API, used in LegacyStyleProjectGeneration
public static readonly string MSBuildNamespaceUri = "http://schemas.microsoft.com/developer/msbuild/2003";
public IAssemblyNameProvider AssemblyNameProvider => m_AssemblyNameProvider;
public string ProjectDirectory { get; }
// Use this to have the same newline ending on all platforms for consistency.
const string k_WindowsNewline = "\r\n";
internal const string k_WindowsNewline = "\r\n";
const string m_SolutionProjectEntryTemplate = @"Project(""{{{0}}}"") = ""{1}"", ""{2}"", ""{{{3}}}""{4}EndProject";
@@ -60,7 +62,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
HashSet<string> m_BuiltinSupportedExtensions = new HashSet<string>();
readonly string m_ProjectName;
readonly IAssemblyNameProvider m_AssemblyNameProvider;
internal readonly IAssemblyNameProvider m_AssemblyNameProvider;
readonly IFileIO m_FileIOProvider;
readonly IGUIDGenerator m_GUIDGenerator;
bool m_ShouldGenerateAll;
@@ -106,9 +108,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
SetupProjectSupportedExtensions();
// See https://devblogs.microsoft.com/setup/configure-visual-studio-across-your-organization-with-vsconfig/
// We create a .vsconfig file to make sure our ManagedGame workload is installed
CreateVsConfigIfNotFound();
CreateExtraFiles(m_CurrentInstallation);
// Don't sync if we haven't synced before
var affected = affectedFiles as ICollection<string> ?? affectedFiles.ToArray();
@@ -148,26 +148,9 @@ namespace Microsoft.Unity.VisualStudio.Editor
}
}
private void CreateVsConfigIfNotFound()
private void CreateExtraFiles(IVisualStudioInstallation installation)
{
try
{
var vsConfigFile = VsConfigFile();
if (m_FileIOProvider.Exists(vsConfigFile))
return;
var content = $@"{{
""version"": ""1.0"",
""components"": [
""{Discovery.ManagedWorkload}""
]
}}
";
m_FileIOProvider.WriteAllText(vsConfigFile, content);
}
catch (IOException)
{
}
installation?.CreateExtraFiles(ProjectDirectory);
}
private bool HasFilesBeenModified(IEnumerable<string> affectedFiles, IEnumerable<string> reimportedFiles)
@@ -183,7 +166,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
private void RefreshCurrentInstallation()
{
var editor = CodeEditor.CurrentEditor as VisualStudioEditor;
editor?.TryGetVisualStudioInstallationForPath(CodeEditor.CurrentEditorInstallation, searchInstallations: true, out m_CurrentInstallation);
editor?.TryGetVisualStudioInstallationForPath(CodeEditor.CurrentEditorInstallation, lookupDiscoveredInstallations: true, out m_CurrentInstallation);
}
static ProfilerMarker solutionSyncMarker = new ProfilerMarker("SolutionSynchronizerSync");
@@ -199,7 +182,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
// See https://devblogs.microsoft.com/setup/configure-visual-studio-across-your-organization-with-vsconfig/
// We create a .vsconfig file to make sure our ManagedGame workload is installed
CreateVsConfigIfNotFound();
CreateExtraFiles(m_CurrentInstallation);
var externalCodeAlreadyGeneratedProjects = OnPreGeneratingCSProjectFiles();
@@ -366,7 +349,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
stringBuilders[assemblyName] = projectBuilder;
}
IncludeAsset(projectBuilder, "None", asset);
IncludeAsset(projectBuilder, IncludeAssetTag.None, asset);
}
}
@@ -378,7 +361,13 @@ namespace Microsoft.Unity.VisualStudio.Editor
return result;
}
private void IncludeAsset(StringBuilder builder, string tag, string asset)
internal enum IncludeAssetTag
{
Compile,
None
}
internal virtual void IncludeAsset(StringBuilder builder, IncludeAssetTag tag, string asset)
{
var filename = EscapedRelativePathFor(asset, out var packageInfo);
@@ -517,7 +506,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
if ("dll" != extensionWithoutDot)
{
IncludeAsset(projectBuilder, "Compile", file);
IncludeAsset(projectBuilder, IncludeAssetTag.Compile, file);
}
else
{
@@ -562,19 +551,13 @@ namespace Microsoft.Unity.VisualStudio.Editor
projectBuilder.Append(" <ItemGroup>").Append(k_WindowsNewline);
foreach (var reference in assembly.assemblyReferences.Where(i => i.sourceFiles.Any(ShouldFileBePartOfSolution)))
{
// If the current assembly is a Player project, we want to project-reference the corresponding Player project
var referenceName = m_AssemblyNameProvider.GetAssemblyName(assembly.outputPath, reference.name);
projectBuilder.Append(@" <ProjectReference Include=""").Append(referenceName).Append(GetProjectExtension()).Append(@""">").Append(k_WindowsNewline);
projectBuilder.Append(" <Project>{").Append(ProjectGuid(referenceName)).Append("}</Project>").Append(k_WindowsNewline);
projectBuilder.Append(" <Name>").Append(referenceName).Append("</Name>").Append(k_WindowsNewline);
projectBuilder.Append(" </ProjectReference>").Append(k_WindowsNewline);
AppendProjectReference(assembly, reference, projectBuilder);
}
projectBuilder.Append(@" </ItemGroup>").Append(k_WindowsNewline);
}
projectBuilder.Append(GetProjectFooter());
GetProjectFooter(projectBuilder);
return projectBuilder.ToString();
}
@@ -594,6 +577,10 @@ namespace Microsoft.Unity.VisualStudio.Editor
return SecurityElement.Escape(s);
}
internal virtual void AppendProjectReference(Assembly assembly, Assembly reference, StringBuilder projectBuilder)
{
}
private void AppendReference(string fullReference, StringBuilder projectBuilder)
{
var escapedFullPath = EscapedRelativePathFor(fullReference, out _);
@@ -614,11 +601,6 @@ namespace Microsoft.Unity.VisualStudio.Editor
return Path.Combine(ProjectDirectory.NormalizePathSeparators(), $"{InvalidCharactersRegexPattern.Replace(m_ProjectName, "_")}.sln");
}
internal string VsConfigFile()
{
return Path.Combine(ProjectDirectory.NormalizePathSeparators(), ".vsconfig");
}
internal string GetLangVersion(Assembly assembly)
{
var targetLanguageVersion = "latest"; // danger: latest is not the same absolute value depending on the VS version.
@@ -674,16 +656,25 @@ namespace Microsoft.Unity.VisualStudio.Editor
var additionalFilePaths = new List<string>();
var rulesetPath = string.Empty;
var analyzerConfigPath = string.Empty;
var compilerOptions = assembly.compilerOptions;
#if UNITY_2020_2_OR_NEWER
// Analyzers + ruleset provided by Unity
analyzers.AddRange(assembly.compilerOptions.RoslynAnalyzerDllPaths);
rulesetPath = assembly.compilerOptions.RoslynAnalyzerRulesetPath;
analyzers.AddRange(compilerOptions.RoslynAnalyzerDllPaths);
rulesetPath = compilerOptions.RoslynAnalyzerRulesetPath;
#endif
#if UNITY_2021_3_OR_NEWER && !UNITY_2022_1 // we have support in 2021.3, 2022.2 but without a backport in 2022.1
additionalFilePaths.AddRange(assembly.compilerOptions.RoslynAdditionalFilePaths);
analyzerConfigPath = assembly.compilerOptions.AnalyzerConfigPath;
// We have support in 2021.3, 2022.2 but without a backport in 2022.1
#if UNITY_2021_3
// Unfortunately those properties were introduced in a patch release of 2021.3, so not found in 2021.3.2f1 for example
var scoType = compilerOptions.GetType();
var afpProperty = scoType.GetProperty("RoslynAdditionalFilePaths");
var acpProperty = scoType.GetProperty("AnalyzerConfigPath");
additionalFilePaths.AddRange(afpProperty?.GetValue(compilerOptions) as string[] ?? Array.Empty<string>());
analyzerConfigPath = acpProperty?.GetValue(compilerOptions) as string ?? analyzerConfigPath;
#elif UNITY_2022_2_OR_NEWER
additionalFilePaths.AddRange(compilerOptions.RoslynAdditionalFilePaths);
analyzerConfigPath = compilerOptions.AnalyzerConfigPath;
#endif
// Analyzers and additional files provided by csc.rsp
@@ -765,30 +756,13 @@ namespace Microsoft.Unity.VisualStudio.Editor
return ProjectType.Game;
}
private void GetProjectHeader(ProjectProperties properties, out StringBuilder headerBuilder)
internal virtual void GetProjectHeader(ProjectProperties properties, out StringBuilder headerBuilder)
{
headerBuilder = new StringBuilder();
headerBuilder = default;
}
//Header
headerBuilder.Append(@"<?xml version=""1.0"" encoding=""utf-8""?>").Append(k_WindowsNewline);
headerBuilder.Append(@"<Project ToolsVersion=""4.0"" DefaultTargets=""Build"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">").Append(k_WindowsNewline);
headerBuilder.Append(@" <PropertyGroup>").Append(k_WindowsNewline);
headerBuilder.Append(@" <LangVersion>").Append(properties.LangVersion).Append(@"</LangVersion>").Append(k_WindowsNewline);
headerBuilder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
headerBuilder.Append(@" <PropertyGroup>").Append(k_WindowsNewline);
headerBuilder.Append(@" <Configuration Condition="" '$(Configuration)' == '' "">Debug</Configuration>").Append(k_WindowsNewline);
headerBuilder.Append(@" <Platform Condition="" '$(Platform)' == '' "">AnyCPU</Platform>").Append(k_WindowsNewline);
headerBuilder.Append(@" <ProductVersion>10.0.20506</ProductVersion>").Append(k_WindowsNewline);
headerBuilder.Append(@" <SchemaVersion>2.0</SchemaVersion>").Append(k_WindowsNewline);
headerBuilder.Append(@" <RootNamespace>").Append(properties.RootNamespace).Append(@"</RootNamespace>").Append(k_WindowsNewline);
headerBuilder.Append(@" <ProjectGuid>{").Append(properties.ProjectGuid).Append(@"}</ProjectGuid>").Append(k_WindowsNewline);
headerBuilder.Append(@" <OutputType>Library</OutputType>").Append(k_WindowsNewline);
headerBuilder.Append(@" <AppDesignerFolder>Properties</AppDesignerFolder>").Append(k_WindowsNewline);
headerBuilder.Append(@" <AssemblyName>").Append(properties.AssemblyName).Append(@"</AssemblyName>").Append(k_WindowsNewline);
headerBuilder.Append(@" <TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>").Append(k_WindowsNewline);
headerBuilder.Append(@" <FileAlignment>512</FileAlignment>").Append(k_WindowsNewline);
headerBuilder.Append(@" <BaseDirectory>.</BaseDirectory>").Append(k_WindowsNewline);
headerBuilder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
internal static void GetProjectHeaderConfigurations(ProjectProperties properties, StringBuilder headerBuilder)
{
headerBuilder.Append(@" <PropertyGroup Condition="" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "">").Append(k_WindowsNewline);
headerBuilder.Append(@" <DebugSymbols>true</DebugSymbols>").Append(k_WindowsNewline);
headerBuilder.Append(@" <DebugType>full</DebugType>").Append(k_WindowsNewline);
@@ -809,26 +783,10 @@ namespace Microsoft.Unity.VisualStudio.Editor
headerBuilder.Append(@" <NoWarn>0169</NoWarn>").Append(k_WindowsNewline);
headerBuilder.Append(@" <AllowUnsafeBlocks>").Append(properties.Unsafe).Append(@"</AllowUnsafeBlocks>").Append(k_WindowsNewline);
headerBuilder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
}
// Explicit references
headerBuilder.Append(@" <PropertyGroup>").Append(k_WindowsNewline);
headerBuilder.Append(@" <NoConfig>true</NoConfig>").Append(k_WindowsNewline);
headerBuilder.Append(@" <NoStdLib>true</NoStdLib>").Append(k_WindowsNewline);
headerBuilder.Append(@" <AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>").Append(k_WindowsNewline);
headerBuilder.Append(@" <ImplicitlyExpandNETStandardFacades>false</ImplicitlyExpandNETStandardFacades>").Append(k_WindowsNewline);
headerBuilder.Append(@" <ImplicitlyExpandDesignTimeFacades>false</ImplicitlyExpandDesignTimeFacades>").Append(k_WindowsNewline);
headerBuilder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
// Flavoring
headerBuilder.Append(@" <PropertyGroup>").Append(k_WindowsNewline);
headerBuilder.Append(@" <ProjectTypeGuids>{E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>").Append(k_WindowsNewline);
headerBuilder.Append(@" <UnityProjectGenerator>Package</UnityProjectGenerator>").Append(k_WindowsNewline);
headerBuilder.Append(@" <UnityProjectGeneratorVersion>").Append(properties.FlavoringPackageVersion).Append(@"</UnityProjectGeneratorVersion>").Append(k_WindowsNewline);
headerBuilder.Append(@" <UnityProjectType>").Append(properties.FlavoringProjectType).Append(@"</UnityProjectType>").Append(k_WindowsNewline);
headerBuilder.Append(@" <UnityBuildTarget>").Append(properties.FlavoringBuildTarget).Append(@"</UnityBuildTarget>").Append(k_WindowsNewline);
headerBuilder.Append(@" <UnityVersion>").Append(properties.FlavoringUnityVersion).Append(@"</UnityVersion>").Append(k_WindowsNewline);
headerBuilder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
internal static void GetProjectHeaderAnalyzers(ProjectProperties properties, StringBuilder headerBuilder)
{
if (!string.IsNullOrEmpty(properties.RulesetPath))
{
headerBuilder.Append(@" <PropertyGroup>").Append(k_WindowsNewline);
@@ -864,20 +822,26 @@ namespace Microsoft.Unity.VisualStudio.Editor
}
}
private static string GetProjectFooter()
internal static void GetProjectHeaderVstuFlavoring(ProjectProperties properties, StringBuilder headerBuilder, bool includeProjectTypeGuids = true)
{
// Flavoring
headerBuilder.Append(@" <PropertyGroup>").Append(k_WindowsNewline);
if (includeProjectTypeGuids)
{
headerBuilder.Append(@" <ProjectTypeGuids>{E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>").Append(k_WindowsNewline);
}
headerBuilder.Append(@" <UnityProjectGenerator>Package</UnityProjectGenerator>").Append(k_WindowsNewline);
headerBuilder.Append(@" <UnityProjectGeneratorVersion>").Append(properties.FlavoringPackageVersion).Append(@"</UnityProjectGeneratorVersion>").Append(k_WindowsNewline);
headerBuilder.Append(@" <UnityProjectType>").Append(properties.FlavoringProjectType).Append(@"</UnityProjectType>").Append(k_WindowsNewline);
headerBuilder.Append(@" <UnityBuildTarget>").Append(properties.FlavoringBuildTarget).Append(@"</UnityBuildTarget>").Append(k_WindowsNewline);
headerBuilder.Append(@" <UnityVersion>").Append(properties.FlavoringUnityVersion).Append(@"</UnityVersion>").Append(k_WindowsNewline);
headerBuilder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
}
internal virtual void GetProjectFooter(StringBuilder footerBuilder)
{
return string.Join(k_WindowsNewline,
@" <Import Project=""$(MSBuildToolsPath)\Microsoft.CSharp.targets"" />",
@" <Target Name=""GenerateTargetFrameworkMonikerAttribute"" />",
@" <!-- To modify your build process, add your task inside one of the targets below and uncomment it.",
@" Other similar extension points exist, see Microsoft.Common.targets.",
@" <Target Name=""BeforeBuild"">",
@" </Target>",
@" <Target Name=""AfterBuild"">",
@" </Target>",
@" -->",
@"</Project>",
@"");
}
private static string GetSolutionText()
@@ -1024,7 +988,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
projectGuid);
}
private string EscapedRelativePathFor(string file, out UnityEditor.PackageManager.PackageInfo packageInfo)
internal string EscapedRelativePathFor(string file, out UnityEditor.PackageManager.PackageInfo packageInfo)
{
var projectDir = ProjectDirectory.NormalizePathSeparators();
file = file.NormalizePathSeparators();
@@ -1042,24 +1006,24 @@ namespace Microsoft.Unity.VisualStudio.Editor
return XmlFilename(path);
}
private static string SkipPathPrefix(string path, string prefix)
internal static string SkipPathPrefix(string path, string prefix)
{
if (path.StartsWith($"{prefix}{Path.DirectorySeparatorChar}") && (path.Length > prefix.Length))
return path.Substring(prefix.Length + 1);
return path;
}
static string GetProjectExtension()
internal static string GetProjectExtension()
{
return ".csproj";
}
private string ProjectGuid(string assemblyName)
internal string ProjectGuid(string assemblyName)
{
return m_GUIDGenerator.ProjectGuid(m_ProjectName, assemblyName);
}
private string ProjectGuid(Assembly assembly)
internal string ProjectGuid(Assembly assembly)
{
return ProjectGuid(m_AssemblyNameProvider.GetAssemblyName(assembly.outputPath, assembly.name));
}