Use zig env to find zig lib path instead of assuming the executable comes from a distribution tarball

This commit is contained in:
Alexandros Naskos 2020-11-15 21:32:27 +02:00
parent 892847d939
commit 78e74743e1
No known key found for this signature in database
GPG Key ID: 02BF2E72B0EA32D2
3 changed files with 78 additions and 39 deletions

View File

@ -813,7 +813,7 @@ pub fn resolveTypeOfNodeInternal(
const import_str = handle.tree.tokenSlice(import_param.castTag(.StringLiteral).?.token); const import_str = handle.tree.tokenSlice(import_param.castTag(.StringLiteral).?.token);
const new_handle = (store.resolveImport(handle, import_str[1 .. import_str.len - 1]) catch |err| { const new_handle = (store.resolveImport(handle, import_str[1 .. import_str.len - 1]) catch |err| {
log.debug("Error {} while processing import {}\n", .{ err, import_str }); log.debug("Error {} while processing import {}", .{ err, import_str });
return null; return null;
}) orelse return null; }) orelse return null;
@ -1071,7 +1071,7 @@ pub fn getFieldAccessType(
current_type = (try resolveUnwrapOptionalType(store, arena, current_type, &bound_type_params)) orelse return null; current_type = (try resolveUnwrapOptionalType(store, arena, current_type, &bound_type_params)) orelse return null;
}, },
else => { else => {
log.debug("Unrecognized token {} after period.\n", .{after_period.id}); log.debug("Unrecognized token {} after period.", .{after_period.id});
return null; return null;
}, },
} }
@ -1122,7 +1122,7 @@ pub fn getFieldAccessType(
current_type = (try resolveBracketAccessType(store, arena, current_type, if (is_range) .Range else .Single, &bound_type_params)) orelse return null; current_type = (try resolveBracketAccessType(store, arena, current_type, if (is_range) .Range else .Single, &bound_type_params)) orelse return null;
}, },
else => { else => {
log.debug("Unimplemented token: {}\n", .{tok.id}); log.debug("Unimplemented token: {}", .{tok.id});
return null; return null;
}, },
} }
@ -1169,7 +1169,7 @@ pub fn nodeToString(tree: *ast.Tree, node: *ast.Node) ?[]const u8 {
} }
}, },
else => { else => {
log.debug("INVALID: {}\n", .{node.tag}); log.debug("INVALID: {}", .{node.tag});
}, },
} }

View File

@ -107,7 +107,7 @@ fn loadPackages(context: LoadPackagesContext) !void {
switch (zig_run_result.term) { switch (zig_run_result.term) {
.Exited => |exit_code| { .Exited => |exit_code| {
if (exit_code == 0) { if (exit_code == 0) {
log.debug("Finished zig run for build file {}\n", .{build_file.uri}); log.debug("Finished zig run for build file {}", .{build_file.uri});
for (build_file.packages.items) |old_pkg| { for (build_file.packages.items) |old_pkg| {
allocator.free(old_pkg.name); allocator.free(old_pkg.name);
@ -145,7 +145,7 @@ fn loadPackages(context: LoadPackagesContext) !void {
/// This function asserts the document is not open yet and takes ownership /// This function asserts the document is not open yet and takes ownership
/// of the uri and text passed in. /// of the uri and text passed in.
fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Handle { fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Handle {
log.debug("Opened document: {}\n", .{uri}); log.debug("Opened document: {}", .{uri});
var handle = try self.allocator.create(Handle); var handle = try self.allocator.create(Handle);
errdefer self.allocator.destroy(handle); errdefer self.allocator.destroy(handle);
@ -173,7 +173,7 @@ fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Hand
// TODO: Better logic for detecting std or subdirectories? // TODO: Better logic for detecting std or subdirectories?
const in_std = std.mem.indexOf(u8, uri, "/std/") != null; const in_std = std.mem.indexOf(u8, uri, "/std/") != null;
if (self.zig_exe_path != null and std.mem.endsWith(u8, uri, "/build.zig") and !in_std) { if (self.zig_exe_path != null and std.mem.endsWith(u8, uri, "/build.zig") and !in_std) {
log.debug("Document is a build file, extracting packages...\n", .{}); log.debug("Document is a build file, extracting packages...", .{});
// This is a build file. // This is a build file.
var build_file = try self.allocator.create(BuildFile); var build_file = try self.allocator.create(BuildFile);
errdefer self.allocator.destroy(build_file); errdefer self.allocator.destroy(build_file);
@ -195,7 +195,7 @@ fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Hand
.build_runner_path = self.build_runner_path, .build_runner_path = self.build_runner_path,
.zig_exe_path = self.zig_exe_path.?, .zig_exe_path = self.zig_exe_path.?,
}) catch |err| { }) catch |err| {
log.debug("Failed to load packages of build file {} (error: {})\n", .{ build_file.uri, err }); log.debug("Failed to load packages of build file {} (error: {})", .{ build_file.uri, err });
}; };
} else if (self.zig_exe_path != null and !in_std) associate_build_file: { } else if (self.zig_exe_path != null and !in_std) associate_build_file: {
// Look into build files to see if we already have one that fits // Look into build files to see if we already have one that fits
@ -203,7 +203,7 @@ fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Hand
const build_file_base_uri = build_file.uri[0 .. std.mem.lastIndexOfScalar(u8, build_file.uri, '/').? + 1]; const build_file_base_uri = build_file.uri[0 .. std.mem.lastIndexOfScalar(u8, build_file.uri, '/').? + 1];
if (std.mem.startsWith(u8, uri, build_file_base_uri)) { if (std.mem.startsWith(u8, uri, build_file_base_uri)) {
log.debug("Found an associated build file: {}\n", .{build_file.uri}); log.debug("Found an associated build file: {}", .{build_file.uri});
build_file.refs += 1; build_file.refs += 1;
handle.associated_build_file = build_file; handle.associated_build_file = build_file;
break :associate_build_file; break :associate_build_file;
@ -255,12 +255,12 @@ fn newDocument(self: *DocumentStore, uri: []const u8, text: []u8) anyerror!*Hand
pub fn openDocument(self: *DocumentStore, uri: []const u8, text: []const u8) !*Handle { pub fn openDocument(self: *DocumentStore, uri: []const u8, text: []const u8) !*Handle {
if (self.handles.getEntry(uri)) |entry| { if (self.handles.getEntry(uri)) |entry| {
log.debug("Document already open: {}, incrementing count\n", .{uri}); log.debug("Document already open: {}, incrementing count", .{uri});
entry.value.count += 1; entry.value.count += 1;
if (entry.value.is_build_file) |build_file| { if (entry.value.is_build_file) |build_file| {
build_file.refs += 1; build_file.refs += 1;
} }
log.debug("New count: {}\n", .{entry.value.count}); log.debug("New count: {}", .{entry.value.count});
return entry.value; return entry.value;
} }
@ -275,7 +275,7 @@ pub fn openDocument(self: *DocumentStore, uri: []const u8, text: []const u8) !*H
fn decrementBuildFileRefs(self: *DocumentStore, build_file: *BuildFile) void { fn decrementBuildFileRefs(self: *DocumentStore, build_file: *BuildFile) void {
build_file.refs -= 1; build_file.refs -= 1;
if (build_file.refs == 0) { if (build_file.refs == 0) {
log.debug("Freeing build file {}\n", .{build_file.uri}); log.debug("Freeing build file {}", .{build_file.uri});
for (build_file.packages.items) |pkg| { for (build_file.packages.items) |pkg| {
self.allocator.free(pkg.name); self.allocator.free(pkg.name);
self.allocator.free(pkg.uri); self.allocator.free(pkg.uri);
@ -301,7 +301,7 @@ fn decrementCount(self: *DocumentStore, uri: []const u8) void {
if (entry.value.count > 0) if (entry.value.count > 0)
return; return;
log.debug("Freeing document: {}\n", .{uri}); log.debug("Freeing document: {}", .{uri});
if (entry.value.associated_build_file) |build_file| { if (entry.value.associated_build_file) |build_file| {
self.decrementBuildFileRefs(build_file); self.decrementBuildFileRefs(build_file);
@ -338,7 +338,7 @@ pub fn getHandle(self: *DocumentStore, uri: []const u8) ?*Handle {
// Check if the document text is now sane, move it to sane_text if so. // Check if the document text is now sane, move it to sane_text if so.
fn refreshDocument(self: *DocumentStore, handle: *Handle, zig_lib_path: ?[]const u8) !void { fn refreshDocument(self: *DocumentStore, handle: *Handle, zig_lib_path: ?[]const u8) !void {
log.debug("New text for document {}\n", .{handle.uri()}); log.debug("New text for document {}", .{handle.uri()});
handle.tree.deinit(); handle.tree.deinit();
handle.tree = try std.zig.parse(self.allocator, handle.document.text); handle.tree = try std.zig.parse(self.allocator, handle.document.text);
@ -384,7 +384,7 @@ fn refreshDocument(self: *DocumentStore, handle: *Handle, zig_lib_path: ?[]const
while (idx < still_exist.len) : (idx += 1) { while (idx < still_exist.len) : (idx += 1) {
if (still_exist[idx]) continue; if (still_exist[idx]) continue;
log.debug("Import removed: {}\n", .{handle.import_uris.items[idx - offset]}); log.debug("Import removed: {}", .{handle.import_uris.items[idx - offset]});
const uri = handle.import_uris.orderedRemove(idx - offset); const uri = handle.import_uris.orderedRemove(idx - offset);
offset += 1; offset += 1;
@ -401,7 +401,7 @@ pub fn applySave(self: *DocumentStore, handle: *Handle) !void {
.build_runner_path = self.build_runner_path, .build_runner_path = self.build_runner_path,
.zig_exe_path = self.zig_exe_path.?, .zig_exe_path = self.zig_exe_path.?,
}) catch |err| { }) catch |err| {
log.debug("Failed to load packages of build file {} (error: {})\n", .{ build_file.uri, err }); log.debug("Failed to load packages of build file {} (error: {})", .{ build_file.uri, err });
}; };
} }
} }
@ -483,7 +483,7 @@ pub fn uriFromImportStr(
) !?[]const u8 { ) !?[]const u8 {
if (std.mem.eql(u8, import_str, "std")) { if (std.mem.eql(u8, import_str, "std")) {
if (self.std_uri) |uri| return try std.mem.dupe(allocator, u8, uri) else { if (self.std_uri) |uri| return try std.mem.dupe(allocator, u8, uri) else {
log.debug("Cannot resolve std library import, path is null.\n", .{}); log.debug("Cannot resolve std library import, path is null.", .{});
return null; return null;
} }
} else if (std.mem.eql(u8, import_str, "builtin")) { } else if (std.mem.eql(u8, import_str, "builtin")) {
@ -549,7 +549,7 @@ pub fn resolveImport(self: *DocumentStore, handle: *Handle, import_str: []const
defer allocator.free(file_path); defer allocator.free(file_path);
var file = std.fs.cwd().openFile(file_path, .{}) catch { var file = std.fs.cwd().openFile(file_path, .{}) catch {
log.debug("Cannot open import file {}\n", .{file_path}); log.debug("Cannot open import file {}", .{file_path});
return null; return null;
}; };
@ -561,7 +561,7 @@ pub fn resolveImport(self: *DocumentStore, handle: *Handle, import_str: []const
errdefer allocator.free(file_contents); errdefer allocator.free(file_contents);
file.reader().readNoEof(file_contents) catch { file.reader().readNoEof(file_contents) catch {
log.debug("Could not read from file {}\n", .{file_path}); log.debug("Could not read from file {}", .{file_path});
return null; return null;
}; };
@ -582,7 +582,7 @@ fn stdUriFromLibPath(allocator: *std.mem.Allocator, zig_lib_path: ?[]const u8) !
const std_path = std.fs.path.resolve(allocator, &[_][]const u8{ const std_path = std.fs.path.resolve(allocator, &[_][]const u8{
zpath, "./std/std.zig", zpath, "./std/std.zig",
}) catch |err| { }) catch |err| {
log.debug("Failed to resolve zig std library path, error: {}\n", .{err}); log.debug("Failed to resolve zig std library path, error: {}", .{err});
return null; return null;
}; };

View File

@ -1031,20 +1031,20 @@ fn loadConfig(folder_path: []const u8) ?Config {
const file_buf = folder.readFileAlloc(allocator, "zls.json", 0x1000000) catch |err| { const file_buf = folder.readFileAlloc(allocator, "zls.json", 0x1000000) catch |err| {
if (err != error.FileNotFound) if (err != error.FileNotFound)
logger.warn("Error while reading configuration file: {}\n", .{err}); logger.warn("Error while reading configuration file: {}", .{err});
return null; return null;
}; };
defer allocator.free(file_buf); defer allocator.free(file_buf);
// TODO: Better errors? Doesn't seem like std.json can provide us positions or context. // TODO: Better errors? Doesn't seem like std.json can provide us positions or context.
var config = std.json.parse(Config, &std.json.TokenStream.init(file_buf), std.json.ParseOptions{ .allocator = allocator }) catch |err| { var config = std.json.parse(Config, &std.json.TokenStream.init(file_buf), std.json.ParseOptions{ .allocator = allocator }) catch |err| {
logger.warn("Error while parsing configuration file: {}\n", .{err}); logger.warn("Error while parsing configuration file: {}", .{err});
return null; return null;
}; };
if (config.zig_lib_path) |zig_lib_path| { if (config.zig_lib_path) |zig_lib_path| {
if (!std.fs.path.isAbsolute(zig_lib_path)) { if (!std.fs.path.isAbsolute(zig_lib_path)) {
logger.warn("zig library path is not absolute, defaulting to null.\n", .{}); logger.warn("zig library path is not absolute, defaulting to null.", .{});
allocator.free(zig_lib_path); allocator.free(zig_lib_path);
config.zig_lib_path = null; config.zig_lib_path = null;
} }
@ -1154,8 +1154,8 @@ fn initializeHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req:
}); });
logger.notice("zls initialized", .{}); logger.notice("zls initialized", .{});
logger.info("{}\n", .{client_capabilities}); logger.info("{}", .{client_capabilities});
logger.notice("Using offset encoding: {}\n", .{std.meta.tagName(offset_encoding)}); logger.notice("Using offset encoding: {}", .{std.meta.tagName(offset_encoding)});
} }
var keep_running = true; var keep_running = true;
@ -1334,7 +1334,7 @@ fn formattingHandler(arena: *std.heap.ArenaAllocator, id: types.RequestId, req:
process.stdout_behavior = .Pipe; process.stdout_behavior = .Pipe;
process.spawn() catch |err| { process.spawn() catch |err| {
logger.warn("Failed to spawn zig fmt process, error: {}\n", .{err}); logger.warn("Failed to spawn zig fmt process, error: {}", .{err});
return try respondGeneric(id, null_result_response); return try respondGeneric(id, null_result_response);
}; };
try process.stdin.?.writeAll(handle.document.text); try process.stdin.?.writeAll(handle.document.text);
@ -1429,7 +1429,7 @@ fn processJsonRpc(arena: *std.heap.ArenaAllocator, parser: *std.json.Parser, jso
const start_time = std.time.milliTimestamp(); const start_time = std.time.milliTimestamp();
defer { defer {
const end_time = std.time.milliTimestamp(); const end_time = std.time.milliTimestamp();
logger.debug("Took {}ms to process method {}\n", .{ end_time - start_time, method }); logger.debug("Took {}ms to process method {}", .{ end_time - start_time, method });
} }
const method_map = .{ const method_map = .{
@ -1469,7 +1469,7 @@ fn processJsonRpc(arena: *std.heap.ArenaAllocator, parser: *std.json.Parser, jso
done = extractErr(method_info[2](arena, id, request_obj, config)); done = extractErr(method_info[2](arena, id, request_obj, config));
} else |err| { } else |err| {
if (err == error.MalformedJson) { if (err == error.MalformedJson) {
logger.warn("Could not create request type {} from JSON {}\n", .{ @typeName(ReqT), json }); logger.warn("Could not create request type {} from JSON {}", .{ @typeName(ReqT), json });
} }
done = err; done = err;
} }
@ -1526,9 +1526,9 @@ pub fn main() anyerror!void {
defer allocator.free(arg); defer allocator.free(arg);
if (std.mem.eql(u8, arg, "--debug-log")) { if (std.mem.eql(u8, arg, "--debug-log")) {
actual_log_level = .debug; actual_log_level = .debug;
std.debug.print("Enabled debug logging\n", .{}); std.debug.print("Enabled debug logging", .{});
} else { } else {
std.debug.print("Unrecognized argument {}\n", .{arg}); std.debug.print("Unrecognized argument {}", .{arg});
std.os.exit(1); std.os.exit(1);
} }
} }
@ -1582,12 +1582,12 @@ pub fn main() anyerror!void {
break :find_zig; break :find_zig;
} }
logger.debug("zig path `{}` is not absolute, will look in path\n", .{exe_path}); logger.debug("zig path `{}` is not absolute, will look in path", .{exe_path});
} }
const env_path = std.process.getEnvVarOwned(allocator, "PATH") catch |err| switch (err) { const env_path = std.process.getEnvVarOwned(allocator, "PATH") catch |err| switch (err) {
error.EnvironmentVariableNotFound => { error.EnvironmentVariableNotFound => {
logger.warn("Could not get PATH.\n", .{}); logger.warn("Could not get PATH environmental variable", .{});
break :find_zig; break :find_zig;
}, },
else => return err, else => return err,
@ -1608,22 +1608,61 @@ pub fn main() anyerror!void {
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
zig_exe_path = try std.mem.dupe(allocator, u8, std.os.realpath(full_path, &buf) catch continue); zig_exe_path = try std.mem.dupe(allocator, u8, std.os.realpath(full_path, &buf) catch continue);
logger.info("Found zig in PATH: {}\n", .{zig_exe_path}); logger.info("Found zig in PATH: {}", .{zig_exe_path});
break :find_zig; break :find_zig;
} }
} }
if (zig_exe_path) |exe_path| { if (zig_exe_path) |exe_path| {
config.zig_exe_path = exe_path; config.zig_exe_path = exe_path;
logger.info("Using zig executable {}\n", .{exe_path}); logger.info("Using zig executable {}", .{exe_path});
if (config.zig_lib_path == null) { if (config.zig_lib_path == null) find_lib_path: {
// Set the lib path relative to the executable path. // Use `zig env` to find the lib path
config.zig_lib_path = try std.fs.path.resolve(allocator, &[_][]const u8{ const zig_env_result = try std.ChildProcess.exec(.{
std.fs.path.dirname(exe_path).?, "./lib/zig", .allocator = allocator,
.argv = &[_][]const u8{ exe_path, "env" },
}); });
logger.info("Resolved standard library from executable: {}\n", .{config.zig_lib_path}); defer {
allocator.free(zig_env_result.stdout);
allocator.free(zig_env_result.stderr);
}
switch (zig_env_result.term) {
.Exited => |exit_code| {
if (exit_code == 0) {
const Env = struct {
zig_exe: []const u8,
lib_dir: ?[]const u8,
std_dir: []const u8,
global_cache_dir: []const u8,
version: []const u8,
};
var json_env = std.json.parse(
Env,
&std.json.TokenStream.init(zig_env_result.stdout),
.{ .allocator = allocator },
) catch {
logger.alert("Failed to parse zig env JSON result", .{});
break :find_lib_path;
};
defer std.json.parseFree(Env, json_env, .{ .allocator = allocator });
// We know this is allocated with `allocator`, we just steal it!
config.zig_lib_path = json_env.lib_dir.?;
json_env.lib_dir = null;
logger.notice("Using zig lib path '{}'", .{config.zig_lib_path});
}
},
else => logger.alert("zig env invocation failed", .{}),
}
} }
} else {
logger.warn("Zig executable path not specified in zls.json and could not be found in PATH", .{});
}
if (config.zig_lib_path == null) {
logger.warn("Zig standard library path not specified in zls.json and could not be resolved from the zig executable", .{});
} }
if (config.build_runner_path) |build_runner_path| { if (config.build_runner_path) |build_runner_path| {