From 53af0877444ea6c14b1ad5baec94afbeebc5e5e0 Mon Sep 17 00:00:00 2001 From: Uko Kokņevičs Date: Thu, 28 Apr 2022 15:27:11 +0300 Subject: Added support for config files --- libs/xdg | 2 +- src/Config.zig | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Installation.zig | 27 +++++++++++---- src/install.zig | 7 ++-- src/list.zig | 7 ++-- src/main.zig | 16 ++++----- src/remove.zig | 6 ++-- src/subcommand.zig | 12 +++---- src/switch.zig | 6 ++-- src/update.zig | 8 +++-- 10 files changed, 150 insertions(+), 33 deletions(-) create mode 100644 src/Config.zig diff --git a/libs/xdg b/libs/xdg index 0d9f782..26639e5 160000 --- a/libs/xdg +++ b/libs/xdg @@ -1 +1 @@ -Subproject commit 0d9f7828de76bbae685be30b8f75a5aefad408f3 +Subproject commit 26639e50682ecb0f7373935de2dbc8d1d2319226 diff --git a/src/Config.zig b/src/Config.zig new file mode 100644 index 0000000..a7affa0 --- /dev/null +++ b/src/Config.zig @@ -0,0 +1,92 @@ +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); + } + } +} diff --git a/src/Installation.zig b/src/Installation.zig index fb06824..031b59a 100644 --- a/src/Installation.zig +++ b/src/Installation.zig @@ -1,9 +1,10 @@ -const builtin = @import("builtin"); const curl = @import("curl"); const std = @import("std"); const xdg = @import("xdg"); +const zup = @import("zup"); const Allocator = std.mem.Allocator; +const Config = zup.Config; const ChildProcess = std.ChildProcess; const JsonValue = std.json.Value; const SemanticVersion = std.SemanticVersion; @@ -128,7 +129,9 @@ pub fn isInstalled(allocator: Allocator, name: []const u8) !bool { return true; } -pub fn getAvailableList(allocator: Allocator) !Installations { +pub fn getAvailableList(config: Config) !Installations { + const allocator = config.allocator; + var json_str = try curl.easyDownload(allocator, "https://ziglang.org/download/index.json"); defer allocator.free(json_str); @@ -147,7 +150,7 @@ pub fn getAvailableList(allocator: Allocator) !Installations { var it = vt.root.Object.iterator(); while (it.next()) |kv| { - if (try parseInstallation(allocator, kv.key_ptr.*, kv.value_ptr.*)) |*installation| { + if (try parseInstallation(config, kv.key_ptr.*, kv.value_ptr.*)) |*installation| { errdefer installation.deinit(); var name = try allocator.dupe(u8, kv.key_ptr.*); @@ -160,15 +163,27 @@ pub fn getAvailableList(allocator: Allocator) !Installations { return installations; } -fn parseInstallation(allocator: Allocator, name: []const u8, value: JsonValue) !?Installation { +fn parseInstallation(config: Config, name: []const u8, value: JsonValue) !?Installation { + const allocator = config.allocator; + if (value != .Object) { return error.JsonSchema; } const map = value.Object; - const triple = @tagName(builtin.target.cpu.arch) ++ "-" ++ @tagName(builtin.target.os.tag); + const url_root = url_root: { + for (config.supported_targets.items) |target| { + const triple = try std.fmt.allocPrint(allocator, "{s}-{s}", .{ + @tagName(target.cpu.arch), + @tagName(target.os.tag), + }); + defer allocator.free(triple); + + if (map.get(triple)) |url_root| { + break :url_root url_root; + } + } - const url_root = map.get(triple) orelse { return null; }; if (url_root != .Object) { diff --git a/src/install.zig b/src/install.zig index ebf1c01..f9c7309 100644 --- a/src/install.zig +++ b/src/install.zig @@ -5,6 +5,7 @@ const xdg = @import("xdg"); const zup = @import("zup"); const Allocator = std.mem.Allocator; +const Config = zup.Config; const ArchiveRead = libarchive.Read; const Installation = zup.Installation; const Installations = zup.Installations; @@ -17,8 +18,10 @@ pub const description = "Installs a Zig version. Run `zup list -i` to see insta pub const min_args = 1; pub const max_args = 1; -pub fn main(comptime Result: type, allocator: Allocator, res: Result) !void { - var available = try Installation.getAvailableList(allocator); +pub fn main(comptime Result: type, config: Config, res: Result) !void { + const allocator = config.allocator; + + var available = try Installation.getAvailableList(config); defer Installation.deinitMap(allocator, &available); return perform(allocator, res.positionals[0], res.args.force, available); diff --git a/src/list.zig b/src/list.zig index b6e3847..bf95c2c 100644 --- a/src/list.zig +++ b/src/list.zig @@ -3,6 +3,7 @@ const zup = @import("zup"); const Allocator = std.mem.Allocator; const ArrayList = std.ArrayList; +const Config = zup.Config; const Installation = zup.Installation; const Installations = zup.Installations; @@ -16,7 +17,9 @@ pub const description = "Lists Zig versions. Default is `--active -i`."; pub const min_args = 0; pub const max_args = 0; -pub fn main(comptime Result: type, allocator: Allocator, res: Result) !void { +pub fn main(comptime Result: type, config: Config, res: Result) !void { + const allocator = config.allocator; + var list_active = res.args.active; var list_available = res.args.available; var list_installed = res.args.installed; @@ -44,7 +47,7 @@ pub fn main(comptime Result: type, allocator: Allocator, res: Result) !void { } if (list_available) { - var available = try Installation.getAvailableList(allocator); + var available = try Installation.getAvailableList(config); defer Installation.deinitMap(allocator, &available); try printAvailableList(allocator, available); } diff --git a/src/main.zig b/src/main.zig index f2868b6..197a224 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,3 +1,4 @@ +pub const Config = @import("Config.zig"); pub const Installation = @import("Installation.zig"); pub const Installations = Installation.Installations; pub const SubCommand = @import("subcommand.zig").SubCommand; @@ -13,20 +14,19 @@ pub const version = SubCommand(Version); const std = @import("std"); const zup_config = @import("zup-config"); -const Allocator = std.mem.Allocator; const ArgIterator = std.process.ArgIterator; const ComptimeStringMap = std.ComptimeStringMap; const GPA = std.heap.GeneralPurposeAllocator(.{}); const Tuple = std.meta.Tuple; -// TODO: config for supported triples. while smth like x86_64-macos on aarch64-macos can be hardcoded, that won't be -// the case for someone with qemu-user on linux - pub fn main() !void { var gpa = GPA{}; const allocator = gpa.allocator(); defer _ = gpa.deinit(); + var config = try Config.init(allocator); + defer config.deinit(); + var args = try std.process.argsWithAllocator(allocator); defer args.deinit(); @@ -35,7 +35,7 @@ pub fn main() !void { return Help.mainHelp(); }; - return dispatch(cmd, "main", unknownCmd, .{ cmd, allocator, &args }); + return dispatch(cmd, "main", unknownCmd, .{ cmd, config, &args }); } pub fn printVersion() !void { @@ -92,7 +92,7 @@ inline fn call(fun: anytype, args: anytype) !void { return @call(.{}, fun, args); } -fn unknownCmd(cmd: []const u8, _: Allocator, _: *ArgIterator) !void { +fn unknownCmd(cmd: []const u8, _: Config, _: *ArgIterator) !void { std.log.err("Unknown subcommand: {s}", .{cmd}); return error.ArgError; } @@ -103,7 +103,7 @@ const Help = struct { pub const min_args = 0; pub const max_args = 1; - pub fn main(comptime Result: type, _: Allocator, res: Result) !void { + pub fn main(comptime Result: type, _: Config, res: Result) !void { if (res.positionals.len == 0) { return mainHelp(); } @@ -145,7 +145,7 @@ const Version = struct { pub const min_args = 0; pub const max_args = 0; - pub fn main(comptime Result: type, _: Allocator, _: Result) !void { + pub fn main(comptime Result: type, _: Config, _: Result) !void { return printVersion(); } }; diff --git a/src/remove.zig b/src/remove.zig index ad1a610..f795df7 100644 --- a/src/remove.zig +++ b/src/remove.zig @@ -2,7 +2,7 @@ const std = @import("std"); const xdg = @import("xdg"); const zup = @import("zup"); -const Allocator = std.mem.Allocator; +const Config = zup.Config; const Installation = zup.Installation; pub const params = @@ -13,7 +13,9 @@ pub const description = "Removes an installed Zig version. Run `zup list -i` to pub const min_args = 1; pub const max_args = 1; -pub fn main(comptime Result: type, allocator: Allocator, res: Result) !void { +pub fn main(comptime Result: type, config: Config, res: Result) !void { + const allocator = config.allocator; + const name = res.positionals[0]; if (!try Installation.isInstalled(allocator, name)) { diff --git a/src/subcommand.zig b/src/subcommand.zig index ebd57ed..d750e94 100644 --- a/src/subcommand.zig +++ b/src/subcommand.zig @@ -2,8 +2,8 @@ const clap = @import("clap"); const std = @import("std"); const zup = @import("zup"); -const Allocator = std.mem.Allocator; const ArgIterator = std.process.ArgIterator; +const Config = zup.Config; const parsers = .{ .COMMAND = clap.parsers.string, @@ -35,7 +35,9 @@ pub fn SubCommand(comptime template: type) type { try writer.writeAll("\n" ++ template.description ++ "\n"); } - pub fn main(name: []const u8, allocator: Allocator, args: *ArgIterator) !void { + pub fn main(name: []const u8, config: Config, args: *ArgIterator) !void { + const allocator = config.allocator; + var diag = clap.Diagnostic{}; var res = clap.parseEx(clap.Help, ¶ms, parsers, args, .{ .allocator = allocator, @@ -60,11 +62,7 @@ pub fn SubCommand(comptime template: type) type { return error.ArgError; } - return template.main( - clap.ResultEx(clap.Help, ¶ms, parsers), - allocator, - res, - ); + return template.main(@TypeOf(res), config, res); } }; } diff --git a/src/switch.zig b/src/switch.zig index 058067d..e5d243f 100644 --- a/src/switch.zig +++ b/src/switch.zig @@ -2,7 +2,7 @@ const std = @import("std"); const xdg = @import("xdg"); const zup = @import("zup"); -const Allocator = std.mem.Allocator; +const Config = zup.Config; const Installation = zup.Installation; pub const params = ""; @@ -10,7 +10,9 @@ pub const description = "Switches to a Zig version. Run `zup list -i` to see in pub const min_args = 1; pub const max_args = 1; -pub fn main(comptime Result: type, allocator: Allocator, res: Result) !void { +pub fn main(comptime Result: type, config: Config, res: Result) !void { + const allocator = config.allocator; + const name = res.positionals[0]; if (!try Installation.isInstalled(allocator, name)) { std.log.err( diff --git a/src/update.zig b/src/update.zig index a8fd075..3451d90 100644 --- a/src/update.zig +++ b/src/update.zig @@ -1,7 +1,7 @@ const std = @import("std"); const zup = @import("zup"); -const Allocator = std.mem.Allocator; +const Config = zup.Config; const Installation = zup.Installation; // TODO: A way to specify a subset? @@ -11,11 +11,13 @@ pub const description = "Updates all installed Zig versions."; pub const min_args = 0; pub const max_args = 0; -pub fn main(comptime Result: type, allocator: Allocator, _: Result) !void { +pub fn main(comptime Result: type, config: Config, _: Result) !void { + const allocator = config.allocator; + var installed = try Installation.getInstalledList(allocator); defer Installation.deinitMap(allocator, &installed); - var available = try Installation.getAvailableList(allocator); + var available = try Installation.getAvailableList(config); defer Installation.deinitMap(allocator, &available); var it = installed.iterator(); -- cgit v1.2.3