diff --git a/CHANGELOG.md b/CHANGELOG.md index f07308e85..000dec9c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,9 @@ ## Improvements: ## Bug fixes: +* Fix: GenerateFeatureFileCodeBehindTask fails with misleading DirectoryNotFoundException when ndjson output path exceeds Windows MAX_PATH (260) -*Contributors of this release (in alphabetical order):* +*Contributors of this release (in alphabetical order):* @clrudolphi # v3.3.4 - 2026-03-23 diff --git a/Reqnroll.Tools.MsBuild.Generation/GeneratedFileWriter.cs b/Reqnroll.Tools.MsBuild.Generation/GeneratedFileWriter.cs index 11bce6031..bd1dc6017 100644 --- a/Reqnroll.Tools.MsBuild.Generation/GeneratedFileWriter.cs +++ b/Reqnroll.Tools.MsBuild.Generation/GeneratedFileWriter.cs @@ -1,12 +1,10 @@ +using System; using System.IO; using System.Text; using Reqnroll.Utils; namespace Reqnroll.Tools.MsBuild.Generation; -/// -/// This class is going to be obsolete once we implement MsBuild level up-to-date checks. -/// public class GeneratedFileWriter(IReqnrollTaskLoggingHelper log) { public void WriteGeneratedFile(string outputPath, string generatedFileContent) @@ -17,13 +15,15 @@ public void WriteGeneratedFile(string outputPath, string generatedFileContent) public void DeleteGeneratedFile(string outputPath) { - if (!File.Exists(outputPath)) + var path = ChangePathToSupportLongPaths(outputPath); + + if (!File.Exists(path)) return; log.LogTaskDiagnosticMessage($"Deleting {outputPath}"); try { - File.Delete(outputPath); + File.Delete(path); } catch (IOException ex) { @@ -34,12 +34,40 @@ public void DeleteGeneratedFile(string outputPath) private void WriteFile(string filePath, string content) { string directoryPath = Path.GetDirectoryName(filePath); - if (directoryPath != null && !Directory.Exists(directoryPath)) + var longDirPath = ChangePathToSupportLongPaths(directoryPath); + if (!string.IsNullOrEmpty(longDirPath) && !Directory.Exists(longDirPath)) + { + Directory.CreateDirectory(longDirPath); + } + var longPath = ChangePathToSupportLongPaths(filePath); + WriteAllTextWithRetry(longPath, content, Encoding.UTF8); + } + + private static string ChangePathToSupportLongPaths(string path) + { + if (string.IsNullOrWhiteSpace(path)) + return path; + + string fullPath = Path.GetFullPath(path); + + // Cross-platform: only apply extended syntax on Windows. + if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform( + System.Runtime.InteropServices.OSPlatform.Windows)) { - Directory.CreateDirectory(directoryPath); + return fullPath; } - WriteAllTextWithRetry(filePath, content, Encoding.UTF8); + // Already device/extended syntax. + if (fullPath.StartsWith(@"\\?\", StringComparison.Ordinal) || + fullPath.StartsWith(@"\\.\", StringComparison.Ordinal)) + return fullPath; + + // UNC longDirPath. + if (fullPath.StartsWith(@"\\", StringComparison.Ordinal)) + return @"\\?\UNC\" + fullPath.Substring(2); + + // Drive-qualified longDirPath. + return @"\\?\" + fullPath; } ///