Radix/third_party/zls/zls_runner.zig

124 lines
4.4 KiB
Zig
Raw Permalink Normal View History

/// Custom ZLS launcher.
///
/// Sets up paths to ZLS dependencies with Bazel runfiles.
///
/// This file is used as a template by `zls_write_runner_zig_src.bzl`.
const std = @import("std");
const runfiles = @import("runfiles");
const bazel_builtin = @import("bazel_builtin");
fn getRandomFilename(buf: *[std.fs.max_name_bytes]u8, extension: []const u8) ![]const u8 {
const random_bytes_count = 12;
const sub_path_len = comptime std.fs.base64_encoder.calcSize(random_bytes_count);
var random_bytes: [random_bytes_count]u8 = undefined;
std.crypto.random.bytes(&random_bytes);
var random_name: [sub_path_len]u8 = undefined;
_ = std.fs.base64_encoder.encode(&random_name, &random_bytes);
const fmt_template = "/tmp/{s}{s}";
const fmt_args = .{
@as([]const u8, &random_name),
extension,
};
return std.fmt.bufPrint(buf, fmt_template, fmt_args) catch @panic("OOM");
}
const Config = struct {
/// Override the Zig library path. Will be automatically resolved using the 'zig_exe_path'.
zig_lib_path: ?[]const u8 = null,
/// Specify the path to the Zig executable (not the directory). If unset, zig is looked up in `PATH`. e.g. `/path/to/zig-templeos-armless-1.0.0/zig`.
zig_exe_path: ?[]const u8 = null,
/// Specify a custom build runner to resolve build system information.
build_runner_path: ?[]const u8 = null,
/// Path to a directory that will be used as zig's cache. Will default to `${KnownFolders.Cache}/zls`.
global_cache_path: ?[]const u8 = null,
};
pub fn main() !void {
const gpa = std.heap.page_allocator;
var arena = std.heap.ArenaAllocator.init(gpa);
const allocator = arena.allocator();
var r_ = try runfiles.Runfiles.create(.{ .allocator = allocator }) orelse
return error.RunfilesNotFound;
defer r_.deinit(allocator);
const r = r_.withSourceRepo(bazel_builtin.current_repository);
const zls_bin_rpath = "@@__ZLS_BIN_RPATH__@@";
var zls_bin_path_buf: [std.fs.max_path_bytes]u8 = undefined;
const zls_bin_path = try r.rlocation(zls_bin_rpath, &zls_bin_path_buf) orelse
return error.RLocationNotFound;
const zig_exe_rpath = "@@__ZIG_EXE_RPATH__@@";
var zig_exe_path_buf: [std.fs.max_path_bytes]u8 = undefined;
const zig_exe_path = blk2: {
if (zig_exe_rpath[0] == '/') {
break :blk2 zig_exe_rpath;
} else {
break :blk2 try r.rlocation(zig_exe_rpath, &zig_exe_path_buf) orelse
return error.RLocationNotFound;
}
};
const zig_lib_path = "@@__ZIG_LIB_PATH__@@";
const zig_lib_computed_path = blk: {
if (zig_lib_path[0] == '/') {
break :blk zig_lib_path;
} else {
break :blk null;
}
};
const zls_build_runner_rpath = "@@__ZLS_BUILD_RUNNER_RPATH__@@";
var zls_build_runner_path_buf: [std.fs.max_path_bytes]u8 = undefined;
const zls_build_runner_path = try r.rlocation(zls_build_runner_rpath, &zls_build_runner_path_buf) orelse
return error.RLocationNotFound;
const global_cache_path = "@@__GLOBAL_CACHE_PATH__@@";
const config: Config = .{
.zig_exe_path = zig_exe_path,
.zig_lib_path = zig_lib_computed_path,
.build_runner_path = zls_build_runner_path,
.global_cache_path = global_cache_path,
};
var buf: [std.fs.max_name_bytes]u8 = undefined;
const tmp_file_path = try getRandomFilename(&buf, ".json");
{
var tmp_file = try std.fs.createFileAbsolute(tmp_file_path, .{});
defer tmp_file.close();
var out_buf: [4096]u8 = undefined;
var tmp_file_writer = tmp_file.writer(&out_buf);
const formatter = std.json.fmt(config, .{ .whitespace = .indent_2 });
try tmp_file_writer.interface.print("{f}", .{formatter});
try tmp_file_writer.interface.flush();
}
const args = std.process.argsAlloc(allocator) catch return error.ArgsAllocFailed;
defer std.process.argsFree(allocator, args);
const exec_args_len = args.len - 1 + 3; // Skip args[0] and add "zls" + --config-path + tmp_file_path
var exec_args = try allocator.alloc([]const u8, exec_args_len);
exec_args[0] = zls_bin_path; // "zls"
// ${@}
for (args[1..], 0..) |arg, i| {
exec_args[1 + i] = arg;
}
exec_args[exec_args.len - 2] = "--config-path";
exec_args[exec_args.len - 1] = tmp_file_path;
return std.process.execv(arena.allocator(), exec_args);
}