feat: zupper tracks what version is in use

This commit is contained in:
LordMZTE 2022-12-07 12:22:29 +01:00
parent 22c39a6712
commit aef6ee81aa
Signed by: LordMZTE
GPG key ID: B64802DC33A64FF6
9 changed files with 135 additions and 56 deletions

View file

@ -1,6 +1,6 @@
pkgs:
zupper:
version: 0.1.0
version: 0.2.0
description: Zig version manager
license: GPL-3.0
source_url: "https://mzte.de/git/LordMZTE/zupper"

View file

@ -4,6 +4,7 @@ const json = @import("json");
const getty = @import("getty");
versions: std.StringHashMap(std.SemanticVersion),
in_use: ?[]u8 = null,
const Self = @This();
@ -91,6 +92,17 @@ pub fn removeVersion(self: *Self, version: []const u8) void {
}
}
pub fn setInUse(self: *Self, in_use: ?[]const u8) !void {
if (self.in_use) |old| {
self.versions.allocator.free(old);
}
if (in_use) |v| {
const dup = try self.versions.allocator.dupe(u8, v);
self.in_use = dup;
}
}
pub fn save(self: *Self) !void {
const mpath = try path(self.versions.allocator);
defer self.versions.allocator.free(mpath);

View file

@ -1,6 +1,6 @@
const std = @import("std");
pub const version = "0.1.0";
pub const version = "0.2.0";
pub const Info = struct {};
@ -13,6 +13,7 @@ pub const Install = struct {
};
pub const Uninstall = struct {};
pub const Unuse = struct {};
pub const Update = struct {};
pub const Use = struct {};
@ -28,6 +29,7 @@ pub const Args = union(enum) {
info: Info,
install: Install,
uninstall: Uninstall,
unuse: Unuse,
update: Update,
use: Use,
};
@ -42,9 +44,10 @@ const help_s =
\\Subcommands:
\\ {[a0]s} info prints information about the setup
\\ {[a0]s} install <VERSIONS...> [--use, -u] downloads the given zig versions and optionally uses them
\\ {[a0]s} uninstall <VERSIONS...> uninstall the given versions
\\ {[a0]s} unuse unuse the version currently in use (essentially a soft-uninstall)
\\ {[a0]s} update [VERSIONS...] update the given version, or all versions if none are given
\\ {[a0]s} use <VERSION> uses the given version by symlinking the compiler into $PATH
\\ {[a0]s} uninstall <VERSIONS...> uninstall the given versions
\\
;

View file

@ -69,6 +69,6 @@ pub fn run(
}
if (args.use) {
try dirs.useVersion(alloc, home, positionals[0]);
try dirs.useVersion(alloc, manifest, home, positionals[0]);
}
}

View file

@ -32,5 +32,9 @@ pub fn run(
std.log.info("deleting {s}", .{ver_path});
manifest.removeVersion(version);
try std.fs.cwd().deleteTree(ver_path);
if (manifest.in_use != null and std.mem.eql(u8, manifest.in_use.?, version)) {
try dirs.unuseCurrentVersion(alloc, manifest);
}
}
}

25
src/commands/unuse.zig Normal file
View file

@ -0,0 +1,25 @@
const std = @import("std");
const dirs = @import("../dirs.zig");
const Manifest = @import("../Manifest.zig");
const Args = @import("../args.zig").Unuse;
pub fn run(
alloc: std.mem.Allocator,
manifest: *Manifest,
args: Args,
positionals: []const [:0]const u8,
) !void {
_ = args;
if (positionals.len != 0) {
std.log.err("expected exactly 0 positional arguments", .{});
return error.Explained;
}
if (manifest.in_use == null) {
std.log.err("no version currently in use!", .{});
return error.Explained;
}
try dirs.unuseCurrentVersion(alloc, manifest);
}

View file

@ -1,9 +1,11 @@
const std = @import("std");
const dirs = @import("../dirs.zig");
const Manifest = @import("../Manifest.zig");
const Args = @import("../args.zig").Use;
pub fn run(
alloc: std.mem.Allocator,
manifest: *Manifest,
args: Args,
positionals: []const [:0]const u8,
) !void {
@ -22,5 +24,5 @@ pub fn run(
return error.Explained;
}
try dirs.useVersion(alloc, home, positionals[0]);
try dirs.useVersion(alloc, manifest, home, positionals[0]);
}

View file

@ -1,5 +1,6 @@
const std = @import("std");
const kf = @import("known-folders");
const Manifest = @import("Manifest.zig");
pub fn zupperHome(alloc: std.mem.Allocator) ![]const u8 {
const datapath = (try kf.getPath(alloc, .data)) orelse return error.GetDataFolder;
@ -21,9 +22,44 @@ pub fn isVersionInstalled(alloc: std.mem.Allocator, home: []const u8, version: [
return true;
}
pub fn useVersion(alloc: std.mem.Allocator, home: []const u8, version: []const u8) !void {
pub fn binInstallationPath(alloc: std.mem.Allocator) !?[]u8 {
switch (@import("builtin").os.tag) {
.linux => {
const user_home = (try kf.getPath(alloc, .home)) orelse return error.GetHomeDir;
defer alloc.free(user_home);
return try std.fs.path.join(alloc, &.{ user_home, ".local", "bin" });
},
.windows => {
return try std.fs.selfExeDirPathAlloc(alloc);
},
.macos => {
const user_home = (try kf.getPath(alloc, .home)) orelse return error.GetHomeDir;
defer alloc.free(user_home);
// not sure if this is the correct path. mac got kind of a windowsy situation too
return try std.fs.path.join(alloc, &.{ user_home, "Applications" });
},
else => {
return null;
},
}
}
pub fn useVersion(
alloc: std.mem.Allocator,
manifest: *Manifest,
home: []const u8,
version: []const u8,
) !void {
if (manifest.in_use != null and std.mem.eql(u8, manifest.in_use.?, version)) {
std.log.err("version '{s}' is already in use!", .{version});
return error.Explained;
}
if (!try isVersionInstalled(alloc, home, version)) {
std.log.err("this version isn't installed! have you tried installing it first?", .{});
std.log.err(
"version '{s}' isn't installed! have you tried installing it first?",
.{version},
);
return error.Explained;
}
@ -45,36 +81,22 @@ pub fn useVersion(alloc: std.mem.Allocator, home: []const u8, version: []const u
return error.Explained;
};
const target_binary_directory = switch (@import("builtin").os.tag) {
.linux => blk: {
const user_home = (try kf.getPath(alloc, .home)) orelse return error.GetHomeDir;
defer alloc.free(user_home);
break :blk try std.fs.path.join(alloc, &.{ user_home, ".local", "bin" });
},
.windows => blk: {
std.log.warn(
\\installing on windows! windows is so bad, it can't get it's conventions
\\for locally installed programs right. i'll use my own install directory...
,
.{},
);
if (@import("builtin").os.tag == .windows) {
std.log.warn(
\\installing on windows! windows is so bad, it can't get it's conventions
\\for locally installed programs right. i'll use my own install directory...
,
.{},
);
}
break :blk try std.fs.selfExeDirPathAlloc(alloc);
},
.macos => blk: {
const user_home = (try kf.getPath(alloc, .home)) orelse return error.GetHomeDir;
defer alloc.free(user_home);
// not sure if this is the correct path. mac got kind of a windowsy situation too
break :blk try std.fs.path.join(alloc, &.{ user_home, "Applications" });
},
else => {
std.log.err(
"using a version isn't supported on {s}. please install the zig binary @ '{s}' manually",
.{ @tagName(@import("builtin").os.tag), zig_exe_path },
);
const target_binary_directory = try binInstallationPath(alloc) orelse {
std.log.err(
"using a version isn't supported on {s}. please install the zig binary @ '{s}' manually",
.{ @tagName(@import("builtin").os.tag), zig_exe_path },
);
return;
},
return;
};
defer alloc.free(target_binary_directory);
@ -92,4 +114,28 @@ pub fn useVersion(alloc: std.mem.Allocator, home: []const u8, version: []const u
}
};
try std.fs.cwd().symLink(zig_exe_path, target_binary, .{});
try manifest.setInUse(version);
}
pub fn unuseCurrentVersion(
alloc: std.mem.Allocator,
manifest: *Manifest,
) !void {
const install_dir = try binInstallationPath(alloc) orelse return;
defer alloc.free(install_dir);
const target_binary = try std.fs.path.join(alloc, &.{
install_dir,
comptime "zig" ++ @import("builtin").target.exeFileExt(),
});
defer alloc.free(target_binary);
std.log.info("unusing zig installation @ {s}", .{target_binary});
try std.fs.cwd().deleteFile(target_binary);
if (manifest.in_use) |old| {
manifest.versions.allocator.free(old);
}
manifest.in_use = null;
}

View file

@ -38,42 +38,29 @@ fn runCmd(alloc: std.mem.Allocator, opts: anytype) !void {
try args.printHelp(alloc);
return error.Explained;
};
var manifest = try Manifest.load(alloc);
defer manifest.deinit();
switch (verb) {
.info => |a| {
var manifest = try Manifest.load(alloc);
defer manifest.deinit();
try @import("commands/info.zig").run(alloc, &manifest, a, opts.positionals);
try manifest.save();
},
.install => |a| {
var manifest = try Manifest.load(alloc);
defer manifest.deinit();
try @import("commands/install.zig").run(alloc, &manifest, a, opts.positionals);
try manifest.save();
},
.update => |a| {
var manifest = try Manifest.load(alloc);
defer manifest.deinit();
try @import("commands/update.zig").run(alloc, &manifest, a, opts.positionals);
try manifest.save();
},
.use => |a| {
try @import("commands/use.zig").run(alloc, a, opts.positionals);
try @import("commands/use.zig").run(alloc, &manifest, a, opts.positionals);
},
.uninstall => |a| {
var manifest = try Manifest.load(alloc);
defer manifest.deinit();
try @import("commands/uninstall.zig").run(alloc, &manifest, a, opts.positionals);
try manifest.save();
},
.unuse => |a| {
try @import("commands/unuse.zig").run(alloc, &manifest, a, opts.positionals);
},
}
try manifest.save();
}