diff --git a/Directory.Packages.props b/Directory.Packages.props index 13682a1ed8a..b5b30003d44 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -53,8 +53,8 @@ - - - + + + \ No newline at end of file diff --git a/eng/Versions.props b/eng/Versions.props index 19609d973d6..5a713f0b8bb 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -2,9 +2,9 @@ 10.0.1 - servicing + servicing - False + False true - 17.14.28 - 17.14.28 - 17.14.28 - 4.14.0 - 4.14.0 - 4.14.0 - - 17.15.0 17.15.0 17.15.0 5.0.0 5.0.0 5.0.0 - --> - - 1.1.3-beta1.24423.1 - 1.1.3-beta1.24352.1 - 1.14.2 - 1.3.2 - 1.12.0 - 2.1.11 diff --git a/src/EFCore.Design/EFCore.Design.csproj b/src/EFCore.Design/EFCore.Design.csproj index f40ebae32f8..981497651ac 100644 --- a/src/EFCore.Design/EFCore.Design.csproj +++ b/src/EFCore.Design/EFCore.Design.csproj @@ -58,7 +58,7 @@ - + diff --git a/src/EFCore.Tasks/Tasks/Internal/OperationTaskBase.cs b/src/EFCore.Tasks/Tasks/Internal/OperationTaskBase.cs index 830d4ca98e6..4e10cd493c0 100644 --- a/src/EFCore.Tasks/Tasks/Internal/OperationTaskBase.cs +++ b/src/EFCore.Tasks/Tasks/Internal/OperationTaskBase.cs @@ -81,6 +81,11 @@ public abstract class OperationTaskBase : ToolTask /// public bool Nullable { get; set; } + /// + /// Runtime copy local items for dependency resolution. + /// + public ITaskItem[]? RuntimeCopyLocalItems { get; set; } + /// /// The additional arguments to pass to the dotnet-ef command. /// diff --git a/src/EFCore.Tasks/Tasks/OptimizeDbContext.cs b/src/EFCore.Tasks/Tasks/OptimizeDbContext.cs index 05ffa8615c8..aec1e5f8e02 100644 --- a/src/EFCore.Tasks/Tasks/OptimizeDbContext.cs +++ b/src/EFCore.Tasks/Tasks/OptimizeDbContext.cs @@ -80,6 +80,8 @@ public override bool Execute() if (PrecompileQueries) { AdditionalArguments.Add("--precompile-queries"); + + CopyBuildHost(); } AdditionalArguments.Add("--nativeaot"); @@ -106,4 +108,48 @@ public override bool Execute() return !Log.HasLoggedErrors; } + + private void CopyBuildHost() + { + var msbuildWorkspacesItem = RuntimeCopyLocalItems?.FirstOrDefault(item => + string.Equals(item.GetMetadata("Filename"), "Microsoft.CodeAnalysis.Workspaces.MSBuild", StringComparison.OrdinalIgnoreCase)); + if (msbuildWorkspacesItem == null + || !string.Equals(msbuildWorkspacesItem.GetMetadata("CopyLocal"), "true", StringComparison.OrdinalIgnoreCase) + || msbuildWorkspacesItem.GetMetadata("FullPath") is not { } fullPath + || string.IsNullOrEmpty(fullPath) + || Path.GetDirectoryName(fullPath) is not { } itemDirectory + || string.IsNullOrEmpty(itemDirectory)) + { + return; + } + + var contentFilesPath = Path.GetFullPath(Path.Combine(itemDirectory, "..", "..", "contentFiles", "any", "any")); + var targetDir = Path.GetDirectoryName(Path.GetFullPath(Assembly.ItemSpec))!; + + CopyDirectoryRecursive(contentFilesPath, targetDir); + } + + private static void CopyDirectoryRecursive(string sourceDir, string targetDir) + { + var directory = new DirectoryInfo(sourceDir); + if (!directory.Exists) + { + return; + } + + Directory.CreateDirectory(targetDir); + foreach (var file in directory.GetFiles()) + { + var filePath = Path.Combine(targetDir, file.Name); + if (!File.Exists(filePath)) + { + file.CopyTo(filePath, overwrite: false); + } + } + + foreach (var subDir in directory.GetDirectories()) + { + CopyDirectoryRecursive(subDir.FullName, Path.Combine(targetDir, subDir.Name)); + } + } } diff --git a/src/EFCore.Tasks/buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets b/src/EFCore.Tasks/buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets index 31e0dbe20a3..1032f4edbea 100644 --- a/src/EFCore.Tasks/buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets +++ b/src/EFCore.Tasks/buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets @@ -106,6 +106,7 @@ For Publish: TargetNamespace="$(EFTargetNamespace)" Language="$(Language)" Nullable="$(EFNullable)" + RuntimeCopyLocalItems="@(RuntimeCopyLocalItems)" OutputDir="$(EFOutputDir)" Project="$(MSBuildProjectFullPath)" ProjectDir="$(MSBuildProjectDirectory)" diff --git a/src/EFCore.Tools/tools/EntityFrameworkCore.psm1 b/src/EFCore.Tools/tools/EntityFrameworkCore.psm1 index ce63472efc5..f236877f45c 100644 --- a/src/EFCore.Tools/tools/EntityFrameworkCore.psm1 +++ b/src/EFCore.Tools/tools/EntityFrameworkCore.psm1 @@ -1338,6 +1338,24 @@ function EF($project, $startupProject, $params, $applicationArgs, [switch] $skip $params += '--design-assembly', $designReference.FullPath } + $msbuildWorkspacesItem = $references.Items.RuntimeCopyLocalItems | ? { + $_.Filename -eq 'Microsoft.CodeAnalysis.Workspaces.MSBuild' + } | Select-Object -First 1 + + if ($msbuildWorkspacesItem -ne $null -and $msbuildWorkspacesItem.CopyLocal -eq 'true') + { + $itemDirectory = [IO.Path]::GetDirectoryName($msbuildWorkspacesItem.FullPath) + if ($itemDirectory) + { + $contentFilesPath = [IO.Path]::GetFullPath([IO.Path]::Combine($itemDirectory, '..', '..', 'contentFiles', 'any', 'any')) + + if ([IO.Directory]::Exists($contentFilesPath)) + { + Copy-Item "$contentFilesPath\*" $targetDir -Recurse -ErrorAction SilentlyContinue + } + } + } + $arguments = ToArguments $params if ($applicationArgs) { diff --git a/src/dotnet-ef/Project.cs b/src/dotnet-ef/Project.cs index 68e0203665e..578550045ce 100644 --- a/src/dotnet-ef/Project.cs +++ b/src/dotnet-ef/Project.cs @@ -90,11 +90,16 @@ public static Project FromFile( var metadata = JsonSerializer.Deserialize(output.ToString())!; - var designAssembly = metadata.Items["RuntimeCopyLocalItems"] + var runtimeCopyLocalItems = metadata.Items["RuntimeCopyLocalItems"]; + + var designAssembly = runtimeCopyLocalItems .Select(i => i["FullPath"]) .FirstOrDefault(i => i.Contains("Microsoft.EntityFrameworkCore.Design", StringComparison.InvariantCulture)); var properties = metadata.Properties; + var outputPath = Path.GetFullPath(Path.Combine(properties[nameof(ProjectDir)]!, properties[nameof(OutputPath)]!)); + CopyBuildHost(runtimeCopyLocalItems, outputPath); + var platformTarget = properties[nameof(PlatformTarget)]; if (platformTarget.Length == 0) { @@ -126,6 +131,50 @@ private record class ProjectMetadata public Dictionary[]> Items { get; set; } = null!; } + private static void CopyBuildHost( + Dictionary[] runtimeCopyLocalItems, + string targetDir) + { + var msbuildWorkspacesItem = runtimeCopyLocalItems.FirstOrDefault(item => + string.Equals(item["Filename"], "Microsoft.CodeAnalysis.Workspaces.MSBuild", StringComparison.OrdinalIgnoreCase)); + + if (msbuildWorkspacesItem == null + || !msbuildWorkspacesItem.TryGetValue("CopyLocal", out var copyLocal) + || !string.Equals(copyLocal, "true", StringComparison.OrdinalIgnoreCase) + || !msbuildWorkspacesItem.TryGetValue("FullPath", out var fullPath) + || string.IsNullOrEmpty(fullPath)) + { + return; + } + + var contentFilesPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(fullPath)!, "..", "..", "contentFiles", "any", "any")); + CopyDirectoryRecursive(contentFilesPath, targetDir); + } + + private static void CopyDirectoryRecursive(string sourceDir, string targetDir) + { + var directory = new DirectoryInfo(sourceDir); + if (!directory.Exists) + { + return; + } + + Directory.CreateDirectory(targetDir); + foreach (var file in directory.GetFiles()) + { + var filePath = Path.Combine(targetDir, file.Name); + if (!File.Exists(filePath)) + { + file.CopyTo(filePath, overwrite: false); + } + } + + foreach (var subDir in directory.GetDirectories()) + { + CopyDirectoryRecursive(subDir.FullName, Path.Combine(targetDir, subDir.Name)); + } + } + public void Build(IEnumerable? additionalArgs) { var args = new List { "build" }; diff --git a/src/ef/ReflectionOperationExecutor.cs b/src/ef/ReflectionOperationExecutor.cs index ca4997884ce..9314a4326dd 100644 --- a/src/ef/ReflectionOperationExecutor.cs +++ b/src/ef/ReflectionOperationExecutor.cs @@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore.Design.Internal; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Tools.Properties; + #if NET using System.Runtime.Loader; #endif @@ -58,18 +59,13 @@ public ReflectionOperationExecutor( AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly; #if NET - _commandsAssembly = AssemblyLoadContext.LoadFromAssemblyName(new AssemblyName(DesignAssemblyName)); + _commandsAssembly = DesignAssemblyPath != null + ? AssemblyLoadContext.LoadFromAssemblyPath(DesignAssemblyPath) + : AssemblyLoadContext.LoadFromAssemblyName(new AssemblyName(DesignAssemblyName)); #else - if (DesignAssemblyPath != null) - { - var assemblyPath = Path.GetDirectoryName(DesignAssemblyPath); - assemblyPath = Path.Combine(assemblyPath, DesignAssemblyName + ".dll"); - _commandsAssembly = Assembly.LoadFrom(assemblyPath); - } - else - { - _commandsAssembly = Assembly.Load(DesignAssemblyName); - } + _commandsAssembly = DesignAssemblyPath != null + ? Assembly.LoadFrom(DesignAssemblyPath) + : Assembly.Load(DesignAssemblyName); #endif var reportHandlerType = _commandsAssembly.GetType(ReportHandlerTypeName, throwOnError: true, ignoreCase: false)!; @@ -109,16 +105,12 @@ protected AssemblyLoadContext AssemblyLoadContext return _assemblyLoadContext; } - if (DesignAssemblyPath != null) + AssemblyLoadContext.Default.Resolving += (context, name) => { - AssemblyLoadContext.Default.Resolving += (context, name) => - { - var assemblyPath = Path.GetDirectoryName(DesignAssemblyPath)!; - assemblyPath = Path.Combine(assemblyPath, name.Name + ".dll"); - return File.Exists(assemblyPath) ? context.LoadFromAssemblyPath(assemblyPath) : null; - }; - _assemblyLoadContext = AssemblyLoadContext.Default; - } + var assemblyPath = Path.Combine(AppBasePath, name.Name + ".dll"); + return File.Exists(assemblyPath) ? context.LoadFromAssemblyPath(assemblyPath) : null; + }; + _assemblyLoadContext = AssemblyLoadContext.Default; return AssemblyLoadContext.Default; } @@ -136,18 +128,13 @@ public override string? EFCoreVersion Assembly? assembly = null; #if NET - assembly = AssemblyLoadContext.LoadFromAssemblyName(new AssemblyName(DesignAssemblyName)); + assembly = DesignAssemblyPath != null + ? AssemblyLoadContext.LoadFromAssemblyPath(DesignAssemblyPath) + : AssemblyLoadContext.LoadFromAssemblyName(new AssemblyName(DesignAssemblyName)); #else - if (DesignAssemblyPath != null) - { - var assemblyPath = Path.GetDirectoryName(DesignAssemblyPath); - assemblyPath = Path.Combine(assemblyPath, DesignAssemblyName + ".dll"); - assembly = Assembly.LoadFrom(assemblyPath); - } - else - { - assembly = Assembly.Load(DesignAssemblyName); - } + assembly = DesignAssemblyPath != null + ? Assembly.LoadFrom(DesignAssemblyPath) + : Assembly.Load(DesignAssemblyName); #endif _efcoreVersion = assembly.GetCustomAttribute() ?.InformationalVersion; diff --git a/src/ef/ef.csproj b/src/ef/ef.csproj index eeb9b64e468..bc690085b1c 100644 --- a/src/ef/ef.csproj +++ b/src/ef/ef.csproj @@ -29,16 +29,6 @@ - - - - $(NoWarn);NU1903 - - - - - - diff --git a/test/Directory.Packages.props b/test/Directory.Packages.props index fb0eada61df..576e68d96da 100644 --- a/test/Directory.Packages.props +++ b/test/Directory.Packages.props @@ -4,12 +4,11 @@ - - - + + + - - + @@ -18,10 +17,10 @@ - - - - + + + +