From a11752011e6dd3760189c1c9d77cd6f408b44b84 Mon Sep 17 00:00:00 2001 From: Suchiman Date: Thu, 18 Jan 2024 21:21:59 +0100 Subject: [PATCH 1/2] Fix incremental builds - Avoid writing to the obj directory unnecessarily to avoid tripping up the up-to-date check - Also fixes a subtle bug around file writing: File.OpenWrite will open an existing file and not truncate it, so if we ever write fewer bytes to that file than it currently contains, those additional bytes will be preserved, corrupting the file --- src/dotnet-ef/Project.cs | 16 +++++++++++----- .../Internal/ModelCodeGeneratorTestFixture.cs | 4 ++-- .../TestUtilities/BuildSource.cs | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/dotnet-ef/Project.cs b/src/dotnet-ef/Project.cs index 7875219d73e..1d4d7b036ea 100644 --- a/src/dotnet-ef/Project.cs +++ b/src/dotnet-ef/Project.cs @@ -53,16 +53,22 @@ public static Project FromFile( Directory.CreateDirectory(buildExtensionsDir); + byte[] efTargets; + using (var input = typeof(Resources).Assembly.GetManifestResourceStream( + "Microsoft.EntityFrameworkCore.Tools.Resources.EntityFrameworkCore.targets")!) + { + efTargets = new byte[input.Length]; + input.Read(efTargets); + } + var efTargetsPath = Path.Combine( buildExtensionsDir, Path.GetFileName(file) + ".EntityFrameworkCore.targets"); - using (var input = typeof(Resources).Assembly.GetManifestResourceStream( - "Microsoft.EntityFrameworkCore.Tools.Resources.EntityFrameworkCore.targets")!) - using (var output = File.OpenWrite(efTargetsPath)) + // Avoid touching the targets file, if it matches what we need, to enable incremental builds + if (!File.Exists(efTargetsPath) || !File.ReadAllBytes(efTargetsPath).SequenceEqual(efTargets)) { - // NB: Copy always in case it changes Reporter.WriteVerbose(Resources.WritingFile(efTargetsPath)); - input.CopyTo(output); + File.WriteAllBytes(efTargetsPath, efTargets); } IDictionary metadata; diff --git a/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestFixture.cs b/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestFixture.cs index 1244b7a15e6..9f6c7752ad8 100644 --- a/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestFixture.cs +++ b/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestFixture.cs @@ -12,14 +12,14 @@ public ModelCodeGeneratorTestFixture() using (var input = typeof(ModelCodeGeneratorTestBase).Assembly.GetManifestResourceStream( "Microsoft.EntityFrameworkCore.Resources.CSharpDbContextGenerator.tt")) - using (var output = File.OpenWrite(Path.Combine(templatesDir, "DbContext.t4"))) + using (var output = File.Create(Path.Combine(templatesDir, "DbContext.t4"))) { input.CopyTo(output); } using (var input = typeof(ModelCodeGeneratorTestBase).Assembly.GetManifestResourceStream( "Microsoft.EntityFrameworkCore.Resources.CSharpEntityTypeGenerator.tt")) - using (var output = File.OpenWrite(Path.Combine(templatesDir, "EntityType.t4"))) + using (var output = File.Create(Path.Combine(templatesDir, "EntityType.t4"))) { input.CopyTo(output); } diff --git a/test/EFCore.Specification.Tests/TestUtilities/BuildSource.cs b/test/EFCore.Specification.Tests/TestUtilities/BuildSource.cs index 4da91e2b178..d484d979912 100644 --- a/test/EFCore.Specification.Tests/TestUtilities/BuildSource.cs +++ b/test/EFCore.Specification.Tests/TestUtilities/BuildSource.cs @@ -60,7 +60,7 @@ public BuildFileResult Build() var targetPath = Path.Combine(TargetDir ?? Path.GetTempPath(), projectName + ".dll"); - using (var stream = File.OpenWrite(targetPath)) + using (var stream = File.Create(targetPath)) { var result = compilation.Emit(stream); if (!result.Success) From f5bef32bb003ff239de1f5c510124a17b07a7fc3 Mon Sep 17 00:00:00 2001 From: Suchiman Date: Sun, 28 Jan 2024 16:30:37 +0100 Subject: [PATCH 2/2] Handle ReadAllBytes exceptions --- src/dotnet-ef/Project.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/dotnet-ef/Project.cs b/src/dotnet-ef/Project.cs index 1d4d7b036ea..1953c0f1a46 100644 --- a/src/dotnet-ef/Project.cs +++ b/src/dotnet-ef/Project.cs @@ -64,8 +64,21 @@ public static Project FromFile( var efTargetsPath = Path.Combine( buildExtensionsDir, Path.GetFileName(file) + ".EntityFrameworkCore.targets"); + + bool FileMatches() + { + try + { + return !File.ReadAllBytes(efTargetsPath).SequenceEqual(efTargets); + } + catch + { + return false; + } + } + // Avoid touching the targets file, if it matches what we need, to enable incremental builds - if (!File.Exists(efTargetsPath) || !File.ReadAllBytes(efTargetsPath).SequenceEqual(efTargets)) + if (!File.Exists(efTargetsPath) || !FileMatches()) { Reporter.WriteVerbose(Resources.WritingFile(efTargetsPath)); File.WriteAllBytes(efTargetsPath, efTargets);