From e1a94bf8f271a4543d962e1df99bdb6ca6c93c20 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sun, 23 Jun 2024 15:49:40 +0200 Subject: [PATCH] fix: move flow state files from ~/.cache/flow to ~/.local/state/flow This better matches the XDG Base Directory Specification. Please move existing state files from ~/.cache/flow to ~/.local/state/flow manually if you want to keep them. --- src/LSP.zig | 4 ++-- src/main.zig | 50 ++++++++++++++++++++++++++++++++++++++++- src/project_manager.zig | 8 +++---- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/LSP.zig b/src/LSP.zig index a35f816..e89824b 100644 --- a/src/LSP.zig +++ b/src/LSP.zig @@ -131,8 +131,8 @@ const Process = struct { var log_file_path = std.ArrayList(u8).init(self.a); defer log_file_path.deinit(); - const cache_dir = root.get_cache_dir() catch |e| return tp.exit_error(e); - log_file_path.writer().print("{s}/lsp-{s}.log", .{ cache_dir, self.tag }) catch |e| return tp.exit_error(e); + const state_dir = root.get_state_dir() catch |e| return tp.exit_error(e); + log_file_path.writer().print("{s}/lsp-{s}.log", .{ state_dir, self.tag }) catch |e| return tp.exit_error(e); self.log_file = std.fs.createFileAbsolute(log_file_path.items, .{ .truncate = true }) catch |e| return tp.exit_error(e); } diff --git a/src/main.zig b/src/main.zig index c6a2c5d..2414e2a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -274,7 +274,7 @@ fn trace_to_file(m: thespian.message.c_buffer_type) callconv(.C) void { const a = std.heap.c_allocator; var path = std.ArrayList(u8).init(a); defer path.deinit(); - path.writer().print("{s}/trace.log", .{get_cache_dir() catch return}) catch return; + path.writer().print("{s}/trace.log", .{get_state_dir() catch return}) catch return; const file = std.fs.createFileAbsolute(path.items, .{ .truncate = true }) catch return; State.state = .{ .file = file, @@ -445,6 +445,54 @@ fn get_app_cache_dir(appname: []const u8) ![]const u8 { return cache_dir; } +pub fn get_state_dir() ![]const u8 { + return get_app_state_dir(application_name); +} + +fn get_app_state_dir(appname: []const u8) ![]const u8 { + const a = std.heap.c_allocator; + const local = struct { + var state_dir_buffer: [std.posix.PATH_MAX]u8 = undefined; + var state_dir: ?[]const u8 = null; + }; + const state_dir = if (local.state_dir) |dir| + dir + else if (std.process.getEnvVarOwned(a, "XDG_STATE_HOME") catch null) |xdg| ret: { + defer a.free(xdg); + break :ret try std.fmt.bufPrint(&local.state_dir_buffer, "{s}/{s}", .{ xdg, appname }); + } else if (std.process.getEnvVarOwned(a, "HOME") catch null) |home| ret: { + defer a.free(home); + var dir = try std.fmt.bufPrint(&local.state_dir_buffer, "{s}/.local", .{home}); + std.fs.makeDirAbsolute(dir) catch |e| switch (e) { + error.PathAlreadyExists => {}, + else => return e, + }; + dir = try std.fmt.bufPrint(&local.state_dir_buffer, "{s}/.local/state", .{home}); + std.fs.makeDirAbsolute(dir) catch |e| switch (e) { + error.PathAlreadyExists => {}, + else => return e, + }; + break :ret try std.fmt.bufPrint(&local.state_dir_buffer, "{s}/.local/state/{s}", .{ home, appname }); + } else if (builtin.os.tag == .windows) ret: { + if (std.process.getEnvVarOwned(a, "APPDATA") catch null) |appdata| { + defer a.free(appdata); + const dir = try std.fmt.bufPrint(&local.state_dir_buffer, "{s}/{s}", .{ appdata, appname }); + std.fs.makeDirAbsolute(dir) catch |e| switch (e) { + error.PathAlreadyExists => {}, + else => return e, + }; + break :ret dir; + } else return error.AppCacheDirUnavailable; + } else return error.AppCacheDirUnavailable; + + local.state_dir = state_dir; + std.fs.makeDirAbsolute(state_dir) catch |e| switch (e) { + error.PathAlreadyExists => {}, + else => return e, + }; + return state_dir; +} + fn get_app_config_file_name(appname: []const u8) ![]const u8 { const local = struct { var config_file_buffer: [std.posix.PATH_MAX]u8 = undefined; diff --git a/src/project_manager.zig b/src/project_manager.zig index ab75b11..9951706 100644 --- a/src/project_manager.zig +++ b/src/project_manager.zig @@ -344,7 +344,7 @@ const Process = struct { fn persist_project(self: *Process, project: *Project) !void { self.logger.print("saving: {s}", .{project.name}); - const file_name = try get_project_cache_file_path(self.a, project); + const file_name = try get_project_state_file_path(self.a, project); defer self.a.free(file_name); var file = try std.fs.createFileAbsolute(file_name, .{ .truncate = true }); defer file.close(); @@ -354,7 +354,7 @@ const Process = struct { } fn restore_project(self: *Process, project: *Project) !void { - const file_name = try get_project_cache_file_path(self.a, project); + const file_name = try get_project_state_file_path(self.a, project); defer self.a.free(file_name); var file = std.fs.openFileAbsolute(file_name, .{ .mode = .read_only }) catch |e| switch (e) { error.FileNotFound => return, @@ -368,11 +368,11 @@ const Process = struct { try project.restore_state(buffer[0..size]); } - fn get_project_cache_file_path(a: std.mem.Allocator, project: *Project) ![]const u8 { + fn get_project_state_file_path(a: std.mem.Allocator, project: *Project) ![]const u8 { const path = project.name; var stream = std.ArrayList(u8).init(a); const writer = stream.writer(); - _ = try writer.write(try root.get_cache_dir()); + _ = try writer.write(try root.get_state_dir()); _ = try writer.writeByte(std.fs.path.sep); _ = try writer.write("projects"); _ = try writer.writeByte(std.fs.path.sep);