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...@@ -436,7 +436,6 @@ set(ZIG_STAGE2_SOURCES
436 lib/std/fmt.zig436 lib/std/fmt.zig
437 lib/std/fmt/parse_float.zig437 lib/std/fmt/parse_float.zig
438 lib/std/fs.zig438 lib/std/fs.zig
439 lib/std/fs/get_app_data_dir.zig
440 lib/std/fs/path.zig439 lib/std/fs/path.zig
441 lib/std/hash.zig440 lib/std/hash.zig
442 lib/std/hash/auto_hash.zig441 lib/std/hash/auto_hash.zig
lib/std/fs.zig-4
...@@ -6,9 +6,6 @@ const std = @import("std.zig");...@@ -6,9 +6,6 @@ const std = @import("std.zig");
6pub const path = @import("fs/path.zig");6pub const path = @import("fs/path.zig");
7pub const wasi = @import("fs/wasi.zig");7pub 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
12pub const base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*;9pub const base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*;
1310
14/// Base64 encoder, replacing the standard `+/` with `-_` so that it can be used in a file name on any filesystem.11/// 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;...@@ -25,5 +22,4 @@ pub const max_name_bytes = std.Io.Dir.max_name_bytes;
25test {22test {
26 _ = path;23 _ = path;
27 _ = @import("fs/test.zig");24 _ = @import("fs/test.zig");
28 _ = @import("fs/get_app_data_dir.zig");
29}25}
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 {...@@ -743,6 +743,7 @@ pub const EnvVar = enum {
743 NO_COLOR,743 NO_COLOR,
744 CLICOLOR_FORCE,744 CLICOLOR_FORCE,
745 XDG_CACHE_HOME,745 XDG_CACHE_HOME,
746 LOCALAPPDATA,
746 HOME,747 HOME,
747748
748 pub fn isSet(comptime ev: EnvVar) bool {749 pub fn isSet(comptime ev: EnvVar) bool {
lib/std/zig/WindowsSdk.zig+8-1
...@@ -860,7 +860,14 @@ const MsvcLibDir = struct {...@@ -860,7 +860,14 @@ const MsvcLibDir = struct {
860860
861 // %localappdata%\Microsoft\VisualStudio\861 // %localappdata%\Microsoft\VisualStudio\
862 // %appdata%\Local\Microsoft\VisualStudio\862 // %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 });
864 defer gpa.free(visualstudio_folder_path);871 defer gpa.free(visualstudio_folder_path);
865872
866 const vs_versions: []const []const u8 = vs_versions: {873 const vs_versions: []const []const u8 = vs_versions: {
src/introspect.zig+29-19
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const build_options = @import("build_options");
32
4const std = @import("std");3const std = @import("std");
5const Io = std.Io;4const Io = std.Io;
...@@ -8,6 +7,8 @@ const mem = std.mem;...@@ -8,6 +7,8 @@ const mem = std.mem;
8const Allocator = std.mem.Allocator;7const Allocator = std.mem.Allocator;
9const Cache = std.Build.Cache;8const Cache = std.Build.Cache;
109
10const build_options = @import("build_options");
11
11const Compilation = @import("Compilation.zig");12const Compilation = @import("Compilation.zig");
12const Package = @import("Package.zig");13const Package = @import("Package.zig");
1314
...@@ -101,26 +102,35 @@ pub fn findZigLibDirFromSelfExe(...@@ -101,26 +102,35 @@ pub fn findZigLibDirFromSelfExe(
101}102}
102103
103/// Caller owns returned memory.104/// Caller owns returned memory.
104pub fn resolveGlobalCacheDir(allocator: Allocator) ![]u8 {105pub fn resolveGlobalCacheDir(gpa: Allocator) ![]u8 {
105 if (builtin.os.tag == .wasi)106 if (try std.zig.EnvVar.ZIG_GLOBAL_CACHE_DIR.get(gpa)) |value| return value;
106 @compileError("on WASI the global cache dir must be resolved with preopens");107
107108 const app_name = "zig";
108 if (try std.zig.EnvVar.ZIG_GLOBAL_CACHE_DIR.get(allocator)) |value| return value;109
109110 switch (builtin.os.tag) {
110 const appname = "zig";111 .wasi => @compileError("on WASI the global cache dir must be resolved with preopens"),
111112 .windows => {
112 if (builtin.os.tag != .windows) {113 const local_app_data_dir = (std.zig.EnvVar.LOCALAPPDATA.get(gpa) catch |err| switch (err) {
113 if (std.zig.EnvVar.XDG_CACHE_HOME.getPosix()) |cache_root| {114 error.OutOfMemory => |e| return e,
114 if (cache_root.len > 0) {115 error.InvalidWtf8 => return error.AppDataDirUnavailable,
115 return Dir.path.join(allocator, &.{ cache_root, appname });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 }
116 }125 }
117 }126 if (std.zig.EnvVar.HOME.getPosix()) |home| {
118 if (std.zig.EnvVar.HOME.getPosix()) |home| {127 if (home.len > 0) {
119 return Dir.path.join(allocator, &.{ home, ".cache", appname });128 return Dir.path.join(gpa, &.{ home, ".cache", app_name });
120 }129 }
130 }
131 return error.AppDataDirUnavailable;
132 },
121 }133 }
122
123 return std.fs.getAppDataDir(allocator, appname);
124}134}
125135
126/// Similar to `Dir.path.resolve`, but converts to a cwd-relative path, or, if that would136/// Similar to `Dir.path.resolve`, but converts to a cwd-relative path, or, if that would