Skip to content

Commit eb726f7

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

File tree

4 files changed

+266
-18
lines changed

4 files changed

+266
-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: 65 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,25 @@ pub fn main() !void {
6173
.{ .with_compilers = with_compilers },
6274
&shared_sibling_state,
6375
);
76+
77+
// we need to patch the old install dir
78+
const input_install_dir = blk: {
79+
var file = try std.fs.cwd().openFile(install_dir_setting_path, .{});
80+
defer file.close();
81+
break :blk try file.readToEndAlloc(arena, std.math.maxInt(usize));
82+
};
83+
defer arena.free(input_install_dir);
84+
switch (parseInstallDir(input_install_dir)) {
85+
.good => |input_install_dir_parsed| {
86+
std.debug.assert(std.mem.eql(u8, install_dir_parsed.cache_o, input_install_dir_parsed.cache_o));
87+
var file = try std.fs.cwd().createFile(install_dir_setting_path, .{});
88+
defer file.close();
89+
try file.writer().writeAll(install_dir);
90+
},
91+
.bad => {
92+
// the install dir must have been customized, we'll keep it
93+
},
94+
}
6495
}
6596

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

93124
var argv = std.ArrayList([]const u8).init(arena);
94125
try argv.append(zigup_exe);
126+
try argv.append("--appdata");
127+
try argv.append(appdata);
95128
try argv.append("--path-link");
96129
try argv.append(path_link);
97-
try argv.append("--install-dir");
98-
try argv.append(install_dir);
99130
try argv.appendSlice(zigup_args);
100131

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

103142
if (add_path) {
@@ -156,6 +195,30 @@ pub fn main() !void {
156195
}
157196
}
158197

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

0 commit comments

Comments
 (0)