Skip to content

Commit d0c1e9a

Browse files
committed
add persistent install-dir setting
1 parent a9b48e4 commit d0c1e9a

File tree

4 files changed

+265
-18
lines changed

4 files changed

+265
-18
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,10 @@ zigup run <version> <args>...
4343

4444
# How the compilers are managed
4545

46-
zigup stores each compiler in a global "install directory" in a versioned subdirectory. On posix systems the "install directory" is `$HOME/.local/share/zigup` (or `$XDG_DATA_HOME/zigup`; see below) and on windows the install directory will be a directory named "zig" in the same directory as the "zigup.exe".
46+
zigup stores each compiler in a global "install directory" in a versioned subdirectory. Run `zigup get-install-dir` to see what this PATH is on your system. You can change this default with `zigup set-install-dir PATH`.
4747

4848
zigup makes the zig program available by creating an entry in a directory that occurs in the `PATH` environment variable. On posix systems this entry is a symlink to one of the `zig` executables in the install directory. On windows this is an executable that forwards invocations to one of the `zig` executables in the install directory.
4949

50-
Both the "install directory" and "path link" are configurable through command-line options `--install-dir` and `--path-link` respectively. On posix systems the default "install directory" follows the [XDG basedir spec](https://specifications.freedesktop.org/basedir-spec/latest/#variables), ie. `$XDG_DATA_HOME/zigup` or `$HOME/.local/share/zigup` if `XDG_DATA_HOME` environment variable is empty or undefined.
5150
# Building
5251

5352
Run `zig build` to build, `zig build test` to test and install with:

build.zig

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,47 @@ fn addTests(
261261
},
262262
});
263263

264+
tests.addWithClean(.{
265+
.name = "test-get-install-dir",
266+
.argv = &.{"get-install-dir"},
267+
});
268+
tests.addWithClean(.{
269+
.name = "test-get-install-dir2",
270+
.argv = &.{ "--install-dir", "/a/fake/install/dir", "get-install-dir" },
271+
.checks = &.{
272+
.{ .expect_stdout_exact = "/a/fake/install/dir\n" },
273+
},
274+
});
275+
tests.addWithClean(.{
276+
.name = "test-set-install-dir-relative",
277+
.argv = &.{ "set-install-dir", "foo/bar" },
278+
.checks = &.{
279+
.{ .expect_stderr_match = "error: set-install-dir requires an absolute path" },
280+
},
281+
});
282+
283+
{
284+
// just has to be an absolute path that exists
285+
const install_dir = b.build_root.path.?;
286+
const with_install_dir = tests.add(.{
287+
.name = "test-set-install-dir",
288+
.argv = &.{ "set-install-dir", install_dir },
289+
});
290+
tests.addWithClean(.{
291+
.name = "test-get-install-dir3",
292+
.argv = &.{"get-install-dir"},
293+
.env = .{ .dir = with_install_dir },
294+
.checks = &.{
295+
.{ .expect_stdout_exact = b.fmt("{s}\n", .{install_dir}) },
296+
},
297+
});
298+
tests.addWithClean(.{
299+
.name = "test-revert-install-dir",
300+
.argv = &.{"set-install-dir"},
301+
.env = .{ .dir = with_install_dir },
302+
});
303+
}
304+
264305
tests.addWithClean(.{
265306
.name = "test-no-default",
266307
.argv = &.{"default"},

runtest.zig

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,23 @@ pub fn main() !void {
4545
// try file.writer().print("this file marks this directory as the output for test: {s}\n", .{test_name});
4646
// }
4747

48+
const appdata = try std.fs.path.join(arena, &.{ out_env_dir, "appdata" });
4849
const path_link = try std.fs.path.join(arena, &.{ out_env_dir, "zig" ++ exe_ext });
4950
const install_dir = try std.fs.path.join(arena, &.{ out_env_dir, "install" });
51+
const install_dir_parsed = switch (parseInstallDir(install_dir)) {
52+
.good => |p| p,
53+
.bad => |reason| std.debug.panic("failed to parse install dir '{s}': {s}", .{ install_dir, reason }),
54+
};
55+
56+
const install_dir_setting_path = try std.fs.path.join(arena, &.{ appdata, "install-dir" });
57+
defer arena.free(install_dir_setting_path);
5058

5159
if (std.mem.eql(u8, in_env_dir, "--no-input-environment")) {
5260
try std.fs.cwd().makeDir(install_dir);
61+
try std.fs.cwd().makeDir(appdata);
62+
var file = try std.fs.cwd().createFile(install_dir_setting_path, .{});
63+
defer file.close();
64+
try file.writer().writeAll(install_dir);
5365
} else {
5466
var shared_sibling_state: SharedSiblingState = .{};
5567
try copyEnvDir(
@@ -61,6 +73,24 @@ pub fn main() !void {
6173
.{ .with_compilers = with_compilers },
6274
&shared_sibling_state,
6375
);
76+
77+
const input_install_dir = blk: {
78+
var file = try std.fs.cwd().openFile(install_dir_setting_path, .{});
79+
defer file.close();
80+
break :blk try file.readToEndAlloc(arena, std.math.maxInt(usize));
81+
};
82+
defer arena.free(input_install_dir);
83+
switch (parseInstallDir(input_install_dir)) {
84+
.good => |input_install_dir_parsed| {
85+
std.debug.assert(std.mem.eql(u8, install_dir_parsed.cache_o, input_install_dir_parsed.cache_o));
86+
var file = try std.fs.cwd().createFile(install_dir_setting_path, .{});
87+
defer file.close();
88+
try file.writer().writeAll(install_dir);
89+
},
90+
.bad => {
91+
// the install dir must have been customized, keep it
92+
},
93+
}
6494
}
6595

6696
var maybe_second_bin_dir: ?[]const u8 = null;
@@ -92,12 +122,20 @@ pub fn main() !void {
92122

93123
var argv = std.ArrayList([]const u8).init(arena);
94124
try argv.append(zigup_exe);
125+
try argv.append("--appdata");
126+
try argv.append(appdata);
95127
try argv.append("--path-link");
96128
try argv.append(path_link);
97-
try argv.append("--install-dir");
98-
try argv.append(install_dir);
99129
try argv.appendSlice(zigup_args);
100130

131+
if (true) {
132+
try std.io.getStdErr().writer().writeAll("runtest exec: ");
133+
for (argv.items) |arg| {
134+
try std.io.getStdErr().writer().print(" {s}", .{arg});
135+
}
136+
try std.io.getStdErr().writer().writeAll("\n");
137+
}
138+
101139
var child = std.process.Child.init(argv.items, arena);
102140

103141
if (add_path) {
@@ -156,6 +194,30 @@ pub fn main() !void {
156194
}
157195
}
158196

197+
const ParsedInstallDir = struct {
198+
test_name: []const u8,
199+
hash: []const u8,
200+
cache_o: []const u8,
201+
};
202+
fn parseInstallDir(install_dir: []const u8) union(enum) {
203+
good: ParsedInstallDir,
204+
bad: []const u8,
205+
} {
206+
{
207+
const name = std.fs.path.basename(install_dir);
208+
if (!std.mem.eql(u8, name, "install")) return .{ .bad = "did not end with 'install'" };
209+
}
210+
const test_dir = std.fs.path.dirname(install_dir) orelse return .{ .bad = "missing test dir" };
211+
const test_name = std.fs.path.basename(test_dir);
212+
const cache_dir = std.fs.path.dirname(test_dir) orelse return .{ .bad = "missing cache/hash dir" };
213+
const hash = std.fs.path.basename(cache_dir);
214+
return .{ .good = .{
215+
.test_name = test_name,
216+
.hash = hash,
217+
.cache_o = std.fs.path.dirname(cache_dir) orelse return .{ .bad = "missing cache o dir" },
218+
} };
219+
}
220+
159221
fn containsCompiler(compilers: []const u8, compiler: []const u8) bool {
160222
var it = std.mem.splitScalar(u8, compilers, ',');
161223
while (it.next()) |c| {

0 commit comments

Comments
 (0)