From 16cf11b28d607cbb3b829a2479da25bd48dade25 Mon Sep 17 00:00:00 2001 From: Techatrix Date: Wed, 15 Jan 2025 18:02:17 +0100 Subject: [PATCH] =?UTF-8?q?build=5Frunner:=20handle=20non=20semver=20?= =?UTF-8?q?=C4=BAinux=20kernel=20release=20versions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Server.zig | 7 +++--- src/features/diagnostics.zig | 41 ++++++++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/Server.zig b/src/Server.zig index c85e7b232..4d5d126ee 100644 --- a/src/Server.zig +++ b/src/Server.zig @@ -764,7 +764,7 @@ const Workspace = struct { }) error{OutOfMemory}!void { comptime std.debug.assert(BuildOnSave.isSupportedComptime()); - const build_on_save_supported = if (args.runtime_zig_version) |version| BuildOnSave.isSupportedRuntime(version) else false; + const build_on_save_supported = if (args.runtime_zig_version) |version| BuildOnSave.isSupportedRuntime(version, false) else false; const build_on_save_wanted = args.server.config.enable_build_on_save orelse true; const enable = build_on_save_supported and build_on_save_wanted; @@ -1075,9 +1075,8 @@ pub fn updateConfiguration( log.warn("'enable_build_on_save' is ignored because it is not supported by {s}", .{server.client_capabilities.client_name orelse "your editor"}); } else if (server.status == .initialized and options.resolve and resolve_result.build_runner_version == .unresolved and server.config.build_runner_path == null) { log.warn("'enable_build_on_save' is ignored because no build runner is available", .{}); - } else if (server.status == .initialized and options.resolve and resolve_result.zig_runtime_version != null and !BuildOnSave.isSupportedRuntime(resolve_result.zig_runtime_version.?)) { - // There is one edge-case where build on save is not supported because of Linux pre 5.17 - log.warn("'enable_build_on_save' is not supported by Zig {}", .{resolve_result.zig_runtime_version.?}); + } else if (server.status == .initialized and options.resolve and resolve_result.zig_runtime_version != null and !BuildOnSave.isSupportedRuntime(resolve_result.zig_runtime_version.?, true)) { + // already logged } } diff --git a/src/features/diagnostics.zig b/src/features/diagnostics.zig index 09c954b93..4fae81ce5 100644 --- a/src/features/diagnostics.zig +++ b/src/features/diagnostics.zig @@ -548,21 +548,25 @@ pub const BuildOnSave = struct { return true; } - pub fn isSupportedRuntime(runtime_zig_version: std.SemanticVersion) bool { - if (!isSupportedComptime()) return false; + pub fn isSupportedRuntime(runtime_zig_version: std.SemanticVersion, log_message: bool) bool { + comptime std.debug.assert(isSupportedComptime()); if (builtin.os.tag == .linux) blk: { // std.build.Watch requires `FAN_REPORT_TARGET_FID` which is Linux 5.17+ const utsname = std.posix.uname(); - const version = std.SemanticVersion.parse(&utsname.release) catch break :blk; + const version = parseUnameKernelVersion(&utsname.release) catch |err| { + if (log_message) log.warn("failed to parse kernel version '{s}': {}", .{ utsname.release, err }); + break :blk; + }; if (version.order(.{ .major = 5, .minor = 17, .patch = 0 }) != .lt) break :blk; + if (log_message) log.err("Build-On-Save is not supported by Linux '{s}' (requires 5.17+)", .{utsname.release}); return false; } // We can't rely on `std.Build.Watch.have_impl` because we need to // check the runtime Zig version instead of Zig version that ZLS // has been built with. - return switch (builtin.os.tag) { + const zig_version_supported = switch (builtin.os.tag) { .linux => true, .windows => runtime_zig_version.order(windows_support_version) != .lt, .dragonfly, @@ -578,6 +582,35 @@ pub const BuildOnSave = struct { => runtime_zig_version.order(kqueue_support_version) != .lt, else => false, }; + + if (!zig_version_supported) { + log.warn("Build-On-Save is not supported on {s} by Zig {}", .{ @tagName(builtin.os.tag), runtime_zig_version }); + } + + return zig_version_supported; + } + + fn parseUnameKernelVersion(kernel_version: []const u8) !std.SemanticVersion { + const extra_index = std.mem.indexOfAny(u8, kernel_version, "-+"); + const required = kernel_version[0..(extra_index orelse kernel_version.len)]; + var it = std.mem.splitScalar(u8, required, '.'); + return .{ + .major = try std.fmt.parseUnsigned(usize, it.next() orelse return error.InvalidVersion, 10), + .minor = try std.fmt.parseUnsigned(usize, it.next() orelse return error.InvalidVersion, 10), + .patch = try std.fmt.parseUnsigned(usize, it.next() orelse return error.InvalidVersion, 10), + }; + } + + test parseUnameKernelVersion { + try std.testing.expectFmt("5.17.0", "{}", .{try parseUnameKernelVersion("5.17.0")}); + try std.testing.expectFmt("6.12.9", "{}", .{try parseUnameKernelVersion("6.12.9-rc7")}); + try std.testing.expectFmt("6.6.71", "{}", .{try parseUnameKernelVersion("6.6.71-42-generic")}); + try std.testing.expectFmt("5.15.167", "{}", .{try parseUnameKernelVersion("5.15.167.4-microsoft-standard-WSL2")}); // WSL2 + try std.testing.expectFmt("4.4.0", "{}", .{try parseUnameKernelVersion("4.4.0-20241-Microsoft")}); // WSL1 + + try std.testing.expectError(error.InvalidCharacter, parseUnameKernelVersion("")); + try std.testing.expectError(error.InvalidVersion, parseUnameKernelVersion("5")); + try std.testing.expectError(error.InvalidVersion, parseUnameKernelVersion("5.5")); } fn loop(