From b8d5c1cf420d96151dc34eae522dff615941ef6b Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Tue, 8 Jul 2025 15:13:58 -0500 Subject: [PATCH] build: update `zig build update-translations` - The order of the arguments to xgettext influences the output. Since directorty walking does not guarantee that files will be listed in a deterministic order (especially when run on different systems) the translation files would see a lot of churn depending on who updated them last. In this update the files are sorted so that the arguments to xgettext are always in the same order. This should reduce churn in the future. - Mark all of the files as inputs so that the Zig build system caching will work properly. --- src/build/GhosttyI18n.zig | 56 ++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/src/build/GhosttyI18n.zig b/src/build/GhosttyI18n.zig index 7667d30c3..778cfabc5 100644 --- a/src/build/GhosttyI18n.zig +++ b/src/build/GhosttyI18n.zig @@ -79,24 +79,38 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step { xgettext.has_side_effects = true; inline for (gresource.blueprint_files) |blp| { - // We avoid using addFileArg here since the full, absolute file path - // would be added to the file as its location, which differs for - // everyone's checkout of the repository. - // This comes at a cost of losing per-file caching, of course. - xgettext.addArg(std.fmt.comptimePrint( + const path = std.fmt.comptimePrint( "src/apprt/gtk/ui/{[major]}.{[minor]}/{[name]s}.blp", blp, - )); + ); + // The arguments to xgettext must be the relative path in the build root + // or the resulting files will contain the absolute path. This will cause + // a lot of churn because not everyone has the Ghostty code checked out in + // exactly the same location. + xgettext.addArg(path); + // Mark the file as an input so that the Zig build system caching will work. + xgettext.addFileInput(b.path(path)); } { - var gtk_files = try b.build_root.handle.openDir( + // Iterate over all of the files underneath `src/apprt/gtk`. We store + // them in an array so that they can be sorted into a determininistic + // order. That will minimize code churn as directory walking is not + // guaranteed to happen in any particular order. + + var gtk_files: std.ArrayListUnmanaged([]const u8) = .empty; + defer { + for (gtk_files.items) |item| b.allocator.free(item); + gtk_files.deinit(b.allocator); + } + + var gtk_dir = try b.build_root.handle.openDir( "src/apprt/gtk", .{ .iterate = true }, ); - defer gtk_files.close(); + defer gtk_dir.close(); - var walk = try gtk_files.walk(b.allocator); + var walk = try gtk_dir.walk(b.allocator); defer walk.deinit(); while (try walk.next()) |src| { switch (src.kind) { @@ -109,7 +123,29 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step { else => continue, } - xgettext.addArg((b.pathJoin(&.{ "src/apprt/gtk", src.path }))); + try gtk_files.append(b.allocator, try b.allocator.dupe(u8, src.path)); + } + + std.mem.sort( + []const u8, + gtk_files.items, + {}, + struct { + fn lt(_: void, lhs: []const u8, rhs: []const u8) bool { + return std.mem.order(u8, lhs, rhs) == .lt; + } + }.lt, + ); + + for (gtk_files.items) |item| { + const path = b.pathJoin(&.{ "src/apprt/gtk", item }); + // The arguments to xgettext must be the relative path in the build root + // or the resulting files will contain the absolute path. This will + // cause a lot of churn because not everyone has the Ghostty code + // checked out in exactly the same location. + xgettext.addArg(path); + // Mark the file as an input so that the Zig build system caching will work. + xgettext.addFileInput(b.path(path)); } }