Skip to content

Commit

Permalink
add a fallback mode for build on save when using a pre 6.5 linux kernel
Browse files Browse the repository at this point in the history
  • Loading branch information
Techatrix committed Jan 22, 2025
1 parent 932c7a6 commit 8065ad9
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 21 deletions.
41 changes: 34 additions & 7 deletions src/Server.zig
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,7 @@ fn handleConfiguration(server: *Server, json: std.json.Value) error{OutOfMemory}
const Workspace = struct {
uri: types.URI,
build_on_save: if (BuildOnSaveSupport.isSupportedComptime()) ?BuildOnSave else void,
build_on_save_mode: if (BuildOnSaveSupport.isSupportedComptime()) ?enum { watch, manual } else void,

fn init(server: *Server, uri: types.URI) error{OutOfMemory}!Workspace {
const duped_uri = try server.allocator.dupe(u8, uri);
Expand All @@ -745,6 +746,7 @@ const Workspace = struct {
return .{
.uri = duped_uri,
.build_on_save = if (BuildOnSaveSupport.isSupportedComptime()) null else {},
.build_on_save_mode = if (BuildOnSaveSupport.isSupportedComptime()) null else {},
};
}

Expand All @@ -755,6 +757,16 @@ const Workspace = struct {
allocator.free(workspace.uri);
}

fn sendManualWatchUpdate(workspace: *Workspace) void {
comptime std.debug.assert(BuildOnSaveSupport.isSupportedComptime());

const build_on_save = if (workspace.build_on_save) |*build_on_save| build_on_save else return;
const mode = workspace.build_on_save_mode orelse return;
if (mode != .manual) return;

build_on_save.sendManualWatchUpdate();
}

fn refreshBuildOnSave(workspace: *Workspace, args: struct {
server: *Server,
/// If null, build on save will be disabled
Expand All @@ -764,7 +776,17 @@ const Workspace = struct {
}) error{OutOfMemory}!void {
comptime std.debug.assert(BuildOnSaveSupport.isSupportedComptime());

const build_on_save_supported = if (args.runtime_zig_version) |version| BuildOnSaveSupport.isSupportedRuntime(version) == .supported else false;
if (args.runtime_zig_version) |runtime_zig_version| {
workspace.build_on_save_mode = switch (BuildOnSaveSupport.isSupportedRuntime(runtime_zig_version)) {
.supported => .watch,
// If if build on save has been explicitly enabled, fallback to the implementation with manual updates
else => if (args.server.config.enable_build_on_save orelse false) .manual else null,
};
} else {
workspace.build_on_save_mode = null;
}

const build_on_save_supported = workspace.build_on_save_mode != null;
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;

Expand Down Expand Up @@ -1071,9 +1093,7 @@ pub fn updateConfiguration(
}

if (server.config.enable_build_on_save orelse false) {
if (!BuildOnSaveSupport.isSupportedComptime() and @TypeOf(BuildOnSaveSupport.minimum_zig_version) == void) {
log.info("'enable_build_on_save' is ignored because it is not supported on {s}", .{@tagName(zig_builtin.os.tag)});
} else if (!BuildOnSaveSupport.isSupportedComptime()) {
if (!BuildOnSaveSupport.isSupportedComptime()) {
// This message is not very helpful but it relatively uncommon to happen anyway.
log.info("'enable_build_on_save' is ignored because build on save is not supported by this ZLS build", .{});
} else if (server.status == .initialized and (server.config.zig_exe_path == null or server.config.zig_lib_path == null)) {
Expand All @@ -1085,9 +1105,10 @@ pub fn updateConfiguration(
} else if (server.status == .initialized and options.resolve and resolve_result.zig_runtime_version != null) {
switch (BuildOnSaveSupport.isSupportedRuntime(resolve_result.zig_runtime_version.?)) {
.supported => {},
.invalid_linux_kernel_version => |*utsname_release| log.warn("'enable_build_on_save' is ignored because it because the Linux version '{s}' could not be parsed", .{std.mem.sliceTo(utsname_release, 0)}),
.unsupported_linux_kernel_version => |kernel_version| log.warn("'enable_build_on_save' is ignored because it is not supported by Linux '{}' (requires at least {})", .{ kernel_version, BuildOnSaveSupport.minimum_linux_version }),
.unsupported_zig_version => log.warn("'enable_build_on_save' is ignored because it is not supported on {s} by Zig {} (requires at least {})", .{ @tagName(zig_builtin.os.tag), resolve_result.zig_runtime_version.?, BuildOnSaveSupport.minimum_zig_version }),
.invalid_linux_kernel_version => |*utsname_release| log.warn("Build-On-Save cannot run in watch mode because it because the Linux version '{s}' could not be parsed", .{std.mem.sliceTo(utsname_release, 0)}),
.unsupported_linux_kernel_version => |kernel_version| log.warn("Build-On-Save cannot run in watch mode because it is not supported by Linux '{}' (requires at least {})", .{ kernel_version, BuildOnSaveSupport.minimum_linux_version }),
.unsupported_zig_version => log.warn("Build-On-Save cannot run in watch mode because it is not supported on {s} by Zig {} (requires at least {})", .{ @tagName(zig_builtin.os.tag), resolve_result.zig_runtime_version.?, BuildOnSaveSupport.minimum_zig_version }),
.unsupported_os => log.warn("Build-On-Save cannot run in watch mode because it is not supported on {s}", .{@tagName(zig_builtin.os.tag)}),
}
}
}
Expand Down Expand Up @@ -1463,6 +1484,12 @@ fn saveDocumentHandler(server: *Server, arena: std.mem.Allocator, notification:
);
server.allocator.free(json_message);
}

if (BuildOnSaveSupport.isSupportedComptime()) {
for (server.workspaces.items) |*workspace| {
workspace.sendManualWatchUpdate();
}
}
}

fn closeDocumentHandler(server: *Server, _: std.mem.Allocator, notification: types.DidCloseTextDocumentParams) error{}!void {
Expand Down
43 changes: 31 additions & 12 deletions src/build_runner/master.zig
Original file line number Diff line number Diff line change
Expand Up @@ -376,20 +376,25 @@ pub fn main() !void {
return;
}

if (!std.Build.Watch.have_impl) {
std.log.warn("Build-On-Save is not supported on {} by Zig {}", .{ builtin.target.os.tag, builtin.zig_version });
process.exit(1);
}
const watch_mode_supported = @TypeOf(Watch) != void and shared.BuildOnSaveSupport.isSupportedRuntime(builtin.zig_version) == .supported;

const suicide_thread = try std.Thread.spawn(.{}, struct {
fn do() void {
_ = std.io.getStdIn().reader().readByte() catch process.exit(1);
process.exit(0);
}
}.do, .{});
suicide_thread.detach();
var w = if (@TypeOf(Watch) != void) try Watch.init() else {};
var watch_event: std.Thread.ResetEvent = .{};

var w = try Watch.init();
const message_thread = try std.Thread.spawn(.{}, struct {
fn do(event: *std.Thread.ResetEvent) void {
while (std.io.getStdIn().reader().readByte()) |tag| {
switch (tag) {
'\x00' => event.set(),
else => process.exit(1),
}
} else |err| switch (err) {
error.EndOfStream => process.exit(0),
else => process.exit(1),
}
}
}.do, .{&watch_event});
message_thread.detach();

const gpa = arena;
var transport = Transport.init(.{
Expand Down Expand Up @@ -423,6 +428,13 @@ pub fn main() !void {
else => return err,
};

if (!watch_mode_supported) {
watch_event.wait();
watch_event.reset();
markFailedStepsDirty(gpa, step_stack.keys());
continue;
}

try w.update(gpa, step_stack.keys());

// Wait until a file system notification arrives. Read all such events
Expand Down Expand Up @@ -457,6 +469,13 @@ fn markFailedStepsDirty(gpa: Allocator, all_steps: []const *Step) void {
};
}

fn markStepsDirty(gpa: Allocator, all_steps: []const *Step) void {
for (all_steps) |step| switch (step.state) {
.precheck_done => continue,
else => step.recursiveReset(gpa),
};
}

const Run = struct {
max_rss: u64,
max_rss_is_default: bool,
Expand Down
8 changes: 6 additions & 2 deletions src/build_runner/shared.zig
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ pub const BuildOnSaveSupport = union(enum) {
supported,
invalid_linux_kernel_version: if (builtin.os.tag == .linux) std.meta.FieldType(std.posix.utsname, .release) else noreturn,
unsupported_linux_kernel_version: if (builtin.os.tag == .linux) std.SemanticVersion else noreturn,
unsupported_zig_version: void,
unsupported_zig_version: if (@TypeOf(minimum_zig_version) != void) void else noreturn,
unsupported_os: if (@TypeOf(minimum_zig_version) == void) void else noreturn,

const linux_support_version = std.SemanticVersion.parse("0.14.0-dev.283+1d20ff11d") catch unreachable;
const windows_support_version = std.SemanticVersion.parse("0.14.0-dev.625+2de0e2eca") catch unreachable;
Expand Down Expand Up @@ -184,7 +185,6 @@ pub const BuildOnSaveSupport = union(enum) {
pub inline fn isSupportedComptime() bool {
if (!std.process.can_spawn) return false;
if (builtin.single_threaded) return false;
if (@TypeOf(minimum_zig_version) == void) return false;
return true;
}

Expand All @@ -204,6 +204,10 @@ pub const BuildOnSaveSupport = union(enum) {
};
}

if (@TypeOf(minimum_zig_version) == void) {
return .unsupported_os;
}

if (runtime_zig_version.order(minimum_zig_version) == .lt) {
return .unsupported_zig_version;
}
Expand Down
4 changes: 4 additions & 0 deletions src/features/diagnostics.zig
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,10 @@ pub const BuildOnSave = struct {
self.thread.join();
}

pub fn sendManualWatchUpdate(self: *BuildOnSave) void {
self.child_process.stdin.?.writeAll("\x00") catch {};
}

fn loop(
allocator: std.mem.Allocator,
child_process: *std.process.Child,
Expand Down

0 comments on commit 8065ad9

Please sign in to comment.