feature. See also
. The project being documented here (as the example) is the Zig library itself.
zig.Directories
pub const Directories = struct
File
Code
pub const Directories = struct {
cwd: []const u8,
zig_lib: Cache.Directory,
global_cache: Cache.Directory,
local_cache: Cache.Directory,
pub fn deinit(dirs: *Directories, io: Io) void {
const close_local = dirs.local_cache.handle.handle != dirs.global_cache.handle.handle;
dirs.global_cache.handle.close(io);
if (close_local) dirs.local_cache.handle.close(io);
dirs.zig_lib.handle.close(io);
}
pub fn withoutLocalCache(dirs: Directories) Directories {
return .{
.cwd = dirs.cwd,
.zig_lib = dirs.zig_lib,
.global_cache = dirs.global_cache,
.local_cache = dirs.global_cache,
};
}
const LocalCacheStrategy = union(enum) {
override: []const u8,
search,
global,
};
pub fn init(
arena: Allocator,
io: Io,
override_zig_lib: ?[]const u8,
override_global_cache: ?[]const u8,
local_cache_strat: LocalCacheStrategy,
preopens: std.process.Preopens,
self_exe_path: switch (builtin.target.os.tag) {
.wasi => void,
else => []const u8,
},
environ_map: *const std.process.Environ.Map,
cwd: []const u8,
) Directories {
const wasi = builtin.target.os.tag == .wasi;
const zig_lib: Cache.Directory = d: {
if (override_zig_lib) |path| break :d openUnresolved(arena, io, cwd, path, .@"zig lib");
if (wasi) break :d getPreopen(preopens, "/lib");
break :d findZigLibDirFromSelfExe(arena, io, cwd, self_exe_path) catch |err| {
fatal("unable to find zig installation directory from executable path {q}: {t}", .{ self_exe_path, err });
};
};
const global_cache: Cache.Directory = d: {
if (override_global_cache) |path| break :d openUnresolved(arena, io, cwd, path, .@"global cache");
if (wasi) break :d getPreopen(preopens, "/cache");
const path = resolveGlobalCacheDir(arena, environ_map) catch |err| {
fatal("unable to resolve zig cache directory: {t}", .{err});
};
break :d openUnresolved(arena, io, cwd, path, .@"global cache");
};
const local_cache = getLocalCacheDirectory(arena, io, cwd, global_cache, local_cache_strat);
if (mem.eql(u8, zig_lib.path orelse "", global_cache.path orelse "")) {
fatal("zig lib directory '{f}' cannot be equal to global cache directory '{f}'", .{ zig_lib, global_cache });
}
if (mem.eql(u8, zig_lib.path orelse "", local_cache.path orelse "")) {
fatal("zig lib directory '{f}' cannot be equal to local cache directory '{f}'", .{ zig_lib, local_cache });
}
return .{
.cwd = cwd,
.zig_lib = zig_lib,
.global_cache = global_cache,
.local_cache = local_cache,
};
}
fn getLocalCacheDirectory(
arena: Allocator,
io: Io,
cwd: []const u8,
global_cache: Cache.Directory,
local_cache_strat: LocalCacheStrategy,
) Cache.Directory {
return switch (local_cache_strat) {
.override => |path| openUnresolved(arena, io, cwd, path, .@"local cache"),
.search => d: {
const maybe_path = resolveSuitableLocalCacheDir(arena, io, cwd) catch |err|
fatal("unable to resolve zig cache directory: {t}", .{err});
const path = maybe_path orelse break :d global_cache;
break :d openUnresolved(arena, io, cwd, path, .@"local cache");
},
.global => global_cache,
};
}
fn getPreopen(preopens: std.process.Preopens, name: []const u8) Cache.Directory {
return .{
.path = if (mem.eql(u8, name, ".")) null else name,
.handle = switch (preopens.get(name) orelse fatal("preopen not found: {q}", .{name})) {
.file => fatal("preopen {q} is not a directory", .{name}),
.dir => |d| d,
},
};
}
pub fn openUnresolved(
arena: Allocator,
io: Io,
cwd: []const u8,
unresolved_path: []const u8,
thing: enum { @"zig lib", @"global cache", @"local cache" },
) Cache.Directory {
const path = resolvePath(arena, cwd, &.{unresolved_path}) catch |err| {
fatal("unable to resolve {t} directory: {t}", .{ thing, err });
};
const nonempty_path = if (path.len == 0) "." else path;
const handle_or_err = switch (thing) {
.@"zig lib" => Dir.cwd().openDir(io, nonempty_path, .{}),
.@"global cache", .@"local cache" => Dir.cwd().createDirPathOpen(io, nonempty_path, .{}),
};
return .{
.path = if (path.len == 0) null else path,
.handle = handle_or_err catch |err| {
const extra_str: []const u8 = e: {
if (thing == .@"global cache") switch (err) {
error.AccessDenied, error.ReadOnlyFileSystem => break :e "\n" ++
"If this location is not writable then consider specifying an alternative with " ++
"the ZIG_GLOBAL_CACHE_DIR environment variable or the --global-cache-dir option.",
else => {},
};
break :e "";
};
fatal("unable to open {t} directory {q}: {t}{s}", .{ thing, nonempty_path, err, extra_str });
},
};
}
}