commit e163eb0e9cd9e2451ca7b5e1e639ed69db50ecab
parent 526335ffac7ca5ee620a3c6cbc654317dbddcc5f
Author: Martin Ashby <martin@ashbysoft.com>
Date: Mon, 27 May 2024 22:12:27 +0100
Add list command
Diffstat:
M | src/main.zig | | | 72 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ |
1 file changed, 66 insertions(+), 6 deletions(-)
diff --git a/src/main.zig b/src/main.zig
@@ -43,12 +43,20 @@ pub fn main() !void {
.defaultargvalue = defaultCacheDir,
};
try ap.addFlag(&cacheDirFlag);
+ var listFlag: ArgParse.Flag = .{
+ .long = "list",
+ .short = "l",
+ .description = "List available zig versions",
+ .hasarg = false,
+ };
+ try ap.addFlag(&listFlag);
if (!try ap.parseOrHelp()) {
return;
}
const installDirPath = installDirFlag.argvalue orelse return error.MissingArg;
const cacheDirPath = cacheDirFlag.argvalue orelse return error.MissingArg;
const version = versionArg.value orelse return error.MissingArg;
+ const currentDirName = "current";
// Check the install dir is present in PATH, warn if it isn't
var toks = std.mem.splitScalar(u8, path, ':');
@@ -95,11 +103,57 @@ pub fn main() !void {
defer rdr.deinit();
var doc = try std.json.parseFromTokenSource(std.json.Value, a, &rdr, .{});
defer doc.deinit();
+
+ if (listFlag.waspresent) {
+ // List the files present in .zigvm, store in a hashmap
+ var hm: std.StringHashMapUnmanaged(void) = .{};
+ defer {
+ var i = hm.iterator();
+ while (i.next()) |*e| {
+ a.free(e.key_ptr.*);
+ }
+ hm.deinit(a);
+ }
+ var it = cacheDir.iterate();
+ while (try it.next()) |e| {
+ try hm.put(a, try a.dupe(u8, e.name), undefined);
+ }
+ // Check what the 'current' directory is symlinked to
+ const currentLink = try cacheDir.realpathAlloc(a, currentDirName);
+ defer a.free(currentLink);
+ const currentLinkBasename = std.fs.path.basename(currentLink);
+ const currentTarball = try std.fmt.allocPrint(a, "{s}.tar.xz", .{currentLinkBasename});
+ defer a.free(currentTarball);
+ const wtr = std.io.getStdOut().writer();
+ var vit = doc.value.object.iterator();
+ while (vit.next()) |e| {
+ const versionObj = e.value_ptr.object;
+ const versionObjForArch = versionObj.get(tuple) orelse continue;
+ const tarballUrl = versionObjForArch.object.get("tarball").?.string;
+ const tarballName = try baseNameFromUrl(a, tarballUrl);
+ defer a.free(tarballName);
+ const isPresent = hm.contains(tarballName);
+ const isCurrent = std.mem.eql(u8, tarballName, currentTarball);
+ try std.fmt.format(wtr, "version: {s}", .{e.key_ptr.*});
+ if (versionObj.get("version")) |vs| {
+ try std.fmt.format(wtr, " ({s})", .{vs.string});
+ }
+ if (isPresent) {
+ try wtr.writeAll(", downloaded");
+ }
+ if (isCurrent) {
+ try wtr.writeAll(", current");
+ }
+ try wtr.writeByte('\n');
+ }
+ return;
+ }
+
const versionDoc: std.json.Value = doc.value.object.get(version) orelse return error.ZigVersionNotFound;
const versionString = if (versionDoc.object.get("version")) |versionObj| versionObj.string else version;
std.log.info("version {s} mapped to {s}", .{ version, versionString });
- // // Fetch the version if necessary
+ // Fetch the version if necessary
const systemVersion = versionDoc.object.get(tuple) orelse return error.SystemNotFound;
const tarballUrlObj = systemVersion.object.get("tarball") orelse return error.InvalidIndex;
const tarballHashObj = systemVersion.object.get("shasum") orelse return error.InvalidIndex;
@@ -110,10 +164,7 @@ pub fn main() !void {
return error.UnsupportedFileFormat;
}
- const tarballUri = try std.Uri.parse(tarballUrl);
- const tarballUriPath = try std.fmt.allocPrint(a, "{path}", .{tarballUri.path});
- defer a.free(tarballUriPath);
- const tarballBasename = std.fs.path.basename(tarballUriPath);
+ const tarballBasename = try baseNameFromUrl(a, tarballUrl);
std.log.info("basename: {s}", .{tarballBasename});
const tarballPath = try std.fs.path.join(a, &.{ cacheDirPath, tarballBasename });
defer a.free(tarballPath);
@@ -163,7 +214,7 @@ pub fn main() !void {
};
// then symlink the selected dir to 'current'
- const currentDirName = "current";
+
cacheDir.deleteFile(currentDirName) catch |e| switch (e) {
error.FileNotFound => {},
else => return e,
@@ -184,6 +235,15 @@ pub fn main() !void {
std.log.info("done!", .{});
}
+// Caller owns the result and must free it with a.
+fn baseNameFromUrl(a: std.mem.Allocator, url: []const u8) ![]const u8 {
+ const tarballUri = try std.Uri.parse(url);
+ const tarballUriPath = try std.fmt.allocPrint(a, "{path}", .{tarballUri.path});
+ defer a.free(tarballUriPath);
+ const tarballBasename = std.fs.path.basename(tarballUriPath);
+ return try a.dupe(u8, tarballBasename);
+}
+
const ClientWithBuffer = struct {
client: *std.http.Client,
buffer: [std.mem.page_size]u8 = .{0} ** std.mem.page_size,