Browse Source

add keep and unkeep commands (#7)

* add keep and unkeep commands

* refactor to less code

* update readme

* remove unkeep but add arg to clean

* change help

* consilidate clean

* clean up

* more clean up

* more more cleanup
g-w1 4 years ago
parent
commit
74aa0ca368
3 changed files with 87 additions and 33 deletions
  1. 7 2
      README.md
  2. 4 3
      test
  3. 76 28
      zigup.zig

+ 7 - 2
README.md

@@ -22,6 +22,12 @@ zigup default <version>
 
 # list the installed compiler versions
 zigup list
+
+# clean compilers that are not the default, not master, and not marked to keep. when a version is specified, it will clean that version
+zigup clean [<version>]
+
+# mark a compiler to keep
+zigup keep <version>
 ```
 
 # Configuration
@@ -49,13 +55,12 @@ My breakdown of the operations I'd like.
 * set/get the default compiler (sets the link/script in PATH) (`zigup default` and `zigup default <version>`)
 * set/clear the "keep" flag on a compiler.  Each keep flag can also have a note explaining why it's being kept.
 * clean (cleans compilers without the "keep" flag and aren't the default)
+* keep a compiler (in conjunction with clean)
 * set/remove compiler in current environment. Probably require creating a bash/batch script that the user could source for each installed compiler.
 * setup the environment for a specific version of the compiler?
 
 * download zig index file (`zigup fetch-index`)
 
-I think to manage compilers, users can mark them as "keep".  The tool will "keep" all compilers marked as "keep" and also the default compiler. I could probably just create an empty file called "keep" to make that mark.
-
 > NOTE: by default `zigup list` should display more information, like release date, its "keep" value, etc.  Maybe it should also sort them, probably by release date?
 
 # Building

+ 4 - 3
test

@@ -26,12 +26,13 @@ $zigup default 0.5.0
 
 testCompilerCount 3
 
-touch scratch/install/0.6.0/keep
+$zigup keep 0.6.0
 $zigup clean # doesn't delete anything because we have keepfile and master doens't get deleted
 testCompilerCount 3
 
-rm scratch/install/0.6.0/keep
-$zigup clean 2>&1 | grep "because it is master" # DOESN't delete master because we dont delete master, but DOES delete 0.6.0
+$zigup clean 0.6.0 2>&1 | grep "deleting '.*0.6.0'"
+testCompilerCount 2
+$zigup clean 2>&1 | grep "it is master" # DOESN't delete master because we dont delete master, but DOES delete 0.6.0
 testCompilerCount 2
 
 $zigup master

+ 76 - 28
zigup.zig

@@ -136,6 +136,9 @@ fn help() void {
         \\  zigup VERSION                 download and set VERSION compiler as default
         \\  zigup fetch VERSION           download VERSION compiler
         \\  zigup default [VERSION]       get or set the default compiler
+        \\  zigup clean   [VERSION]       deletes the given compiler version, otherwise, cleans all compilers
+        \\                                that aren't the default, master, or marked to keep.
+        \\  zigup keep VERSION            mark a compiler to be kept during clean
         \\
         \\Uncommon Usage:
         \\
@@ -224,11 +227,22 @@ pub fn main2() !u8 {
         return 0;
     }
     if (std.mem.eql(u8, "clean", args[0])) {
-        if (args.len != 1) {
-            std.debug.warn("Error: 'clean' command requires 0 arguments but got {}\n", .{args.len - 1});
+        if (args.len == 1) {
+            try cleanCompilers(allocator, null);
+        } else if (args.len == 2) {
+            try cleanCompilers(allocator, args[1]);
+        } else {
+            std.debug.warn("Error: 'clean' command requires 0 or 1 arguments but got {}\n", .{args.len - 1});
+            return 1;
+        }
+        return 0;
+    }
+    if (std.mem.eql(u8, "keep", args[0])) {
+        if (args.len != 2) {
+            std.debug.warn("Error: 'keep' command requires 1 argument but got {}\n", .{args.len - 1});
             return 1;
         }
-        try cleanCompilers(allocator);
+        try keepCompiler(allocator, args[1]);
         return 0;
     }
     if (std.mem.eql(u8, "list", args[0])) {
@@ -429,7 +443,27 @@ fn listCompilers(allocator: *Allocator) !void {
     }
 }
 
-fn cleanCompilers(allocator: *Allocator) !void {
+fn keepCompiler(allocator: *Allocator, compiler_version: []const u8) !void {
+    const install_dir_string = try getInstallDir(allocator, .{ .create = true });
+    defer allocator.free(install_dir_string);
+
+    // TODO openDirAbsolute in stdlib
+    var install_dir = try std.fs.cwd().openDir(install_dir_string, .{ .iterate = true });
+    defer install_dir.close();
+
+    var compiler_dir = install_dir.openDir(compiler_version, .{}) catch |e| switch (e) {
+        error.FileNotFound => {
+            std.debug.warn("Error: compiler not found: {}\n", .{compiler_version});
+            return error.AlreadyReported;
+        },
+        else => return e,
+    };
+    var keep_fd = try compiler_dir.createFile("keep", .{});
+    keep_fd.close();
+    std.debug.warn("created '{}{c}{}{c}{}'\n", .{ install_dir_string, std.fs.path.sep, compiler_version, std.fs.path.sep, "keep" });
+}
+
+fn cleanCompilers(allocator: *Allocator, compiler_name_opt: ?[]const u8) !void {
     const install_dir_string = try getInstallDir(allocator, .{ .create = true });
     defer allocator.free(install_dir_string);
     // getting the current compiler
@@ -444,37 +478,37 @@ fn cleanCompilers(allocator: *Allocator) !void {
     defer install_dir.close();
     const master_points_to_opt = try getMasterDir(allocator, &install_dir);
     defer if (master_points_to_opt) |master_points_to| allocator.free(master_points_to);
-    var it = install_dir.iterate();
-    while (try it.next()) |entry| {
-        if (entry.kind != .Directory)
-            continue;
-        if (default_comp_opt) |default_comp| {
-            if (mem.eql(u8, default_comp, entry.name)) {
-                std.debug.warn("keeping '{}' (is default compiler)\n", .{default_comp});
-                continue;
-            }
+    if (compiler_name_opt) |compiler_name| {
+        if (getKeepReason(master_points_to_opt, default_comp_opt, compiler_name)) |reason| {
+            std.debug.warn("Error: cannot clean '{}' ({})\n", .{ compiler_name, reason });
+            return error.AlreadyReported;
         }
-        if (master_points_to_opt) |master_points_to| {
-            if (mem.eql(u8, master_points_to, entry.name)) {
-                std.debug.warn("keeping '{}' (because it is master)\n", .{master_points_to});
+        std.debug.warn("deleting '{}{c}{}'\n", .{ install_dir_string, std.fs.path.sep, compiler_name });
+        try install_dir.deleteTree(compiler_name);
+    } else {
+        var it = install_dir.iterate();
+        while (try it.next()) |entry| {
+            if (entry.kind != .Directory)
+                continue;
+            if (getKeepReason(master_points_to_opt, default_comp_opt, entry.name)) |reason| {
+                std.debug.warn("keeping '{}' ({})\n", .{ entry.name, reason });
                 continue;
             }
-        }
 
-        var compiler_dir = try install_dir.openDir(entry.name, .{});
-        defer compiler_dir.close();
-        if (compiler_dir.access("keep", .{})) |_| {
-            std.debug.warn("keeping '{}' (has keep file)\n", .{entry.name});
-            continue;
-        } else |e| switch (e) {
-            error.FileNotFound => {},
-            else => return e,
+            var compiler_dir = try install_dir.openDir(entry.name, .{});
+            defer compiler_dir.close();
+            if (compiler_dir.access("keep", .{})) |_| {
+                std.debug.warn("keeping '{}' (has keep file)\n", .{entry.name});
+                continue;
+            } else |e| switch (e) {
+                error.FileNotFound => {},
+                else => return e,
+            }
+            std.debug.warn("deleting '{}{c}{}'\n", .{ install_dir_string, std.fs.path.sep, entry.name });
+            try install_dir.deleteTree(entry.name);
         }
-        std.debug.warn("deleting '{}{}{}'\n", .{ install_dir_string, std.fs.path.sep, entry.name });
-        try install_dir.deleteTree(entry.name);
     }
 }
-
 fn readDefaultCompiler(allocator: *Allocator, buffer: *[std.fs.MAX_PATH_BYTES]u8) !?[]const u8 {
     const path_link = try makeZigPathLinkString(allocator);
     defer allocator.free(path_link);
@@ -636,3 +670,17 @@ pub fn appendCommandString(appender: *appendlib.Appender(u8), argv: []const []co
         prefix = " ";
     }
 }
+
+pub fn getKeepReason(master_points_to_opt: ?[]const u8, default_compiler_opt: ?[]const u8, name: []const u8) ?[]const u8 {
+    if (default_compiler_opt) |default_comp| {
+        if (mem.eql(u8, default_comp, name)) {
+            return "is default compiler";
+        }
+    }
+    if (master_points_to_opt) |master_points_to| {
+        if (mem.eql(u8, master_points_to, name)) {
+            return "it is master";
+        }
+    }
+    return null;
+}