const builtin = @import("builtin"); const std = @import("std"); const xdg = @import("xdg"); const Allocator = std.mem.Allocator; const ArrayList = std.ArrayList; const Config = @This(); const CrossTarget = std.zig.CrossTarget; const File = std.fs.File; const NativeTargetInfo = std.zig.system.NativeTargetInfo; const Target = std.Target; allocator: Allocator, /// Earlier in the list means more preferred. supported_targets: ArrayList(Target), pub fn init(allocator: Allocator) !Config { var self = Config{ .allocator = allocator, .supported_targets = ArrayList(Target).init(allocator), }; errdefer self.deinit(); // Native target is always supported and at highest priority try self.supported_targets.append(builtin.target); const config_dirs = try xdg.getAllConfigDirs(allocator, "zup"); defer { for (config_dirs) |s| allocator.free(s); allocator.free(config_dirs); } for (config_dirs) |config_dir| { const file_name = try std.fs.path.join(allocator, &.{ config_dir, "zup.json" }); defer allocator.free(file_name); var file = std.fs.openFileAbsolute(file_name, .{}) catch |err| { if (err == error.FileNotFound) { continue; } else { return err; } }; defer file.close(); try self.readConfig(file); } return self; } pub fn deinit(self: *Config) void { self.supported_targets.deinit(); self.* = undefined; } fn readConfig(self: *Config, file: File) !void { const allocator = self.allocator; const reader = file.reader(); var json_str = try reader.readAllAlloc(allocator, std.math.maxInt(u64)); defer allocator.free(json_str); var parser = std.json.Parser.init(allocator, false); defer parser.deinit(); var vt = try parser.parse(json_str); defer vt.deinit(); if (vt.root != .Object) { std.log.warn("Failed at reading config, root isn't object.", .{}); return; } if (vt.root.Object.get("supported_targets")) |supported_targets| blk: { if (supported_targets != .Array) { break :blk; } for (supported_targets.Array.items) |supported_target| { if (supported_target != .String) { continue; } const cross_target = try CrossTarget.parse(.{ .arch_os_abi = supported_target.String, }); const native_target_info = try NativeTargetInfo.detect(allocator, cross_target); try self.supported_targets.append(native_target_info.target); } } }