authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-30 13:34:18-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-30 16:21:25-08:00
loge956948f99338a7cef7d0e9f0602930f3e0528e1
tree65abaa31c2db01201e13c58ea2f14b51ea7adce1
parent96ba0ab930214e15ce09cde0cbddec797f0d2d9f

std: remove fs.getAppDataDir with no replacement

This API is a bit too opinionated for the Zig standard library. Applications should contain this logic instead.

6 files changed, 38 insertions(+), 91 deletions(-)

CMakeLists.txt-1
......@@ -436,7 +436,6 @@ set(ZIG_STAGE2_SOURCES
436436 lib/std/fmt.zig
437437 lib/std/fmt/parse_float.zig
438438 lib/std/fs.zig
439 lib/std/fs/get_app_data_dir.zig
440439 lib/std/fs/path.zig
441440 lib/std/hash.zig
442441 lib/std/hash/auto_hash.zig
lib/std/fs.zig-4
......@@ -6,9 +6,6 @@ const std = @import("std.zig");
66pub const path = @import("fs/path.zig");
77pub const wasi = @import("fs/wasi.zig");
88
9pub const getAppDataDir = @import("fs/get_app_data_dir.zig").getAppDataDir;
10pub const GetAppDataDirError = @import("fs/get_app_data_dir.zig").GetAppDataDirError;
11
129pub const base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*;
1310
1411/// Base64 encoder, replacing the standard `+/` with `-_` so that it can be used in a file name on any filesystem.
......@@ -25,5 +22,4 @@ pub const max_name_bytes = std.Io.Dir.max_name_bytes;
2522test {
2623 _ = path;
2724 _ = @import("fs/test.zig");
28 _ = @import("fs/get_app_data_dir.zig");
2925}
lib/std/fs/get_app_data_dir.zig deleted-66
......@@ -1,66 +0,0 @@
1const std = @import("../std.zig");
2const builtin = @import("builtin");
3const unicode = std.unicode;
4const mem = std.mem;
5const fs = std.fs;
6const native_os = builtin.os.tag;
7const posix = std.posix;
8
9pub const GetAppDataDirError = error{
10 OutOfMemory,
11 AppDataDirUnavailable,
12};
13
14/// Caller owns returned memory.
15/// TODO determine if we can remove the allocator requirement
16pub fn getAppDataDir(allocator: mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
17 switch (native_os) {
18 .windows => {
19 const local_app_data_dir = std.process.getEnvVarOwned(allocator, "LOCALAPPDATA") catch |err| switch (err) {
20 error.OutOfMemory => |e| return e,
21 else => return error.AppDataDirUnavailable,
22 };
23 defer allocator.free(local_app_data_dir);
24 return fs.path.join(allocator, &[_][]const u8{ local_app_data_dir, appname });
25 },
26 .maccatalyst, .macos => {
27 const home_dir = posix.getenv("HOME") orelse {
28 // TODO look in /etc/passwd
29 return error.AppDataDirUnavailable;
30 };
31 return fs.path.join(allocator, &[_][]const u8{ home_dir, "Library", "Application Support", appname });
32 },
33 .linux, .freebsd, .netbsd, .dragonfly, .openbsd, .illumos, .serenity => {
34 if (posix.getenv("XDG_DATA_HOME")) |xdg| {
35 if (xdg.len > 0) {
36 return fs.path.join(allocator, &[_][]const u8{ xdg, appname });
37 }
38 }
39
40 const home_dir = posix.getenv("HOME") orelse {
41 // TODO look in /etc/passwd
42 return error.AppDataDirUnavailable;
43 };
44 return fs.path.join(allocator, &[_][]const u8{ home_dir, ".local", "share", appname });
45 },
46 .haiku => {
47 var dir_path_buf: [std.fs.max_path_bytes]u8 = undefined;
48 const rc = std.c.find_directory(.B_USER_SETTINGS_DIRECTORY, -1, true, &dir_path_buf, dir_path_buf.len);
49 const settings_dir = try allocator.dupeZ(u8, mem.sliceTo(&dir_path_buf, 0));
50 defer allocator.free(settings_dir);
51 switch (rc) {
52 0 => return fs.path.join(allocator, &[_][]const u8{ settings_dir, appname }),
53 else => return error.AppDataDirUnavailable,
54 }
55 },
56 else => @compileError("Unsupported OS"),
57 }
58}
59
60test getAppDataDir {
61 if (native_os == .wasi) return error.SkipZigTest;
62
63 // We can't actually validate the result
64 const dir = getAppDataDir(std.testing.allocator, "zig") catch return;
65 defer std.testing.allocator.free(dir);
66}
lib/std/zig.zig+1
......@@ -743,6 +743,7 @@ pub const EnvVar = enum {
743743 NO_COLOR,
744744 CLICOLOR_FORCE,
745745 XDG_CACHE_HOME,
746 LOCALAPPDATA,
746747 HOME,
747748
748749 pub fn isSet(comptime ev: EnvVar) bool {
lib/std/zig/WindowsSdk.zig+8-1
......@@ -860,7 +860,14 @@ const MsvcLibDir = struct {
860860
861861 // %localappdata%\Microsoft\VisualStudio\
862862 // %appdata%\Local\Microsoft\VisualStudio\
863 const visualstudio_folder_path = std.fs.getAppDataDir(gpa, "Microsoft\\VisualStudio\\") catch return error.PathNotFound;
863 const local_app_data_path = (std.zig.EnvVar.LOCALAPPDATA.get(gpa) catch |err| switch (err) {
864 error.OutOfMemory => |e| return e,
865 error.InvalidWtf8 => return error.PathNotFound,
866 }) orelse return error.PathNotFound;
867 defer gpa.free(local_app_data_path);
868 const visualstudio_folder_path = try Dir.path.join(gpa, &.{
869 local_app_data_path, "Microsoft\\VisualStudio\\",
870 });
864871 defer gpa.free(visualstudio_folder_path);
865872
866873 const vs_versions: []const []const u8 = vs_versions: {
src/introspect.zig+29-19
......@@ -1,5 +1,4 @@
11const builtin = @import("builtin");
2const build_options = @import("build_options");
32
43const std = @import("std");
54const Io = std.Io;
......@@ -8,6 +7,8 @@ const mem = std.mem;
87const Allocator = std.mem.Allocator;
98const Cache = std.Build.Cache;
109
10const build_options = @import("build_options");
11
1112const Compilation = @import("Compilation.zig");
1213const Package = @import("Package.zig");
1314
......@@ -101,26 +102,35 @@ pub fn findZigLibDirFromSelfExe(
101102}
102103
103104/// Caller owns returned memory.
104pub fn resolveGlobalCacheDir(allocator: Allocator) ![]u8 {
105 if (builtin.os.tag == .wasi)
106 @compileError("on WASI the global cache dir must be resolved with preopens");
107
108 if (try std.zig.EnvVar.ZIG_GLOBAL_CACHE_DIR.get(allocator)) |value| return value;
109
110 const appname = "zig";
111
112 if (builtin.os.tag != .windows) {
113 if (std.zig.EnvVar.XDG_CACHE_HOME.getPosix()) |cache_root| {
114 if (cache_root.len > 0) {
115 return Dir.path.join(allocator, &.{ cache_root, appname });
105pub fn resolveGlobalCacheDir(gpa: Allocator) ![]u8 {
106 if (try std.zig.EnvVar.ZIG_GLOBAL_CACHE_DIR.get(gpa)) |value| return value;
107
108 const app_name = "zig";
109
110 switch (builtin.os.tag) {
111 .wasi => @compileError("on WASI the global cache dir must be resolved with preopens"),
112 .windows => {
113 const local_app_data_dir = (std.zig.EnvVar.LOCALAPPDATA.get(gpa) catch |err| switch (err) {
114 error.OutOfMemory => |e| return e,
115 error.InvalidWtf8 => return error.AppDataDirUnavailable,
116 }) orelse return error.AppDataDirUnavailable;
117 defer gpa.free(local_app_data_dir);
118 return Dir.path.join(gpa, &.{ local_app_data_dir, app_name });
119 },
120 else => {
121 if (std.zig.EnvVar.XDG_CACHE_HOME.getPosix()) |cache_root| {
122 if (cache_root.len > 0) {
123 return Dir.path.join(gpa, &.{ cache_root, app_name });
124 }
116125 }
117 }
118 if (std.zig.EnvVar.HOME.getPosix()) |home| {
119 return Dir.path.join(allocator, &.{ home, ".cache", appname });
120 }
126 if (std.zig.EnvVar.HOME.getPosix()) |home| {
127 if (home.len > 0) {
128 return Dir.path.join(gpa, &.{ home, ".cache", app_name });
129 }
130 }
131 return error.AppDataDirUnavailable;
132 },
121133 }
122
123 return std.fs.getAppDataDir(allocator, appname);
124134}
125135
126136/// Similar to `Dir.path.resolve`, but converts to a cwd-relative path, or, if that would