First commit, things mostly work locally, on linux x86
This commit is contained in:
		
						commit
						86bce941de
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					zig-cache/
 | 
				
			||||||
 | 
					zig-out/
 | 
				
			||||||
							
								
								
									
										70
									
								
								build.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								build.zig
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					const std = @import("std");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Although this function looks imperative, note that its job is to
 | 
				
			||||||
 | 
					// declaratively construct a build graph that will be executed by an external
 | 
				
			||||||
 | 
					// runner.
 | 
				
			||||||
 | 
					pub fn build(b: *std.Build) void {
 | 
				
			||||||
 | 
					    // Standard target options allows the person running `zig build` to choose
 | 
				
			||||||
 | 
					    // what target to build for. Here we do not override the defaults, which
 | 
				
			||||||
 | 
					    // means any target is allowed, and the default is native. Other options
 | 
				
			||||||
 | 
					    // for restricting supported target set are available.
 | 
				
			||||||
 | 
					    const target = b.standardTargetOptions(.{});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Standard optimization options allow the person running `zig build` to select
 | 
				
			||||||
 | 
					    // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
 | 
				
			||||||
 | 
					    // set a preferred release mode, allowing the user to decide how to optimize.
 | 
				
			||||||
 | 
					    const optimize = b.standardOptimizeOption(.{});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const exe = b.addExecutable(.{
 | 
				
			||||||
 | 
					        .name = "zim",
 | 
				
			||||||
 | 
					        // In this case the main source file is merely a path, however, in more
 | 
				
			||||||
 | 
					        // complicated build scripts, this could be a generated file.
 | 
				
			||||||
 | 
					        .root_source_file = .{ .path = "src/main.zig" },
 | 
				
			||||||
 | 
					        .target = target,
 | 
				
			||||||
 | 
					        .optimize = optimize,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // This declares intent for the executable to be installed into the
 | 
				
			||||||
 | 
					    // standard location when the user invokes the "install" step (the default
 | 
				
			||||||
 | 
					    // step when running `zig build`).
 | 
				
			||||||
 | 
					    b.installArtifact(exe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // This *creates* a Run step in the build graph, to be executed when another
 | 
				
			||||||
 | 
					    // step is evaluated that depends on it. The next line below will establish
 | 
				
			||||||
 | 
					    // such a dependency.
 | 
				
			||||||
 | 
					    const run_cmd = b.addRunArtifact(exe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // By making the run step depend on the install step, it will be run from the
 | 
				
			||||||
 | 
					    // installation directory rather than directly from within the cache directory.
 | 
				
			||||||
 | 
					    // This is not necessary, however, if the application depends on other installed
 | 
				
			||||||
 | 
					    // files, this ensures they will be present and in the expected location.
 | 
				
			||||||
 | 
					    run_cmd.step.dependOn(b.getInstallStep());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // This allows the user to pass arguments to the application in the build
 | 
				
			||||||
 | 
					    // command itself, like this: `zig build run -- arg1 arg2 etc`
 | 
				
			||||||
 | 
					    if (b.args) |args| {
 | 
				
			||||||
 | 
					        run_cmd.addArgs(args);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // This creates a build step. It will be visible in the `zig build --help` menu,
 | 
				
			||||||
 | 
					    // and can be selected like this: `zig build run`
 | 
				
			||||||
 | 
					    // This will evaluate the `run` step rather than the default, which is "install".
 | 
				
			||||||
 | 
					    const run_step = b.step("run", "Run the app");
 | 
				
			||||||
 | 
					    run_step.dependOn(&run_cmd.step);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Creates a step for unit testing. This only builds the test executable
 | 
				
			||||||
 | 
					    // but does not run it.
 | 
				
			||||||
 | 
					    const unit_tests = b.addTest(.{
 | 
				
			||||||
 | 
					        .root_source_file = .{ .path = "src/main.zig" },
 | 
				
			||||||
 | 
					        .target = target,
 | 
				
			||||||
 | 
					        .optimize = optimize,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const run_unit_tests = b.addRunArtifact(unit_tests);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Similar to creating the run step earlier, this exposes a `test` step to
 | 
				
			||||||
 | 
					    // the `zig build --help` menu, providing a way for the user to request
 | 
				
			||||||
 | 
					    // running the unit tests.
 | 
				
			||||||
 | 
					    const test_step = b.step("test", "Run unit tests");
 | 
				
			||||||
 | 
					    test_step.dependOn(&run_unit_tests.step);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										237
									
								
								src/main.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								src/main.zig
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,237 @@
 | 
				
			|||||||
 | 
					const std = @import("std");
 | 
				
			||||||
 | 
					const zim = @import("zim.zig");
 | 
				
			||||||
 | 
					const utils = @import("utils.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const string = []const u8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub const ZIM_MAJOR_VER = 0;
 | 
				
			||||||
 | 
					pub const ZIM_MINOR_VER = 0;
 | 
				
			||||||
 | 
					pub const ZIM_BUILD = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The availble arguments for the ZiM program
 | 
				
			||||||
 | 
					const Args = enum(u8) {
 | 
				
			||||||
 | 
					    help,
 | 
				
			||||||
 | 
					    install,
 | 
				
			||||||
 | 
					    list,
 | 
				
			||||||
 | 
					    use,
 | 
				
			||||||
 | 
					    gir,
 | 
				
			||||||
 | 
					    version,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A type of argument for the ZiM program
 | 
				
			||||||
 | 
					const ArgType = enum {
 | 
				
			||||||
 | 
					    single,
 | 
				
			||||||
 | 
					    expectsOneParam,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Allocates a string with the version of Zim, call `allocator.free()` with
 | 
				
			||||||
 | 
					/// the string when done using it.
 | 
				
			||||||
 | 
					pub fn versionStr(allocator: std.mem.Allocator) ![]const u8 {
 | 
				
			||||||
 | 
					    var buf = try allocator.alloc(u8, 10);
 | 
				
			||||||
 | 
					    _ = try std.fmt.bufPrint(buf, "{d}.{d}.{d}", .{ ZIM_MAJOR_VER, ZIM_MINOR_VER, ZIM_BUILD });
 | 
				
			||||||
 | 
					    return buf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns what each argument expects to follow it
 | 
				
			||||||
 | 
					fn get_arg_parse_type(arg: Args) ArgType {
 | 
				
			||||||
 | 
					    return switch (arg) {
 | 
				
			||||||
 | 
					        .help => ArgType.single,
 | 
				
			||||||
 | 
					        .install => ArgType.expectsOneParam,
 | 
				
			||||||
 | 
					        .list => ArgType.expectsOneParam,
 | 
				
			||||||
 | 
					        .use => ArgType.expectsOneParam,
 | 
				
			||||||
 | 
					        .gir => ArgType.single,
 | 
				
			||||||
 | 
					        .version => ArgType.single,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// For a given `Args`, returns a string description of what each does
 | 
				
			||||||
 | 
					fn command_desc(arg: Args) string {
 | 
				
			||||||
 | 
					    return switch (arg) {
 | 
				
			||||||
 | 
					        .help => "  help\t\tDisplays this help message",
 | 
				
			||||||
 | 
					        .install => "  install\tInstall the zig version",
 | 
				
			||||||
 | 
					        .list => "  list\t\tLists all versions available on the system",
 | 
				
			||||||
 | 
					        .use => "  use\t\tSets the active version of zig to use",
 | 
				
			||||||
 | 
					        .version => "  version\t\tPrint out the zim version you are using",
 | 
				
			||||||
 | 
					        .gir => "  gir\t\tPrint out ascii Gir",
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Shows the main help menu for the program
 | 
				
			||||||
 | 
					fn show_help() void {
 | 
				
			||||||
 | 
					    std.debug.print("Welcome to the ZIg version Manager (ZIM)\nHelp Menu:\n\n", .{});
 | 
				
			||||||
 | 
					    inline for (@typeInfo(Args).Enum.fields) |arg_type| {
 | 
				
			||||||
 | 
					        const tag = utils.nameToEnumTag(arg_type.name, Args) catch {
 | 
				
			||||||
 | 
					            unreachable;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        std.debug.print("{s}\n", .{command_desc(tag)});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    std.debug.print("\n", .{});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Shows a help menu for a specific `Args` action, like a help sub-menu
 | 
				
			||||||
 | 
					fn show_context_help(arg: Args) void {
 | 
				
			||||||
 | 
					    switch (arg) {
 | 
				
			||||||
 | 
					        .install => {
 | 
				
			||||||
 | 
					            std.debug.print(
 | 
				
			||||||
 | 
					                \\zim install <version>
 | 
				
			||||||
 | 
					                \\  Used to install zig versions, that will then be available to
 | 
				
			||||||
 | 
					                \\  the `zim use <version>` command.
 | 
				
			||||||
 | 
					                \\
 | 
				
			||||||
 | 
					                \\  To see all available versions to install, run `zim list global`
 | 
				
			||||||
 | 
					                \\
 | 
				
			||||||
 | 
					                \\
 | 
				
			||||||
 | 
					            , .{});
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        .list => {
 | 
				
			||||||
 | 
					            std.debug.print(
 | 
				
			||||||
 | 
					                \\zim list <local or global>
 | 
				
			||||||
 | 
					                \\  Used to list zig versions, either locally or remotely available.
 | 
				
			||||||
 | 
					                \\  Running zim global will make a network request to fetch the latest
 | 
				
			||||||
 | 
					                \\  versions of zig.
 | 
				
			||||||
 | 
					                \\
 | 
				
			||||||
 | 
					                \\
 | 
				
			||||||
 | 
					            , .{});
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        .use => {
 | 
				
			||||||
 | 
					            std.debug.print(
 | 
				
			||||||
 | 
					                \\zim use <version>
 | 
				
			||||||
 | 
					                \\  Used to switch the actively used zig version on the system. If
 | 
				
			||||||
 | 
					                \\  your system PATH environment is set to use `~/.config/zim/zig`.
 | 
				
			||||||
 | 
					                \\  If your system is not setup, you can run `zim init` and cross 
 | 
				
			||||||
 | 
					                \\  your fingers that it supports your setup.
 | 
				
			||||||
 | 
					                \\
 | 
				
			||||||
 | 
					                \\
 | 
				
			||||||
 | 
					            , .{});
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        .gir, .version, .help => {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Given `arg`, does the action with the provided optional `param`
 | 
				
			||||||
 | 
					fn do_arg_action(allocator: std.mem.Allocator, arg: Args, param: ?[]const u8) void {
 | 
				
			||||||
 | 
					    switch (arg) {
 | 
				
			||||||
 | 
					        .help => {
 | 
				
			||||||
 | 
					            show_help();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        .gir => {
 | 
				
			||||||
 | 
					            utils.printGir();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        .version => {
 | 
				
			||||||
 | 
					            const ver = versionStr(allocator) catch {
 | 
				
			||||||
 | 
					                std.debug.print("Error getting version\n", .{});
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            defer allocator.free(ver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (param) |command| {
 | 
				
			||||||
 | 
					                std.debug.print("{s}\nRunning ZiM Version {s}\n", .{ command, ver });
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                std.debug.print("Running ZiM Version {s}\n", .{ver});
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            utils.printGir();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        .install => {
 | 
				
			||||||
 | 
					            if (param == null) {
 | 
				
			||||||
 | 
					                std.debug.print("Error: Expected version to follow\n\n", .{});
 | 
				
			||||||
 | 
					                std.os.exit(1);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const p = param.?;
 | 
				
			||||||
 | 
					            if (std.mem.eql(u8, p, "help")) {
 | 
				
			||||||
 | 
					                show_context_help(arg);
 | 
				
			||||||
 | 
					                std.os.exit(0);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            zim.install(allocator, param.?) catch |err| {
 | 
				
			||||||
 | 
					                std.debug.print("Error running `install {s}`\n{any}", .{ param.?, err });
 | 
				
			||||||
 | 
					                std.os.exit(1);
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        .list => {
 | 
				
			||||||
 | 
					            if (param == null) {
 | 
				
			||||||
 | 
					                std.debug.print("Error: Expected `local` or `global` to follow.\nRun `zim list help` for details.\n\n", .{});
 | 
				
			||||||
 | 
					                std.os.exit(1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const p = param.?;
 | 
				
			||||||
 | 
					            if (std.mem.eql(u8, p, "help")) {
 | 
				
			||||||
 | 
					                show_context_help(arg);
 | 
				
			||||||
 | 
					                std.os.exit(0);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (!std.mem.eql(u8, p, "local") and !std.mem.eql(u8, p, "global")) {
 | 
				
			||||||
 | 
					                std.debug.print("Error: List available versions either `list local` or `list global`\n\n", .{});
 | 
				
			||||||
 | 
					                show_context_help(arg);
 | 
				
			||||||
 | 
					                std.os.exit(1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            zim.list(allocator, param.?) catch |err| {
 | 
				
			||||||
 | 
					                std.debug.print("Error running `list {s}`\n{any}", .{ param.?, err });
 | 
				
			||||||
 | 
					                std.os.exit(1);
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        .use => {
 | 
				
			||||||
 | 
					            if (param == null) {
 | 
				
			||||||
 | 
					                std.debug.print("Error: Expected version to follow\n\n", .{});
 | 
				
			||||||
 | 
					                std.os.exit(1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const p = param.?;
 | 
				
			||||||
 | 
					            if (std.mem.eql(u8, p, "help")) {
 | 
				
			||||||
 | 
					                show_context_help(arg);
 | 
				
			||||||
 | 
					                std.os.exit(0);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            zim.use(allocator, param.?) catch |err| {
 | 
				
			||||||
 | 
					                std.debug.print("Error running `use {s}`\n{any}", .{ param.?, err });
 | 
				
			||||||
 | 
					                std.os.exit(1);
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn main() !void {
 | 
				
			||||||
 | 
					    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
 | 
				
			||||||
 | 
					    const allocator = gpa.allocator();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var args_iter = try std.process.argsWithAllocator(allocator);
 | 
				
			||||||
 | 
					    defer args_iter.deinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // var parsed_args = std.ArrayList(string).init(allocator);
 | 
				
			||||||
 | 
					    // defer parsed_args.deinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const valid = arg_loop: {
 | 
				
			||||||
 | 
					        var index: u8 = 0;
 | 
				
			||||||
 | 
					        const command = args_iter.next();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (args_iter.next()) |arg| {
 | 
				
			||||||
 | 
					            index += 1;
 | 
				
			||||||
 | 
					            const arg_tag = utils.nameToEnumTag(arg, Args) catch {
 | 
				
			||||||
 | 
					                break :arg_loop false;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            var param: ?[]const u8 = null;
 | 
				
			||||||
 | 
					            if (get_arg_parse_type(arg_tag) == ArgType.expectsOneParam) {
 | 
				
			||||||
 | 
					                param = args_iter.next();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (arg_tag == .version) {
 | 
				
			||||||
 | 
					                do_arg_action(
 | 
				
			||||||
 | 
					                    allocator,
 | 
				
			||||||
 | 
					                    arg_tag,
 | 
				
			||||||
 | 
					                    command,
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            do_arg_action(allocator, arg_tag, param);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (index == 0) {
 | 
				
			||||||
 | 
					            show_help();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break :arg_loop true;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!valid) {
 | 
				
			||||||
 | 
					        std.debug.print("Something is not right with the command, try running `zim help` for details.\n", .{});
 | 
				
			||||||
 | 
					        std.os.exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								src/utils.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/utils.zig
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					const std = @import("std");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const enumError = error{EnumFieldNotFound};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn nameToEnumTag(name: []const u8, comptime Enum: type) enumError!Enum {
 | 
				
			||||||
 | 
					    comptime {
 | 
				
			||||||
 | 
					        if (@typeInfo(Enum) != .Enum) {
 | 
				
			||||||
 | 
					            @compileError("Non enum type passed into function: " ++ @typeName(Enum));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline for (@typeInfo(Enum).Enum.fields) |field| {
 | 
				
			||||||
 | 
					        if (std.mem.eql(u8, name, field.name)) {
 | 
				
			||||||
 | 
					            const tag: Enum = @enumFromInt(field.value);
 | 
				
			||||||
 | 
					            return tag;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return enumError.EnumFieldNotFound;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test {
 | 
				
			||||||
 | 
					    const State = enum {
 | 
				
			||||||
 | 
					        good,
 | 
				
			||||||
 | 
					        bad,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const enum_tag = try nameToEnumTag("good", State);
 | 
				
			||||||
 | 
					    try std.testing.expect(enum_tag == State.good);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn printGir() void {
 | 
				
			||||||
 | 
					    std.debug.print(
 | 
				
			||||||
 | 
					        \\                   n    n 
 | 
				
			||||||
 | 
					        \\         o       (        )
 | 
				
			||||||
 | 
					        \\     ___/_      /   I am   \
 | 
				
			||||||
 | 
					        \\    /    / . o (    your    )
 | 
				
			||||||
 | 
					        \\   0>  0 /      \   Doom!  /
 | 
				
			||||||
 | 
					        \\    Lu__/        (        )
 | 
				
			||||||
 | 
					        \\     ||            - u  -
 | 
				
			||||||
 | 
					        \\   o^  ^ o
 | 
				
			||||||
 | 
					        \\ _/ /  /  \_
 | 
				
			||||||
 | 
					        \\    |__|
 | 
				
			||||||
 | 
					        \\ O=>  (O
 | 
				
			||||||
 | 
					        \\
 | 
				
			||||||
 | 
					        \\
 | 
				
			||||||
 | 
					    , .{});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										101
									
								
								src/version.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/version.zig
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					const std = @import("std");
 | 
				
			||||||
 | 
					const string = []const u8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub const ZigVersion = struct {
 | 
				
			||||||
 | 
					    allocator: std.mem.Allocator,
 | 
				
			||||||
 | 
					    version_string: string,
 | 
				
			||||||
 | 
					    tarball_url: ?string,
 | 
				
			||||||
 | 
					    src_tarball_url: ?string,
 | 
				
			||||||
 | 
					    platform_string: ?string,
 | 
				
			||||||
 | 
					    docs_url: ?string,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn init(allocator: std.mem.Allocator, scanner: *std.json.Scanner, ver_string: string) ZigVersion {
 | 
				
			||||||
 | 
					        var version_string = allocator.dupe(u8, ver_string) catch unreachable;
 | 
				
			||||||
 | 
					        var docs_url: ?string = null;
 | 
				
			||||||
 | 
					        var tarball_url: ?string = null;
 | 
				
			||||||
 | 
					        var platform_string: ?string = null;
 | 
				
			||||||
 | 
					        var src_tarball_url: ?string = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var scanning = true;
 | 
				
			||||||
 | 
					        while (scanning) {
 | 
				
			||||||
 | 
					            if (scanner.*.next()) |token| {
 | 
				
			||||||
 | 
					                switch (token) {
 | 
				
			||||||
 | 
					                    .object_begin => {},
 | 
				
			||||||
 | 
					                    .object_end => {
 | 
				
			||||||
 | 
					                        const t_type = scanner.*.peekNextTokenType() catch {
 | 
				
			||||||
 | 
					                            unreachable;
 | 
				
			||||||
 | 
					                        };
 | 
				
			||||||
 | 
					                        if (t_type == std.json.TokenType.object_end) {
 | 
				
			||||||
 | 
					                            scanning = false;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    .string => {
 | 
				
			||||||
 | 
					                        if (std.mem.eql(u8, token.string, "docs")) {
 | 
				
			||||||
 | 
					                            const docs_token = scanner.*.next() catch unreachable;
 | 
				
			||||||
 | 
					                            docs_url = allocator.dupe(u8, docs_token.string) catch unreachable;
 | 
				
			||||||
 | 
					                        } else if (std.mem.eql(u8, token.string, "src")) {
 | 
				
			||||||
 | 
					                            // ignore the object begin
 | 
				
			||||||
 | 
					                            checkNextToken(scanner, .object_begin);
 | 
				
			||||||
 | 
					                            _ = scanner.*.next() catch unreachable;
 | 
				
			||||||
 | 
					                            // ignore tarball string
 | 
				
			||||||
 | 
					                            checkNextToken(scanner, .string);
 | 
				
			||||||
 | 
					                            _ = scanner.*.next() catch unreachable;
 | 
				
			||||||
 | 
					                            const tar_token = scanner.*.next() catch unreachable;
 | 
				
			||||||
 | 
					                            src_tarball_url = allocator.dupe(u8, tar_token.string) catch unreachable;
 | 
				
			||||||
 | 
					                        } else if (std.mem.eql(u8, token.string, "x86_64-linux")) {
 | 
				
			||||||
 | 
					                            platform_string = allocator.dupe(u8, token.string) catch unreachable;
 | 
				
			||||||
 | 
					                            // ignore object begin
 | 
				
			||||||
 | 
					                            checkNextToken(scanner, .object_begin);
 | 
				
			||||||
 | 
					                            _ = scanner.*.next() catch unreachable;
 | 
				
			||||||
 | 
					                            checkNextToken(scanner, .string);
 | 
				
			||||||
 | 
					                            const tar_token = scanner.*.next() catch unreachable;
 | 
				
			||||||
 | 
					                            if (std.mem.eql(u8, tar_token.string, "tarball")) {
 | 
				
			||||||
 | 
					                                const tar_url_token = scanner.*.next() catch unreachable;
 | 
				
			||||||
 | 
					                                tarball_url = allocator.dupe(u8, tar_url_token.string) catch unreachable;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    else => {
 | 
				
			||||||
 | 
					                        unreachable;
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else |err| {
 | 
				
			||||||
 | 
					                std.debug.print("Error scanning in ZigVersion: {any}\n", .{err});
 | 
				
			||||||
 | 
					                scanning = false;
 | 
				
			||||||
 | 
					                unreachable;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ZigVersion{ .allocator = allocator, .version_string = version_string, .tarball_url = tarball_url, .src_tarball_url = src_tarball_url, .platform_string = platform_string, .docs_url = docs_url };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn deinit() void {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn fmtPrint(zv: *const ZigVersion) void {
 | 
				
			||||||
 | 
					        std.debug.print("  zig-{s}\n", .{zv.version_string});
 | 
				
			||||||
 | 
					        if (zv.platform_string) |plat| {
 | 
				
			||||||
 | 
					            std.debug.print("\tplatform: {s}\n", .{plat});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (zv.docs_url) |docs| {
 | 
				
			||||||
 | 
					            std.debug.print("\tdocs_url: {s}\n", .{docs});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (zv.tarball_url) |tar| {
 | 
				
			||||||
 | 
					            std.debug.print("\ttar_url: {s}\n", .{tar});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (zv.src_tarball_url) |tar| {
 | 
				
			||||||
 | 
					            std.debug.print("\tsrc_tar_url: {s}\n", .{tar});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn hasTar(zv: *ZigVersion) bool {
 | 
				
			||||||
 | 
					        return zv.tarball_url != null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn checkNextToken(scanner: *std.json.Scanner, t_type: std.json.TokenType) void {
 | 
				
			||||||
 | 
					    const t = scanner.*.peekNextTokenType() catch unreachable;
 | 
				
			||||||
 | 
					    if (t != t_type) {
 | 
				
			||||||
 | 
					        std.debug.print("Expected to find {any} but got {any}\n", .{ t_type, t });
 | 
				
			||||||
 | 
					        unreachable;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										348
									
								
								src/zim.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										348
									
								
								src/zim.zig
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,348 @@
 | 
				
			|||||||
 | 
					const std = @import("std");
 | 
				
			||||||
 | 
					const utils = @import("utils.zig");
 | 
				
			||||||
 | 
					const version = @import("version.zig");
 | 
				
			||||||
 | 
					const string = []const u8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ZigVersion = version.ZigVersion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ZimError = error{
 | 
				
			||||||
 | 
					    BadParameter,
 | 
				
			||||||
 | 
					    MalformedJson,
 | 
				
			||||||
 | 
					    NetworkError,
 | 
				
			||||||
 | 
					    NotImplemented,
 | 
				
			||||||
 | 
					    NoHomeConfigured,
 | 
				
			||||||
 | 
					    Unexpected,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const BIN_SYM_ZIG_PATH = "bin/zig";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn createSubDir(dir: std.fs.Dir, path: string) ZimError!void {
 | 
				
			||||||
 | 
					    dir.makeDir(path) catch |err| blk: {
 | 
				
			||||||
 | 
					        if (err == error.PathAlreadyExists) {
 | 
				
			||||||
 | 
					            // std.debug.print("{s} already exists\n", .{path});
 | 
				
			||||||
 | 
					            break :blk;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        std.debug.print("Encountered error creating directory {s}: {any}\n", .{ path, err });
 | 
				
			||||||
 | 
					        return ZimError.Unexpected;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn openZimDir(allocator: std.mem.Allocator) ZimError!std.fs.Dir {
 | 
				
			||||||
 | 
					    const home_dir = std.os.getenv("HOME");
 | 
				
			||||||
 | 
					    if (home_dir == null) {
 | 
				
			||||||
 | 
					        return ZimError.NoHomeConfigured;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // std.debug.print("Found home env to be: {s}\n", .{home_dir.?});
 | 
				
			||||||
 | 
					    const zimPath = std.mem.concat(allocator, u8, &[_][]const u8{ home_dir.?, "/.config/zim" }) catch {
 | 
				
			||||||
 | 
					        return ZimError.Unexpected;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    defer allocator.free(zimPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // std.debug.print("Creating zim directory in {s}\n", .{zimPath});
 | 
				
			||||||
 | 
					    std.fs.makeDirAbsolute(zimPath) catch |err| blk: {
 | 
				
			||||||
 | 
					        if (err == error.PathAlreadyExists) {
 | 
				
			||||||
 | 
					            // std.debug.print("Do not need to create new directory\n", .{});
 | 
				
			||||||
 | 
					            break :blk;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        std.debug.print("Error creating directory: {any}\n", .{err});
 | 
				
			||||||
 | 
					        return ZimError.Unexpected;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var zim_dir = std.fs.openDirAbsolute(zimPath, .{}) catch {
 | 
				
			||||||
 | 
					        // std.debug.print("Encountered error opening directory: {any}\n", .{err});
 | 
				
			||||||
 | 
					        return ZimError.Unexpected;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try createSubDir(zim_dir, "bin");
 | 
				
			||||||
 | 
					    try createSubDir(zim_dir, "versions");
 | 
				
			||||||
 | 
					    return zim_dir;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn getLocalVersionsList(
 | 
				
			||||||
 | 
					    allocator: std.mem.Allocator,
 | 
				
			||||||
 | 
					    zim_dir: std.fs.Dir,
 | 
				
			||||||
 | 
					) ZimError!std.ArrayList(string) {
 | 
				
			||||||
 | 
					    var versions_dir = zim_dir.openIterableDir("versions", .{}) catch {
 | 
				
			||||||
 | 
					        return ZimError.Unexpected;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    defer versions_dir.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var ver_walker = versions_dir.walk(allocator) catch {
 | 
				
			||||||
 | 
					        return ZimError.Unexpected;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    defer ver_walker.deinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var versions_list = std.ArrayList(string).init(allocator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var walking = true;
 | 
				
			||||||
 | 
					    while (walking) blk: {
 | 
				
			||||||
 | 
					        var ver = ver_walker.next() catch {
 | 
				
			||||||
 | 
					            walking = false;
 | 
				
			||||||
 | 
					            break :blk;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        if (ver == null) {
 | 
				
			||||||
 | 
					            walking = false;
 | 
				
			||||||
 | 
					            break :blk;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // Dont recursively enter into any of the zig directories
 | 
				
			||||||
 | 
					        if (!std.mem.eql(u8, ver.?.basename, ver.?.path)) {
 | 
				
			||||||
 | 
					            break :blk;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (ver.?.kind == .directory) {
 | 
				
			||||||
 | 
					            const path = ver.?.path;
 | 
				
			||||||
 | 
					            const start_name = path[0..3];
 | 
				
			||||||
 | 
					            if (std.mem.eql(u8, start_name, "zig")) {
 | 
				
			||||||
 | 
					                var p = allocator.dupe(u8, path) catch {
 | 
				
			||||||
 | 
					                    return ZimError.Unexpected;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                versions_list.append(p) catch {
 | 
				
			||||||
 | 
					                    return ZimError.Unexpected;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // std.debug.print("Got entry in `versions:` base: {s}, path: {s}, kind: {any}\n", .{ ver.?.basename, ver.?.path, ver.?.kind });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return versions_list;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn getRemoteVersionsList(allocator: std.mem.Allocator) ZimError!std.ArrayList(ZigVersion) {
 | 
				
			||||||
 | 
					    const versions_json_url = "https://ziglang.org/download/index.json";
 | 
				
			||||||
 | 
					    const versions_json_uri = std.Uri.parse(versions_json_url) catch {
 | 
				
			||||||
 | 
					        return ZimError.Unexpected;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var headers = std.http.Headers{ .allocator = allocator };
 | 
				
			||||||
 | 
					    defer headers.deinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Accept anything.
 | 
				
			||||||
 | 
					    headers.append("accept", "*/*") catch {
 | 
				
			||||||
 | 
					        std.debug.print("Error adding headers\n", .{});
 | 
				
			||||||
 | 
					        return ZimError.Unexpected;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    var client = std.http.Client{ .allocator = allocator };
 | 
				
			||||||
 | 
					    defer client.deinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var request = client.request(.GET, versions_json_uri, headers, .{}) catch {
 | 
				
			||||||
 | 
					        std.debug.print("Error creating request\n", .{});
 | 
				
			||||||
 | 
					        return ZimError.NetworkError;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    defer request.deinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    request.start() catch {
 | 
				
			||||||
 | 
					        std.debug.print("Error starting request\n", .{});
 | 
				
			||||||
 | 
					        return ZimError.NetworkError;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    std.debug.print("Querying ziglang.org for latest zig versions...\n", .{});
 | 
				
			||||||
 | 
					    request.wait() catch {
 | 
				
			||||||
 | 
					        std.debug.print("Error waiting for request\n", .{});
 | 
				
			||||||
 | 
					        return ZimError.NetworkError;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const sixty_four_kilobytes = 65536;
 | 
				
			||||||
 | 
					    const body = request.reader().readAllAlloc(allocator, sixty_four_kilobytes) catch |err| {
 | 
				
			||||||
 | 
					        std.debug.print("Error getting body: {any}\n", .{err});
 | 
				
			||||||
 | 
					        return ZimError.NetworkError;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    defer allocator.free(body);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var diag = std.json.Diagnostics{};
 | 
				
			||||||
 | 
					    var body_scanner = std.json.Scanner.initCompleteInput(allocator, body);
 | 
				
			||||||
 | 
					    body_scanner.enableDiagnostics(&diag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var remote_zig_versions = std.ArrayList(ZigVersion).init(allocator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var scanning = true;
 | 
				
			||||||
 | 
					    var last_version: string = "";
 | 
				
			||||||
 | 
					    while (scanning) {
 | 
				
			||||||
 | 
					        if (body_scanner.next()) |token| {
 | 
				
			||||||
 | 
					            switch (token) {
 | 
				
			||||||
 | 
					                .object_begin => {
 | 
				
			||||||
 | 
					                    const zv = ZigVersion.init(allocator, &body_scanner, last_version);
 | 
				
			||||||
 | 
					                    remote_zig_versions.append(zv) catch {
 | 
				
			||||||
 | 
					                        return ZimError.Unexpected;
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                .end_of_document => {
 | 
				
			||||||
 | 
					                    scanning = false;
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                .string => {
 | 
				
			||||||
 | 
					                    last_version = token.string;
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                else => {},
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else |err| switch (err) {
 | 
				
			||||||
 | 
					            error.SyntaxError => {
 | 
				
			||||||
 | 
					                std.debug.print("Syntax error at line {d} col {d}\n", .{ diag.line_number, diag.getColumn() });
 | 
				
			||||||
 | 
					                scanning = false;
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            else => {
 | 
				
			||||||
 | 
					                std.debug.print("Got error {any}\n", .{err});
 | 
				
			||||||
 | 
					                scanning = false;
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return remote_zig_versions;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ShellType = enum {
 | 
				
			||||||
 | 
					    bash,
 | 
				
			||||||
 | 
					    zsh,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn shellName(s: ?ShellType) string {
 | 
				
			||||||
 | 
					    comptime switch (s) {
 | 
				
			||||||
 | 
					        .bash => "bash",
 | 
				
			||||||
 | 
					        .zsh => "zsh",
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn printZimPathHelp(shell_tag: ?ShellType, zim_path: string) void {
 | 
				
			||||||
 | 
					    if (shell_tag == undefined) {
 | 
				
			||||||
 | 
					        std.debug.print("Unrecognized shell\n", .{});
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const t = "something";
 | 
				
			||||||
 | 
					    _ = t;
 | 
				
			||||||
 | 
					    switch (shell_tag.?) {
 | 
				
			||||||
 | 
					        .bash => {
 | 
				
			||||||
 | 
					            std.debug.print("\nDetected shell as {s}\n", .{@tagName(shell_tag.?)});
 | 
				
			||||||
 | 
					            std.debug.print("For ZiM to work, you need to add\n'{s}'\nto your PATH. To do that, you can\nrun the following command:\n\n", .{zim_path});
 | 
				
			||||||
 | 
					            std.debug.print("\techo \"export PATH={s}:$PATH\" >> ~/.zshrc\n\nOr edit your .zshrc to add it manually.", .{zim_path});
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        .zsh => {
 | 
				
			||||||
 | 
					            std.debug.print("\nDetected shell as {s}\n", .{@tagName(shell_tag.?)});
 | 
				
			||||||
 | 
					            std.debug.print("For ZiM to work, you need to add\n'{s}'\nto your PATH. To do that, you can\nrun the following command:\n\n", .{zim_path});
 | 
				
			||||||
 | 
					            std.debug.print("\techo \"export PATH={s}:$PATH\" >> ~/.zshrc\n\nOr edit your .zshrc to add it manually.", .{zim_path});
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn install(allocator: std.mem.Allocator, param: string) ZimError!void {
 | 
				
			||||||
 | 
					    _ = param;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var zim_dir = try openZimDir(allocator);
 | 
				
			||||||
 | 
					    defer zim_dir.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ZimError.NotImplemented;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn use(allocator: std.mem.Allocator, param: string) ZimError!void {
 | 
				
			||||||
 | 
					    var zim_dir = try openZimDir(allocator);
 | 
				
			||||||
 | 
					    defer zim_dir.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var versions_list = try getLocalVersionsList(allocator, zim_dir);
 | 
				
			||||||
 | 
					    defer versions_list.deinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const version_num = std.fmt.parseInt(u8, param, 0) catch null;
 | 
				
			||||||
 | 
					    if (version_num != null) {
 | 
				
			||||||
 | 
					        const num = version_num.?;
 | 
				
			||||||
 | 
					        if (num > versions_list.items.len) {
 | 
				
			||||||
 | 
					            std.debug.print("{d} exceeds the range of available versions: {d}\n", .{ num, versions_list.items.len });
 | 
				
			||||||
 | 
					            return ZimError.BadParameter;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const ver_path = versions_list.items[version_num.? - 1];
 | 
				
			||||||
 | 
					        std.debug.print("Using version {s}\n", .{ver_path});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const zim_path = zim_dir.realpathAlloc(allocator, "./") catch "err";
 | 
				
			||||||
 | 
					        defer allocator.free(zim_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const target_version_path = std.mem.concat(allocator, u8, &[_][]const u8{ zim_path, "/versions/", ver_path }) catch {
 | 
				
			||||||
 | 
					            return ZimError.Unexpected;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        defer allocator.free(target_version_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        zim_dir.deleteFile(BIN_SYM_ZIG_PATH) catch |err| {
 | 
				
			||||||
 | 
					            if (err != error.FileNotFound) {
 | 
				
			||||||
 | 
					                std.debug.print("Error deleting old link: {any}\n", .{err});
 | 
				
			||||||
 | 
					                return ZimError.Unexpected;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        std.debug.print("Creating sym link to {s}\n", .{target_version_path});
 | 
				
			||||||
 | 
					        zim_dir.symLink(target_version_path, BIN_SYM_ZIG_PATH, .{ .is_directory = true }) catch |err| {
 | 
				
			||||||
 | 
					            std.debug.print("Could not link new version: {any}\n", .{err});
 | 
				
			||||||
 | 
					            return ZimError.Unexpected;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const path_environment = std.os.getenv("PATH");
 | 
				
			||||||
 | 
					        if (path_environment) |path_env| {
 | 
				
			||||||
 | 
					            if (!std.mem.containsAtLeast(u8, path_env, 1, zim_path)) {
 | 
				
			||||||
 | 
					                var shell_tag: ?ShellType = null;
 | 
				
			||||||
 | 
					                const shell_env = std.os.getenv("SHELL");
 | 
				
			||||||
 | 
					                if (shell_env) |s| {
 | 
				
			||||||
 | 
					                    var split = std.mem.splitSequence(u8, s, "/");
 | 
				
			||||||
 | 
					                    var shell: []const u8 = "";
 | 
				
			||||||
 | 
					                    while (split.next()) |field| {
 | 
				
			||||||
 | 
					                        shell = field;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    shell_tag = utils.nameToEnumTag(shell, ShellType) catch null;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                const shell_bin_path =
 | 
				
			||||||
 | 
					                    std.mem.concat(allocator, u8, &[_][]const u8{ zim_path, "/", BIN_SYM_ZIG_PATH }) catch "<ZimERR>";
 | 
				
			||||||
 | 
					                printZimPathHelp(
 | 
				
			||||||
 | 
					                    shell_tag,
 | 
				
			||||||
 | 
					                    shell_bin_path,
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        std.debug.print("Using raw string version {s}\n", .{param});
 | 
				
			||||||
 | 
					        return ZimError.NotImplemented;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // std.debug.print("Local Zig Versions:\n", .{});
 | 
				
			||||||
 | 
					    // var i: u8 = 0;
 | 
				
			||||||
 | 
					    // while (versions_list.popOrNull()) |version| {
 | 
				
			||||||
 | 
					    //     std.debug.print("\n  [{d}]\tZig Version {s}", .{ i + 1, version });
 | 
				
			||||||
 | 
					    //     i += 1;
 | 
				
			||||||
 | 
					    // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ZimListType = enum { local, global };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Runs the `list` subcommand
 | 
				
			||||||
 | 
					pub fn list(allocator: std.mem.Allocator, param: string) !void {
 | 
				
			||||||
 | 
					    const list_type = utils.nameToEnumTag(param, ZimListType) catch {
 | 
				
			||||||
 | 
					        std.debug.print("Unexpected parameter to `list`: {s}\n", .{param});
 | 
				
			||||||
 | 
					        return ZimError.BadParameter;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    switch (list_type) {
 | 
				
			||||||
 | 
					        .local => {
 | 
				
			||||||
 | 
					            var zim_dir = try openZimDir(allocator);
 | 
				
			||||||
 | 
					            defer zim_dir.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var versions_list = try getLocalVersionsList(allocator, zim_dir);
 | 
				
			||||||
 | 
					            defer versions_list.deinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            std.debug.print("Local Zig Versions:\n", .{});
 | 
				
			||||||
 | 
					            var i: u8 = 0;
 | 
				
			||||||
 | 
					            while (versions_list.popOrNull()) |version_str| {
 | 
				
			||||||
 | 
					                std.debug.print("\n  [{d}]\tZig Version {s}", .{ i + 1, version_str });
 | 
				
			||||||
 | 
					                i += 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            std.debug.print("\n", .{});
 | 
				
			||||||
 | 
					            std.debug.print(
 | 
				
			||||||
 | 
					                \\
 | 
				
			||||||
 | 
					                \\  Run `zim use` to select which version you want active in your environment.
 | 
				
			||||||
 | 
					                \\  You can also just specify the index of the version you would like to use.
 | 
				
			||||||
 | 
					                \\
 | 
				
			||||||
 | 
					            , .{});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        .global => {
 | 
				
			||||||
 | 
					            var remote_versions = try getRemoteVersionsList(allocator);
 | 
				
			||||||
 | 
					            if (remote_versions.items.len == 0) {
 | 
				
			||||||
 | 
					                std.debug.print("Failed to get remote versions\n", .{});
 | 
				
			||||||
 | 
					                return ZimError.Unexpected;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            std.debug.print("Retrieved remote zig versions:\n", .{});
 | 
				
			||||||
 | 
					            for (remote_versions.items) |remote_version| {
 | 
				
			||||||
 | 
					                remote_version.fmtPrint();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user