summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Uko Kokņevičs2022-04-28 15:27:11 +0300
committerGravatar Uko Kokņevičs2022-04-28 15:29:33 +0300
commit53af0877444ea6c14b1ad5baec94afbeebc5e5e0 (patch)
tree837fba9d78c895243f598c95916bff4a4c56f609 /src
parentAdd Installation.isActive, use it (diff)
downloadzup-53af0877444ea6c14b1ad5baec94afbeebc5e5e0.tar.gz
zup-53af0877444ea6c14b1ad5baec94afbeebc5e5e0.tar.xz
zup-53af0877444ea6c14b1ad5baec94afbeebc5e5e0.zip
Added support for config files
Diffstat (limited to 'src')
-rw-r--r--src/Config.zig92
-rw-r--r--src/Installation.zig27
-rw-r--r--src/install.zig7
-rw-r--r--src/list.zig7
-rw-r--r--src/main.zig16
-rw-r--r--src/remove.zig6
-rw-r--r--src/subcommand.zig12
-rw-r--r--src/switch.zig6
-rw-r--r--src/update.zig8
9 files changed, 149 insertions, 32 deletions
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 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const xdg = @import("xdg");
4
5const Allocator = std.mem.Allocator;
6const ArrayList = std.ArrayList;
7const Config = @This();
8const CrossTarget = std.zig.CrossTarget;
9const File = std.fs.File;
10const NativeTargetInfo = std.zig.system.NativeTargetInfo;
11const Target = std.Target;
12
13allocator: Allocator,
14/// Earlier in the list means more preferred.
15supported_targets: ArrayList(Target),
16
17pub fn init(allocator: Allocator) !Config {
18 var self = Config{
19 .allocator = allocator,
20 .supported_targets = ArrayList(Target).init(allocator),
21 };
22 errdefer self.deinit();
23
24 // Native target is always supported and at highest priority
25 try self.supported_targets.append(builtin.target);
26
27 const config_dirs = try xdg.getAllConfigDirs(allocator, "zup");
28 defer {
29 for (config_dirs) |s| allocator.free(s);
30 allocator.free(config_dirs);
31 }
32
33 for (config_dirs) |config_dir| {
34 const file_name = try std.fs.path.join(allocator, &.{ config_dir, "zup.json" });
35 defer allocator.free(file_name);
36 var file = std.fs.openFileAbsolute(file_name, .{}) catch |err| {
37 if (err == error.FileNotFound) {
38 continue;
39 } else {
40 return err;
41 }
42 };
43 defer file.close();
44
45 try self.readConfig(file);
46 }
47
48 return self;
49}
50
51pub fn deinit(self: *Config) void {
52 self.supported_targets.deinit();
53
54 self.* = undefined;
55}
56
57fn readConfig(self: *Config, file: File) !void {
58 const allocator = self.allocator;
59 const reader = file.reader();
60
61 var json_str = try reader.readAllAlloc(allocator, std.math.maxInt(u64));
62 defer allocator.free(json_str);
63
64 var parser = std.json.Parser.init(allocator, false);
65 defer parser.deinit();
66
67 var vt = try parser.parse(json_str);
68 defer vt.deinit();
69
70 if (vt.root != .Object) {
71 std.log.warn("Failed at reading config, root isn't object.", .{});
72 return;
73 }
74
75 if (vt.root.Object.get("supported_targets")) |supported_targets| blk: {
76 if (supported_targets != .Array) {
77 break :blk;
78 }
79
80 for (supported_targets.Array.items) |supported_target| {
81 if (supported_target != .String) {
82 continue;
83 }
84
85 const cross_target = try CrossTarget.parse(.{
86 .arch_os_abi = supported_target.String,
87 });
88 const native_target_info = try NativeTargetInfo.detect(allocator, cross_target);
89 try self.supported_targets.append(native_target_info.target);
90 }
91 }
92}
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 @@
1const builtin = @import("builtin");
2const curl = @import("curl"); 1const curl = @import("curl");
3const std = @import("std"); 2const std = @import("std");
4const xdg = @import("xdg"); 3const xdg = @import("xdg");
4const zup = @import("zup");
5 5
6const Allocator = std.mem.Allocator; 6const Allocator = std.mem.Allocator;
7const Config = zup.Config;
7const ChildProcess = std.ChildProcess; 8const ChildProcess = std.ChildProcess;
8const JsonValue = std.json.Value; 9const JsonValue = std.json.Value;
9const SemanticVersion = std.SemanticVersion; 10const SemanticVersion = std.SemanticVersion;
@@ -128,7 +129,9 @@ pub fn isInstalled(allocator: Allocator, name: []const u8) !bool {
128 return true; 129 return true;
129} 130}
130 131
131pub fn getAvailableList(allocator: Allocator) !Installations { 132pub fn getAvailableList(config: Config) !Installations {
133 const allocator = config.allocator;
134
132 var json_str = try curl.easyDownload(allocator, "https://ziglang.org/download/index.json"); 135 var json_str = try curl.easyDownload(allocator, "https://ziglang.org/download/index.json");
133 defer allocator.free(json_str); 136 defer allocator.free(json_str);
134 137
@@ -147,7 +150,7 @@ pub fn getAvailableList(allocator: Allocator) !Installations {
147 150
148 var it = vt.root.Object.iterator(); 151 var it = vt.root.Object.iterator();
149 while (it.next()) |kv| { 152 while (it.next()) |kv| {
150 if (try parseInstallation(allocator, kv.key_ptr.*, kv.value_ptr.*)) |*installation| { 153 if (try parseInstallation(config, kv.key_ptr.*, kv.value_ptr.*)) |*installation| {
151 errdefer installation.deinit(); 154 errdefer installation.deinit();
152 155
153 var name = try allocator.dupe(u8, kv.key_ptr.*); 156 var name = try allocator.dupe(u8, kv.key_ptr.*);
@@ -160,15 +163,27 @@ pub fn getAvailableList(allocator: Allocator) !Installations {
160 return installations; 163 return installations;
161} 164}
162 165
163fn parseInstallation(allocator: Allocator, name: []const u8, value: JsonValue) !?Installation { 166fn parseInstallation(config: Config, name: []const u8, value: JsonValue) !?Installation {
167 const allocator = config.allocator;
168
164 if (value != .Object) { 169 if (value != .Object) {
165 return error.JsonSchema; 170 return error.JsonSchema;
166 } 171 }
167 const map = value.Object; 172 const map = value.Object;
168 173
169 const triple = @tagName(builtin.target.cpu.arch) ++ "-" ++ @tagName(builtin.target.os.tag); 174 const url_root = url_root: {
175 for (config.supported_targets.items) |target| {
176 const triple = try std.fmt.allocPrint(allocator, "{s}-{s}", .{
177 @tagName(target.cpu.arch),
178 @tagName(target.os.tag),
179 });
180 defer allocator.free(triple);
181
182 if (map.get(triple)) |url_root| {
183 break :url_root url_root;
184 }
185 }
170 186
171 const url_root = map.get(triple) orelse {
172 return null; 187 return null;
173 }; 188 };
174 if (url_root != .Object) { 189 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");
5const zup = @import("zup"); 5const zup = @import("zup");
6 6
7const Allocator = std.mem.Allocator; 7const Allocator = std.mem.Allocator;
8const Config = zup.Config;
8const ArchiveRead = libarchive.Read; 9const ArchiveRead = libarchive.Read;
9const Installation = zup.Installation; 10const Installation = zup.Installation;
10const Installations = zup.Installations; 11const Installations = zup.Installations;
@@ -17,8 +18,10 @@ pub const description = "Installs a Zig version. Run `zup list -i` to see insta
17pub const min_args = 1; 18pub const min_args = 1;
18pub const max_args = 1; 19pub const max_args = 1;
19 20
20pub fn main(comptime Result: type, allocator: Allocator, res: Result) !void { 21pub fn main(comptime Result: type, config: Config, res: Result) !void {
21 var available = try Installation.getAvailableList(allocator); 22 const allocator = config.allocator;
23
24 var available = try Installation.getAvailableList(config);
22 defer Installation.deinitMap(allocator, &available); 25 defer Installation.deinitMap(allocator, &available);
23 26
24 return perform(allocator, res.positionals[0], res.args.force, available); 27 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");
3 3
4const Allocator = std.mem.Allocator; 4const Allocator = std.mem.Allocator;
5const ArrayList = std.ArrayList; 5const ArrayList = std.ArrayList;
6const Config = zup.Config;
6const Installation = zup.Installation; 7const Installation = zup.Installation;
7const Installations = zup.Installations; 8const Installations = zup.Installations;
8 9
@@ -16,7 +17,9 @@ pub const description = "Lists Zig versions. Default is `--active -i`.";
16pub const min_args = 0; 17pub const min_args = 0;
17pub const max_args = 0; 18pub const max_args = 0;
18 19
19pub fn main(comptime Result: type, allocator: Allocator, res: Result) !void { 20pub fn main(comptime Result: type, config: Config, res: Result) !void {
21 const allocator = config.allocator;
22
20 var list_active = res.args.active; 23 var list_active = res.args.active;
21 var list_available = res.args.available; 24 var list_available = res.args.available;
22 var list_installed = res.args.installed; 25 var list_installed = res.args.installed;
@@ -44,7 +47,7 @@ pub fn main(comptime Result: type, allocator: Allocator, res: Result) !void {
44 } 47 }
45 48
46 if (list_available) { 49 if (list_available) {
47 var available = try Installation.getAvailableList(allocator); 50 var available = try Installation.getAvailableList(config);
48 defer Installation.deinitMap(allocator, &available); 51 defer Installation.deinitMap(allocator, &available);
49 try printAvailableList(allocator, available); 52 try printAvailableList(allocator, available);
50 } 53 }
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 @@
1pub const Config = @import("Config.zig");
1pub const Installation = @import("Installation.zig"); 2pub const Installation = @import("Installation.zig");
2pub const Installations = Installation.Installations; 3pub const Installations = Installation.Installations;
3pub const SubCommand = @import("subcommand.zig").SubCommand; 4pub const SubCommand = @import("subcommand.zig").SubCommand;
@@ -13,20 +14,19 @@ pub const version = SubCommand(Version);
13const std = @import("std"); 14const std = @import("std");
14const zup_config = @import("zup-config"); 15const zup_config = @import("zup-config");
15 16
16const Allocator = std.mem.Allocator;
17const ArgIterator = std.process.ArgIterator; 17const ArgIterator = std.process.ArgIterator;
18const ComptimeStringMap = std.ComptimeStringMap; 18const ComptimeStringMap = std.ComptimeStringMap;
19const GPA = std.heap.GeneralPurposeAllocator(.{}); 19const GPA = std.heap.GeneralPurposeAllocator(.{});
20const Tuple = std.meta.Tuple; 20const Tuple = std.meta.Tuple;
21 21
22// TODO: config for supported triples. while smth like x86_64-macos on aarch64-macos can be hardcoded, that won't be
23// the case for someone with qemu-user on linux
24
25pub fn main() !void { 22pub fn main() !void {
26 var gpa = GPA{}; 23 var gpa = GPA{};
27 const allocator = gpa.allocator(); 24 const allocator = gpa.allocator();
28 defer _ = gpa.deinit(); 25 defer _ = gpa.deinit();
29 26
27 var config = try Config.init(allocator);
28 defer config.deinit();
29
30 var args = try std.process.argsWithAllocator(allocator); 30 var args = try std.process.argsWithAllocator(allocator);
31 defer args.deinit(); 31 defer args.deinit();
32 32
@@ -35,7 +35,7 @@ pub fn main() !void {
35 return Help.mainHelp(); 35 return Help.mainHelp();
36 }; 36 };
37 37
38 return dispatch(cmd, "main", unknownCmd, .{ cmd, allocator, &args }); 38 return dispatch(cmd, "main", unknownCmd, .{ cmd, config, &args });
39} 39}
40 40
41pub fn printVersion() !void { 41pub fn printVersion() !void {
@@ -92,7 +92,7 @@ inline fn call(fun: anytype, args: anytype) !void {
92 return @call(.{}, fun, args); 92 return @call(.{}, fun, args);
93} 93}
94 94
95fn unknownCmd(cmd: []const u8, _: Allocator, _: *ArgIterator) !void { 95fn unknownCmd(cmd: []const u8, _: Config, _: *ArgIterator) !void {
96 std.log.err("Unknown subcommand: {s}", .{cmd}); 96 std.log.err("Unknown subcommand: {s}", .{cmd});
97 return error.ArgError; 97 return error.ArgError;
98} 98}
@@ -103,7 +103,7 @@ const Help = struct {
103 pub const min_args = 0; 103 pub const min_args = 0;
104 pub const max_args = 1; 104 pub const max_args = 1;
105 105
106 pub fn main(comptime Result: type, _: Allocator, res: Result) !void { 106 pub fn main(comptime Result: type, _: Config, res: Result) !void {
107 if (res.positionals.len == 0) { 107 if (res.positionals.len == 0) {
108 return mainHelp(); 108 return mainHelp();
109 } 109 }
@@ -145,7 +145,7 @@ const Version = struct {
145 pub const min_args = 0; 145 pub const min_args = 0;
146 pub const max_args = 0; 146 pub const max_args = 0;
147 147
148 pub fn main(comptime Result: type, _: Allocator, _: Result) !void { 148 pub fn main(comptime Result: type, _: Config, _: Result) !void {
149 return printVersion(); 149 return printVersion();
150 } 150 }
151}; 151};
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");
2const xdg = @import("xdg"); 2const xdg = @import("xdg");
3const zup = @import("zup"); 3const zup = @import("zup");
4 4
5const Allocator = std.mem.Allocator; 5const Config = zup.Config;
6const Installation = zup.Installation; 6const Installation = zup.Installation;
7 7
8pub const params = 8pub const params =
@@ -13,7 +13,9 @@ pub const description = "Removes an installed Zig version. Run `zup list -i` to
13pub const min_args = 1; 13pub const min_args = 1;
14pub const max_args = 1; 14pub const max_args = 1;
15 15
16pub fn main(comptime Result: type, allocator: Allocator, res: Result) !void { 16pub fn main(comptime Result: type, config: Config, res: Result) !void {
17 const allocator = config.allocator;
18
17 const name = res.positionals[0]; 19 const name = res.positionals[0];
18 20
19 if (!try Installation.isInstalled(allocator, name)) { 21 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");
2const std = @import("std"); 2const std = @import("std");
3const zup = @import("zup"); 3const zup = @import("zup");
4 4
5const Allocator = std.mem.Allocator;
6const ArgIterator = std.process.ArgIterator; 5const ArgIterator = std.process.ArgIterator;
6const Config = zup.Config;
7 7
8const parsers = .{ 8const parsers = .{
9 .COMMAND = clap.parsers.string, 9 .COMMAND = clap.parsers.string,
@@ -35,7 +35,9 @@ pub fn SubCommand(comptime template: type) type {
35 try writer.writeAll("\n" ++ template.description ++ "\n"); 35 try writer.writeAll("\n" ++ template.description ++ "\n");
36 } 36 }
37 37
38 pub fn main(name: []const u8, allocator: Allocator, args: *ArgIterator) !void { 38 pub fn main(name: []const u8, config: Config, args: *ArgIterator) !void {
39 const allocator = config.allocator;
40
39 var diag = clap.Diagnostic{}; 41 var diag = clap.Diagnostic{};
40 var res = clap.parseEx(clap.Help, &params, parsers, args, .{ 42 var res = clap.parseEx(clap.Help, &params, parsers, args, .{
41 .allocator = allocator, 43 .allocator = allocator,
@@ -60,11 +62,7 @@ pub fn SubCommand(comptime template: type) type {
60 return error.ArgError; 62 return error.ArgError;
61 } 63 }
62 64
63 return template.main( 65 return template.main(@TypeOf(res), config, res);
64 clap.ResultEx(clap.Help, &params, parsers),
65 allocator,
66 res,
67 );
68 } 66 }
69 }; 67 };
70} 68}
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");
2const xdg = @import("xdg"); 2const xdg = @import("xdg");
3const zup = @import("zup"); 3const zup = @import("zup");
4 4
5const Allocator = std.mem.Allocator; 5const Config = zup.Config;
6const Installation = zup.Installation; 6const Installation = zup.Installation;
7 7
8pub const params = "<NAME>"; 8pub const params = "<NAME>";
@@ -10,7 +10,9 @@ pub const description = "Switches to a Zig version. Run `zup list -i` to see in
10pub const min_args = 1; 10pub const min_args = 1;
11pub const max_args = 1; 11pub const max_args = 1;
12 12
13pub fn main(comptime Result: type, allocator: Allocator, res: Result) !void { 13pub fn main(comptime Result: type, config: Config, res: Result) !void {
14 const allocator = config.allocator;
15
14 const name = res.positionals[0]; 16 const name = res.positionals[0];
15 if (!try Installation.isInstalled(allocator, name)) { 17 if (!try Installation.isInstalled(allocator, name)) {
16 std.log.err( 18 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 @@
1const std = @import("std"); 1const std = @import("std");
2const zup = @import("zup"); 2const zup = @import("zup");
3 3
4const Allocator = std.mem.Allocator; 4const Config = zup.Config;
5const Installation = zup.Installation; 5const Installation = zup.Installation;
6 6
7// TODO: A way to specify a subset? 7// TODO: A way to specify a subset?
@@ -11,11 +11,13 @@ pub const description = "Updates all installed Zig versions.";
11pub const min_args = 0; 11pub const min_args = 0;
12pub const max_args = 0; 12pub const max_args = 0;
13 13
14pub fn main(comptime Result: type, allocator: Allocator, _: Result) !void { 14pub fn main(comptime Result: type, config: Config, _: Result) !void {
15 const allocator = config.allocator;
16
15 var installed = try Installation.getInstalledList(allocator); 17 var installed = try Installation.getInstalledList(allocator);
16 defer Installation.deinitMap(allocator, &installed); 18 defer Installation.deinitMap(allocator, &installed);
17 19
18 var available = try Installation.getAvailableList(allocator); 20 var available = try Installation.getAvailableList(config);
19 defer Installation.deinitMap(allocator, &available); 21 defer Installation.deinitMap(allocator, &available);
20 22
21 var it = installed.iterator(); 23 var it = installed.iterator();