diff --git a/README.md b/README.md index cd03258..60ce67d 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,10 @@ Run `zig build` to build, `zig build test` to test and install with: cp zig-out/bin/zigup BIN_PATH ``` +# Building Zigup + +Zigup is currently built/tested using zig 0.11.0. + # TODO * set/remove compiler in current environment without overriding the system-wide version. diff --git a/test.zig b/test.zig index 6600b71..2e9110e 100644 --- a/test.zig +++ b/test.zig @@ -126,6 +126,41 @@ pub fn main() !u8 { dumpExecResult(result); try testing.expect(std.mem.eql(u8, result.stdout, "0.7.0\n")); } + + // verify we print a nice error message if we can't update the symlink + // because it's a directory + { + const zig_exe_link = comptime "scratch" ++ sep ++ "bin" ++ sep ++ "zig" ++ builtin.target.exeFileExt(); + + if (std.fs.cwd().access(zig_exe_link, .{})) { + try std.fs.cwd().deleteFile(zig_exe_link); + } else |err| switch (err) { + error.FileNotFound => {}, + else => |e| return e, + } + try std.fs.cwd().makeDir(zig_exe_link); + + const result = try runCaptureOuts(allocator, zigup_args ++ &[_][]const u8{ "default", "0.7.0" }); + defer { + allocator.free(result.stdout); + allocator.free(result.stderr); + } + dumpExecResult(result); + switch (result.term) { + .Exited => |code| try testing.expectEqual(@as(u8, 1), code), + else => |term| std.debug.panic("unexpected exit {}", .{term}), + } + if (builtin.os.tag == .windows) { + try testing.expect(std.mem.containsAtLeast(u8, result.stderr, 1, "unable to create the exe link, the path '")); + try testing.expect(std.mem.containsAtLeast(u8, result.stderr, 1, "' is a directory")); + } else { + try testing.expect(std.mem.containsAtLeast(u8, result.stderr, 1, "unable to update/overwrite the 'zig' PATH symlink, the file '")); + try testing.expect(std.mem.containsAtLeast(u8, result.stderr, 1, "' already exists and is not a symlink")); + } + + try std.fs.cwd().deleteDir(zig_exe_link); + } + { const result = try runCaptureOuts(allocator, zigup_args ++ &[_][]const u8{ "fetch", "0.7.0" }); defer { diff --git a/zigup.zig b/zigup.zig index 413d30d..13a2f10 100644 --- a/zigup.zig +++ b/zigup.zig @@ -466,6 +466,13 @@ pub fn loggyUpdateSymlink(target_path: []const u8, sym_link_path: []const u8, fl try std.os.unlink(sym_link_path); } else |e| switch (e) { error.FileNotFound => {}, + error.NotLink => { + std.debug.print( + "unable to update/overwrite the 'zig' PATH symlink, the file '{s}' already exists and is not a symlink\n", + .{ sym_link_path}, + ); + std.os.exit(1); + }, else => return e, } try loggySymlinkAbsolute(target_path, sym_link_path, flags); @@ -725,6 +732,9 @@ fn verifyPathLink(allocator: Allocator, path_link: []const u8) !void { while (path_it.next()) |path| { switch (try compareDir(path_link_dir_id, path)) { .missing => continue, + // can't be the same directory because we were able to open and get + // the file id for path_link_dir_id + .access_denied => {}, .match => return, .mismatch => {}, } @@ -751,6 +761,9 @@ fn verifyPathLink(allocator: Allocator, path_link: []const u8) !void { while (path_it.next()) |path| { switch (try compareDir(path_link_dir_id, path)) { .missing => continue, + // can't be the same directory because we were able to open and get + // the file id for path_link_dir_id + .access_denied => {}, .match => return, .mismatch => {}, } @@ -764,9 +777,10 @@ fn verifyPathLink(allocator: Allocator, path_link: []const u8) !void { return error.AlreadyReported; } -fn compareDir(dir_id: FileId, other_dir: []const u8) !enum { missing, match, mismatch } { +fn compareDir(dir_id: FileId, other_dir: []const u8) !enum { missing, access_denied, match, mismatch } { var dir = std.fs.cwd().openDir(other_dir, .{}) catch |err| switch (err) { error.FileNotFound, error.NotDir, error.BadPathName => return .missing, + error.AccessDenied => return .access_denied, else => |e| return e, }; defer dir.close(); @@ -776,6 +790,7 @@ fn compareDir(dir_id: FileId, other_dir: []const u8) !enum { missing, match, mis fn enforceNoZig(path_link: []const u8, exe: []const u8) !void { var file = std.fs.cwd().openFile(exe, .{}) catch |err| switch (err) { error.FileNotFound, error.IsDir => return, + error.AccessDenied => return, // if there is a Zig it must not be accessible else => |e| return e, }; defer file.close(); @@ -868,7 +883,16 @@ fn createExeLink(link_target: []const u8, path_link: []const u8) !void { std.debug.print("Error: path_link (size {}) is too large (max {})\n", .{ path_link.len, std.fs.MAX_PATH_BYTES }); return error.AlreadyReported; } - const file = try std.fs.cwd().createFile(path_link, .{}); + const file = std.fs.cwd().createFile(path_link, .{}) catch |err| switch (err) { + error.IsDir => { + std.debug.print( + "unable to create the exe link, the path '{s}' is a directory\n", + .{ path_link}, + ); + std.os.exit(1); + }, + else => |e| return e, + }; defer file.close(); try file.writer().writeAll(win32exelink.content[0..win32exelink.exe_offset]); try file.writer().writeAll(link_target);