Add OptimizeContext MSBuild target that runs on build (#33049)

Fixes #24894
This commit is contained in:
Andriy Svyryd 2024-02-29 14:51:18 -08:00 коммит произвёл GitHub
Родитель 4341961f47
Коммит 52f37b3826
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
29 изменённых файлов: 967 добавлений и 78 удалений

Просмотреть файл

@ -10,6 +10,7 @@
( $(MSBuildProjectName.EndsWith('.Tests')) OR
$(MSBuildProjectName.EndsWith('.FunctionalTests'))) ">true</IsUnitTestProject>
<IsUnitTestProject Condition=" '$(IsUnitTestProject)' == '' ">false</IsUnitTestProject>
<SolutionRoot>$(MSBuildThisFileDirectory)</SolutionRoot>
</PropertyGroup>
<PropertyGroup>

Просмотреть файл

@ -8,7 +8,7 @@
<ItemGroup Condition="'$(PackageReadmeFile)' != ''">
<None Include="$(PackageReadmeFile)" Pack="true" PackagePath="\" />
</ItemGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.DotNet.Arcade.Sdk" />
<Import Project="eng\testing\linker\trimmingTests.targets" Condition="'$(IsPublishedAppTestProject)' == 'true'" />

Просмотреть файл

@ -138,6 +138,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFCore.SqlServer.Abstractio
EndProject
Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "EFCore.VisualBasic.FunctionalTests", "test\EFCore.VisualBasic.FunctionalTests\EFCore.VisualBasic.FunctionalTests.vbproj", "{2AC6A8AC-5C0A-422A-B21A-CDC8D75F20A3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFCore.Tasks", "src\EFCore.Tasks\EFCore.Tasks.csproj", "{711EE8F3-F92D-4470-8B0B-25D8B13EF282}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -152,6 +154,10 @@ Global
{4F7C93F3-A30F-4061-804C-32293DC256A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F7C93F3-A30F-4061-804C-32293DC256A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F7C93F3-A30F-4061-804C-32293DC256A1}.Release|Any CPU.Build.0 = Release|Any CPU
{711EE8F3-F92D-4470-8B0B-25D8B13EF282}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{711EE8F3-F92D-4470-8B0B-25D8B13EF282}.Debug|Any CPU.Build.0 = Debug|Any CPU
{711EE8F3-F92D-4470-8B0B-25D8B13EF282}.Release|Any CPU.ActiveCfg = Release|Any CPU
{711EE8F3-F92D-4470-8B0B-25D8B13EF282}.Release|Any CPU.Build.0 = Release|Any CPU
{715C38E9-B2F5-4DB2-8025-0C6492DEBDD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{715C38E9-B2F5-4DB2-8025-0C6492DEBDD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{715C38E9-B2F5-4DB2-8025-0C6492DEBDD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -371,6 +377,7 @@ Global
GlobalSection(NestedProjects) = preSolution
{2D66A1DA-D102-4DD9-960B-7D863BBB53DE} = {CE6B50B2-34AE-44C9-940A-4E48C3E1B3BC}
{4F7C93F3-A30F-4061-804C-32293DC256A1} = {CE6B50B2-34AE-44C9-940A-4E48C3E1B3BC}
{711EE8F3-F92D-4470-8B0B-25D8B13EF282} = {CE6B50B2-34AE-44C9-940A-4E48C3E1B3BC}
{715C38E9-B2F5-4DB2-8025-0C6492DEBDD4} = {CE6B50B2-34AE-44C9-940A-4E48C3E1B3BC}
{11B51A41-47CB-4EDB-9D8A-17095A65034A} = {CE6B50B2-34AE-44C9-940A-4E48C3E1B3BC}
{D3D0A8E8-EC2F-4E01-8650-8554E186A66F} = {CE6B50B2-34AE-44C9-940A-4E48C3E1B3BC}

Просмотреть файл

@ -31,10 +31,11 @@
<MicrosoftDotNetBuildTasksTemplatingVersion>9.0.0-beta.24114.1</MicrosoftDotNetBuildTasksTemplatingVersion>
</PropertyGroup>
<PropertyGroup Label="Other dependencies">
<MicrosoftBuildFrameworkVersion>17.0.0</MicrosoftBuildFrameworkVersion>
<MicrosoftBuildTasksCoreVersion>17.0.0</MicrosoftBuildTasksCoreVersion>
<MicrosoftBuildUtilitiesCoreVersion>17.0.0</MicrosoftBuildUtilitiesCoreVersion>
<!-- NB: This version affects Visual Studio compatibility. See https://learn.microsoft.com/visualstudio/extensibility/roslyn-version-support -->
<MicrosoftCodeAnalysisVersion>4.8.0</MicrosoftCodeAnalysisVersion>
<MicrosoftCodeAnalysisTestingVersion>1.1.2-beta1.23578.3</MicrosoftCodeAnalysisTestingVersion>
<XUnitVersion>2.6.1</XUnitVersion>
<XUnitRunnerVisualstudioVersion>2.5.3</XUnitRunnerVisualstudioVersion>
</PropertyGroup>
</Project>

Просмотреть файл

@ -1,7 +1,6 @@
<Project>
<PropertyGroup>
<TrimmingTestDir>$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'trimmingTests'))</TrimmingTestDir>
<TrimmingTestProjectsDir>$([MSBuild]::NormalizeDirectory('$(TrimmingTestDir)', 'projects'))</TrimmingTestProjectsDir>
<TrimmingTestProjectsDir>$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)'))</TrimmingTestProjectsDir>
<ProjectTemplate>$(MSBuildThisFileDirectory)project.csproj.template</ProjectTemplate>
<Nullable>enable</Nullable>
</PropertyGroup>

Просмотреть файл

@ -64,7 +64,7 @@
<ItemGroup Condition="'$(AdditionalProjectReferences)' != ''">
<_additionalProjectReferenceTemp Include="$(AdditionalProjectReferences)" />
<_additionalProjectReference Include="&lt;ProjectReference Include=&quot;$(LibrariesProjectRoot)%(_additionalProjectReferenceTemp.Identity)\src\%(_additionalProjectReferenceTemp.Identity).csproj&quot; SkipUseReferenceAssembly=&quot;true&quot; /&gt;" />
<_additionalProjectReference Include="&lt;ProjectReference Include=&quot;$(SolutionRoot)%(_additionalProjectReferenceTemp.Identity)\src\%(_additionalProjectReferenceTemp.Identity).csproj&quot; SkipUseReferenceAssembly=&quot;true&quot; /&gt;" />
</ItemGroup>
<PropertyGroup>

Просмотреть файл

@ -47,10 +47,7 @@
</ItemGroup>
<ItemGroup>
<None Include="build\**\*">
<Pack>True</Pack>
<PackagePath>build</PackagePath>
</None>
<None Include="build\**\*" PackagePath="build\" Pack="true" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -0,0 +1,88 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>MSBuild tasks for Entity Framework Core projects.</Description>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
<AssemblyName>Microsoft.EntityFrameworkCore.Tasks</AssemblyName>
<RootNamespace>Microsoft.EntityFrameworkCore</RootNamespace>
<IncludeSymbols>false</IncludeSymbols>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<GenerateDependencyFile>true</GenerateDependencyFile>
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
<NoWarn>NU5100;NU5128</NoWarn>
<ImplicitUsings>true</ImplicitUsings>
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)..\..\rulesets\EFCore.noxmldocs.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\dotnet-ef\Exe.cs" Link="Tools\Exe.cs" />
<Compile Include="..\ef\AnsiConsole.cs" Link="Tools\AnsiConsole.cs"/>
<Compile Include="..\ef\AnsiConstants.cs" Link="Tools\AnsiConstants.cs"/>
<Compile Include="..\ef\AnsiTextWriter.cs" Link="Tools\AnsiTextWriter.cs"/>
<Compile Include="..\ef\Reporter.cs" Link="Tools\Reporter.cs"/>
<Compile Include="..\ef\NotNullIfNotNullAttribute.cs" Link="Tools\NotNullIfNotNullAttribute.cs"/>
</ItemGroup>
<ItemGroup>
<None Update="Properties\Resources.Designer.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<CustomToolNamespace>Microsoft.EntityFrameworkCore.Tools.Properties</CustomToolNamespace>
</None>
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.Designer.tt</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Using Include="Microsoft.Build" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ef\ef.csproj" ReferenceOutputAssembly="false" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'net472'">
<PackageReference Include="Microsoft.Build.Framework" Version="$(MicrosoftBuildFrameworkVersion)" PrivateAssets="all" ExcludeAssets="Runtime" IsImplicitlyDefined="true" />
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="$(MicrosoftBuildTasksCoreVersion)" PrivateAssets="all" ExcludeAssets="Runtime" IsImplicitlyDefined="true" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="$(MicrosoftBuildUtilitiesCoreVersion)" PrivateAssets="all" ExcludeAssets="Runtime" IsImplicitlyDefined="true" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
<PackageReference Include="System.Text.Json" Version="$(SystemTextJsonVersion)" PrivateAssets="All" />
<Reference Include="Microsoft.Build" />
<Reference Include="Microsoft.Build.Framework" />
<Reference Include="Microsoft.Build.Tasks.v4.0" />
<Reference Include="Microsoft.Build.Utilities.v4.0" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Configuration" />
</ItemGroup>
<!--
Workaround for insufficient support for task packages by NuGet Pack: https://github.com/NuGet/Home/issues/6321
and bugs with ProjectReference: https://github.com/NuGet/Home/issues/10907, https://github.com/NuGet/Home/issues/10312
-->
<PropertyGroup>
<NoPackageAnalysis>true</NoPackageAnalysis>
<NuspecFile>$(MSBuildThisFileDirectory)$(MSBuildProjectName).nuspec</NuspecFile>
</PropertyGroup>
<Target Name="SetPackageProperties" BeforeTargets="InitializeStandardNuspecProperties" DependsOnTargets="Build">
<ItemGroup>
<NuspecProperty Include="AssemblyName=$(AssemblyName)" />
<NuspecProperty Include="OutputPath=$(OutputPath)" />
<NuspecProperty Include="DefaultNetCoreTargetFramework=$(DefaultNetCoreTargetFramework)" />
<NuspecProperty Include="Configuration=$(Configuration)" />
</ItemGroup>
</Target>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
$CommonMetadataElements$
<dependencies>
<group targetFramework=".NET8.0">
<dependency id="Microsoft.EntityFrameworkCore.Design" version="$Version$" />
</group>
</dependencies>
<readme>docs\PACKAGE.md</readme>
</metadata>
<files>
$CommonFileElements$
<file src="PACKAGE.md" target="docs\" />
<file src="$OutputPath$$DefaultNetCoreTargetFramework$\$AssemblyName$.dll" target="tasks\$DefaultNetCoreTargetFramework$\" />
<file src="$OutputPath$$DefaultNetCoreTargetFramework$\$AssemblyName$.pdb" target="tasks\$DefaultNetCoreTargetFramework$\" />
<file src="$OutputPath$$DefaultNetCoreTargetFramework$\$AssemblyName$.deps.json" target="tasks\$DefaultNetCoreTargetFramework$\" />
<file src="$OutputPath$net472\*" target="tasks\net472\" />
<file src="..\..\artifacts\bin\ef\$Configuration$\netcoreapp2.0\*" target="tools\netcoreapp2.0\" />
<file src="buildTransitive\*" target="buildTransitive\" />
</files>
</package>

Просмотреть файл

@ -0,0 +1,17 @@
The Entity Framework Core MSBuild tasks integrate EF design-time tools into the build process. They're primarily used to generate the compiled model.
This package should be referenced by the project containing the derived `DbContext`.
## Usage
Install the package into your project, set `<EFOptimizeContext Condition="'$(Configuration)'=='Release'">true</EFOptimizeContext>` and then run build normally.
If the startup project is different from the current project it needs to be specified: `<EFStartupProject>..\Startup\Startup.csproj</EFStartupProject>`
## Getting started with EF Core
See [Getting started with EF Core](https://learn.microsoft.com/ef/core/get-started/overview/install) for more information about EF NuGet packages, including which to install when getting started.
## Feedback
If you encounter a bug or issues with this package,you can [open an Github issue](https://github.com/dotnet/efcore/issues/new/choose). For more details, see [getting support](https://github.com/dotnet/efcore/blob/main/.github/SUPPORT.md).

58
src/EFCore.Tasks/Properties/Resources.Designer.cs сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,58 @@
// <auto-generated />
using System;
using System.Reflection;
using System.Resources;
#nullable enable
namespace Microsoft.EntityFrameworkCore.Tools.Properties
{
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
internal static class Resources
{
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.EntityFrameworkCore.Properties.Resources", typeof(Resources).Assembly);
/// <summary>
/// Startup project '{startupProject}' targets framework '.NETCoreApp' version '{targetFrameworkVersion}'. This version of the Entity Framework Core .NET Command-line Tools only supports version 2.0 or higher. For information on using older versions of the tools, see https://go.microsoft.com/fwlink/?linkid=871254
/// </summary>
public static string NETCoreApp1StartupProject(object? startupProject, object? targetFrameworkVersion)
=> string.Format(
GetString("NETCoreApp1StartupProject", nameof(startupProject), nameof(targetFrameworkVersion)),
startupProject, targetFrameworkVersion);
/// <summary>
/// Startup project '{startupProject}' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the Entity Framework Core .NET Command-line Tools with this project, add an executable project targeting .NET Core or .NET Framework that references this project, and set it as the startup project using --startup-project; or, update this project to cross-target .NET Core or .NET Framework. For more information on using the Entity Framework Tools with .NET Standard projects, see https://go.microsoft.com/fwlink/?linkid=2034781
/// </summary>
public static string NETStandardStartupProject(object? startupProject)
=> string.Format(
GetString("NETStandardStartupProject", nameof(startupProject)),
startupProject);
/// <summary>
/// Startup project '{startupProject}' targets framework '{targetFramework}'. The Entity Framework Core .NET Command-line Tools don't support this framework. See https://aka.ms/efcore-docs-cli-tfms for more information.
/// </summary>
public static string UnsupportedFramework(object? startupProject, object? targetFramework)
=> string.Format(
GetString("UnsupportedFramework", nameof(startupProject), nameof(targetFramework)),
startupProject, targetFramework);
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name)!;
for (var i = 0; i < formatterNames.Length; i++)
{
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
}
return value;
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
<#
Session["ResourceFile"] = "Resources.resx";
Session["ResourceNamespace"] = "Microsoft.EntityFrameworkCore.Properties";
Session["AccessModifier"] = "internal";
Session["NoDiagnostics"] = true;
#>
<#@ include file="..\..\..\tools\Resources.tt" #>

Просмотреть файл

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="NETCoreApp1StartupProject" xml:space="preserve">
<value>Startup project '{startupProject}' targets framework '.NETCoreApp' version '{targetFrameworkVersion}'. This version of the Entity Framework Core .NET Command-line Tools only supports version 2.0 or higher. For information on using older versions of the tools, see https://go.microsoft.com/fwlink/?linkid=871254</value>
</data>
<data name="NETStandardStartupProject" xml:space="preserve">
<value>Startup project '{startupProject}' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the Entity Framework Core .NET Command-line Tools with this project, add an executable project targeting .NET Core or .NET Framework that references this project, and set it as the startup project using --startup-project; or, update this project to cross-target .NET Core or .NET Framework. For more information on using the Entity Framework Tools with .NET Standard projects, see https://go.microsoft.com/fwlink/?linkid=2034781</value>
</data>
<data name="UnsupportedFramework" xml:space="preserve">
<value>Startup project '{startupProject}' targets framework '{targetFramework}'. The Entity Framework Core .NET Command-line Tools don't support this framework. See https://aka.ms/efcore-docs-cli-tfms for more information.</value>
</data>
</root>

Просмотреть файл

@ -0,0 +1,54 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#if NET472
using System.Configuration;
#endif
namespace Microsoft.EntityFrameworkCore.Tasks.Internal;
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
internal class MsBuildUtilities
{
public static string[] Split(string s)
=> !string.IsNullOrEmpty(s)
? s.Split(';')
.Select(entry => entry.Trim())
.Where(entry => entry.Length != 0)
.ToArray()
: [];
public static string? TrimAndGetNullForEmpty(string? s)
{
if (s == null)
{
return null;
}
s = s.Trim();
return s.Length == 0 ? null : s;
}
public static string[] TrimAndExcludeNullOrEmpty(string?[]? strings)
=> strings == null
? []
: strings
.Select(TrimAndGetNullForEmpty)
.Where(s => s != null)
.Cast<string>()
.ToArray();
public static bool IsTrue(string? value) => bool.TrueString.Equals(TrimAndGetNullForEmpty(value), StringComparison.OrdinalIgnoreCase);
public static bool IsTrueOrEmpty(string? value) => TrimAndGetNullForEmpty(value) == null || IsTrue(value);
public static bool? GetBooleanOrNull(string? value) => bool.TryParse(value, out var result) ? result : null;
public static string? ToMsBuild(string? value) => value?.Replace(',', ';');
}

Просмотреть файл

@ -0,0 +1,253 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Runtime.Versioning;
using System.Text;
using System.Text.Json;
using Microsoft.Build.Framework;
using Microsoft.EntityFrameworkCore.Tools;
using Microsoft.EntityFrameworkCore.Tools.Properties;
namespace Microsoft.EntityFrameworkCore.Tasks.Internal;
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public abstract class OperationTaskBase : Build.Utilities.Task
{
/// <summary>
/// The assembly to use.
/// </summary>
[Required]
public ITaskItem Assembly { get; set; } = null!;
/// <summary>
/// The startup assembly to use.
/// </summary>
[Required]
public ITaskItem StartupAssembly { get; set; } = null!;
/// <summary>
/// The target framework moniker.
/// </summary>
[Required]
public string TargetFrameworkMoniker { get; set; } = null!;
/// <summary>
/// The target runtime framework version.
/// </summary>
public string? RuntimeFrameworkVersion { get; set; }
/// <summary>
/// The project assets file.
/// </summary>
public string? ProjectAssetsFile { get; set; }
/// <summary>
/// The directory containing the database files.
/// </summary>
public ITaskItem? DataDir { get; set; }
/// <summary>
/// The project directory.
/// </summary>
public ITaskItem? ProjectDir { get; set; }
/// <summary>
/// The root namespace to use.
/// </summary>
public string? RootNamespace { get; set; }
/// <summary>
/// The language to use. Defaults to C#.
/// </summary>
public string? Language { get; set; }
/// <summary>
/// A flag indicating whether nullable reference types are enabled.
/// </summary>
public bool Nullable { get; set; }
protected virtual bool Execute(IEnumerable<string> additionalArguments, out string? result)
{
var args = new List<string>();
var startupAssemblyName = Path.GetFileNameWithoutExtension(StartupAssembly.ItemSpec);
var targetDir = Path.GetDirectoryName(Path.GetFullPath(StartupAssembly.ItemSpec))!;
var depsFile = Path.Combine(
targetDir,
startupAssemblyName + ".deps.json");
var runtimeConfig = Path.Combine(
targetDir,
startupAssemblyName + ".runtimeconfig.json");
var projectAssetsFile = MsBuildUtilities.TrimAndGetNullForEmpty(ProjectAssetsFile);
string executable;
var targetFramework = new FrameworkName(TargetFrameworkMoniker);
if (targetFramework.Identifier == ".NETCoreApp")
{
if (targetFramework.Version < new Version(2, 0))
{
throw new InvalidOperationException(
Resources.NETCoreApp1StartupProject(startupAssemblyName, targetFramework.Version));
}
executable = "dotnet";
args.Add("exec");
if (File.Exists(depsFile))
{
args.Add("--depsfile");
args.Add(depsFile);
}
if (projectAssetsFile != null
&& File.Exists(projectAssetsFile))
{
using var file = File.OpenRead(projectAssetsFile);
using var reader = JsonDocument.Parse(file);
var projectAssets = reader.RootElement;
var packageFolders = projectAssets.GetProperty("packageFolders").EnumerateObject().Select(p => p.Name);
foreach (var packageFolder in packageFolders)
{
args.Add("--additionalprobingpath");
args.Add(packageFolder.TrimEnd(Path.DirectorySeparatorChar));
}
}
var runtimeFrameworkVersion = MsBuildUtilities.TrimAndGetNullForEmpty(RuntimeFrameworkVersion);
if (File.Exists(runtimeConfig))
{
args.Add("--runtimeconfig");
args.Add(runtimeConfig);
}
else if (runtimeFrameworkVersion != null)
{
args.Add("--fx-version");
args.Add(runtimeFrameworkVersion);
}
args.Add(Path.Combine(
Path.GetDirectoryName(typeof(OperationTaskBase).Assembly.Location)!,
"..",
"..",
"tools",
"netcoreapp2.0",
"ef.dll"));
}
else if (targetFramework.Identifier == ".NETStandard")
{
throw new InvalidOperationException(Resources.NETStandardStartupProject(startupAssemblyName));
}
else
{
throw new InvalidOperationException(
Resources.UnsupportedFramework(startupAssemblyName, targetFramework.Identifier));
}
args.AddRange(additionalArguments);
args.Add("--assembly");
args.Add(Assembly.ItemSpec);
if (StartupAssembly != null)
{
args.Add("--startup-assembly");
args.Add(StartupAssembly.ItemSpec);
}
if (ProjectDir != null)
{
args.Add("--project-dir");
args.Add(ProjectDir.ItemSpec);
}
if (DataDir != null) {
args.Add("--data-dir");
args.Add(DataDir.ItemSpec);
}
var rootNamespace = MsBuildUtilities.TrimAndGetNullForEmpty(RootNamespace);
if (rootNamespace != null) {
args.Add("--root-namespace");
args.Add(rootNamespace);
}
var language = MsBuildUtilities.TrimAndGetNullForEmpty(Language);
if (language != null) {
args.Add("--language");
args.Add(language);
}
if (Nullable)
{
args.Add("--nullable");
}
args.Add("--working-dir");
args.Add(Directory.GetCurrentDirectory());
args.Add("--verbose");
args.Add("--no-color");
args.Add("--prefix-output");
var resultBuilder = new StringBuilder();
var exitCode = Exe.Run(executable, args, ProjectDir?.ItemSpec, HandleOutput, processCommandLine: Log.LogCommandLine);
result = resultBuilder.Length > 0 ? resultBuilder.ToString() : null;
return exitCode == 0;
void HandleOutput(string? output)
{
if (output == null)
{
return;
}
if (output.StartsWith(Reporter.ErrorPrefix, StringComparison.InvariantCulture))
{
Log.LogError(output.Substring(Reporter.ErrorPrefix.Length));
}
else if (output.StartsWith(Reporter.WarningPrefix, StringComparison.InvariantCulture))
{
Log.LogWarning(output.Substring(Reporter.WarningPrefix.Length));
}
else if (output.StartsWith(Reporter.InfoPrefix, StringComparison.InvariantCulture))
{
Log.LogMessage(output.Substring(Reporter.InfoPrefix.Length));
}
else if (output.StartsWith(Reporter.VerbosePrefix, StringComparison.InvariantCulture))
{
Log.LogMessage(MessageImportance.Low, output.Substring(Reporter.VerbosePrefix.Length));
}
else if (output.StartsWith(Reporter.DataPrefix, StringComparison.InvariantCulture))
{
resultBuilder.AppendLine(output.Substring(Reporter.DataPrefix.Length));
}
else if(output.StartsWith("fail: ", StringComparison.InvariantCulture))
{
Log.LogError(output.Substring(6));
}
else if (output.StartsWith("warn: ", StringComparison.InvariantCulture))
{
Log.LogWarning(output.Substring(6));
}
else if (output.StartsWith("info: ", StringComparison.InvariantCulture))
{
Log.LogMessage(output.Substring(6));
}
else if (output.StartsWith("dbug: ", StringComparison.InvariantCulture)
|| output.StartsWith("trce: ", StringComparison.InvariantCulture))
{
Log.LogMessage(MessageImportance.Low, output.Substring(6));
}
else
{
Log.LogError(output);
}
}
}
}

Просмотреть файл

@ -0,0 +1,84 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Xml.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.EntityFrameworkCore.Tasks.Internal;
using Microsoft.EntityFrameworkCore.Tools.Properties;
namespace Microsoft.EntityFrameworkCore.Tasks;
/// <summary>
/// Generates files that contain tailored code for some runtime services.
/// </summary>
public class OptimizeContext : OperationTaskBase
{
/// <summary>
/// The name of the target DbContext.
/// </summary>
public string? DbContextName { get; set; }
/// <summary>
/// The namespace to use for the generated classes.
/// </summary>
public string? TargetNamespace { get; set; }
/// <summary>
/// The output directory. Usually, relative to the project directory.
/// </summary>
public ITaskItem? OutputDir { get; set; }
/// <summary>
/// Generated files that should be include in the build.
/// </summary>
[Output]
public ITaskItem[] GeneratedFiles { get; private set; } = null!;
/// <inheritdoc/>
public override bool Execute()
{
try
{
Log.LogMessage(MessageImportance.High, "Optimizing DbContext...");
var additionalArguments = new List<string> { "dbcontext", "optimize" };
if (OutputDir != null)
{
additionalArguments.Add("--output-dir");
additionalArguments.Add(OutputDir.ItemSpec);
}
var targetNamespace = MsBuildUtilities.TrimAndGetNullForEmpty(TargetNamespace);
if (targetNamespace != null)
{
additionalArguments.Add("--namespace");
additionalArguments.Add(targetNamespace);
}
var dbContextName = MsBuildUtilities.TrimAndGetNullForEmpty(DbContextName);
if(dbContextName != null)
{
additionalArguments.Add("--context");
additionalArguments.Add(dbContextName);
}
var success = Execute(additionalArguments, out var result);
if (!success
|| result == null)
{
return false;
}
GeneratedFiles = result.Split(new string[] { Environment.NewLine }, StringSplitOptions.None)
.Select(f => new TaskItem(f)).ToArray();
}
catch (Exception e)
{
Log.LogErrorFromException(e);
}
return !Log.HasLoggedErrors;
}
}

Просмотреть файл

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_TaskTargetFramework Condition="'$(MSBuildRuntimeType)' == 'core'">net8.0</_TaskTargetFramework>
<_TaskTargetFramework Condition="'$(MSBuildRuntimeType)' != 'core'">net472</_TaskTargetFramework>
<_EFCustomTasksAssembly>$([MSBuild]::NormalizePath($(MSBuildThisFileDirectory), '..\tasks\$(_TaskTargetFramework)\$(MSBuildThisFileName).dll'))</_EFCustomTasksAssembly>
</PropertyGroup>
<UsingTask TaskName="$(MSBuildThisFileName).OptimizeContext" AssemblyFile="$(_EFCustomTasksAssembly)"/>
<PropertyGroup>
<EFOptimizeContext Condition="'$(EFOptimizeContext)' == ''">false</EFOptimizeContext>
</PropertyGroup>
<PropertyGroup Condition="'$(EFTargetLanguage)' == ''">
<EFTargetLanguage Condition="'$(MSBuildProjectExtension)' == '.csproj'">C#</EFTargetLanguage>
<EFTargetLanguage Condition="'$(MSBuildProjectExtension)' == '.vbproj'">VB</EFTargetLanguage>
<EFTargetLanguage Condition="'$(MSBuildProjectExtension)' == '.fsproj'">F#</EFTargetLanguage>
</PropertyGroup>
</Project>

Просмотреть файл

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<EFGeneratedFilesList Condition="'$(EFGeneratedFilesList)' == ''">$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), '$(IntermediateOutputPath)$(AssemblyName).EFGeneratedFiles.txt'))</EFGeneratedFilesList>
</PropertyGroup>
<!-- Invokes OptimizeContext on the startup project to generate files if needed -->
<Target Name="_GenerateFiles"
BeforeTargets="_ReadGeneratedFilesList"
Condition="'$(EFOptimizeContext)'=='true'">
<PropertyGroup>
<EFStartupProject Condition="'$(EFStartupProject)' ==''">$(MSBuildProjectFullPath)</EFStartupProject>
<EFRootNamespace Condition="'$(EFRootNamespace)' == ''">$(RootNamespace)</EFRootNamespace>
<EFRootNamespace Condition="'$(EFRootNamespace)' == ''">$(AssemblyName)</EFRootNamespace>
<EFTargetNamespace Condition="'$(EFTargetNamespace)' == ''">$(EFRootNamespace)</EFTargetNamespace>
<_FullOutputPath>$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), '$(OutputPath)'))</_FullOutputPath>
<_FullIntermediateOutputPath>$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), '$(IntermediateOutputPath)'))</_FullIntermediateOutputPath>
<EFNullable>false</EFNullable>
</PropertyGroup>
<PropertyGroup Condition="'$(Nullable)'=='enable' Or '$(Nullable)'=='annotations'">
<EFNullable>true</EFNullable>
</PropertyGroup>
<PropertyGroup Condition="'$(OutputType)'=='Library'">
<_AssemblyFullName>$(_FullOutputPath)$(AssemblyName).dll</_AssemblyFullName>
</PropertyGroup>
<PropertyGroup Condition="'$(OutputType)'=='Exe'">
<_AssemblyFullName>$(_FullOutputPath)$(AssemblyName).exe</_AssemblyFullName>
</PropertyGroup>
<PropertyGroup Condition="'$(OutputType)'=='WinExe'">
<_AssemblyFullName>$(_FullOutputPath)$(AssemblyName).exe</_AssemblyFullName>
</PropertyGroup>
<MSBuild Projects="$(EFStartupProject)"
Targets="OptimizeContext"
BuildInParallel="true"
Properties="Configuration=$(Configuration);Platform=$(Platform);PublishAot=false;EFOptimizeContext=false;EFGeneratedFilesListToWrite=$(EFGeneratedFilesList);DbContextAssembly=$(_AssemblyFullName);DbContextName=$(DbContextName);EFRootNamespace=$(EFRootNamespace);EFTargetNamespace=$(EFTargetNamespace);EFTargetLanguage=$(EFTargetLanguage);EFNullable=$(EFNullable);EFOutputDir=$(_FullIntermediateOutputPath);EFProjectDir=$(MSBuildProjectDirectory)">
<Output TaskParameter="TargetOutputs" ItemName="_GeneratedFiles" />
</MSBuild>
<Message Text="Generated files: @(_GeneratedFiles)" Importance="low" />
</Target>
<Target Name="OptimizeContext"
DependsOnTargets="Build"
Inputs="$(DbContextAssembly)"
Outputs="$(EFGeneratedFilesListToWrite)"
Returns="$(_GeneratedFiles)">
<PropertyGroup>
<_FullOutputPath>$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), '$(OutputPath)'))</_FullOutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(OutputType)'=='Library'">
<_StartupAssemblyFullName>$(_FullOutputPath)$(AssemblyName).dll</_StartupAssemblyFullName>
</PropertyGroup>
<PropertyGroup Condition="'$(OutputType)'=='Exe'">
<_StartupAssemblyFullName>$(_FullOutputPath)$(AssemblyName).exe</_StartupAssemblyFullName>
</PropertyGroup>
<PropertyGroup Condition="'$(OutputType)'=='WinExe'">
<_StartupAssemblyFullName>$(_FullOutputPath)$(AssemblyName).exe</_StartupAssemblyFullName>
</PropertyGroup>
<ItemGroup>
<MyItemGroup Remove="@(_GeneratedFiles)"/>
</ItemGroup>
<OptimizeContext Assembly="$(DbContextAssembly)"
StartupAssembly="$(_StartupAssemblyFullName)"
ProjectAssetsFile="$(ProjectAssetsFile)"
RuntimeFrameworkVersion="$(RuntimeFrameworkVersion)"
TargetFrameworkMoniker="$(TargetFrameworkMoniker)"
DbContextName="$(DbContextName)"
RootNamespace="$(EFRootNamespace)"
TargetNamespace="$(EFTargetNamespace)"
Language="$(EFTargetLanguage)"
Nullable="$(EFNullable)"
OutputDir="$(EFOutputDir)"
ProjectDir="$(EFProjectDir)">
<Output TaskParameter="GeneratedFiles" PropertyName="_GeneratedFiles" />
</OptimizeContext>
</Target>
<!-- Read the previously generated files if the files weren't regenerated -->
<Target Name="_ReadGeneratedFilesList"
BeforeTargets="_CompileGeneratedFiles"
Condition="Exists($(EFGeneratedFilesList))">
<ReadLinesFromFile File="$(EFGeneratedFilesList)" Condition="@(_GeneratedFiles->Count()) == 0">
<Output TaskParameter="Lines" ItemName="_ReadGeneratedFiles"/>
</ReadLinesFromFile>
<Message Text="Found previously generated files: @(_ReadGeneratedFiles)" Importance="low" Condition="@(_GeneratedFiles->Count()) == 0" />
<ItemGroup>
<_GeneratedFiles Include="@(_ReadGeneratedFiles)" />
</ItemGroup>
</Target>
<!-- Adds the generated files to compilation -->
<Target Name="_CompileGeneratedFiles"
BeforeTargets="CoreCompile">
<ItemGroup>
<Compile Include="@(_GeneratedFiles)" />
</ItemGroup>
</Target>
<!-- Writes the list of generated files with a newer timestamp than the assembly compiled with them -->
<Target Name="_WriteGeneratedFilesList"
AfterTargets="Build"
Condition="'$(EFOptimizeContext)'=='true' And @(_GeneratedFiles->Count()) &gt; 0">
<Message Text="Writing generated files list to: $(EFGeneratedFilesList)" Importance="low" />
<WriteLinesToFile File="$(EFGeneratedFilesList)" Lines="@(_GeneratedFiles)" Overwrite="true"/>
</Target>
</Project>

Просмотреть файл

@ -1,4 +1,4 @@
<Project>
<Project>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
@ -7,9 +7,12 @@
<PackageId>Microsoft.EntityFrameworkCore.Tools</PackageId>
<NuspecFile>$(MSBuildThisFileDirectory)$(MSBuildProjectName).nuspec</NuspecFile>
<DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
<NoPackageAnalysis>true</NoPackageAnalysis>
<DevelopmentDependency>true</DevelopmentDependency>
<IncludeBuildOutput>false</IncludeBuildOutput>
<IncludeSource>false</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
<Description>Entity Framework Core Tools for the NuGet Package Manager Console in Visual Studio.
Enables these commonly used commands:
@ -25,58 +28,25 @@ Script-Migration
Update-Database
</Description>
<CheckEolTargetFramework>False</CheckEolTargetFramework>
<ImplicitUsings>true</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Diagnostics" />
<Using Include="System.Linq.Expressions" />
<Using Include="System.Reflection" />
<Using Include="Microsoft.EntityFrameworkCore" />
<Using Include="Microsoft.EntityFrameworkCore.ChangeTracking" />
<Using Include="Microsoft.EntityFrameworkCore.Diagnostics" />
<Using Include="Microsoft.EntityFrameworkCore.Design" />
<Using Include="Microsoft.EntityFrameworkCore.Infrastructure" />
<Using Include="Microsoft.EntityFrameworkCore.Metadata" />
<Using Include="Microsoft.EntityFrameworkCore.Metadata.Builders" />
<Using Include="Microsoft.EntityFrameworkCore.Metadata.Conventions" />
<Using Include="Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure" />
<Using Include="Microsoft.EntityFrameworkCore.Migrations" />
<Using Include="Microsoft.EntityFrameworkCore.Migrations.Design" />
<Using Include="Microsoft.EntityFrameworkCore.Migrations.Operations" />
<Using Include="Microsoft.EntityFrameworkCore.Query" />
<Using Include="Microsoft.EntityFrameworkCore.Scaffolding" />
<Using Include="Microsoft.EntityFrameworkCore.Storage" />
<Using Include="Microsoft.EntityFrameworkCore.Storage.ValueConversion" />
<Using Include="Microsoft.EntityFrameworkCore.Update" />
<Using Include="Microsoft.EntityFrameworkCore.ValueGeneration" />
<Using Include="Microsoft.EntityFrameworkCore.Utilities" />
<Using Include="Microsoft.Extensions.Logging" />
<Using Include="Microsoft.Extensions.DependencyInjection" />
<ProjectReference Include="..\ef\ef.csproj" ReferenceOutputAssembly="false" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ef\ef.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.DotNet.Build.Tasks.Templating" Version="$(MicrosoftDotNetBuildTasksTemplatingVersion)" AllowExplicitReference="true" PrivateAssets="All" IsImplicitlyDefined="true" />
<PackageReference Include="Microsoft.DotNet.Build.Tasks.Templating" Version="$(MicrosoftDotNetBuildTasksTemplatingVersion)" PrivateAssets="All" IsImplicitlyDefined="true" />
</ItemGroup>
<ItemGroup>
<GeneratedContent Include="*.psd1.in" />
</ItemGroup>
<!--
Workaround for insufficient support for tools packages by NuGet Pack: https://github.com/NuGet/Home/issues/6321.
-->
<Target Name="SetPackageProperties" BeforeTargets="InitializeStandardNuspecProperties" DependsOnTargets="Build">
<PropertyGroup>
<DevelopmentDependency>true</DevelopmentDependency>
<!-- Make sure we create a symbols.nupkg -->
<IncludeSymbols>true</IncludeSymbols>
</PropertyGroup>
<ItemGroup>
<NuspecProperty Include="version=$(PackageVersion)" />
<NuspecProperty Include="configuration=$(Configuration)" />
<NuspecProperty Include="intermediateOutputPath=$(IntermediateOutputPath)" />
</ItemGroup>

Просмотреть файл

@ -1,12 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata minClientVersion="3.6">
<metadata>
$CommonMetadataElements$
<minClientVersion>3.6</minClientVersion>
<dependencies>
<group targetFramework=".NET8.0">
<dependency id="Microsoft.EntityFrameworkCore.Design" version="$version$" />
<dependency id="Microsoft.EntityFrameworkCore.Design" version="$Version$" />
</group>
</dependencies>
<readme>docs\PACKAGE.md</readme>
@ -14,7 +13,6 @@
<files>
$CommonFileElements$
<file src="PACKAGE.md" target="docs\" />
<file src="lib\**\*" target="lib/" />
<file src="tools\**\*" target="tools/" />
<file src="$intermediateOutputPath$*.psd1" target="tools/" />
<file src="../../artifacts/bin/ef/$configuration$/net472/ef.exe" target="tools/net472/any/" />

Просмотреть файл

Просмотреть файл

@ -1,7 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
@ -13,33 +12,53 @@ internal static class Exe
string executable,
IReadOnlyList<string> args,
string? workingDirectory = null,
bool interceptOutput = false)
Action<string?>? handleOutput = null,
Action<string?>? handleError = null,
Action<string>? processCommandLine = null)
{
var arguments = ToArguments(args);
Reporter.WriteVerbose(executable + " " + arguments);
processCommandLine ??= Reporter.WriteVerbose;
processCommandLine(executable + " " + arguments);
var startInfo = new ProcessStartInfo
{
FileName = executable,
Arguments = arguments,
UseShellExecute = false,
RedirectStandardOutput = interceptOutput
RedirectStandardOutput = handleOutput != null,
RedirectStandardError = handleError != null
};
if (workingDirectory != null)
{
startInfo.WorkingDirectory = workingDirectory;
}
var process = Process.Start(startInfo)!;
if (interceptOutput)
var process = new Process
{
string? line;
while ((line = process.StandardOutput.ReadLine()) != null)
{
Reporter.WriteVerbose(line);
}
StartInfo = startInfo
};
if (handleOutput != null)
{
process.OutputDataReceived += (sender, args) => handleOutput(args.Data);
}
if (handleError != null)
{
process.ErrorDataReceived += (sender, args) => handleError(args.Data);
}
process.Start();
if (handleOutput != null)
{
process.BeginOutputReadLine();
}
if (handleError != null)
{
process.BeginErrorReadLine();
}
process.WaitForExit();

Просмотреть файл

@ -185,7 +185,7 @@ internal class Project
args.Add("/nologo");
args.Add("/p:PublishAot=false"); // Avoid NativeAOT warnings
var exitCode = Exe.Run("dotnet", args, interceptOutput: true);
var exitCode = Exe.Run("dotnet", args, handleOutput: Reporter.WriteVerbose);
if (exitCode != 0)
{
throw new CommandException(Resources.BuildFailed);

Просмотреть файл

@ -1,10 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace Microsoft.EntityFrameworkCore.Tools;
@ -30,7 +27,7 @@ internal class AnsiTextWriter
private void Interpret(string value)
{
var matches = Regex.Matches(value, "\x1b\\[([0-9]+)?m");
var matches = Regex.Matches(value, "\x1b\\[([0-9]+)?m", RegexOptions.None, TimeSpan.FromSeconds(10));
var start = 0;
foreach (var match in matches.Cast<Match>())

Просмотреть файл

@ -17,11 +17,21 @@ internal partial class DbContextOptimizeCommand
}
using var executor = CreateExecutor(args);
executor.OptimizeContext(
var result = executor.OptimizeContext(
_outputDir!.Value(),
_namespace!.Value(),
Context!.Value());
ReportResults(result);
return base.Execute(args);
}
private static void ReportResults(IEnumerable<string> generatedFiles)
{
foreach (var file in generatedFiles)
{
Reporter.WriteData(file);
}
}
}

Просмотреть файл

@ -177,7 +177,7 @@ internal partial class MigrationsBundleCommand
publishArgs.Add("--disable-build-servers");
var exitCode = Exe.Run("dotnet", publishArgs, directory, interceptOutput: true);
var exitCode = Exe.Run("dotnet", publishArgs, directory, handleOutput: Reporter.WriteVerbose);
if (exitCode != 0)
{
throw new CommandException(Resources.BuildBundleFailed);

Просмотреть файл

@ -8,6 +8,12 @@ namespace Microsoft.EntityFrameworkCore.Tools;
internal static class Reporter
{
public const string ErrorPrefix = "error: ";
public const string WarningPrefix = "warn: ";
public const string InfoPrefix = "info: ";
public const string DataPrefix = "data: ";
public const string VerbosePrefix = "verbose: ";
public static bool IsVerbose { get; set; }
public static bool NoColor { get; set; }
public static bool PrefixOutput { get; set; }
@ -17,22 +23,22 @@ internal static class Reporter
=> NoColor ? value : colorizeFunc(value);
public static void WriteError(string? message)
=> WriteLine(Prefix("error: ", Colorize(message, x => Bold + Red + x + Reset)));
=> WriteLine(Prefix(ErrorPrefix, Colorize(message, x => Bold + Red + x + Reset)));
public static void WriteWarning(string? message)
=> WriteLine(Prefix("warn: ", Colorize(message, x => Bold + Yellow + x + Reset)));
=> WriteLine(Prefix(WarningPrefix, Colorize(message, x => Bold + Yellow + x + Reset)));
public static void WriteInformation(string? message)
=> WriteLine(Prefix("info: ", message));
=> WriteLine(Prefix(InfoPrefix, message));
public static void WriteData(string? message)
=> WriteLine(Prefix("data: ", Colorize(message, x => Bold + Gray + x + Reset)));
=> WriteLine(Prefix(DataPrefix, Colorize(message, x => Bold + Gray + x + Reset)));
public static void WriteVerbose(string? message)
{
if (IsVerbose)
{
WriteLine(Prefix("verbose: ", Colorize(message, x => Bold + Black + x + Reset)));
WriteLine(Prefix(VerbosePrefix, Colorize(message, x => Bold + Black + x + Reset)));
}
}

Просмотреть файл

@ -48,7 +48,6 @@
<ItemGroup>
<ProjectReference Include="..\..\src\EFCore\EFCore.csproj" />
<ProjectReference Include="..\..\src\EFCore.Analyzers\EFCore.Analyzers.csproj" />
<ProjectReference Include="..\..\src\EFCore.Design\EFCore.Design.csproj" />
<ProjectReference Include="..\..\src\EFCore.Proxies\EFCore.Proxies.csproj" />
<ProjectReference Include="..\..\src\EFCore.Abstractions\EFCore.Abstractions.csproj" />

Просмотреть файл

@ -72,6 +72,10 @@ public class ModelAsserter
expectedEntityTypes = expectedEntityTypes.OrderBy(p => p.Name);
actualEntityTypes = actualEntityTypes.OrderBy(p => p.Name);
}
else
{
expectedEntityTypes = expectedEntityTypes.Select(x => x);
}
Assert.Equal(expectedEntityTypes, actualEntityTypes,
(expected, actual) =>
@ -214,6 +218,10 @@ public class ModelAsserter
expectedProperties = expectedProperties.OrderBy(p => p.Name);
actualProperties = actualProperties.OrderBy(p => p.Name);
}
else
{
expectedProperties = expectedProperties.Select(x => x);
}
Assert.Equal(expectedProperties, actualProperties,
(expected, actual) =>
@ -280,6 +288,10 @@ public class ModelAsserter
expectedProperties = expectedProperties.OrderBy(p => p.Name);
actualProperties = actualProperties.OrderBy(p => p.Name);
}
else
{
expectedProperties = expectedProperties.Select(x => x);
}
Assert.Equal(expectedProperties, actualProperties,
(expected, actual) =>
@ -407,6 +419,10 @@ public class ModelAsserter
expectedProperties = expectedProperties.OrderBy(p => p.Name);
actualProperties = actualProperties.OrderBy(p => p.Name);
}
else
{
expectedProperties = expectedProperties.Select(x => x);
}
Assert.Equal(expectedProperties, actualProperties,
(expected, actual) =>
@ -465,6 +481,10 @@ public class ModelAsserter
expectedNavigations = expectedNavigations.OrderBy(p => p.Name);
actualNavigations = actualNavigations.OrderBy(p => p.Name);
}
else
{
expectedNavigations = expectedNavigations.Select(x => x);
}
Assert.Equal(expectedNavigations, actualNavigations,
(expected, actual) =>
@ -540,6 +560,10 @@ public class ModelAsserter
expectedNavigations = expectedNavigations.OrderBy(p => p.Name);
actualNavigations = actualNavigations.OrderBy(p => p.Name);
}
else
{
expectedNavigations = expectedNavigations.Select(x => x);
}
Assert.Equal(expectedNavigations, actualNavigations,
(expected, actual) =>
@ -615,6 +639,10 @@ public class ModelAsserter
expectedKeys = expectedKeys.Order(KeyComparer.Instance);
actualKeys = actualKeys.Order(KeyComparer.Instance);
}
else
{
expectedKeys = expectedKeys.Select(x => x);
}
Assert.Equal(expectedKeys, actualKeys,
(expected, actual) =>
@ -689,6 +717,10 @@ public class ModelAsserter
expectedForeignKey = expectedForeignKey.Order(ForeignKeyComparer.Instance);
actualForeignKey = actualForeignKey.Order(ForeignKeyComparer.Instance);
}
else
{
expectedForeignKey = expectedForeignKey.Select(x => x);
}
Assert.Equal(expectedForeignKey, actualForeignKey,
(expected, actual) =>
@ -777,6 +809,10 @@ public class ModelAsserter
expectedIndex = expectedIndex.Order(IndexComparer.Instance);
actualIndex = actualIndex.Order(IndexComparer.Instance);
}
else
{
expectedIndex = expectedIndex.Select(x => x);
}
Assert.Equal(expectedIndex, actualIndex,
(expected, actual) =>