diff --git a/app/Build/Commands/UpdateMetadataCommands.cs b/app/Build/Commands/UpdateMetadataCommands.cs index e0145f9b1..9630e5155 100644 --- a/app/Build/Commands/UpdateMetadataCommands.cs +++ b/app/Build/Commands/UpdateMetadataCommands.cs @@ -259,7 +259,7 @@ public sealed partial class UpdateMetadataCommands var foundIssue = false; foreach (var buildOutputLine in dotnetBuildOutputLines) { - if(buildOutputLine.Contains(" error ") || buildOutputLine.Contains("#warning")) + if(IsDotnetBuildIssue(buildOutputLine)) { if(!foundIssue) { @@ -348,7 +348,7 @@ public sealed partial class UpdateMetadataCommands var foundRustIssue = false; foreach (var buildOutputLine in rustBuildOutputLines) { - if(buildOutputLine.Contains("error", StringComparison.OrdinalIgnoreCase) || buildOutputLine.Contains("warning")) + if(IsRustBuildIssue(buildOutputLine)) { if(!foundRustIssue) { @@ -372,6 +372,42 @@ public sealed partial class UpdateMetadataCommands } } + /// + /// Whether a line of the .NET build output is an error or the warning of a #warning directive. + /// + /// + /// MSBuild writes its diagnostics as "origin: error CODE: text" and keeps the keyword English in any + /// language. Looking for the word alone would also catch messages which merely mention an error. + /// + /// One line of the build output. + /// True, when the line reports an issue. + private static bool IsDotnetBuildIssue(string line) => DotnetErrorRegex().IsMatch(line) || line.Contains("#warning", StringComparison.Ordinal); + + /// + /// Whether a line of the Rust build output is an error or a warning. + /// + /// + /// Cargo and rustc start each diagnostic at the beginning of a line, with "error:", "error[", or "warning:". + /// Looking for these words anywhere would also catch the names of crates such as thiserror, which cargo + /// prints while compiling them. The note about dependencies which a future Rust version will reject also + /// starts with "warning:", yet it says nothing about this build. The Tauri CLI reports its own failures + /// with a right-aligned "Error" label. + /// + /// One line of the build output. + /// True, when the line reports an issue. + private static bool IsRustBuildIssue(string line) + { + const string FUTURE_INCOMPATIBILITY_NOTE = "warning: the following packages contain code that will be rejected by a future version of Rust"; + + if (line.StartsWith(FUTURE_INCOMPATIBILITY_NOTE, StringComparison.Ordinal)) + return false; + + return line.StartsWith("error:", StringComparison.Ordinal) + || line.StartsWith("error[", StringComparison.Ordinal) + || line.StartsWith("warning:", StringComparison.Ordinal) + || TauriErrorRegex().IsMatch(line); + } + private async Task CreateNextChangelog(int currentBuildNumber, AppVersion currentAppVersion) { Console.Write("- Create the next changelog ..."); @@ -525,7 +561,6 @@ public sealed partial class UpdateMetadataCommands return new( metadataPath, - metadataContent, metadataLines, appVersion, buildNumber, @@ -558,8 +593,7 @@ public sealed partial class UpdateMetadataCommands releaseState.MetadataLines[BUILD_TIME_INDEX] = buildTimeString; releaseState.MetadataLines[BUILD_NUMBER_INDEX] = buildNumber.ToString(CultureInfo.InvariantCulture); releaseState.MetadataLines[COMMIT_HASH_INDEX] = $"{releaseState.HeadCommitHash}, release"; - var updatedMetadata = JoinLines(releaseState.MetadataContent, releaseState.MetadataLines); - await File.WriteAllTextAsync(releaseState.MetadataPath, updatedMetadata, Environment.UTF8_NO_BOM); + await WriteMetadataLinesAsync(releaseState.MetadataPath, releaseState.MetadataLines); var updatedChangelogHeader = FormatChangelogHeader(releaseState.AppVersion, buildNumber, buildTime); var updatedChangelog = ReplaceExactlyOnce(releaseState.ChangelogContent, releaseState.ChangelogHeader, updatedChangelogHeader); @@ -767,10 +801,20 @@ public sealed partial class UpdateMetadataCommands return content.Replace("\r\n", "\n", StringComparison.Ordinal).Split('\n'); } - private static string JoinLines(string originalContent, string[] lines) + /// + /// Writes the metadata file with a line feed after each line, the last one included. + /// + /// + /// This is the form in which the file is committed, and the build script of the Rust runtime writes it + /// the same way. File.WriteAllLinesAsync would end the lines with the line break of the current OS, so + /// that the file would change with the OS it was last built on. + /// + /// The path of the metadata file. + /// The lines to write. An empty element after the final line break, as SplitLines leaves it, adds no empty line. + private static async Task WriteMetadataLinesAsync(string pathMetadata, IEnumerable lines) { - var lineEnding = originalContent.Contains("\r\n", StringComparison.Ordinal) ? "\r\n" : "\n"; - return string.Join(lineEnding, lines); + var metadata = string.Join('\n', lines).TrimEnd('\n') + '\n'; + await File.WriteAllTextAsync(pathMetadata, metadata, Environment.UTF8_NO_BOM); } private async Task ReadPdfiumVersion() @@ -794,7 +838,7 @@ public sealed partial class UpdateMetadataCommands Console.Write($"- Updating architecture to {rid.ToUserFriendlyName()} ..."); lines[ARCHITECTURE_INDEX] = rid.AsMicrosoftRid(); - await File.WriteAllLinesAsync(pathMetadata, lines, Environment.UTF8_NO_BOM); + await WriteMetadataLinesAsync(pathMetadata, lines); Console.WriteLine(" done."); } @@ -813,7 +857,7 @@ public sealed partial class UpdateMetadataCommands Console.WriteLine($"- Updating commit hash from '{currentCommitHash}' to '{updatedCommitHash}'."); lines[COMMIT_HASH_INDEX] = updatedCommitHash; - await File.WriteAllLinesAsync(pathMetadata, lines, Environment.UTF8_NO_BOM); + await WriteMetadataLinesAsync(pathMetadata, lines); } private async Task UpdateAppVersion(PrepareAction action, string? version = null) @@ -876,7 +920,7 @@ public sealed partial class UpdateMetadataCommands Console.WriteLine($"- Updating app version from '{currentAppVersionLine}' to '{updatedAppVersion}'."); lines[APP_VERSION_INDEX] = updatedAppVersion; - await File.WriteAllLinesAsync(pathMetadata, lines, Environment.UTF8_NO_BOM); + await WriteMetadataLinesAsync(pathMetadata, lines); return new(updatedAppVersion, newMajor, newMinor, newPatch); } @@ -935,7 +979,7 @@ public sealed partial class UpdateMetadataCommands Console.WriteLine($"- Updated Tauri version from {currentTauriVersion} to {updatedTauriVersion}."); lines[TAURI_VERSION_INDEX] = updatedTauriVersion; - await File.WriteAllLinesAsync(pathMetadata, lines, Environment.UTF8_NO_BOM); + await WriteMetadataLinesAsync(pathMetadata, lines); } private async Task UpdateVectorStoreVersion() @@ -960,7 +1004,7 @@ public sealed partial class UpdateMetadataCommands Console.WriteLine($"- Updated vector store version from {currentVectorStoreVersion} to {updatedVectorStoreVersion}."); lines[VECTOR_STORE_VERSION_INDEX] = updatedVectorStoreVersion; - await File.WriteAllLinesAsync(pathMetadata, lines, Environment.UTF8_NO_BOM); + await WriteMetadataLinesAsync(pathMetadata, lines); } private async Task UpdateMudBlazorVersion() @@ -985,7 +1029,7 @@ public sealed partial class UpdateMetadataCommands Console.WriteLine($"- Updated MudBlazor version from {currentMudBlazorVersion} to {updatedMudBlazorVersion}."); lines[MUD_BLAZOR_VERSION_INDEX] = updatedMudBlazorVersion; - await File.WriteAllLinesAsync(pathMetadata, lines, Environment.UTF8_NO_BOM); + await WriteMetadataLinesAsync(pathMetadata, lines); } private async Task UpdateRustVersion() @@ -1009,7 +1053,7 @@ public sealed partial class UpdateMetadataCommands Console.WriteLine($"- Updated Rust version from {currentRustVersion} to {updatedRustVersion}."); lines[RUST_VERSION_INDEX] = updatedRustVersion; - await File.WriteAllLinesAsync(pathMetadata, lines, Environment.UTF8_NO_BOM); + await WriteMetadataLinesAsync(pathMetadata, lines); } private async Task UpdateDotnetVersion() @@ -1040,7 +1084,7 @@ public sealed partial class UpdateMetadataCommands lines[DOTNET_VERSION_INDEX] = updatedDotnetVersion; lines[DOTNET_SDK_VERSION_INDEX] = updatedDotnetSdkVersion; - await File.WriteAllLinesAsync(pathMetadata, lines, Environment.UTF8_NO_BOM); + await WriteMetadataLinesAsync(pathMetadata, lines); } private async Task> DetermineVersion(string name, string workingDirectory, Regex regex, string program, string command) @@ -1126,7 +1170,7 @@ public sealed partial class UpdateMetadataCommands Console.WriteLine($"- Updating build number from '{lines[BUILD_NUMBER_INDEX]}' to '{buildNumber}'."); lines[BUILD_NUMBER_INDEX] = buildNumber.ToString(); - await File.WriteAllLinesAsync(pathMetadata, lines, Environment.UTF8_NO_BOM); + await WriteMetadataLinesAsync(pathMetadata, lines); return buildNumber; } @@ -1140,13 +1184,12 @@ public sealed partial class UpdateMetadataCommands Console.WriteLine($"- Updating build time from '{lines[BUILD_TIME_INDEX]}' to '{buildTime}'."); lines[BUILD_TIME_INDEX] = buildTime; - await File.WriteAllLinesAsync(pathMetadata, lines, Environment.UTF8_NO_BOM); + await WriteMetadataLinesAsync(pathMetadata, lines); return buildTime; } private sealed record RebuildReleaseState( string MetadataPath, - string MetadataContent, string[] MetadataLines, string AppVersion, int BuildNumber, @@ -1200,6 +1243,14 @@ public sealed partial class UpdateMetadataCommands [GeneratedRegex("^[0-9a-fA-F]{40,64}$")] private static partial Regex GitCommitHashRegex(); + // Matches the category of an MSBuild error, e.g., "): error CS0103:", "MSBUILD : error MSB1009:", or "): error :": + [GeneratedRegex(""":\s*error(?:\s+[A-Z]+[0-9]+)?\s*:""")] + private static partial Regex DotnetErrorRegex(); + + // Matches the label of a Tauri CLI error, which is right-aligned to twelve characters: + [GeneratedRegex("""^\s+Error\s""")] + private static partial Regex TauriErrorRegex(); + // Matches one Markdown link. The address may hold one level of parentheses, as Wikipedia addresses do: [GeneratedRegex("""\[(?[^\[\]]+)\]\((?
(?:[^()\s]|\([^()\s]*\))+)\)""")] private static partial Regex MarkdownLinkRegex(); diff --git a/metadata.txt b/metadata.txt index 87f044842..4afa201ab 100644 --- a/metadata.txt +++ b/metadata.txt @@ -9,4 +9,4 @@ 9f102728b59, release osx-arm64 148.0.7763.0 -0.8.0 \ No newline at end of file +0.8.0 diff --git a/runtime/build.rs b/runtime/build.rs index 80a92985a..af6716f8d 100644 --- a/runtime/build.rs +++ b/runtime/build.rs @@ -36,8 +36,16 @@ fn main() { let metadata = include_str!("../metadata.txt"); let mut metadata_lines = metadata.lines().collect::>(); metadata_lines[9] = rid; - let new_metadata = metadata_lines.join("\n"); - std::fs::write("../metadata.txt", new_metadata).unwrap(); + + // Every line ends with a line break, the last one included. The build + // script of the .NET side writes the file the same way: + let mut new_metadata = metadata_lines.join("\n"); + new_metadata.push('\n'); + + // Write only on a change to avoid unnecessary rewrites: + if new_metadata != metadata { + std::fs::write("../metadata.txt", new_metadata).unwrap(); + } // // Read the current version and update the